Skip to content

Commit c40be77

Browse files
committed
Merge branch 'experimental/sql-view' into dbo-reflection
2 parents 5d08a35 + eb8f233 commit c40be77

17 files changed

Lines changed: 267 additions & 157 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ jobs:
9191
# ===================
9292
linux:
9393
runs-on: ${{ matrix.os }}
94+
continue-on-error: ${{ matrix.experimental || false }}
9495
strategy:
9596
fail-fast: false
9697
matrix:
@@ -111,6 +112,33 @@ jobs:
111112
install_compiler: true
112113
compiler_package: g++-10
113114

115+
- name: "clang-14, C++23 (early)"
116+
os: ubuntu-22.04
117+
cc: clang-14
118+
cxx: clang++-14
119+
cxx_standard: "-DSQLITE_ORM_ENABLE_CXX_23=ON"
120+
install_compiler: true
121+
compiler_package: clang-14
122+
experimental: true
123+
124+
- name: "gcc-11, C++23 (early)"
125+
os: ubuntu-22.04
126+
cc: gcc-11
127+
cxx: g++-11
128+
cxx_standard: "-DSQLITE_ORM_ENABLE_CXX_23=ON"
129+
install_compiler: true
130+
compiler_package: g++-11
131+
experimental: true
132+
133+
- name: "gcc-16, C++26"
134+
os: ubuntu-24.04
135+
cc: gcc-16
136+
cxx: g++-16
137+
cxx_standard: "-DSQLITE_ORM_ENABLE_CXX_26=ON"
138+
install_compiler: true
139+
compiler_package: g++-16
140+
compiler_ppa: ppa:ubuntu-toolchain-r/test
141+
114142
name: Linux - ${{ matrix.name }}
115143

116144
env:
@@ -124,6 +152,9 @@ jobs:
124152
- name: Install compiler
125153
if: matrix.install_compiler
126154
run: |
155+
if [ -n "${{ matrix.compiler_ppa }}" ]; then
156+
sudo add-apt-repository -y ${{ matrix.compiler_ppa }}
157+
fi
127158
sudo apt-get update
128159
sudo apt-get install -y ${{ matrix.compiler_package }}
129160

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ cmake-build-debug/
99
build/
1010
build-xcode/
1111
build-code-edit/
12+
build-local/
1213
*.sqlite
13-
*.db
14+
*.db

dev/functional/config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
#define SQLITE_ORM_CPP20_RANGES_SUPPORTED
5656
#endif
5757

58+
#if __cpp_lib_ranges >= 202110L && !defined(SQLITE_ORM_BROKEN_CPP20_VIEWS)
59+
#define SQLITE_ORM_CPP20_VIEWS_SUPPORTED
60+
#endif
61+
5862
#if __cpp_lib_generator >= 202207L
5963
#define SQLITE_ORM_CPP23_GENERATOR_SUPPORTED
6064
#endif

dev/functional/cxx_compiler_quirks.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,7 @@
7272
#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && (defined(__clang__) && (__clang_major__ == 10))
7373
#define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS
7474
#endif
75+
76+
#if defined(__clang__) && (__clang_major__ <= 15)
77+
#define SQLITE_ORM_BROKEN_CPP20_VIEWS
78+
#endif

dev/functional/meta_util.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#ifndef SQLITE_ORM_IMPORT_STD_MODULE
44
#ifdef SQLITE_ORM_REFLECTION_SUPPORTED
55
#include <array> // std::array
6-
#include <meta> // std::meta::access_context, std::meta::nonstatic_data_members_of, std::meta::identifier_of, std::meta::annotations_of
6+
#include <meta> // std::define_static_array, std::meta::access_context, std::meta::nonstatic_data_members_of, std::meta::identifier_of, std::meta::annotations_of
77
#include <tuple> // std::tuple
88
#include <utility> // std::index_sequence, std::make_index_sequence
99
#endif
@@ -12,17 +12,29 @@
1212
#ifdef SQLITE_ORM_REFLECTION_SUPPORTED
1313
namespace sqlite_orm::internal {
1414
/**
15-
* Reflects the non-static data members of `T` and returns them as a fixed-size array
16-
* of `std::meta::info` reflections.
15+
* Reflects the non-static data members of `T` and its base classes
16+
* and returns them as a fixed-size span of `std::meta::info` reflections.
1717
*/
1818
template<class T>
1919
consteval auto extract_members() {
2020
constexpr auto ctx = std::meta::access_context::current();
21-
constexpr size_t N = nonstatic_data_members_of(^^T, ctx).size();
2221

23-
return [&ctx]<size_t... I>(std::index_sequence<I...>) consteval {
24-
return std::array<std::meta::info, N>{nonstatic_data_members_of(^^T, ctx)[I]...};
25-
}(std::make_index_sequence<N>{});
22+
constexpr auto collect = []<class U>(this const auto& self) -> std::vector<std::meta::info> {
23+
std::vector<std::meta::info> result;
24+
25+
// Recurse into direct base classes first (preserves layout order)
26+
template for (constexpr std::meta::info base : std::define_static_array(bases_of(^^U, ctx))) {
27+
using base_type = typename[:type_of(base):];
28+
result.append_range(self.template operator()<base_type>());
29+
}
30+
31+
// Then this class's own non-static data members
32+
result.append_range(nonstatic_data_members_of(^^U, ctx));
33+
34+
return result;
35+
};
36+
37+
return std::define_static_array(collect.template operator()<T>());
2638
}
2739

2840
/**

dev/schema/dbo_name.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ namespace sqlite_orm::internal {
2727
* has no linkage), so a self-contained fixed-size byte array is required.
2828
*/
2929
template<size_t N>
30-
struct dbo_name_t : cstring_literal<N> {
31-
constexpr dbo_name_t(const char (&cstr)[N]) : cstring_literal<N>{cstr} {}
30+
struct dbo_name_literal : cstring_literal<N> {
31+
constexpr dbo_name_literal(const char (&cstr)[N]) : cstring_literal<N>{cstr} {}
3232

3333
constexpr auto name() const noexcept {
3434
return this->cstr;
@@ -39,13 +39,13 @@ namespace sqlite_orm::internal {
3939
constexpr bool is_dbo_name_v = false;
4040

4141
template<size_t N>
42-
constexpr bool is_dbo_name_v<dbo_name_t<N>> = true;
42+
constexpr bool is_dbo_name_v<dbo_name_literal<N>> = true;
4343

4444
template<class T>
4545
using is_dbo_name = std::bool_constant<is_dbo_name_v<T>>;
4646

4747
/**
48-
* Returns the database object name carried by the `dbo_name_t<…>` element of `annotations`,
48+
* Returns the database object name carried by the `dbo_name_literal<…>` element of `annotations`,
4949
* or the type's reflected identifier when no such element is present.
5050
*/
5151
template<class T, class Tuple>
@@ -60,7 +60,7 @@ namespace sqlite_orm::internal {
6060
}
6161

6262
/**
63-
* Returns a copy of `tuple` with all `dbo_name_t<…>` elements removed.
63+
* Returns a copy of `tuple` with all `dbo_name_literal<…>` elements removed.
6464
*/
6565
template<class Tuple>
6666
constexpr auto filter_out_dbo_name(Tuple&& tuple) {
@@ -77,7 +77,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
7777
* the name falls back to `T`'s reflected identifier.
7878
*/
7979
template<size_t N>
80-
constexpr internal::dbo_name_t<N> dbo_name(const char (&dboName)[N]) {
80+
constexpr internal::dbo_name_literal<N> dbo_name(const char (&dboName)[N]) {
8181
return {dboName};
8282
}
8383
}

dev/statement_serializer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ namespace sqlite_orm::internal {
18181818
const Ctx&) SQLITE_ORM_OR_CONST_CALLOP {
18191819
std::stringstream ss;
18201820
ss << "SET ";
1821-
#ifdef SQLITE_ORM_CPP20_RANGES_SUPPORTED
1821+
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
18221822
ss << streaming_serialized(statement | std::views::transform(&dynamic_set_entry::serialized_value));
18231823
#else
18241824
int index = 0;

dev/storage_base.h

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,19 @@ namespace sqlite_orm::internal {
159159
* Calls `DROP VIEW "viewName"`.
160160
* More info: https://www.sqlite.org/lang_droptable.html
161161
*/
162-
void drop_view(const std::string& tableName) {
162+
void drop_view(const std::string& viewName) {
163163
auto connection = this->get_connection();
164-
this->drop_view_internal(connection.get(), tableName, false);
164+
this->drop_view_internal(connection.get(), viewName, false);
165165
}
166166

167167
/**
168168
* Drops the view with the specified name if it exists.
169169
* Calls `DROP VIEW IF EXISTS "viewName"`.
170170
* More info: https://www.sqlite.org/lang_droptable.html
171171
*/
172-
void drop_view_if_exists(const std::string& tableName) {
172+
void drop_view_if_exists(const std::string& viewName) {
173173
auto connection = this->get_connection();
174-
this->drop_view_internal(connection.get(), tableName, true);
174+
this->drop_view_internal(connection.get(), viewName, true);
175175
}
176176

177177
/**
@@ -210,58 +210,24 @@ namespace sqlite_orm::internal {
210210
*/
211211
bool table_exists(const std::string& tableName) {
212212
auto connection = this->get_connection();
213-
return this->table_exists(connection.get(), tableName);
213+
return this->object_exists(connection.get(), "table", tableName);
214214
}
215215

216216
bool table_exists(sqlite3* db, const std::string& tableName) const {
217-
bool result = false;
218-
std::string sql;
219-
{
220-
std::stringstream ss;
221-
ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = " << quote_string_literal("table")
222-
<< " AND name = " << quote_string_literal(tableName) << std::flush;
223-
sql = ss.str();
224-
}
225-
this->executor.perform_exec(
226-
db,
227-
sql,
228-
[](void* userData, int /*argc*/, orm_gsl::zstring* argv, orm_gsl::zstring* /*azColName*/) -> int {
229-
auto& res = *(bool*)userData;
230-
res = !!atoi(argv[0]);
231-
return 0;
232-
},
233-
&result);
234-
return result;
217+
return this->object_exists(db, "table", tableName);
235218
}
236219

237220
/**
238221
* Directly checks the actual database whether the specified view exists, bypassing the library's 'storage' mapping.
239222
* @return true if view with the specified name exists in the database, false otherwise.
240223
*/
241-
bool view_exists(const std::string& tableName) {
224+
bool view_exists(const std::string& viewName) {
242225
auto connection = this->get_connection();
243-
return this->view_exists(connection.get(), tableName);
226+
return this->object_exists(connection.get(), "view", viewName);
244227
}
245228

246-
bool view_exists(sqlite3* db, const std::string& tableName) const {
247-
bool result = false;
248-
std::string sql;
249-
{
250-
std::stringstream ss;
251-
ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = " << quote_string_literal("view")
252-
<< " AND name = " << quote_string_literal(tableName) << std::flush;
253-
sql = ss.str();
254-
}
255-
this->executor.perform_exec(
256-
db,
257-
sql,
258-
[](void* userData, int /*argc*/, orm_gsl::zstring* argv, orm_gsl::zstring* /*azColName*/) -> int {
259-
auto& res = *(bool*)userData;
260-
res = !!atoi(argv[0]);
261-
return 0;
262-
},
263-
&result);
264-
return result;
229+
bool view_exists(sqlite3* db, const std::string& viewName) const {
230+
return this->object_exists(db, "view", viewName);
265231
}
266232

267233
void add_generated_cols(std::vector<const table_xinfo*>& columnsToAdd,
@@ -1151,6 +1117,23 @@ namespace sqlite_orm::internal {
11511117
this->executor.perform_void_exec(db, ss.str().c_str());
11521118
}
11531119

1120+
bool object_exists(sqlite3* db, const std::string& type, const std::string& name) const {
1121+
bool result = false;
1122+
std::stringstream ss;
1123+
ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = " << quote_string_literal(type)
1124+
<< " AND name = " << quote_string_literal(name) << std::flush;
1125+
this->executor.perform_exec(
1126+
db,
1127+
ss.str(),
1128+
[](void* userData, int /*argc*/, orm_gsl::zstring* argv, orm_gsl::zstring* /*azColName*/) -> int {
1129+
auto& res = *(bool*)userData;
1130+
res = !!atoi(argv[0]);
1131+
return 0;
1132+
},
1133+
&result);
1134+
return result;
1135+
}
1136+
11541137
std::string retrieve_object_sql(sqlite3* db, const std::string& type, const std::string& name) const {
11551138
std::string result;
11561139
std::stringstream ss;

0 commit comments

Comments
 (0)