mirror of
https://github.com/getml/sqlgen.git
synced 2026-05-05 14:43:08 -05:00
Add auto-incrementing primary keys (#23)
This commit is contained in:
committed by
GitHub
parent
e4b821138a
commit
aa1a96f1c0
@@ -1,30 +1,40 @@
|
||||
#ifndef SQLGEN_PRIMARY_KEY_HPP_
|
||||
#define SQLGEN_PRIMARY_KEY_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "transpilation/is_nullable.hpp"
|
||||
|
||||
namespace sqlgen {
|
||||
|
||||
template <class T>
|
||||
inline constexpr bool auto_incr = true;
|
||||
|
||||
template <class T, bool _auto_incr = false>
|
||||
struct PrimaryKey {
|
||||
using ReflectionType = T;
|
||||
static constexpr bool auto_incr = _auto_incr;
|
||||
|
||||
static_assert(!transpilation::is_nullable_v<T>,
|
||||
"A primary key cannot be nullable.");
|
||||
static_assert(
|
||||
!transpilation::is_nullable_v<T>,
|
||||
"A primary key cannot be nullable. Please use a non-nullable type.");
|
||||
static_assert(!_auto_incr || std::is_integral_v<T>,
|
||||
"The type of an auto-incrementing primary key must be "
|
||||
"integral. Please use an integral type or remove auto_incr.");
|
||||
|
||||
PrimaryKey() : value_(0) {}
|
||||
PrimaryKey() : value_(T()) {}
|
||||
|
||||
PrimaryKey(const T& _value) : value_(_value) {}
|
||||
|
||||
PrimaryKey(PrimaryKey<T>&& _other) noexcept = default;
|
||||
PrimaryKey(PrimaryKey&& _other) noexcept = default;
|
||||
|
||||
PrimaryKey(const PrimaryKey<T>& _other) = default;
|
||||
PrimaryKey(const PrimaryKey& _other) = default;
|
||||
|
||||
template <class U>
|
||||
PrimaryKey(const PrimaryKey<U>& _other) : value_(_other.get()) {}
|
||||
template <class U, bool _other_auto_incr>
|
||||
PrimaryKey(const PrimaryKey<U, _other_auto_incr>& _other)
|
||||
: value_(_other.get()) {}
|
||||
|
||||
template <class U>
|
||||
PrimaryKey(PrimaryKey<U>&& _other) : value_(_other.get()) {}
|
||||
template <class U, bool _other_auto_incr>
|
||||
PrimaryKey(PrimaryKey<U, _other_auto_incr>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U,
|
||||
typename std::enable_if<std::is_convertible_v<U, ReflectionType>,
|
||||
@@ -71,22 +81,22 @@ struct PrimaryKey {
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
PrimaryKey<T>& operator=(const PrimaryKey<T>& _other) = default;
|
||||
PrimaryKey& operator=(const PrimaryKey& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
PrimaryKey<T>& operator=(PrimaryKey<T>&& _other) = default;
|
||||
PrimaryKey& operator=(PrimaryKey&& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const PrimaryKey<U>& _other) {
|
||||
template <class U, bool _other_auto_incr>
|
||||
auto& operator=(const PrimaryKey<U, _other_auto_incr>& _other) {
|
||||
value_ = _other.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(PrimaryKey<U>&& _other) {
|
||||
value_ = std::forward<T>(_other.value_);
|
||||
template <class U, bool _other_auto_incr>
|
||||
auto& operator=(PrimaryKey<U, _other_auto_incr>&& _other) {
|
||||
value_ = std::move(_other.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
namespace sqlgen::dynamic::types {
|
||||
|
||||
struct Properties {
|
||||
bool auto_incr = false;
|
||||
bool primary = false;
|
||||
bool nullable = false;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef SQLGEN_INTERNAL_REMOVE_AUTO_INCR_PRIMARY_HPP_
|
||||
#define SQLGEN_INTERNAL_REMOVE_AUTO_INCR_PRIMARY_HPP_
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../PrimaryKey.hpp"
|
||||
#include "../transpilation/is_primary_key.hpp"
|
||||
|
||||
namespace sqlgen::internal {
|
||||
|
||||
namespace remove_auto_incr {
|
||||
|
||||
template <class FieldType>
|
||||
struct FieldWrapper {};
|
||||
|
||||
template <class NamedTupleType>
|
||||
struct NamedTupleWrapper;
|
||||
|
||||
template <class... Fields>
|
||||
struct NamedTupleWrapper<rfl::NamedTuple<Fields...>> {
|
||||
using Type = rfl::NamedTuple<Fields...>;
|
||||
|
||||
template <class NewField>
|
||||
friend constexpr auto operator+(const NamedTupleWrapper&,
|
||||
const FieldWrapper<NewField>&) {
|
||||
if constexpr (transpilation::is_primary_key_v<
|
||||
std::remove_pointer_t<typename NewField::Type>>) {
|
||||
if constexpr (std::remove_pointer_t<typename NewField::Type>::auto_incr) {
|
||||
return NamedTupleWrapper<rfl::NamedTuple<Fields...>>{};
|
||||
} else {
|
||||
return NamedTupleWrapper<rfl::NamedTuple<Fields..., NewField>>{};
|
||||
}
|
||||
} else {
|
||||
return NamedTupleWrapper<rfl::NamedTuple<Fields..., NewField>>{};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class NamedTupleType>
|
||||
struct RemoveAutoIncrPrimary;
|
||||
|
||||
template <class... Fields>
|
||||
struct RemoveAutoIncrPrimary<rfl::NamedTuple<Fields...>> {
|
||||
static constexpr auto wrapper =
|
||||
(NamedTupleWrapper<rfl::NamedTuple<>>{} + ... + FieldWrapper<Fields>{});
|
||||
|
||||
using Type = decltype(wrapper)::Type;
|
||||
};
|
||||
|
||||
} // namespace remove_auto_incr
|
||||
|
||||
template <class NamedTupleType>
|
||||
using remove_auto_incr_primary_t =
|
||||
typename remove_auto_incr::RemoveAutoIncrPrimary<
|
||||
std::remove_cvref_t<NamedTupleType>>::Type;
|
||||
|
||||
} // namespace sqlgen::internal
|
||||
|
||||
#endif
|
||||
@@ -7,17 +7,20 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "remove_auto_incr_primary_t.hpp"
|
||||
#include "to_str.hpp"
|
||||
|
||||
namespace sqlgen::internal {
|
||||
|
||||
template <class T>
|
||||
std::vector<std::optional<std::string>> to_str_vec(const T& _t) {
|
||||
const auto view = rfl::to_view(_t);
|
||||
using ViewType = remove_auto_incr_primary_t<decltype(view)>;
|
||||
return rfl::apply(
|
||||
[](auto... _ptrs) {
|
||||
return std::vector<std::optional<std::string>>({to_str(*_ptrs)...});
|
||||
},
|
||||
rfl::to_view(_t).values());
|
||||
ViewType(view).values());
|
||||
}
|
||||
|
||||
} // namespace sqlgen::internal
|
||||
|
||||
@@ -11,23 +11,29 @@
|
||||
|
||||
namespace sqlgen::parsing {
|
||||
|
||||
template <class T>
|
||||
struct Parser<PrimaryKey<T>> {
|
||||
static Result<PrimaryKey<T>> read(
|
||||
template <class T, bool _auto_incr>
|
||||
struct Parser<PrimaryKey<T, _auto_incr>> {
|
||||
static Result<PrimaryKey<T, _auto_incr>> read(
|
||||
const std::optional<std::string>& _str) noexcept {
|
||||
return Parser<std::remove_cvref_t<T>>::read(_str).transform(
|
||||
[](auto&& _t) -> PrimaryKey<T> {
|
||||
return PrimaryKey<T>(std::move(_t));
|
||||
[](auto&& _t) -> PrimaryKey<T, _auto_incr> {
|
||||
return PrimaryKey<T, _auto_incr>(std::move(_t));
|
||||
});
|
||||
}
|
||||
|
||||
static std::optional<std::string> write(const PrimaryKey<T>& _p) noexcept {
|
||||
return Parser<std::remove_cvref_t<T>>::write(_p.value());
|
||||
static std::optional<std::string> write(
|
||||
const PrimaryKey<T, _auto_incr>& _p) noexcept {
|
||||
if constexpr (_auto_incr) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return Parser<std::remove_cvref_t<T>>::write(_p.value());
|
||||
}
|
||||
}
|
||||
|
||||
static dynamic::Type to_type() noexcept {
|
||||
return Parser<std::remove_cvref_t<T>>::to_type().visit(
|
||||
[](auto _t) -> dynamic::Type {
|
||||
_t.properties.auto_incr = _auto_incr;
|
||||
_t.properties.primary = true;
|
||||
return _t;
|
||||
});
|
||||
|
||||
@@ -13,8 +13,8 @@ class is_primary_key;
|
||||
template <class T>
|
||||
class is_primary_key : public std::false_type {};
|
||||
|
||||
template <class T>
|
||||
class is_primary_key<PrimaryKey<T>> : public std::true_type {};
|
||||
template <class T, bool _auto_incr>
|
||||
class is_primary_key<PrimaryKey<T, _auto_incr>> : public std::true_type {};
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_primary_key_v = is_primary_key<std::remove_cvref_t<T>>::value;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "../dynamic/CreateTable.hpp"
|
||||
#include "../dynamic/Table.hpp"
|
||||
#include "../internal/remove_auto_incr_primary_t.hpp"
|
||||
#include "get_schema.hpp"
|
||||
#include "get_tablename.hpp"
|
||||
#include "make_columns.hpp"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "../dynamic/Table.hpp"
|
||||
#include "../internal/collect/vector.hpp"
|
||||
#include "../internal/remove_auto_incr_primary_t.hpp"
|
||||
#include "get_schema.hpp"
|
||||
#include "get_tablename.hpp"
|
||||
#include "make_columns.hpp"
|
||||
@@ -22,7 +23,8 @@ template <class T, class InsertOrWrite>
|
||||
InsertOrWrite to_insert_or_write() {
|
||||
using namespace std::ranges::views;
|
||||
|
||||
using NamedTupleType = rfl::named_tuple_t<std::remove_cvref_t<T>>;
|
||||
using NamedTupleType = sqlgen::internal::remove_auto_incr_primary_t<
|
||||
rfl::named_tuple_t<std::remove_cvref_t<T>>>;
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
|
||||
const auto columns = make_columns<Fields>(
|
||||
|
||||
Reference in New Issue
Block a user