Skip to content

Commit db8f444

Browse files
committed
Added support for primary key table constraint with inheritance
Like for foreign keys, primary keys now accept an explicit template parameter for a derived class. Additionally: * Unit tests for primary key table constraints with inheritance * Split primary key table and column constraint tests * Creating primary keys can be done at compile-time * Foreign keys can be counted at compile-time
1 parent b8eb4e1 commit db8f444

File tree

8 files changed

+363
-241
lines changed

8 files changed

+363
-241
lines changed

dev/constraints.h

+36-17
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ namespace sqlite_orm {
5454
return *this;
5555
}
5656
#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED
57-
primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {}
57+
constexpr primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {}
5858
#endif
5959
};
6060

@@ -65,59 +65,58 @@ namespace sqlite_orm {
6565
*/
6666
template<class... Cs>
6767
struct primary_key_t : primary_key_base {
68-
using self = primary_key_t<Cs...>;
6968
using order_by = primary_key_base::order_by;
7069
using columns_tuple = std::tuple<Cs...>;
7170

7271
columns_tuple columns;
7372

74-
primary_key_t(columns_tuple columns) : columns(std::move(columns)) {}
73+
constexpr primary_key_t(columns_tuple columns) : columns(std::move(columns)) {}
7574

76-
self asc() const {
75+
constexpr primary_key_t asc() const {
7776
auto res = *this;
7877
res.options.asc_option = order_by::ascending;
7978
return res;
8079
}
8180

82-
self desc() const {
81+
constexpr primary_key_t desc() const {
8382
auto res = *this;
8483
res.options.asc_option = order_by::descending;
8584
return res;
8685
}
8786

88-
primary_key_with_autoincrement<self> autoincrement() const {
87+
constexpr primary_key_with_autoincrement<primary_key_t> autoincrement() const {
8988
return {*this};
9089
}
9190

92-
self on_conflict_rollback() const {
91+
constexpr primary_key_t on_conflict_rollback() const {
9392
auto res = *this;
9493
res.options.conflict_clause_is_on = true;
9594
res.options.conflict_clause = conflict_clause_t::rollback;
9695
return res;
9796
}
9897

99-
self on_conflict_abort() const {
98+
constexpr primary_key_t on_conflict_abort() const {
10099
auto res = *this;
101100
res.options.conflict_clause_is_on = true;
102101
res.options.conflict_clause = conflict_clause_t::abort;
103102
return res;
104103
}
105104

106-
self on_conflict_fail() const {
105+
constexpr primary_key_t on_conflict_fail() const {
107106
auto res = *this;
108107
res.options.conflict_clause_is_on = true;
109108
res.options.conflict_clause = conflict_clause_t::fail;
110109
return res;
111110
}
112111

113-
self on_conflict_ignore() const {
112+
constexpr primary_key_t on_conflict_ignore() const {
114113
auto res = *this;
115114
res.options.conflict_clause_is_on = true;
116115
res.options.conflict_clause = conflict_clause_t::ignore;
117116
return res;
118117
}
119118

120-
self on_conflict_replace() const {
119+
constexpr primary_key_t on_conflict_replace() const {
121120
auto res = *this;
122121
res.options.conflict_clause_is_on = true;
123122
res.options.conflict_clause = conflict_clause_t::replace;
@@ -536,7 +535,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
536535

537536
#if SQLITE_VERSION_NUMBER >= 3006019
538537
/**
539-
* FOREIGN KEY constraint builder function taking one or more fields [member pointer or column pointer] as argument.
538+
* Composite FOREIGN KEY constraint builder function taking one or more fields [member pointer or column pointer] as argument.
540539
* Available since SQLite 3.6.19
541540
*/
542541
template<class... Cs>
@@ -545,7 +544,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
545544
}
546545

547546
/**
548-
* FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
547+
* Composite FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
549548
* Available since SQLite 3.6.19
550549
*/
551550
template<class O, class... Base, class... F>
@@ -557,7 +556,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
557556

558557
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
559558
/**
560-
* FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
559+
* Composite FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
561560
* Available since SQLite 3.6.19
562561
*/
563562
template<orm_table_reference auto table, class... Base, class... F>
@@ -637,14 +636,34 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
637636
* PRIMARY KEY table constraint builder function.
638637
*/
639638
template<class... Cs>
640-
internal::primary_key_t<Cs...> primary_key(Cs... cs) {
639+
constexpr internal::primary_key_t<Cs...> primary_key(Cs... cs) {
641640
return {{std::forward<Cs>(cs)...}};
642641
}
643642

644643
/**
645-
* PRIMARY KEY column constraint builder function.
644+
* Composite PRIMARY KEY table constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
646645
*/
647-
inline internal::primary_key_t<> primary_key() {
646+
template<class O, class... Base, class... F>
647+
constexpr internal::primary_key_t<F O::*...> primary_key(F Base::*... columns) {
648+
static_assert(std::conjunction<internal::is_field_of<F Base::*, O>...>::value,
649+
"Fields must be from explicitly specified derived class");
650+
return {{columns...}};
651+
}
652+
653+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
654+
/**
655+
* Composite PRIMARY KEY table constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
656+
*/
657+
template<orm_table_reference auto table, class... Base, class... F>
658+
constexpr auto primary_key(F Base::*... columns) {
659+
return primary_key<internal::auto_decay_table_ref_t<table>>(columns...);
660+
}
661+
#endif
662+
663+
/**
664+
* PRIMARY KEY column constraint builder function (used at a single column).
665+
*/
666+
inline constexpr internal::primary_key_t<> primary_key() {
648667
return {{}};
649668
}
650669

dev/statement_serializer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ namespace sqlite_orm {
10481048
ss << " ON CONFLICT " << serialize(statement.options.conflict_clause, context);
10491049
}
10501050
using columns_tuple = typename statement_type::columns_tuple;
1051-
const size_t columnsCount = std::tuple_size<columns_tuple>::value;
1051+
constexpr size_t columnsCount = std::tuple_size<columns_tuple>::value;
10521052
if (columnsCount) {
10531053
ss << "(" << streaming_mapped_columns_expressions(statement.columns, context) << ")";
10541054
}

dev/storage.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ namespace sqlite_orm {
112112
storage_base{std::move(filename),
113113
storage_opt_or_default<connection_control>(options),
114114
storage_opt_or_default<on_open_spec>(options),
115-
foreign_keys_count(dbObjects)},
115+
foreign_keys_count<db_objects_type>()},
116116
db_objects{std::move(dbObjects)} {}
117117

118118
storage_t(const storage_t&) = default;

dev/storage_impl.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ namespace sqlite_orm {
2424
using tables_index_sequence = filter_tuple_sequence_t<DBOs, is_table>;
2525

2626
template<class DBOs, satisfies<is_db_objects, DBOs> = true>
27-
int foreign_keys_count(const DBOs& dbObjects) {
27+
constexpr int foreign_keys_count() {
2828
int res = 0;
29-
iterate_tuple<true>(dbObjects, tables_index_sequence<DBOs>{}, [&res](const auto& table) {
30-
res += table.template count_of<is_foreign_key>();
29+
iterate_tuple<DBOs>(tables_index_sequence<DBOs>{}, [&res](const auto* dummy) {
30+
using table_type = std::remove_pointer_t<decltype(dummy)>;
31+
res += table_type::template count_of<is_foreign_key>();
3132
});
3233
return res;
3334
}

include/sqlite_orm/sqlite_orm.h

+42-22
Original file line numberDiff line numberDiff line change
@@ -3371,7 +3371,7 @@ namespace sqlite_orm {
33713371
return *this;
33723372
}
33733373
#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED
3374-
primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {}
3374+
constexpr primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {}
33753375
#endif
33763376
};
33773377

@@ -3382,59 +3382,58 @@ namespace sqlite_orm {
33823382
*/
33833383
template<class... Cs>
33843384
struct primary_key_t : primary_key_base {
3385-
using self = primary_key_t<Cs...>;
33863385
using order_by = primary_key_base::order_by;
33873386
using columns_tuple = std::tuple<Cs...>;
33883387

33893388
columns_tuple columns;
33903389

3391-
primary_key_t(columns_tuple columns) : columns(std::move(columns)) {}
3390+
constexpr primary_key_t(columns_tuple columns) : columns(std::move(columns)) {}
33923391

3393-
self asc() const {
3392+
constexpr primary_key_t asc() const {
33943393
auto res = *this;
33953394
res.options.asc_option = order_by::ascending;
33963395
return res;
33973396
}
33983397

3399-
self desc() const {
3398+
constexpr primary_key_t desc() const {
34003399
auto res = *this;
34013400
res.options.asc_option = order_by::descending;
34023401
return res;
34033402
}
34043403

3405-
primary_key_with_autoincrement<self> autoincrement() const {
3404+
constexpr primary_key_with_autoincrement<primary_key_t> autoincrement() const {
34063405
return {*this};
34073406
}
34083407

3409-
self on_conflict_rollback() const {
3408+
constexpr primary_key_t on_conflict_rollback() const {
34103409
auto res = *this;
34113410
res.options.conflict_clause_is_on = true;
34123411
res.options.conflict_clause = conflict_clause_t::rollback;
34133412
return res;
34143413
}
34153414

3416-
self on_conflict_abort() const {
3415+
constexpr primary_key_t on_conflict_abort() const {
34173416
auto res = *this;
34183417
res.options.conflict_clause_is_on = true;
34193418
res.options.conflict_clause = conflict_clause_t::abort;
34203419
return res;
34213420
}
34223421

3423-
self on_conflict_fail() const {
3422+
constexpr primary_key_t on_conflict_fail() const {
34243423
auto res = *this;
34253424
res.options.conflict_clause_is_on = true;
34263425
res.options.conflict_clause = conflict_clause_t::fail;
34273426
return res;
34283427
}
34293428

3430-
self on_conflict_ignore() const {
3429+
constexpr primary_key_t on_conflict_ignore() const {
34313430
auto res = *this;
34323431
res.options.conflict_clause_is_on = true;
34333432
res.options.conflict_clause = conflict_clause_t::ignore;
34343433
return res;
34353434
}
34363435

3437-
self on_conflict_replace() const {
3436+
constexpr primary_key_t on_conflict_replace() const {
34383437
auto res = *this;
34393438
res.options.conflict_clause_is_on = true;
34403439
res.options.conflict_clause = conflict_clause_t::replace;
@@ -3853,7 +3852,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
38533852

38543853
#if SQLITE_VERSION_NUMBER >= 3006019
38553854
/**
3856-
* FOREIGN KEY constraint builder function taking one or more fields [member pointer or column pointer] as argument.
3855+
* Composite FOREIGN KEY constraint builder function taking one or more fields [member pointer or column pointer] as argument.
38573856
* Available since SQLite 3.6.19
38583857
*/
38593858
template<class... Cs>
@@ -3862,7 +3861,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
38623861
}
38633862

38643863
/**
3865-
* FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
3864+
* Composite FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
38663865
* Available since SQLite 3.6.19
38673866
*/
38683867
template<class O, class... Base, class... F>
@@ -3874,7 +3873,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
38743873

38753874
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
38763875
/**
3877-
* FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
3876+
* Composite FOREIGN KEY constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
38783877
* Available since SQLite 3.6.19
38793878
*/
38803879
template<orm_table_reference auto table, class... Base, class... F>
@@ -3954,14 +3953,34 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
39543953
* PRIMARY KEY table constraint builder function.
39553954
*/
39563955
template<class... Cs>
3957-
internal::primary_key_t<Cs...> primary_key(Cs... cs) {
3956+
constexpr internal::primary_key_t<Cs...> primary_key(Cs... cs) {
39583957
return {{std::forward<Cs>(cs)...}};
39593958
}
39603959

39613960
/**
3962-
* PRIMARY KEY column constraint builder function.
3961+
* Composite PRIMARY KEY table constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
3962+
*/
3963+
template<class O, class... Base, class... F>
3964+
constexpr internal::primary_key_t<F O::*...> primary_key(F Base::*... columns) {
3965+
static_assert(std::conjunction<internal::is_field_of<F Base::*, O>...>::value,
3966+
"Fields must be from explicitly specified derived class");
3967+
return {{columns...}};
3968+
}
3969+
3970+
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
3971+
/**
3972+
* Composite PRIMARY KEY table constraint builder function taking one or more fields from a derived class as a member pointer of a base class as argument.
39633973
*/
3964-
inline internal::primary_key_t<> primary_key() {
3974+
template<orm_table_reference auto table, class... Base, class... F>
3975+
constexpr auto primary_key(F Base::*... columns) {
3976+
return primary_key<internal::auto_decay_table_ref_t<table>>(columns...);
3977+
}
3978+
#endif
3979+
3980+
/**
3981+
* PRIMARY KEY column constraint builder function (used at a single column).
3982+
*/
3983+
inline constexpr internal::primary_key_t<> primary_key() {
39653984
return {{}};
39663985
}
39673986

@@ -12715,10 +12734,11 @@ namespace sqlite_orm {
1271512734
using tables_index_sequence = filter_tuple_sequence_t<DBOs, is_table>;
1271612735

1271712736
template<class DBOs, satisfies<is_db_objects, DBOs> = true>
12718-
int foreign_keys_count(const DBOs& dbObjects) {
12737+
constexpr int foreign_keys_count() {
1271912738
int res = 0;
12720-
iterate_tuple<true>(dbObjects, tables_index_sequence<DBOs>{}, [&res](const auto& table) {
12721-
res += table.template count_of<is_foreign_key>();
12739+
iterate_tuple<DBOs>(tables_index_sequence<DBOs>{}, [&res](const auto* dummy) {
12740+
using table_type = std::remove_pointer_t<decltype(dummy)>;
12741+
res += table_type::template count_of<is_foreign_key>();
1272212742
});
1272312743
return res;
1272412744
}
@@ -20820,7 +20840,7 @@ namespace sqlite_orm {
2082020840
ss << " ON CONFLICT " << serialize(statement.options.conflict_clause, context);
2082120841
}
2082220842
using columns_tuple = typename statement_type::columns_tuple;
20823-
const size_t columnsCount = std::tuple_size<columns_tuple>::value;
20843+
constexpr size_t columnsCount = std::tuple_size<columns_tuple>::value;
2082420844
if (columnsCount) {
2082520845
ss << "(" << streaming_mapped_columns_expressions(statement.columns, context) << ")";
2082620846
}
@@ -22638,7 +22658,7 @@ namespace sqlite_orm {
2263822658
storage_base{std::move(filename),
2263922659
storage_opt_or_default<connection_control>(options),
2264022660
storage_opt_or_default<on_open_spec>(options),
22641-
foreign_keys_count(dbObjects)},
22661+
foreign_keys_count<db_objects_type>()},
2264222662
db_objects{std::move(dbObjects)} {}
2264322663

2264422664
storage_t(const storage_t&) = default;

0 commit comments

Comments
 (0)