Lightweight 0.20261105.1
Loading...
Searching...
No Matches
Migrate.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../DataMapper/BelongsTo.hpp"
6#include "../DataMapper/Field.hpp"
7#include "../DataMapper/Record.hpp"
8#include "../Utils.hpp"
9#include "Core.hpp"
10#include "MigrationPlan.hpp"
11
12#include <reflection-cpp/reflection.hpp>
13
14namespace Lightweight
15{
16
17/// @brief Index type for simplified CreateIndex API.
18/// @ingroup QueryBuilder
19enum class IndexType : std::uint8_t
20{
21 NonUnique, ///< Regular (non-unique) index
22 Unique ///< Unique index
23};
24
25/// @brief Optional settings for `SqlMigrationQueryBuilder::CreateIndex`.
26///
27/// Designed for designated initialisers, so a call only spells out what it needs:
28///
29/// @code
30/// migration.CreateIndex("idx_queue_key", "queue", { "dedup_key" },
31/// { .type = IndexType::Unique, .whereExpression = R"("dedup_key" <> '')" });
32/// @endcode
33///
34/// @ingroup QueryBuilder
36{
37 /// Whether the index enforces uniqueness.
39
40 /// Predicate body of a partial (PostgreSQL / SQLite) or filtered (SQL Server) index,
41 /// without the leading `WHERE`. Empty creates a regular index over every row.
42 /// The text is emitted verbatim; the caller is responsible for dialect-safe quoting
43 /// and for staying within what every target DBMS accepts (SQL Server only takes
44 /// simple comparisons, `IS [NOT] NULL` and `IN` lists joined by `AND`).
45 std::string whereExpression {};
46};
47
48/// @brief Query builder for building CREATE TABLE queries.
49///
50/// @see SqlQueryBuilder
51/// @ingroup QueryBuilder
52class [[nodiscard]] SqlCreateTableQueryBuilder final
53{
54 public:
55 /// Constructs a CREATE TABLE query builder.
56 explicit SqlCreateTableQueryBuilder(SqlCreateTablePlan& plan):
57 _plan { plan }
58 {
59 }
60
61 /// Adds a new column to the table.
63
64 /// Creates a new nullable column.
65 LIGHTWEIGHT_API SqlCreateTableQueryBuilder& Column(std::string columnName, SqlColumnTypeDefinition columnType);
66
67 /// Creates a new column that is non-nullable.
68 LIGHTWEIGHT_API SqlCreateTableQueryBuilder& RequiredColumn(std::string columnName, SqlColumnTypeDefinition columnType);
69
70 /// Adds the created_at and updated_at columns to the table.
72
73 /// Creates a new primary key column.
74 /// Primary keys are always required, unique, have an index, and are non-nullable.
75 LIGHTWEIGHT_API SqlCreateTableQueryBuilder& PrimaryKey(std::string columnName, SqlColumnTypeDefinition columnType);
76
77 /// Creates a new primary key column with auto-increment.
79 std::string columnName, SqlColumnTypeDefinition columnType = SqlColumnTypeDefinitions::Bigint {});
80
81 /// Creates a new nullable foreign key column.
82 LIGHTWEIGHT_API SqlCreateTableQueryBuilder& ForeignKey(std::string columnName,
83 SqlColumnTypeDefinition columnType,
85
86 /// Creates a new non-nullable foreign key column.
87 LIGHTWEIGHT_API SqlCreateTableQueryBuilder& RequiredForeignKey(std::string columnName,
88 SqlColumnTypeDefinition columnType,
90
91 /// Adds a composite foreign key constraint.
92 LIGHTWEIGHT_API SqlCreateTableQueryBuilder& ForeignKey(std::vector<std::string> columns,
93 std::string referencedTableName,
94 std::vector<std::string> referencedColumns);
95
96 /// Enables the UNIQUE constraint on the last declared column.
98
99 /// Enables the INDEX constraint on the last declared column.
101
102 /// Enables the UNIQUE and INDEX constraint on the last declared column and makes it an index.
104
105 private:
106 SqlCreateTablePlan& _plan;
107};
108
109/// @brief Query builder for building ALTER TABLE queries.
110///
111/// @see SqlQueryBuilder
112/// @ingroup QueryBuilder
113class [[nodiscard]] SqlAlterTableQueryBuilder final
114{
115 public:
116 /// Constructs an ALTER TABLE query builder.
118 _plan { plan }
119 {
120 }
121
122 /// Renames the table.
123 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& RenameTo(std::string_view newTableName);
124
125 /// Adds a new column to the table that is non-nullable.
126 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddColumn(std::string columnName, SqlColumnTypeDefinition columnType);
127
128 /// Adds a new column to the table that is non-nullable.
129 ///
130 /// @tparam MemberPointer The pointer to the member field in the record.
131 ///
132 /// @see AddColumn(std::string, SqlColumnTypeDefinition)
133 template <auto MemberPointer>
135 {
136 return AddColumn(std::string(FieldNameOf<MemberPointer>),
138 }
139
140 /// Adds a new column to the table that is nullable.
141 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddNotRequiredColumn(std::string columnName,
142 SqlColumnTypeDefinition columnType);
143
144 /// Adds a new column to the table that is nullable.
145 ///
146 /// @tparam MemberPointer The pointer to the member field in the record.
147 ///
148 /// @see AddNotRequiredColumn(std::string, SqlColumnTypeDefinition)
149 template <auto MemberPointer>
151 {
152 return AddNotRequiredColumn(std::string(FieldNameOf<MemberPointer>),
154 }
155
156 /// @brief Alters the column to have a new non-nullable type.
157 ///
158 /// @param columnName The name of the column to alter.
159 /// @param columnType The new type of the column.
160 /// @param nullable The new nullable state of the column.
161 ///
162 /// @return The current query builder for chaining.
163 ///
164 /// @see SqlColumnTypeDefinition
165 ///
166 /// @note On SQLite, `ALTER COLUMN` has no native SQL form: it is applied by rebuilding the table,
167 /// which only happens through @ref SqlMigration::MigrationManager. Executing the generated `ToSql()`
168 /// text yourself (the formatter emits a `-- LIGHTWEIGHT_SQLITE_GUARD:` sentinel comment for SQLite)
169 /// would silently do nothing — apply the migration via the manager, as shown below.
170 ///
171 /// @code
172 /// auto widen = SqlMigration::Migration<202602010001>(
173 /// "widen column",
174 /// [](SqlMigrationQueryBuilder& plan) {
175 /// plan.AlterTable("Table").AlterColumn("column", Integer {}, SqlNullable::NotNull);
176 /// },
177 /// [](SqlMigrationQueryBuilder&) {});
178 ///
179 /// auto& manager = SqlMigration::MigrationManager::GetInstance();
180 /// manager.CreateMigrationHistory();
181 /// manager.ApplyPendingMigrations();
182 /// @endcode
183 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AlterColumn(std::string columnName,
184 SqlColumnTypeDefinition columnType,
185 SqlNullable nullable);
186
187 /// Renames a column.
188 /// @param oldColumnName The old column name.
189 /// @param newColumnName The new column name.
190 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& RenameColumn(std::string_view oldColumnName, std::string_view newColumnName);
191
192 /// Drops a column from the table.
193 /// @param columnName The name of the column to drop.
194 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& DropColumn(std::string_view columnName);
195
196 /// Adds a new column to the table only if it does not already exist.
197 ///
198 /// @note Database support varies:
199 /// - PostgreSQL: Native IF NOT EXISTS support
200 /// - SQL Server: Uses conditional IF NOT EXISTS query
201 /// - SQLite: Limited support (may require raw SQL)
202 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddColumnIfNotExists(std::string columnName,
203 SqlColumnTypeDefinition columnType);
204
205 /// Adds a new nullable column to the table only if it does not already exist.
206 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddNotRequiredColumnIfNotExists(std::string columnName,
207 SqlColumnTypeDefinition columnType);
208
209 /// Drops a column from the table only if it exists.
210 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& DropColumnIfExists(std::string_view columnName);
211
212 /// Add an index to the table for the specified column.
213 /// @param columnName The name of the column to index.
214 ///
215 /// @code
216 /// SqlQueryBuilder q;
217 /// q.Migration().AlterTable("Table").AddIndex("column");
218 /// // Will execute CREATE INDEX "Table_column_index" ON "Table" ("column");
219 /// @endcode
220 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddIndex(std::string_view columnName);
221
222 /// Add an index to the table for the specified column that is unique.
223 /// @param columnName The name of the column to index.
224 ///
225 /// @code
226 /// SqlQueryBuilder q;
227 /// q.Migration().AlterTable("Table").AddUniqueIndex("column");
228 /// // Will execute CREATE UNIQUE INDEX "Table_column_index" ON "Table" ("column");
229 /// @endcode
230 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddUniqueIndex(std::string_view columnName);
231
232 /// Drop an index from the table for the specified column.
233 /// @param columnName The name of the column to drop the index from.
234 ///
235 /// @code
236 /// SqlQueryBuilder q;
237 /// q.Migration().AlterTable("Table").DropIndex("column");
238 /// // Will execute DROP INDEX "Table_column_index";
239 /// @endcode
240 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& DropIndex(std::string_view columnName);
241
242 /// Drop an index from the table only if it exists.
243 /// @param columnName The name of the column to drop the index from.
244 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& DropIndexIfExists(std::string_view columnName);
245
246 /// Adds a foreign key column @p columnName to @p referencedColumn to an existing column.
247 ///
248 /// @param columnName The name of the column to add.
249 /// @param referencedColumn The column to reference.
250 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddForeignKey(std::string columnName,
251 SqlForeignKeyReferenceDefinition referencedColumn);
252
253 /// Adds a foreign key column @p columnName of type @p columnType to @p referencedColumn.
254 ///
255 /// @param columnName The name of the column to add.
256 /// @param columnType The type of the column to add.
257 /// @param referencedColumn The column to reference.
258 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddForeignKeyColumn(std::string columnName,
259 SqlColumnTypeDefinition columnType,
260 SqlForeignKeyReferenceDefinition referencedColumn);
261
262 /// Adds a nullable foreign key column @p columnName of type @p columnType to @p referencedColumn.
263 ///
264 /// @param columnName The name of the column to add.
265 /// @param columnType The type of the column to add.
266 /// @param referencedColumn The column to reference.
268 std::string columnName, SqlColumnTypeDefinition columnType, SqlForeignKeyReferenceDefinition referencedColumn);
269
270 /// Drops a foreign key for the column @p columnName from the table.
271 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& DropForeignKey(std::string columnName);
272
273 /// Adds a composite foreign key constraint.
274 ///
275 /// @param columns The columns in the current table.
276 /// @param referencedTableName The referenced table name.
277 /// @param referencedColumns The referenced columns in the referenced table.
278 LIGHTWEIGHT_API SqlAlterTableQueryBuilder& AddCompositeForeignKey(std::vector<std::string> columns,
279 std::string referencedTableName,
280 std::vector<std::string> referencedColumns);
281
282 private:
283 SqlAlterTablePlan& _plan;
284};
285
286namespace detail
287{
288 template <typename Record>
289 void PopulateCreateTableBuilder(SqlCreateTableQueryBuilder& builder)
290 {
291 static_assert(DataMapperRecord<Record>, "Record must satisfy DataMapperRecord");
292
293#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
294 constexpr auto ctx = std::meta::access_context::current();
295 template for (constexpr auto el: define_static_array(nonstatic_data_members_of(^^Record, ctx)))
296 {
297 using FieldType = typename[:std::meta::type_of(el):];
298 if constexpr (FieldWithStorage<FieldType>)
299 {
300 if constexpr (IsAutoIncrementPrimaryKey<FieldType>)
302 std::string(FieldNameOf<el>),
303 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
304 else if constexpr (FieldType::IsPrimaryKey)
305 builder.PrimaryKey(std::string(FieldNameOf<el>),
306 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
307 else if constexpr (IsBelongsTo<FieldType>)
308 {
309 constexpr size_t referencedFieldIndex = []() constexpr -> size_t {
310 auto index = size_t(-1);
311 EnumerateRecordMembers<typename FieldType::ReferencedRecord>(
312 [&index]<size_t J, typename ReferencedFieldType>() constexpr -> void {
313 if constexpr (IsField<ReferencedFieldType>)
314 if constexpr (ReferencedFieldType::IsPrimaryKey)
315 index = J;
316 });
317 return index;
318 }();
319 builder.ForeignKey(
320 std::string(FieldNameOf<el>),
321 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value,
322 SqlForeignKeyReferenceDefinition {
323 .tableName = std::string { RecordTableName<typename FieldType::ReferencedRecord> },
324 .columnName = std::string { FieldNameOf<FieldType::ReferencedField> } });
325 // A foreign key is the column every HasMany load filters on, and none of the
326 // supported engines indexes one implicitly - only MySQL does. Without this the
327 // relation query is a full table scan per owner, which measured 36x slower on
328 // SQLite (6270 ms vs 174 ms for 1000 owners x 10 children).
329 builder.Index();
330 }
331 else if constexpr (FieldType::IsMandatory)
332 builder.RequiredColumn(std::string(FieldNameOf<el>),
333 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
334 else
335 builder.Column(std::string(FieldNameOf<el>),
336 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
337 }
338 }
339#else
340 EnumerateRecordMembers<Record>([&builder]<size_t I, typename FieldType>() {
341 if constexpr (FieldWithStorage<FieldType>)
342 {
343 if constexpr (IsAutoIncrementPrimaryKey<FieldType>)
345 std::string(FieldNameAt<I, Record>()),
346 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
347 else if constexpr (FieldType::IsPrimaryKey)
348 builder.PrimaryKey(std::string(FieldNameAt<I, Record>()),
349 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
350 else if constexpr (IsBelongsTo<FieldType>)
351 {
352 constexpr size_t referencedFieldIndex = []() constexpr -> size_t {
353 auto index = size_t(-1);
354 EnumerateRecordMembers<typename FieldType::ReferencedRecord>(
355 [&index]<size_t J, typename ReferencedFieldType>() constexpr -> void {
356 if constexpr (IsField<ReferencedFieldType>)
357 if constexpr (ReferencedFieldType::IsPrimaryKey)
358 index = J;
359 });
360 return index;
361 }();
362 builder.ForeignKey(
363 std::string(FieldNameAt<I, Record>()),
364 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value,
365 SqlForeignKeyReferenceDefinition {
366 .tableName = std::string { RecordTableName<typename FieldType::ReferencedRecord> },
367 .columnName =
368 std::string { FieldNameAt<referencedFieldIndex, typename FieldType::ReferencedRecord>() } });
369 // See the comment in the reflection branch above: an unindexed foreign key turns
370 // every HasMany load into a full table scan.
371 builder.Index();
372 }
373 else if constexpr (FieldType::IsMandatory)
374 builder.RequiredColumn(std::string(FieldNameAt<I, Record>()),
375 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
376 else
377 builder.Column(std::string(FieldNameAt<I, Record>()),
378 detail::SqlColumnTypeDefinitionOf<typename FieldType::ValueType>::value);
379 }
380 });
381#endif
382 }
383} // namespace detail
384
385/// @brief Query builder for building INSERT queries in migrations.
386///
387/// @see SqlMigrationQueryBuilder
388/// @ingroup QueryBuilder
389class [[nodiscard]] SqlMigrationInsertBuilder final
390{
391 public:
392 /// Constructs a migration INSERT builder.
394 _plan { plan }
395 {
396 }
397
398 /// Sets a column value for the INSERT.
399 template <typename T>
400 SqlMigrationInsertBuilder& Set(std::string columnName, T const& value)
401 {
402 _plan.columns.emplace_back(std::move(columnName), SqlVariant(value));
403 return *this;
404 }
405
406 /// @brief Makes the INSERT skip its row when a row with the same key values already exists.
407 ///
408 /// Renders `INSERT INTO t (...) SELECT ... WHERE NOT EXISTS (SELECT 1 FROM t WHERE key = ...)`,
409 /// so a seed row a database already holds no longer fails the migration. An existing row is
410 /// left as it is, even when its non-key columns differ from the values given here.
411 /// Rendering the plan throws `std::invalid_argument` when a key column is not one of the
412 /// `Set` columns or its value is NULL.
413 ///
414 /// @param keyColumns The columns identifying the row; must not be empty.
415 /// @return This builder, for chaining.
416 /// @throws std::invalid_argument @p keyColumns is empty.
417 LIGHTWEIGHT_API SqlMigrationInsertBuilder& IfNotExists(std::vector<std::string> keyColumns);
418
419 private:
420 SqlInsertDataPlan& _plan;
421};
422
423/// @brief Query builder for building UPDATE queries in migrations.
424///
425/// @see SqlMigrationQueryBuilder
426/// @ingroup QueryBuilder
427class [[nodiscard]] SqlMigrationUpdateBuilder final
428{
429 public:
430 /// Constructs a migration UPDATE builder.
432 _plan { plan }
433 {
434 }
435
436 /// Sets a column value for the UPDATE.
437 template <typename T>
438 SqlMigrationUpdateBuilder& Set(std::string columnName, T const& value)
439 {
440 _plan.setColumns.emplace_back(std::move(columnName), SqlVariant(value));
441 return *this;
442 }
443
444 /// @brief Sets a column to a raw SQL expression — for column-to-column copies
445 /// or arithmetic that cannot be represented as a literal value.
446 ///
447 /// @param columnName The target column.
448 /// @param expression The raw SQL fragment (e.g. `"OTHER_COL"`, `"CTR" + 1`) emitted
449 /// verbatim after the `=`. The caller is responsible for any
450 /// identifier quoting.
451 SqlMigrationUpdateBuilder& SetExpression(std::string columnName, std::string expression)
452 {
453 _plan.setExpressions.emplace_back(std::move(columnName), std::move(expression));
454 return *this;
455 }
456
457 /// Adds a WHERE condition to the UPDATE.
458 template <typename T>
459 SqlMigrationUpdateBuilder& Where(std::string columnName, std::string op, T const& value)
460 {
461 _plan.whereColumn = std::move(columnName);
462 _plan.whereOp = std::move(op);
463 _plan.whereValue = SqlVariant(value);
464 return *this;
465 }
466
467 /// @brief Supplies a pre-rendered WHERE-clause body for cases that don't fit the
468 /// simple `(column, op, value)` form — composite `AND`/`OR`/`NOT`, `IS NULL`,
469 /// `IN (subquery)`, `EXISTS (subquery)`, etc.
470 ///
471 /// The text is emitted verbatim after `WHERE` at execution time; the caller is
472 /// responsible for dialect-safe quoting.
473 /// @param expression Pre-rendered SQL clause body (without the leading `WHERE`).
475 {
476 _plan.whereExpression = std::move(expression);
477 return *this;
478 }
479
480 private:
481 SqlUpdateDataPlan& _plan;
482};
483
484/// @brief Query builder for building DELETE queries in migrations.
485///
486/// @see SqlMigrationQueryBuilder
487/// @ingroup QueryBuilder
488class [[nodiscard]] SqlMigrationDeleteBuilder final
489{
490 public:
491 /// Constructs a migration DELETE builder.
493 _plan { plan }
494 {
495 }
496
497 /// Adds a WHERE condition to the DELETE.
498 template <typename T>
499 SqlMigrationDeleteBuilder& Where(std::string columnName, std::string op, T const& value)
500 {
501 _plan.whereColumn = std::move(columnName);
502 _plan.whereOp = std::move(op);
503 _plan.whereValue = SqlVariant(value);
504 return *this;
505 }
506
507 /// Pre-rendered WHERE-clause body. See `SqlMigrationUpdateBuilder::WhereExpression`.
509 {
510 _plan.whereExpression = std::move(expression);
511 return *this;
512 }
513
514 private:
515 SqlDeleteDataPlan& _plan;
516};
517
518/// @brief Query builder for building SQL migration queries.
519/// @ingroup QueryBuilder
520class [[nodiscard]] SqlMigrationQueryBuilder final
521{
522 public:
523 /// Constructs a migration query builder.
524 explicit SqlMigrationQueryBuilder(SqlQueryFormatter const& formatter):
525 _formatter { formatter },
526 _migrationPlan { .formatter = formatter }
527 {
528 }
529
530 /// Sets the schema name for the migration.
531 ///
532 /// On SQL Server and PostgreSQL, `CreateTable` then creates the table in that schema, which must
533 /// exist. On PostgreSQL this differs from earlier releases, which created it in the `search_path`
534 /// schema, so the checksums of such migrations changed (see `dbtool rewrite-checksums`).
535 LIGHTWEIGHT_API SqlMigrationQueryBuilder& WithSchema(std::string schemaName);
536
537 /// Creates a new database.
538 LIGHTWEIGHT_API SqlMigrationQueryBuilder& CreateDatabase(std::string_view databaseName);
539
540 /// Drops a database.
541 LIGHTWEIGHT_API SqlMigrationQueryBuilder& DropDatabase(std::string_view databaseName);
542
543 /// Creates a new table.
544 LIGHTWEIGHT_API SqlCreateTableQueryBuilder CreateTable(std::string_view tableName);
545
546 /// Creates a new table only if it does not already exist.
547 ///
548 /// @note Database support:
549 /// - SQLite: Native CREATE TABLE IF NOT EXISTS
550 /// - PostgreSQL: Native CREATE TABLE IF NOT EXISTS
551 /// - SQL Server: Uses conditional IF NOT EXISTS block
552 LIGHTWEIGHT_API SqlCreateTableQueryBuilder CreateTableIfNotExists(std::string_view tableName);
553
554 /// Alters an existing table.
555 LIGHTWEIGHT_API SqlAlterTableQueryBuilder AlterTable(std::string_view tableName);
556
557 /// Drops a table.
558 LIGHTWEIGHT_API SqlMigrationQueryBuilder& DropTable(std::string_view tableName);
559
560 /// Drops a table if it exists.
561 LIGHTWEIGHT_API SqlMigrationQueryBuilder& DropTableIfExists(std::string_view tableName);
562
563 /// Drops a table and all foreign key constraints referencing it.
564 /// On PostgreSQL, uses CASCADE. On MS SQL, drops FK constraints first.
565 LIGHTWEIGHT_API SqlMigrationQueryBuilder& DropTableCascade(std::string_view tableName);
566
567 /// Creates a new table for the given record type.
568 template <typename Record>
570 {
571 static_assert(DataMapperRecord<Record>, "Record must satisfy DataMapperRecord");
572
573 auto builder = CreateTable(RecordTableName<Record>);
574 detail::PopulateCreateTableBuilder<Record>(builder);
575 return builder;
576 }
577
578 /// Alters an existing table.
579 template <typename Record>
581 {
582 static_assert(DataMapperRecord<Record>, "Record must satisfy DataMapperRecord");
583 return AlterTable(RecordTableName<Record>);
584 }
585
586 /// Executes raw SQL.
587 LIGHTWEIGHT_API SqlMigrationQueryBuilder& RawSql(std::string_view sql);
588
589 /// Creates an index on a table.
590 ///
591 /// @param indexName The name of the index to create.
592 /// @param tableName The name of the table to create the index on.
593 /// @param columns The columns to include in the index.
594 /// @param unique If true, creates a UNIQUE index.
595 ///
596 /// @code
597 /// SqlQueryBuilder q;
598 /// q.Migration().CreateIndex("idx_user_email", "users", {"email"});
599 /// // Will execute CREATE INDEX "idx_user_email" ON "users" ("email");
600 /// @endcode
601 LIGHTWEIGHT_API SqlMigrationQueryBuilder& CreateIndex(std::string indexName,
602 std::string tableName,
603 std::vector<std::string> columns,
604 bool unique = false);
605
606 /// Creates an index on a table, optionally unique and/or partial.
607 ///
608 /// A non-empty `options.whereExpression` renders a partial / filtered index,
609 /// `CREATE [UNIQUE] INDEX ... ON t (cols) WHERE <expression>`, which SQLite,
610 /// PostgreSQL and SQL Server all support.
611 ///
612 /// @note SQL Server creates a filtered index, and accepts writes to its table, only with
613 /// `ANSI_WARNINGS ON`, i.e. on connections using @ref SqlStringTruncationMode::Error;
614 /// the default @ref SqlStringTruncationMode::Truncate fails them with error 1934.
615 ///
616 /// @param indexName The name of the index to create.
617 /// @param tableName The name of the table to create the index on.
618 /// @param columns The columns to include in the index.
619 /// @param options Uniqueness and the optional index predicate.
620 ///
621 /// @code
622 /// SqlQueryBuilder q;
623 /// q.Migration().CreateIndex("idx_queue_key", "queue", {"dedup_key"},
624 /// {.type = IndexType::Unique, .whereExpression = R"("dedup_key" <> '')"});
625 /// // Will execute CREATE UNIQUE INDEX "idx_queue_key" ON "queue" ("dedup_key") WHERE "dedup_key" <> ''
626 /// @endcode
627 LIGHTWEIGHT_API SqlMigrationQueryBuilder& CreateIndex(std::string indexName,
628 std::string tableName,
629 std::vector<std::string> columns,
630 SqlCreateIndexOptions options);
631
632 /// Creates a unique index on a table.
633 ///
634 /// @param indexName The name of the index to create.
635 /// @param tableName The name of the table to create the index on.
636 /// @param columns The columns to include in the index.
637 LIGHTWEIGHT_API SqlMigrationQueryBuilder& CreateUniqueIndex(std::string indexName,
638 std::string tableName,
639 std::vector<std::string> columns);
640
641 /// Creates an index on a table with auto-generated name.
642 ///
643 /// The index name is automatically generated as `idx_{tableName}_{col1}_{col2}_...`
644 ///
645 /// @param tableName The name of the table to create the index on.
646 /// @param columns The columns to include in the index.
647 /// @param type The type of index (NonUnique or Unique).
648 ///
649 /// @code
650 /// SqlQueryBuilder q;
651 /// q.Migration().CreateIndex("users", {"email"}, IndexType::Unique);
652 /// // Will execute CREATE UNIQUE INDEX "idx_users_email" ON "users" ("email");
653 /// @endcode
654 LIGHTWEIGHT_API SqlMigrationQueryBuilder& CreateIndex(std::string tableName,
655 std::vector<std::string> columns,
657
658 /// Creates an INSERT statement for the migration.
659 LIGHTWEIGHT_API SqlMigrationInsertBuilder Insert(std::string_view tableName);
660
661 /// Creates an UPDATE statement for the migration.
662 LIGHTWEIGHT_API SqlMigrationUpdateBuilder Update(std::string_view tableName);
663
664 /// Creates a DELETE statement for the migration.
665 LIGHTWEIGHT_API SqlMigrationDeleteBuilder Delete(std::string_view tableName);
666
667 /// Starts a transaction.
669
670 /// Commits a transaction.
672
673 /// Gets the migration plan.
674 [[nodiscard]] LIGHTWEIGHT_API SqlMigrationPlan const& GetPlan() const&;
675
676 /// Gets the migration plan.
677 ///
678 /// @note This method is destructive and will invalidate the current builder.
679 LIGHTWEIGHT_API SqlMigrationPlan GetPlan() &&;
680
681 private:
682 SqlQueryFormatter const& _formatter;
683 std::string _schemaName;
684 SqlMigrationPlan _migrationPlan;
685};
686
687} // namespace Lightweight
Query builder for building ALTER TABLE queries.
Definition Migrate.hpp:114
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & DropIndex(std::string_view columnName)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & DropIndexIfExists(std::string_view columnName)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & DropColumn(std::string_view columnName)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddColumn(std::string columnName, SqlColumnTypeDefinition columnType)
Adds a new column to the table that is non-nullable.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & RenameColumn(std::string_view oldColumnName, std::string_view newColumnName)
SqlAlterTableQueryBuilder & AddColumn()
Definition Migrate.hpp:134
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & RenameTo(std::string_view newTableName)
Renames the table.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddIndex(std::string_view columnName)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddNotRequiredForeignKeyColumn(std::string columnName, SqlColumnTypeDefinition columnType, SqlForeignKeyReferenceDefinition referencedColumn)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddNotRequiredColumn(std::string columnName, SqlColumnTypeDefinition columnType)
Adds a new column to the table that is nullable.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddUniqueIndex(std::string_view columnName)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & DropColumnIfExists(std::string_view columnName)
Drops a column from the table only if it exists.
SqlAlterTableQueryBuilder(SqlAlterTablePlan &plan)
Constructs an ALTER TABLE query builder.
Definition Migrate.hpp:117
SqlAlterTableQueryBuilder & AddNotRequiredColumn()
Definition Migrate.hpp:150
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & DropForeignKey(std::string columnName)
Drops a foreign key for the column columnName from the table.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AlterColumn(std::string columnName, SqlColumnTypeDefinition columnType, SqlNullable nullable)
Alters the column to have a new non-nullable type.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddForeignKey(std::string columnName, SqlForeignKeyReferenceDefinition referencedColumn)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddColumnIfNotExists(std::string columnName, SqlColumnTypeDefinition columnType)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddNotRequiredColumnIfNotExists(std::string columnName, SqlColumnTypeDefinition columnType)
Adds a new nullable column to the table only if it does not already exist.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddForeignKeyColumn(std::string columnName, SqlColumnTypeDefinition columnType, SqlForeignKeyReferenceDefinition referencedColumn)
LIGHTWEIGHT_API SqlAlterTableQueryBuilder & AddCompositeForeignKey(std::vector< std::string > columns, std::string referencedTableName, std::vector< std::string > referencedColumns)
Query builder for building CREATE TABLE queries.
Definition Migrate.hpp:53
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & ForeignKey(std::vector< std::string > columns, std::string referencedTableName, std::vector< std::string > referencedColumns)
Adds a composite foreign key constraint.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & Timestamps()
Adds the created_at and updated_at columns to the table.
SqlCreateTableQueryBuilder(SqlCreateTablePlan &plan)
Constructs a CREATE TABLE query builder.
Definition Migrate.hpp:56
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & RequiredColumn(std::string columnName, SqlColumnTypeDefinition columnType)
Creates a new column that is non-nullable.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & RequiredForeignKey(std::string columnName, SqlColumnTypeDefinition columnType, SqlForeignKeyReferenceDefinition foreignKey)
Creates a new non-nullable foreign key column.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & ForeignKey(std::string columnName, SqlColumnTypeDefinition columnType, SqlForeignKeyReferenceDefinition foreignKey)
Creates a new nullable foreign key column.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & Index()
Enables the INDEX constraint on the last declared column.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & UniqueIndex()
Enables the UNIQUE and INDEX constraint on the last declared column and makes it an index.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & PrimaryKey(std::string columnName, SqlColumnTypeDefinition columnType)
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & Column(SqlColumnDeclaration column)
Adds a new column to the table.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & Column(std::string columnName, SqlColumnTypeDefinition columnType)
Creates a new nullable column.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & PrimaryKeyWithAutoIncrement(std::string columnName, SqlColumnTypeDefinition columnType=SqlColumnTypeDefinitions::Bigint {})
Creates a new primary key column with auto-increment.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder & Unique()
Enables the UNIQUE constraint on the last declared column.
Query builder for building DELETE queries in migrations.
Definition Migrate.hpp:489
SqlMigrationDeleteBuilder & Where(std::string columnName, std::string op, T const &value)
Adds a WHERE condition to the DELETE.
Definition Migrate.hpp:499
SqlMigrationDeleteBuilder(SqlDeleteDataPlan &plan)
Constructs a migration DELETE builder.
Definition Migrate.hpp:492
SqlMigrationDeleteBuilder & WhereExpression(std::string expression)
Pre-rendered WHERE-clause body. See SqlMigrationUpdateBuilder::WhereExpression.
Definition Migrate.hpp:508
Query builder for building INSERT queries in migrations.
Definition Migrate.hpp:390
SqlMigrationInsertBuilder(SqlInsertDataPlan &plan)
Constructs a migration INSERT builder.
Definition Migrate.hpp:393
SqlMigrationInsertBuilder & Set(std::string columnName, T const &value)
Sets a column value for the INSERT.
Definition Migrate.hpp:400
LIGHTWEIGHT_API SqlMigrationInsertBuilder & IfNotExists(std::vector< std::string > keyColumns)
Makes the INSERT skip its row when a row with the same key values already exists.
Query builder for building SQL migration queries.
Definition Migrate.hpp:521
LIGHTWEIGHT_API SqlCreateTableQueryBuilder CreateTable(std::string_view tableName)
Creates a new table.
SqlCreateTableQueryBuilder CreateTable()
Creates a new table for the given record type.
Definition Migrate.hpp:569
LIGHTWEIGHT_API SqlMigrationQueryBuilder & CommitTransaction()
Commits a transaction.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & RawSql(std::string_view sql)
Executes raw SQL.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & CreateIndex(std::string indexName, std::string tableName, std::vector< std::string > columns, bool unique=false)
LIGHTWEIGHT_API SqlMigrationDeleteBuilder Delete(std::string_view tableName)
Creates a DELETE statement for the migration.
LIGHTWEIGHT_API SqlAlterTableQueryBuilder AlterTable(std::string_view tableName)
Alters an existing table.
LIGHTWEIGHT_API SqlCreateTableQueryBuilder CreateTableIfNotExists(std::string_view tableName)
LIGHTWEIGHT_API SqlMigrationPlan const & GetPlan() const &
Gets the migration plan.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & DropTable(std::string_view tableName)
Drops a table.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & CreateIndex(std::string tableName, std::vector< std::string > columns, IndexType type=IndexType::NonUnique)
LIGHTWEIGHT_API SqlMigrationUpdateBuilder Update(std::string_view tableName)
Creates an UPDATE statement for the migration.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & WithSchema(std::string schemaName)
LIGHTWEIGHT_API SqlMigrationQueryBuilder & CreateUniqueIndex(std::string indexName, std::string tableName, std::vector< std::string > columns)
LIGHTWEIGHT_API SqlMigrationInsertBuilder Insert(std::string_view tableName)
Creates an INSERT statement for the migration.
SqlAlterTableQueryBuilder AlterTable()
Alters an existing table.
Definition Migrate.hpp:580
LIGHTWEIGHT_API SqlMigrationQueryBuilder & BeginTransaction()
Starts a transaction.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & CreateIndex(std::string indexName, std::string tableName, std::vector< std::string > columns, SqlCreateIndexOptions options)
LIGHTWEIGHT_API SqlMigrationQueryBuilder & DropTableCascade(std::string_view tableName)
SqlMigrationQueryBuilder(SqlQueryFormatter const &formatter)
Constructs a migration query builder.
Definition Migrate.hpp:524
LIGHTWEIGHT_API SqlMigrationQueryBuilder & DropDatabase(std::string_view databaseName)
Drops a database.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & DropTableIfExists(std::string_view tableName)
Drops a table if it exists.
LIGHTWEIGHT_API SqlMigrationQueryBuilder & CreateDatabase(std::string_view databaseName)
Creates a new database.
Query builder for building UPDATE queries in migrations.
Definition Migrate.hpp:428
SqlMigrationUpdateBuilder & Where(std::string columnName, std::string op, T const &value)
Adds a WHERE condition to the UPDATE.
Definition Migrate.hpp:459
SqlMigrationUpdateBuilder & WhereExpression(std::string expression)
Supplies a pre-rendered WHERE-clause body for cases that don't fit the simple (column,...
Definition Migrate.hpp:474
SqlMigrationUpdateBuilder & Set(std::string columnName, T const &value)
Sets a column value for the UPDATE.
Definition Migrate.hpp:438
SqlMigrationUpdateBuilder & SetExpression(std::string columnName, std::string expression)
Sets a column to a raw SQL expression — for column-to-column copies or arithmetic that cannot be repr...
Definition Migrate.hpp:451
SqlMigrationUpdateBuilder(SqlUpdateDataPlan &plan)
Constructs a migration UPDATE builder.
Definition Migrate.hpp:431
API to format SQL queries for different SQL dialects.
Represents a record type that can be used with the DataMapper.
Definition Record.hpp:52
std::remove_cvref_t< decltype(std::declval< MemberClassType< decltype(Field)> >().*Field)>::ValueType ReferencedFieldTypeOf
Retrieves the type of a member field in a record.
Definition Field.hpp:495
IndexType
Index type for simplified CreateIndex API.
Definition Migrate.hpp:20
constexpr auto SqlColumnTypeDefinitionOf
Represents a SQL column type definition of T.
@ NonUnique
Regular (non-unique) index.
@ Unique
Unique index.
Represents a SQL ALTER TABLE plan on a given table.
Represents a SQL column declaration.
Optional settings for SqlMigrationQueryBuilder::CreateIndex.
Definition Migrate.hpp:36
IndexType type
Whether the index enforces uniqueness.
Definition Migrate.hpp:38
Represents a SQL DELETE data plan for migrations.
Represents a foreign key reference definition.
Represents a SQL INSERT data plan for migrations.
Represents a SQL migration plan.
Represents a SQL UPDATE data plan for migrations.
Represents a value that can be any of the supported SQL data types.