Skip to content

Commit 92b7959

Browse files
authored
Merge pull request #1461 from fnc12/feature/hidden-vtab-columns
Hidden virtual table columns and table-valued functions
2 parents 20855b8 + d2ed6a0 commit 92b7959

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2239
-539
lines changed

dev/alias_traits.h

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
#pragma once
22

33
#ifndef SQLITE_ORM_IMPORT_STD_MODULE
4-
#include <type_traits> // std::is_base_of, std::is_same
5-
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
4+
#include <type_traits> // std::is_base_of, std::is_same, std::remove_const
5+
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
66
#include <concepts>
77
#endif
88
#endif
99

1010
#include "functional/cxx_type_traits_polyfill.h"
1111
#include "type_traits.h"
12-
#include "table_reference.h"
1312

1413
SQLITE_ORM_EXPORT namespace sqlite_orm {
1514

@@ -20,6 +19,22 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
2019

2120
namespace sqlite_orm {
2221
namespace internal {
22+
template<class O>
23+
struct table_reference;
24+
25+
template<class RecordSet>
26+
struct decay_table_ref : std::remove_const<RecordSet> {};
27+
template<class O>
28+
struct decay_table_ref<table_reference<O>> : polyfill::type_identity<O> {};
29+
template<class O>
30+
struct decay_table_ref<const table_reference<O>> : polyfill::type_identity<O> {};
31+
32+
template<class RecordSet>
33+
using decay_table_ref_t = typename decay_table_ref<RecordSet>::type;
34+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
35+
template<auto recordset>
36+
using auto_decay_table_ref_t = typename decay_table_ref<decltype(recordset)>::type;
37+
#endif
2338

2439
template<class A>
2540
inline constexpr bool is_alias_v = std::is_base_of<alias_tag, A>::value;
@@ -36,6 +51,13 @@ namespace sqlite_orm {
3651
template<class A>
3752
struct is_column_alias : is_alias<A> {};
3853

54+
template<class O>
55+
inline constexpr bool is_table_reference_v =
56+
polyfill::is_specialization_of_v<std::remove_const_t<O>, table_reference>;
57+
58+
template<class R>
59+
struct is_table_reference : polyfill::bool_constant<is_table_reference_v<R>> {};
60+
3961
/** @short Alias of any type of record set, see `orm_recordset_alias`.
4062
*/
4163
template<class A>
@@ -68,11 +90,20 @@ namespace sqlite_orm {
6890

6991
template<class A>
7092
using is_cte_moniker = polyfill::bool_constant<is_cte_moniker_v<A>>;
93+
94+
/** @short Referring to a recordset.
95+
*/
96+
template<class T>
97+
inline constexpr bool is_referring_to_recordset_v =
98+
polyfill::disjunction_v<is_table_reference<T>, is_recordset_alias<T>>;
99+
100+
template<class T>
101+
using is_referring_to_recordset = polyfill::bool_constant<is_referring_to_recordset_v<T>>;
71102
}
72103
}
73104

74105
SQLITE_ORM_EXPORT namespace sqlite_orm {
75-
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
106+
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
76107
template<class A>
77108
concept orm_alias = std::derived_from<A, alias_tag>;
78109

@@ -85,6 +116,14 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
85116
template<class A>
86117
concept orm_column_alias = (orm_alias<A> && !orm_names_type<A>);
87118

119+
/** @short Specifies that a type is a reference of a concrete table, especially of a derived class.
120+
*
121+
* A concrete table reference has the following traits:
122+
* - specialization of `table_reference`, whose `type` typename references a mapped object.
123+
*/
124+
template<class O>
125+
concept orm_table_reference = polyfill::is_specialization_of_v<std::remove_const_t<O>, internal::table_reference>;
126+
88127
/** @short Specifies that a type is an alias of any type of record set.
89128
*
90129
* A record set alias has the following traits:

dev/ast/match.h

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,51 @@
11
#pragma once
22

33
#ifndef SQLITE_ORM_IMPORT_STD_MODULE
4-
#include <utility>
4+
#include <utility> // std::move
55
#endif
66

7-
namespace sqlite_orm {
8-
namespace internal {
7+
#include "../type_traits.h"
98

10-
template<class T, class X>
11-
struct match_t {
12-
using mapped_type = T;
13-
using argument_type = X;
9+
namespace sqlite_orm::internal {
10+
template<class T, class X>
11+
struct match_with_table_t {
12+
using mapped_type = T;
13+
using argument_type = X;
1414

15-
argument_type argument;
16-
};
17-
}
15+
argument_type argument;
16+
};
17+
18+
/*
19+
* Alternative equality comparison where the left side is always a field.
20+
*/
21+
template<class Field, class X>
22+
struct match_t {
23+
using field_type = Field;
24+
using argument_type = X;
25+
26+
field_type field;
27+
argument_type argument;
28+
};
1829
}
1930

2031
SQLITE_ORM_EXPORT namespace sqlite_orm {
32+
/**
33+
* [Deprecation notice] This expression factory function is deprecated and will be removed in v1.11.
34+
*/
2135
template<class T, class X>
22-
internal::match_t<T, X> match(X argument) {
36+
[[deprecated(
37+
"Use the `match` function accepting the hidden FTS5 'any' field or a field of your FTS table instead")]]
38+
constexpr internal::match_with_table_t<T, X> match(X argument) {
2339
return {std::move(argument)};
2440
}
41+
42+
template<class CP, class X>
43+
constexpr internal::match_t<CP, X> match(CP field, X argument) {
44+
return {std::move(field), std::move(argument)};
45+
}
46+
47+
template<class O, class F, class X>
48+
constexpr internal::match_t<F O::*, X> match(F O::* field, X argument) {
49+
return {field, std::move(argument)};
50+
}
2551
}

dev/ast/rank.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ namespace sqlite_orm {
77
}
88

99
SQLITE_ORM_EXPORT namespace sqlite_orm {
10+
/**
11+
* [Deprecation notice] This expression factory function is deprecated and will be removed in v1.11.
12+
*/
13+
[[deprecated("Use the hidden FTS5 rank column instead")]]
1014
inline internal::rank_t rank() {
1115
return {};
1216
}

dev/ast_iterator.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,18 @@ namespace sqlite_orm {
103103
};
104104

105105
template<class T, class X>
106-
struct ast_iterator<match_t<T, X>, void> {
107-
using node_type = match_t<T, X>;
106+
struct ast_iterator<match_with_table_t<T, X>, void> {
107+
using node_type = match_with_table_t<T, X>;
108+
109+
template<class L>
110+
SQLITE_ORM_STATIC_CALLOP void operator()(const node_type& node, L& lambda) SQLITE_ORM_OR_CONST_CALLOP {
111+
iterate_ast(node.argument, lambda);
112+
}
113+
};
114+
115+
template<class Field, class X>
116+
struct ast_iterator<match_t<Field, X>, void> {
117+
using node_type = match_t<Field, X>;
108118

109119
template<class L>
110120
SQLITE_ORM_STATIC_CALLOP void operator()(const node_type& node, L& lambda) SQLITE_ORM_OR_CONST_CALLOP {
@@ -158,6 +168,27 @@ namespace sqlite_orm {
158168
}
159169
};
160170

171+
template<class T>
172+
struct ast_iterator<T, match_if<is_table_valued_expression, T>> {
173+
using node_type = T;
174+
175+
template<class L>
176+
SQLITE_ORM_STATIC_CALLOP void operator()(const node_type& expression,
177+
L& lambda) SQLITE_ORM_OR_CONST_CALLOP {
178+
iterate_ast(expression.table_values, lambda);
179+
}
180+
};
181+
182+
template<class T>
183+
struct ast_iterator<T, match_if<is_from2, T>> {
184+
using node_type = T;
185+
186+
template<class L>
187+
SQLITE_ORM_STATIC_CALLOP void operator()(const node_type& from, L& lambda) SQLITE_ORM_OR_CONST_CALLOP {
188+
iterate_ast(from.table_expressions, lambda);
189+
}
190+
};
191+
161192
template<class C>
162193
struct ast_iterator<where_t<C>, void> {
163194
using node_type = where_t<C>;

dev/column_pointer.h

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#pragma once
22

33
#ifndef SQLITE_ORM_IMPORT_STD_MODULE
4-
#include <type_traits> // std::enable_if, std::is_convertible
4+
#include <type_traits> // std::enable_if, std::is_convertible, std::is_base_of
55
#include <utility> // std::move
66
#endif
77

@@ -53,49 +53,45 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
5353
*/
5454
template<class O, class Base, class F, internal::satisfies_not<internal::is_recordset_alias, O> = true>
5555
constexpr internal::column_pointer<O, F Base::*> column(F Base::* field) {
56-
static_assert(std::is_convertible<F Base::*, F O::*>::value, "Field must be from derived class");
56+
static_assert(std::is_convertible<F Base::*, F O::*>::value ||
57+
std::is_same<polyfill::detected_t<internal::enclosing_type_of_t, Base, O>, O>::value ||
58+
// trust the `enclosing_type` alias template defined in the virtual table's data struct
59+
polyfill::is_detected_v<internal::enclosing_type_t, Base>,
60+
"Field must be from derived or related class");
5761
return {field};
5862
}
5963

6064
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
6165
/**
6266
* Explicitly refer to a column.
6367
*/
64-
template<orm_table_reference auto table, class O, class F>
65-
constexpr auto column(F O::* field) {
68+
template<orm_table_reference auto table, class Base, class F>
69+
constexpr auto column(F Base::* field) {
6670
return column<internal::auto_type_t<table>>(field);
6771
}
72+
#endif
6873

6974
// Intentionally place pointer-to-member operator for table references in the internal namespace
7075
// to facilitate ADL (Argument Dependent Lookup)
7176
namespace internal {
77+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
7278
/**
7379
* Explicitly refer to a column.
7480
*/
75-
template<orm_table_reference R, class O, class F>
76-
constexpr auto operator->*(const R& /*table*/, F O::* field) {
81+
template<orm_table_reference R, class Base, class F>
82+
constexpr auto operator->*(const R& /*table*/, F Base::* field) {
83+
return column<typename R::type>(field);
84+
}
85+
#else
86+
/**
87+
* Explicitly refer to a column.
88+
*/
89+
template<class R, class Base, class F, std::enable_if_t<internal::is_table_reference_v<R>, bool> = true>
90+
constexpr auto operator->*(const R& /*table*/, F Base::* field) {
7791
return column<typename R::type>(field);
7892
}
79-
}
80-
81-
/**
82-
* Make a table reference.
83-
*/
84-
template<class O>
85-
requires (!orm_recordset_alias<O>)
86-
consteval internal::table_reference<O> column() {
87-
return {};
88-
}
89-
90-
/**
91-
* Make a table reference.
92-
*/
93-
template<class O>
94-
requires (!orm_recordset_alias<O>)
95-
consteval internal::table_reference<O> c() {
96-
return {};
97-
}
9893
#endif
94+
}
9995

10096
#if (SQLITE_VERSION_NUMBER >= 3008003) && defined(SQLITE_ORM_WITH_CTE)
10197
/**

0 commit comments

Comments
 (0)