Skip to content

Commit fcbfb11

Browse files
committed
Considered base members for reflected views/tables
1 parent 68382d8 commit fcbfb11

6 files changed

Lines changed: 100 additions & 48 deletions

File tree

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
/**

include/sqlite_orm/sqlite_orm.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13778,7 +13778,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
1377813778
#ifndef SQLITE_ORM_IMPORT_STD_MODULE
1377913779
#ifdef SQLITE_ORM_REFLECTION_SUPPORTED
1378013780
#include <array> // std::array
13781-
#include <meta> // std::meta::access_context, std::meta::nonstatic_data_members_of, std::meta::identifier_of, std::meta::annotations_of
13781+
#include <meta> // std::define_static_array, std::meta::access_context, std::meta::nonstatic_data_members_of, std::meta::identifier_of, std::meta::annotations_of
1378213782
#include <tuple> // std::tuple
1378313783
#include <utility> // std::index_sequence, std::make_index_sequence
1378413784
#endif
@@ -13787,17 +13787,29 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
1378713787
#ifdef SQLITE_ORM_REFLECTION_SUPPORTED
1378813788
namespace sqlite_orm::internal {
1378913789
/**
13790-
* Reflects the non-static data members of `T` and returns them as a fixed-size array
13791-
* of `std::meta::info` reflections.
13790+
* Reflects the non-static data members of `T` and its base classes
13791+
* and returns them as a fixed-size span of `std::meta::info` reflections.
1379213792
*/
1379313793
template<class T>
1379413794
consteval auto extract_members() {
1379513795
constexpr auto ctx = std::meta::access_context::current();
13796-
constexpr size_t N = nonstatic_data_members_of(^^T, ctx).size();
1379713796

13798-
return [&ctx]<size_t... I>(std::index_sequence<I...>) consteval {
13799-
return std::array<std::meta::info, N>{nonstatic_data_members_of(^^T, ctx)[I]...};
13800-
}(std::make_index_sequence<N>{});
13797+
constexpr auto collect = []<class U>(this const auto& self) -> std::vector<std::meta::info> {
13798+
std::vector<std::meta::info> result;
13799+
13800+
// Recurse into direct base classes first (preserves layout order)
13801+
template for (constexpr std::meta::info base: std::define_static_array(bases_of(^^U, ctx))) {
13802+
using base_type = typename[:type_of(base):];
13803+
result.append_range(self.template operator()<base_type>());
13804+
}
13805+
13806+
// Then this class's own non-static data members
13807+
result.append_range(nonstatic_data_members_of(^^U, ctx));
13808+
13809+
return result;
13810+
};
13811+
13812+
return std::define_static_array(collect.template operator()<T>());
1380113813
}
1380213814

1380313815
/**

tests/schema/view_tests.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace {
1717
};
1818
}
1919

20-
TEST_CASE("make_view - name resolution") {
20+
TEST_CASE("view make_view name resolution") {
2121
struct User {
2222
int64 id = 0;
2323
std::string name;
@@ -40,13 +40,26 @@ TEST_CASE("view::find_column_name") {
4040
std::string name;
4141
};
4242

43-
auto view = make_view<UserViewSchemaTests>(select(asterisk<User>()));
43+
SECTION("direct") {
44+
auto view = make_view<UserViewSchemaTests>(select(asterisk<User>()));
45+
46+
SECTION("fields") {
47+
REQUIRE((view.find_column_name(&UserViewSchemaTests::id) &&
48+
*view.find_column_name(&UserViewSchemaTests::id) == "id"));
49+
REQUIRE((view.find_column_name(&UserViewSchemaTests::name) &&
50+
*view.find_column_name(&UserViewSchemaTests::name) == "name"));
51+
}
52+
}
53+
SECTION("derived") {
54+
struct DerivedUserView : UserViewSchemaTests {};
55+
auto view = make_view<DerivedUserView>(select(asterisk<User>()));
4456

45-
SECTION("fields") {
46-
REQUIRE((view.find_column_name(&UserViewSchemaTests::id) &&
47-
*view.find_column_name(&UserViewSchemaTests::id) == "id"));
48-
REQUIRE((view.find_column_name(&UserViewSchemaTests::name) &&
49-
*view.find_column_name(&UserViewSchemaTests::name) == "name"));
57+
SECTION("fields") {
58+
REQUIRE((view.find_column_name(&UserViewSchemaTests::id) &&
59+
*view.find_column_name(&UserViewSchemaTests::id) == "id"));
60+
REQUIRE((view.find_column_name(&UserViewSchemaTests::name) &&
61+
*view.find_column_name(&UserViewSchemaTests::name) == "name"));
62+
}
5063
}
5164
}
5265
#endif

tests/statement_serializer_tests/schema/view.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
using namespace sqlite_orm;
77
using internal::serialize;
88

9-
struct[[= dbo_name("user_view")]] UserViewSerializerTests {
10-
int id = 0;
11-
std::string name;
12-
};
9+
namespace {
10+
struct[[= dbo_name("user_view")]] UserViewSerializerTests {
11+
int id = 0;
12+
std::string name;
13+
};
14+
}
1315

14-
TEST_CASE("statement_serializer query_view") {
16+
TEST_CASE("view statement_serializer") {
1517
struct User {
1618
int id = 0;
1719
std::string name;

tests/static_tests/view_static_tests.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ using namespace sqlite_orm;
77
using internal::col_index_sequence_of, internal::col_index_sequence_with_field_type;
88
using internal::is_column;
99

10-
struct[[= dbo_name("user_view")]] UserViewStaticTests {
11-
int id = 0;
12-
std::string name;
13-
};
10+
namespace {
11+
struct[[= dbo_name("user_view")]] UserViewStaticTests {
12+
int id = 0;
13+
std::string name;
14+
};
1415
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
15-
constexpr orm_table_reference auto user_view = c<UserViewStaticTests>();
16+
constexpr orm_table_reference auto user_view = c<UserViewStaticTests>();
1617
#endif
18+
}
1719

1820
TEST_CASE("view static count_of<is_column>()") {
1921
struct User {
@@ -28,6 +30,15 @@ TEST_CASE("view static count_of<is_column>()") {
2830
STATIC_REQUIRE(col_index_sequence_of<elements_type>::size() == 2);
2931
STATIC_REQUIRE(col_index_sequence_with_field_type<elements_type, int>::size() == 1);
3032
}
33+
SECTION("derived") {
34+
struct DerivedUserView : UserViewStaticTests {};
35+
36+
auto view = make_view<DerivedUserView>(select(asterisk<User>()));
37+
using elements_type = decltype(view.elements);
38+
STATIC_REQUIRE(view.count_of<is_column>() == 2);
39+
STATIC_REQUIRE(col_index_sequence_of<elements_type>::size() == 2);
40+
STATIC_REQUIRE(col_index_sequence_with_field_type<elements_type, int>::size() == 1);
41+
}
3142
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
3243
SECTION("table reference") {
3344
auto view = make_view<user_view>(select(asterisk<User>()));

tests/view_tests.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,34 @@
66
#ifdef SQLITE_ORM_REFLECTION_SUPPORTED
77
using namespace sqlite_orm;
88

9-
struct[[= dbo_name("user_view")]] UserViewTests {
10-
int id = 0;
11-
std::string name;
9+
namespace {
10+
struct[[= dbo_name("user_view")]] UserViewTests {
11+
int id = 0;
12+
std::string name;
1213

1314
#ifdef SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED
14-
bool operator==(const UserViewTests&) const = default;
15+
bool operator==(const UserViewTests&) const = default;
1516
#else
16-
bool operator==(const UserViewTests& right) const {
17-
return id == right.id && name == right.name;
18-
}
17+
bool operator==(const UserViewTests& right) const {
18+
return id == right.id && name == right.name;
19+
}
1920
#endif
20-
};
21+
};
2122

22-
struct[[= dbo_name("user_view")]] UserView2Tests {
23-
std::string name;
23+
struct[[= dbo_name("user_view")]] UserView2Tests {
24+
std::string name;
2425

2526
#ifdef SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED
26-
bool operator==(const UserView2Tests&) const = default;
27+
bool operator==(const UserView2Tests&) const = default;
2728
#else
28-
bool operator==(const UserView2Tests& right) const {
29-
return name == right.name;
30-
}
29+
bool operator==(const UserView2Tests& right) const {
30+
return name == right.name;
31+
}
3132
#endif
32-
};
33+
};
34+
}
3335

34-
TEST_CASE("sql view") {
36+
TEST_CASE("view") {
3537
using Catch::Matchers::UnorderedEquals;
3638

3739
struct User {
@@ -90,7 +92,7 @@ TEST_CASE("sql view") {
9092
}
9193
}
9294

93-
TEST_CASE("sync sql view") {
95+
TEST_CASE("view sync") {
9496
struct User {
9597
int id = 0;
9698
std::string name;

0 commit comments

Comments
 (0)