10#include <unordered_set>
14#include <boost/pfr.hpp>
21 { T::name } -> std::convertible_to<std::string_view>;
23 std::declval<T>().sql_definition();
32 { T::table_name } -> std::convertible_to<std::string_view>;
33 requires std::is_const_v<std::remove_reference_t<
decltype(T::table_name)>>;
40 { t.sql_definition() } -> std::convertible_to<std::string>;
47template <TableConcept Table>
49 std::vector<std::string> column_defs;
50 std::unordered_set<std::string> added_columns;
52 boost::pfr::for_each_field(table_instance, [&](
const auto& field) {
53 if constexpr (
is_column<std::remove_cvref_t<
decltype(field)>>) {
55 std::string col_name = std::string(std::remove_cvref_t<
decltype(field)>::name);
56 if (added_columns.find(col_name) == added_columns.end()) {
57 column_defs.push_back(field.sql_definition());
58 added_columns.insert(col_name);
64 if (column_defs.empty()) {
68 std::string result = column_defs[0];
69 for (
size_t i = 1; i < column_defs.size(); ++i) {
70 result +=
",\n" + column_defs[i];
80template <TableConcept Table>
82 std::vector<std::string> constraint_defs;
83 std::unordered_set<std::string> added_constraints;
85 boost::pfr::for_each_field(table_instance, [&](
const auto& field) {
86 if constexpr (
is_constraint<std::remove_cvref_t<
decltype(field)>>) {
87 std::string constraint = field.sql_definition();
88 if (added_constraints.find(constraint) == added_constraints.end()) {
89 constraint_defs.push_back(constraint);
90 added_constraints.insert(constraint);
96 if (constraint_defs.empty()) {
100 std::string result = constraint_defs[0];
101 for (
size_t i = 1; i < constraint_defs.size(); ++i) {
102 result +=
",\n" + constraint_defs[i];
112template <TableConcept Table>
115 const Table& table_instance_;
116 bool if_not_exists_ =
false;
117 bool if_exists_ =
false;
119 bool cascade_ =
false;
120 bool restrict_ =
false;
122 std::vector<std::string> bind_params_;
125 create_table(
const Table& table_instance) : table_instance_(table_instance) {}
150 if (if_exists_ && if_not_exists_) {
151 return "if_exists and if_not_exists cannot both be true";
157 std::string sql =
"CREATE TABLE ";
158 if (if_not_exists_) {
159 sql +=
"IF NOT EXISTS ";
165 sql += std::string(Table::table_name) +
" (\n";
172 if (!constraints.empty()) {
173 sql +=
",\n" + constraints;
180 const std::vector<std::string>&
bind_params()
const {
return bind_params_; }
189template <TableConcept Table>
192 drop_table(
const Table& table_instance) : table_instance_(table_instance) {}
210 std::string sql =
"DROP TABLE ";
216 sql += std::string(Table::table_name);
231 const std::vector<std::string>&
bind_params()
const {
return bind_params_; }
234 std::vector<std::string> bind_params_;
235 const Table& table_instance_;
236 bool if_exists_ =
true;
237 bool cascade_ =
false;
238 bool restrict_ =
false;
Generate CREATE TABLE SQL statement for a table struct.
create_table & restrict(bool restrict=true)
create_table & if_exists(bool if_exists=true)
const std::vector< std::string > & bind_params() const
create_table(const Table &table_instance)
std::string to_sql() const
std::optional< std::string > validate() const
Validate the create table configuration.
create_table & cascade(bool cascade=true)
create_table & if_not_exists(bool if_not_exists=true)
Generate DROP TABLE SQL statement for a table struct.
std::string to_sql() const
const std::vector< std::string > & bind_params() const
drop_table & cascade(bool cascade=true)
drop_table(const Table &table_instance)
drop_table & restrict(bool restrict=true)
drop_table & if_exists(bool if_exists=true)
Concept for a database table type.
Helper to detect column members in a table.
Helper to detect constraint members in a table.
std::string collect_column_definitions(const Table &table_instance)
Generate SQL column definitions from a table struct using Boost PFR.
std::string collect_constraint_definitions(const Table &table_instance)
Generate SQL constraint definitions from a table struct.