24template <ColumnType Column, SqlExpr ValExpr>
45template <TableType Table,
typename Columns = std::tuple<>,
typename Values = std::tuple<>,
46 typename SelectStmt = std::nullopt_t,
typename ReturningColumns = std::tuple<>>
53 ReturningColumns returning_columns_;
56 std::string columns_to_sql()
const {
61 [&](
const auto&... cols) { ((ss << (i++ > 0 ?
", " :
"") << cols.column_name()), ...); },
68 template <
typename ValueTuple>
69 std::string values_row_to_sql(
const ValueTuple& value_tuple)
const {
73 std::apply([&](
const auto&... vals) { ((ss << (i++ > 0 ?
", " :
"") << vals.to_sql()), ...); },
80 std::string values_to_sql()
const {
85 [&](
const auto&... value_tuples) {
86 ((ss << (i++ > 0 ?
", " :
"") << values_row_to_sql(value_tuples)), ...);
93 template <
typename ValueTuple>
94 std::vector<std::string> values_row_bind_params(
const ValueTuple& value_tuple)
const {
95 std::vector<std::string> params;
98 [&](
const auto&... vals) {
99 auto process_val = [¶ms](
const auto&
val) {
100 auto val_params =
val.bind_params();
101 params.insert(params.end(), val_params.begin(), val_params.end());
104 (process_val(vals), ...);
112 std::vector<std::string> values_bind_params()
const {
113 std::vector<std::string> params;
116 [&](
const auto&... value_tuples) {
117 auto process_tuple = [¶ms,
this](
const auto& tuple) {
118 auto tuple_params = values_row_bind_params(tuple);
119 params.insert(params.end(), tuple_params.begin(), tuple_params.end());
122 (process_tuple(value_tuples), ...);
130 std::string returning_to_sql()
const {
131 if constexpr (is_empty_tuple<ReturningColumns>()) {
134 std::stringstream ss;
138 [&](
const auto&... cols) { ((ss << (i++ > 0 ?
", " :
"") << cols.to_sql()), ...); },
145 std::vector<std::string> returning_bind_params()
const {
146 std::vector<std::string> params;
148 if constexpr (!is_empty_tuple<ReturningColumns>()) {
150 [&](
const auto&... cols) {
151 auto process_col = [¶ms](
const auto& col) {
152 auto col_params = col.bind_params();
153 params.insert(params.end(), col_params.begin(), col_params.end());
156 (process_col(cols), ...);
178 SelectStmt select = std::nullopt, ReturningColumns returning_columns = {})
180 select_(
std::move(select)), returning_columns_(
std::move(returning_columns)) {}
185 std::stringstream ss;
186 ss <<
"INSERT INTO " << table_.table_name;
189 if constexpr (!is_empty_tuple<Columns>()) {
190 ss <<
" " << columns_to_sql();
196 if constexpr (!is_empty_tuple<Values>() && std::is_same_v<SelectStmt, std::nullopt_t>) {
197 ss <<
" " << values_to_sql();
200 else if constexpr (!std::is_same_v<SelectStmt, std::nullopt_t>) {
201 if (select_.has_value()) {
202 ss <<
" " << select_.value().to_sql();
207 ss << returning_to_sql();
215 std::vector<std::string> params;
218 if constexpr (!is_empty_tuple<Values>() && std::is_same_v<SelectStmt, std::nullopt_t>) {
219 auto values_params = values_bind_params();
220 params.insert(params.end(), values_params.begin(), values_params.end());
223 else if constexpr (!std::is_same_v<SelectStmt, std::nullopt_t>) {
224 if (select_.has_value()) {
225 auto select_params = select_.value().bind_params();
226 params.insert(params.end(), select_params.begin(), select_params.end());
231 auto returning_params = returning_bind_params();
232 params.insert(params.end(), returning_params.begin(), returning_params.end());
243 using NewColumns = std::tuple<ColumnRef<Cols>...>;
247 table_, std::move(column_refs), values_, select_, returning_columns_);
254 template <
typename... Args>
257 auto to_expr = [](
auto&& arg) {
258 if constexpr (
SqlExpr<std::remove_cvref_t<
decltype(arg)>>) {
259 return std::forward<decltype(arg)>(arg);
261 return val(std::forward<
decltype(arg)>(arg));
265 using ValueTuple = std::tuple<decltype(to_expr(std::declval<Args>()))...>;
266 auto value_tuple = std::make_tuple(
to_expr(std::forward<Args>(args))...);
269 if constexpr (!is_empty_tuple<Values>()) {
270 auto new_values = std::tuple_cat(values_, std::make_tuple(value_tuple));
273 table_, columns_, std::move(new_values), select_, returning_columns_);
277 using NewValues = std::tuple<ValueTuple>;
278 auto new_values = std::make_tuple(value_tuple);
281 table_, columns_, std::move(new_values), select_, returning_columns_);
289 template <
typename Select>
291 auto select(
const Select& select)
const {
293 table_, columns_, values_, std::optional<Select>(
select), returning_columns_);
300 template <
typename... Args>
303 auto to_expr = [](
const auto& arg) {
304 if constexpr (
SqlExpr<std::remove_cvref_t<
decltype(arg)>>) {
306 }
else if constexpr (
ColumnType<std::remove_cvref_t<
decltype(arg)>>) {
309 static_assert(
SqlExpr<std::remove_cvref_t<
decltype(arg)>> ||
310 ColumnType<std::remove_cvref_t<
decltype(arg)>>,
311 "Arguments to returning() must be either columns or SQL expressions");
317 using ReturningTuple = std::tuple<decltype(to_expr(std::declval<Args>()))...>;
318 auto returning_tuple = std::make_tuple(
to_expr(args)...);
321 table_, columns_, values_, select_, std::move(returning_tuple));
329template <TableType Table>
Column reference expression.
Base INSERT query builder.
auto values(Args &&... args) const
Add a row of values to insert.
std::vector< std::string > bind_params() const
Get the bind parameters for this INSERT query.
ReturningColumns returning_columns_type
auto columns(const Cols &... cols) const
Specify columns to insert into.
InsertQuery(Table table, Columns columns={}, Values values={}, SelectStmt select=std::nullopt, ReturningColumns returning_columns={})
Constructor for the INSERT query builder.
auto select(const Select &select) const
Set a SELECT query to use for INSERT ... SELECT statements.
auto returning(const Args &... args) const
Specify columns to return after insertion.
std::string to_sql() const
Generate the SQL for this INSERT query.
Represents a column in a database table.
Concept for column types.
Concept for SQL expression components.
auto column_ref(const Column &col)
Create a column reference expression.
auto insert_into(const Table &table)
Create an INSERT query for the specified table.
auto to_expr(const C &col, std::string_view table_name="")
Helper to wrap a schema column in a SQL expression.
auto select(const Args &... args)
Create a column reference from a member pointer without requiring a table instance.
auto val(const char *str)
Helper to create a value expression from a string literal.
Represents a single column-value pair for an INSERT statement.
std::string value_sql() const
std::vector< std::string > bind_params() const
ColumnRef< Column > column
InsertItem(ColumnRef< Column > col, ValExpr val)
std::string column_name() const