11#pragma once
22
3+ #include < sqlite3.h> // sqlite_int64
34#ifndef SQLITE_ORM_IMPORT_STD_MODULE
45#include < tuple> // std::tuple
56#include < string> // std::string
67#include < memory> // std::unique_ptr
7- #include < type_traits> // std::is_same, std::is_member_object_pointer
8+ #include < type_traits> // std::enable_if, std:: is_same, std::is_member_object_pointer, std::is_signed
89#include < utility> // std::move
910#endif
1011
1112#include " ../functional/cxx_type_traits_polyfill.h"
1213#include " ../tuple_helper/tuple_traits.h"
1314#include " ../tuple_helper/tuple_filter.h"
14- #include " ../type_traits.h"
1515#include " ../member_traits/member_traits.h"
16+ #include " ../type_traits.h"
1617#include " ../type_is_nullable.h"
1718#include " ../constraints.h"
1819
@@ -74,13 +75,21 @@ namespace sqlite_orm::internal {
7475 constraints_type constraints;
7576
7677 /* *
77- * Checks whether contraints contain specified type.
78+ * Checks whether constraints contain specified type.
7879 */
7980 template <template <class ...> class Trait >
8081 constexpr static bool is () {
8182 return tuple_has<constraints_type, Trait>::value;
8283 }
8384
85+ /* *
86+ * Checks whether constraints contain specified class template.
87+ */
88+ template <template <class ...> class Primary >
89+ constexpr static bool is_template () {
90+ return tuple_has_template<constraints_type, Primary>::value;
91+ }
92+
8493 /* *
8594 * Simplified interface for `DEFAULT` constraint
8695 * @return string representation of default value if it exists otherwise nullptr
@@ -161,19 +170,65 @@ namespace sqlite_orm::internal {
161170 field_type_t ,
162171 filter_tuple_sequence_t <Elements, mpl::disjunction_fn<is_column, is_hidden_column>::template fn>>;
163172
164- #if SQLITE_VERSION_NUMBER >= 3031000
173+ // Custom type:
174+ // It is the programmer's responsibility to ensure data integrity in the value range of the custom type
175+ // and in purview of SQLite using a 64-bit signed integer.
176+ template <class F , class SFINAE = void >
177+ struct check_pkcol {
178+ static constexpr void validate_column_primary_key_with_autoincrement () {}
179+ };
180+
181+ // For integer types: further checks
182+ template <class F >
183+ struct check_pkcol <F, std::enable_if_t <std::is_integral<F>::value>> {
184+ // For 64-bit signed integer type: valid
185+ template <class X = F,
186+ std::enable_if_t <sizeof (X) == sizeof (sqlite_int64) &&
187+ std::is_signed<X>::value == std::is_signed<sqlite_int64>::value,
188+ bool > = true >
189+ static constexpr void validate_column_primary_key_with_autoincrement () {}
190+
191+ // Design decision for integral types other than 64-bit signed integer:
192+ // It is the programmer's responsibility to ensure data integrity in the value range of the integral type
193+ // and in purview of SQLite using a 64-bit signed integer.
194+ template <class X = F,
195+ std::enable_if_t <sizeof (X) != sizeof (sqlite_int64) ||
196+ std::is_signed<X>::value != std::is_signed<sqlite_int64>::value,
197+ bool > = true >
198+ static constexpr void validate_column_primary_key_with_autoincrement () {}
199+ };
200+
201+ // For non-integer types: static_assert failure
202+ template <class F >
203+ struct check_pkcol <F, std::enable_if_t <!std::is_base_of<integer_printer, type_printer<F>>::value>> {
204+ static constexpr void validate_column_primary_key_with_autoincrement () {
205+ static_assert (polyfill::always_false_v<F>,
206+ R"( AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY as an alias for the "rowid" key)" );
207+ }
208+ };
209+
210+ template <class G , class ... Op>
211+ constexpr void validate_column_definition () {
212+ using constraints_type = std::tuple<Op...>;
213+
214+ static_assert (polyfill::conjunction_v<is_column_constraint<Op>...>, " Incorrect column constraints" );
215+
216+ if constexpr (tuple_has_template<constraints_type, primary_key_with_autoincrement>::value) {
217+ check_pkcol<member_field_type_t <G>>::validate_column_primary_key_with_autoincrement ();
218+ }
219+ }
220+
165221 /* *
166222 * Factory function for a column definition from a member object pointer for hidden virtual table columns.
167223 */
168224 template <class M , class ... Op, satisfies<std::is_member_object_pointer, M> = true >
169225 hidden_column<M, empty_setter, Op...> make_hidden_column (std::string name, M memberPointer, Op... constraints) {
170- static_assert (polyfill::conjunction_v<is_column_constraint<Op>...>, " Incorrect constraints pack " );
226+ static_assert (polyfill::conjunction_v<is_column_constraint<Op>...>, " Incorrect column constraints " );
171227
172228 // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`,
173229 // as this will lead to UB with Clang on MinGW!
174230 return {std::move (name), memberPointer, {}, std::tuple<Op...>{std::move (constraints)...}};
175231 }
176- #endif
177232}
178233
179234SQLITE_ORM_EXPORT namespace sqlite_orm {
@@ -183,7 +238,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
183238 template <class M , class ... Op, internal::satisfies<std::is_member_object_pointer, M> = true >
184239 internal::column_t <M, internal::empty_setter, Op...>
185240 make_column (std::string name, M memberPointer, Op... constraints) {
186- static_assert (polyfill::conjunction_v< internal::is_column_constraint<Op> ...>, " Incorrect constraints pack " );
241+ internal::validate_column_definition<M, Op ...>( );
187242
188243 // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`,
189244 // as this will lead to UB with Clang on MinGW!
@@ -201,7 +256,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
201256 internal::column_t <G, S, Op...> make_column (std::string name, S setter, G getter, Op... constraints) {
202257 static_assert (std::is_same<internal::setter_field_type_t <S>, internal::getter_field_type_t <G>>::value,
203258 " Getter and setter must get and set same data type" );
204- static_assert (polyfill::conjunction_v< internal::is_column_constraint<Op> ...>, " Incorrect constraints pack " );
259+ internal::validate_column_definition<G, Op ...>( );
205260
206261 // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`,
207262 // as this will lead to UB with Clang on MinGW!
@@ -219,7 +274,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm {
219274 internal::column_t <G, S, Op...> make_column (std::string name, G getter, S setter, Op... constraints) {
220275 static_assert (std::is_same<internal::setter_field_type_t <S>, internal::getter_field_type_t <G>>::value,
221276 " Getter and setter must get and set same data type" );
222- static_assert (polyfill::conjunction_v< internal::is_column_constraint<Op> ...>, " Incorrect constraints pack " );
277+ internal::validate_column_definition<G, Op ...>( );
223278
224279 // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`,
225280 // as this will lead to UB with Clang on MinGW!
0 commit comments