Lightweight 0.20260303.0
Loading...
Searching...
No Matches
SqlMigration.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "Api.hpp"
6#include "DataMapper/DataMapper.hpp"
7#include "SqlError.hpp"
8#include "SqlQuery/Migrate.hpp"
9#include "SqlQuery/MigrationPlan.hpp"
10#include "SqlSchema.hpp"
11#include "SqlTransaction.hpp"
12
13#include <cstddef>
14#include <cstdint>
15#include <functional>
16#include <list>
17#include <map>
18#include <optional>
19#include <set>
20#include <string>
21#include <string_view>
22#include <vector>
23
24namespace Lightweight
25{
26
27class SqlConnection;
28
29/// @defgroup SqlMigration SQL Migration
30/// @brief Classes and functions for SQL schema migrations.
31
32namespace SqlMigration
33{
34 class MigrationBase;
35
36 /// Represents a unique timestamp of a migration.
37 ///
38 /// This struct is used to identify migrations and is used as a key in the migration history table.
39 ///
40 /// Note, a recommended format for the timestamp is a human readable format like YYYYMMDDHHMMSS
41 ///
42 /// @code
43 /// MigrationTimestamp { 2026'01'17'00'31'20 };
44 /// @endcode
45 ///
46 /// @ingroup SqlMigration
48 {
49 /// The numeric timestamp value identifying the migration.
50 uint64_t value {};
51
52 /// Three-way comparison operator.
53 constexpr std::weak_ordering operator<=>(MigrationTimestamp const& other) const noexcept = default;
54 };
55
56 /// Exception thrown when applying or reverting a single migration fails.
57 ///
58 /// Carries structured diagnostic context so callers (CLI, GUI) can render
59 /// the *which migration*, *which step*, *which SQL statement* and the
60 /// underlying driver error as separate fields instead of parsing one
61 /// opaque message string.
62 ///
63 /// @ingroup SqlMigration
64 class LIGHTWEIGHT_API MigrationException: public SqlException
65 {
66 public:
67 /// Whether the failure happened while applying (Up) or reverting (Down).
68 enum class Operation : std::uint8_t
69 {
70 Apply,
71 Revert,
72 };
73
74 /// Constructs a migration exception that wraps a driver error with
75 /// the migration identity and the exact SQL statement that failed.
76 ///
77 /// @param operation Whether the failure happened during apply or revert.
78 /// @param timestamp The migration that failed.
79 /// @param title Human-readable migration title.
80 /// @param stepIndex Zero-based step index inside the migration plan.
81 /// @param failedSql The SQL statement that produced the driver error.
82 /// @param driverError The ODBC-level error info as received from the driver.
84 MigrationTimestamp timestamp,
85 std::string title,
86 std::size_t stepIndex,
87 std::string failedSql,
88 SqlErrorInfo driverError);
89
90 /// Whether the failure occurred while applying or reverting.
91 [[nodiscard]] Operation GetOperation() const noexcept
92 {
93 return _operation;
94 }
95 /// Timestamp of the failing migration.
96 [[nodiscard]] MigrationTimestamp GetMigrationTimestamp() const noexcept
97 {
98 return _timestamp;
99 }
100 /// Human-readable title of the failing migration.
101 [[nodiscard]] std::string const& GetMigrationTitle() const noexcept
102 {
103 return _title;
104 }
105 /// Zero-based step index inside the plan of the failing migration.
106 [[nodiscard]] std::size_t GetStepIndex() const noexcept
107 {
108 return _stepIndex;
109 }
110 /// The exact SQL statement that the driver rejected.
111 [[nodiscard]] std::string const& GetFailedSql() const noexcept
112 {
113 return _failedSql;
114 }
115 /// Raw driver error message, without the migration context prefix that
116 /// `what()` and `info().message` decorate it with.
117 [[nodiscard]] std::string const& GetDriverMessage() const noexcept
118 {
119 return _driverMessage;
120 }
121
122 private:
123 Operation _operation;
124 MigrationTimestamp _timestamp;
125 std::string _title;
126 std::size_t _stepIndex;
127 std::string _failedSql;
128 std::string _driverMessage;
129 };
130
131 /// Result of verifying a migration's checksum.
132 ///
133 /// @ingroup SqlMigration
135 {
136 MigrationTimestamp timestamp; ///< The timestamp of the verified migration.
137 std::string_view title; ///< The title of the verified migration.
138 std::string storedChecksum; ///< The checksum stored in the database.
139 std::string computedChecksum; ///< The checksum computed from the current migration definition.
140 bool matches; ///< Whether the stored and computed checksums match.
141 };
142
143 /// Result of reverting multiple migrations.
144 ///
145 /// @ingroup SqlMigration
147 {
148 std::vector<MigrationTimestamp> revertedTimestamps; ///< Successfully reverted migrations
149 std::optional<MigrationTimestamp> failedAt; ///< Migration that failed, if any
150 std::string errorMessage; ///< Short error message if failed (driver message only)
151
152 /// Title of the migration that failed (if any). Empty when no failure or
153 /// when the failure happened before the migration could be located.
154 std::string failedTitle;
155
156 /// Zero-based step index inside the failed migration's plan. Meaningful
157 /// only when `failedAt` is set and the failure came from a driver error
158 /// (not from e.g. a missing registered migration).
159 std::size_t failedStepIndex {};
160
161 /// The exact SQL statement that failed, if available. Empty when the
162 /// failure happened outside of SQL execution (e.g. missing Down()
163 /// implementation, unregistered migration).
164 std::string failedSql;
165
166 /// SQLSTATE diagnostic code from the driver, if available.
167 std::string sqlState;
168
169 /// Native driver error code, if available.
170 SQLINTEGER nativeErrorCode {};
171 };
172
173 /// Status summary of migrations.
174 ///
175 /// @ingroup SqlMigration
177 {
178 size_t appliedCount {}; ///< Number of migrations that have been applied
179 size_t pendingCount {}; ///< Number of migrations waiting to be applied
180 size_t mismatchCount {}; ///< Number of applied migrations with checksum mismatches
181 size_t unknownAppliedCount {}; ///< Number of applied migrations not found in registered list
182 size_t totalRegistered {}; ///< Total number of registered migrations
183 };
184
185 /// Associates a software release with the highest migration timestamp present at release time.
186 ///
187 /// Releases are declared in source (typically a migration plugin) via
188 /// `LIGHTWEIGHT_SQL_RELEASE(version, highestTimestamp)`. They let tools answer questions like
189 /// "which migrations belong to release 6.7.0?" or "roll back everything applied after 6.7.0".
190 ///
191 /// The `highestTimestamp` is an inclusive upper bound: a migration `M` belongs to the release
192 /// iff `prev_release_ts < M.timestamp <= highestTimestamp`, where `prev_release_ts` is the
193 /// previous release's timestamp (or 0 if there is none).
194 ///
195 /// @ingroup SqlMigration
197 {
198 /// Human-readable version string, e.g. "6.7.0".
199 std::string version;
200 /// Highest migration timestamp contained in this release (inclusive).
202 };
203
204 /// Main API to use for managing SQL migrations
205 ///
206 /// This class is a singleton and can be accessed using the GetInstance() method.
207 ///
208 /// @ingroup SqlMigration
210 {
211 public:
212 /// Type alias for a list of migration pointers.
213 using MigrationList = std::list<MigrationBase const*>;
214
215 /// Get the singleton instance of the migration manager.
216 ///
217 /// @return Reference to the migration manager.
218 /// Get the singleton instance of the migration manager.
219 ///
220 /// @return Reference to the migration manager.
221 LIGHTWEIGHT_API static MigrationManager& GetInstance();
222
223 /// Add a migration to the manager.
224 ///
225 /// @param migration Pointer to the migration to add.
226 LIGHTWEIGHT_API void AddMigration(MigrationBase const* migration);
227
228 /// Get all migrations that have been added to the manager.
229 ///
230 /// @return List of migrations.
231 [[nodiscard]] LIGHTWEIGHT_API MigrationList const& GetAllMigrations() const noexcept;
232
233 /// Get a migration by timestamp.
234 ///
235 /// @param timestamp Timestamp of the migration to get.
236 /// @return Pointer to the migration if found, nullptr otherwise.
237 [[nodiscard]] LIGHTWEIGHT_API MigrationBase const* GetMigration(MigrationTimestamp timestamp) const noexcept;
238
239 /// Remove all migrations from the manager.
240 ///
241 /// This function is useful if the migration manager should be reset.
242 LIGHTWEIGHT_API void RemoveAllMigrations();
243
244 /// Get all migrations that have not been applied yet.
245 ///
246 /// @return List of pending migrations.
247 [[nodiscard]] LIGHTWEIGHT_API std::list<MigrationBase const*> GetPending() const noexcept;
248
249 /// Callback type invoked during migration execution to report progress.
251 std::function<void(MigrationBase const& /*migration*/, size_t /*current*/, size_t /*total*/)>;
252
253 /// Apply a single migration from a migration object.
254 ///
255 /// @param migration Pointer to the migration to apply.
256 LIGHTWEIGHT_API void ApplySingleMigration(MigrationBase const& migration);
257
258 /// @brief Variant of `ApplySingleMigration` that threads a caller-owned render
259 /// context through to `ToSql`. Use this from loops over multiple migrations so
260 /// the column-width cache (and other per-run compat state) accumulates across
261 /// the sequence.
262 LIGHTWEIGHT_API void ApplySingleMigration(MigrationBase const& migration, MigrationRenderContext& context);
263
264 /// Revert a single migration from a migration object.
265 ///
266 /// @param migration Pointer to the migration to revert.
267 LIGHTWEIGHT_API void RevertSingleMigration(MigrationBase const& migration);
268
269 /// Apply all migrations that have not been applied yet.
270 ///
271 /// @param feedbackCallback Callback to be called for each migration.
272 /// @return Number of applied migrations.
273 LIGHTWEIGHT_API size_t ApplyPendingMigrations(ExecuteCallback const& feedbackCallback = {});
274
275 /// Apply pending migrations whose timestamp is <= `targetInclusive`.
276 ///
277 /// Honors dependency-respecting topological order, just like
278 /// `ApplyPendingMigrations`, and threads a single render context across
279 /// the run so column-width state from earlier CREATE TABLEs is visible
280 /// to later compat-aware INSERT/UPDATE rendering.
281 ///
282 /// If a pending migration with `ts <= target` declares a dependency on
283 /// a migration whose timestamp is `> target` (i.e. excluded by the
284 /// bound) and is not already applied, this throws — partial states
285 /// that violate dependencies are refused up front.
286 ///
287 /// @param targetInclusive Highest timestamp to apply (inclusive).
288 /// @param feedbackCallback Callback to be called for each migration.
289 /// @return Number of applied migrations (may be zero if already past `targetInclusive`).
290 /// @throws std::runtime_error if a dependency would cross the boundary.
291 LIGHTWEIGHT_API size_t ApplyPendingMigrationsUpTo(MigrationTimestamp targetInclusive,
292 ExecuteCallback const& feedbackCallback = {});
293
294 /// Create the migration history table if it does not exist.
295 LIGHTWEIGHT_API void CreateMigrationHistory();
296
297 /// Get all applied migration IDs.
298 ///
299 /// @return Vector of applied migration IDs.
300 [[nodiscard]] LIGHTWEIGHT_API std::vector<MigrationTimestamp> GetAppliedMigrationIds() const;
301
302 /// Get the data mapper used for migrations.
303 [[nodiscard]] LIGHTWEIGHT_API DataMapper& GetDataMapper();
304
305 /// Get the data mapper used for migrations.
306 [[nodiscard]] LIGHTWEIGHT_API DataMapper& GetDataMapper() const
307 {
308 return const_cast<MigrationManager*>(this)->GetDataMapper();
309 }
310
311 /// Close the data mapper.
312 ///
313 /// This function is useful if explicitly closing the connection is desired before
314 /// the migration manager is destroyed.
315 LIGHTWEIGHT_API void CloseDataMapper();
316
317 /// @brief Per-migration compat policy.
318 ///
319 /// Given a migration about to be applied (or previewed), returns the set of compat
320 /// flags that should be active while rendering it. Plugins that ship legacy
321 /// migrations use this to scope compat behaviour to their own timestamp range
322 /// (e.g. `LupMigrationsPlugin` enables `lup-truncate` for migrations predating
323 /// release 6.0.0). Unset means "strict for every migration".
324 using CompatPolicy = std::function<std::set<std::string>(MigrationBase const&)>;
325
326 /// @brief Installs a per-migration compat policy. Pass `{}` to clear.
327 ///
328 /// Typically called once from a plugin's static initializer. Replaces any policy
329 /// previously installed — composition is the caller's responsibility for now.
330 LIGHTWEIGHT_API void SetCompatPolicy(CompatPolicy policy);
331
332 /// @brief Returns a view of the installed policy so it can be propagated across
333 /// managers (plugin → central). Empty callable if no policy was installed.
334 [[nodiscard]] LIGHTWEIGHT_API CompatPolicy const& GetCompatPolicy() const noexcept;
335
336 /// @brief Composes an additional policy with the currently installed one. If no
337 /// policy is installed, the argument becomes the policy as-is; otherwise both
338 /// policies are consulted and their flag sets unioned per migration.
339 LIGHTWEIGHT_API void ComposeCompatPolicy(CompatPolicy policy);
340
341 /// @brief Returns the compat flags the current policy assigns to `migration`, or
342 /// an empty set if no policy is installed.
343 [[nodiscard]] LIGHTWEIGHT_API std::set<std::string> CompatFlagsFor(MigrationBase const& migration) const;
344
345 /// Get a transaction for the data mapper.
346 ///
347 /// @return Transaction.
348 LIGHTWEIGHT_API SqlTransaction Transaction();
349
350 /// Preview SQL statements for a single migration without executing.
351 ///
352 /// This is useful for dry-run mode to see what SQL would be executed.
353 ///
354 /// @param migration The migration to preview.
355 /// @return Vector of SQL statements that would be executed.
356 [[nodiscard]] LIGHTWEIGHT_API std::vector<std::string> PreviewMigration(MigrationBase const& migration) const;
357
358 /// @brief Variant of `PreviewMigration` that threads a caller-owned render
359 /// context so the column-width cache accumulates across a sequence of preview
360 /// calls. Used by `PreviewPendingMigrations` to render compat-aware dry runs.
361 [[nodiscard]] LIGHTWEIGHT_API std::vector<std::string> PreviewMigrationWithContext(
362 MigrationBase const& migration, MigrationRenderContext& context) const;
363
364 /// @brief One row in the `RewriteChecksumsResult.entries` list.
366 {
367 MigrationTimestamp timestamp; ///< The migration whose stored checksum was rewritten.
368 std::string_view title; ///< Title of the registered migration (or "(Unknown Migration)").
369 std::string oldChecksum; ///< Stored checksum before the rewrite. Empty if there was none.
370 std::string newChecksum; ///< Stored checksum after the rewrite.
371 };
372
373 /// @brief Result of a `RewriteChecksums` call.
375 {
376 std::vector<ChecksumRewriteEntry> entries; ///< One entry per rewritten or would-be-rewritten row.
377 std::vector<MigrationTimestamp>
378 unregisteredTimestamps; ///< Applied rows whose migration is no longer registered.
379 bool wasDryRun = false; ///< True if the call ran in dry-run mode.
380 };
381
382 /// @brief Snapshot of the schema the registered migrations *intend* to produce.
383 ///
384 /// Pure plan-walk — never executes SQL, never opens a connection. Folds the
385 /// effects of every registered migration (up to an optional cut-off timestamp)
386 /// into a per-table view of "the final shape" plus a chronological list of
387 /// data steps and surviving indexes/releases. Used by:
388 ///
389 /// - `dbtool fold` to emit a self-contained baseline (`.cpp` plugin or `.sql`)
390 /// - `HardReset` to know which tables the migrations would have created
391 /// - `UnicodeUpgradeTables` to know which char/varchar columns the migrations
392 /// now declare wide
393 ///
394 /// All three are pure operations — `FoldRegisteredMigrations` itself never
395 /// executes a single statement. See `FoldRegisteredMigrations` for the API.
397 {
398 /// Per-table state: ordered column declarations + per-table FK list.
400 {
401 /// Ordered column declarations as they would be emitted in CREATE TABLE.
402 std::vector<SqlColumnDeclaration> columns;
403 /// Composite foreign keys declared on this table (single-column FKs are
404 /// carried inline on the corresponding `SqlColumnDeclaration::foreignKey`).
405 std::vector<SqlCompositeForeignKeyConstraint> compositeForeignKeys;
406 /// Whether the original CREATE TABLE used IF NOT EXISTS (carried through
407 /// to emitters so they can replay it verbatim).
408 bool ifNotExists = false;
409 };
410
411 /// (schema, table) → folded `TableState`. Insertion order is *not* preserved by
412 /// `std::map` — for emission order use `creationOrder` below.
413 std::map<SqlSchema::FullyQualifiedTableName, TableState> tables;
414
415 /// Tables in *creation* order (first-time-seen). Reverse for safe DROP ordering
416 /// when tearing the schema down.
417 std::vector<SqlSchema::FullyQualifiedTableName> creationOrder;
418
419 /// Indexes that survive folding (created on tables still present at end).
420 std::vector<SqlCreateIndexPlan> indexes;
421
422 /// One data step (INSERT/UPDATE/DELETE/RawSql) tagged with its source migration.
423 struct DataStep
424 {
425 /// Timestamp of the migration that contributed this data step.
427 /// Title of the migration that contributed this data step.
428 std::string sourceTitle;
429 /// The plan element itself (INSERT, UPDATE, DELETE, or RawSql).
431 };
432
433 /// Data steps in chronological order. **No coalescing** — the fold replays
434 /// every data step verbatim, exactly as if migrations were applied in order.
435 std::vector<DataStep> dataSteps;
436
437 /// Releases declared via `LIGHTWEIGHT_SQL_RELEASE` that fall within the fold range.
438 std::vector<MigrationRelease> releases;
439
440 /// Migrations that contributed to the fold (timestamp + title). Used by emitters
441 /// to write a header comment explaining what was collapsed.
442 std::vector<std::pair<MigrationTimestamp, std::string>> foldedMigrations;
443 };
444
445 /// @brief Pure plan-walk that folds the effect of every registered migration.
446 ///
447 /// Visits each migration's `Up()` plan in timestamp order (or up to
448 /// `upToInclusive` if provided) and accumulates the cumulative end-state into a
449 /// `PlanFoldingResult`. **Never** executes SQL or touches a database connection
450 /// — the supplied formatter is only used to build the in-memory plan elements.
451 ///
452 /// @param formatter Formatter used by the migration query builder while walking
453 /// each migration's `Up()`. Any standard formatter works; the
454 /// walk inspects plan element shapes, not rendered SQL.
455 /// @param upToInclusive If set, fold only migrations with `timestamp <= upToInclusive`.
456 /// If unset, fold all registered migrations.
457 ///
458 /// @return The folded snapshot. Safe to call without a `MigrationManager`-attached
459 /// data mapper.
460 [[nodiscard]] LIGHTWEIGHT_API PlanFoldingResult FoldRegisteredMigrations(
461 SqlQueryFormatter const& formatter, std::optional<MigrationTimestamp> upToInclusive = std::nullopt) const;
462
463 /// @brief Result of a `HardReset` call.
465 {
466 /// True when the populating call was a dry-run; the result describes the
467 /// would-be plan and no DDL was issued.
468 bool wasDryRun = false;
469 /// Tables the registered migrations *would* have created and were also present
470 /// in the live DB — these were dropped (or would be dropped on a real run).
471 std::vector<SqlSchema::FullyQualifiedTableName> droppedTables;
472 /// Tables registered migrations declare but that aren't in the live DB —
473 /// nothing to do for these. Reported for visibility only.
474 std::vector<SqlSchema::FullyQualifiedTableName> absentTables;
475 /// Tables in the live DB the registered migrations don't know about — left
476 /// alone (user-owned). Reported prominently so operators notice.
477 std::vector<SqlSchema::FullyQualifiedTableName> preservedTables;
478 /// Whether the `schema_migrations` table itself was dropped (always true on a
479 /// real run, false on dry-run).
481 };
482
483 /// @brief Drops every table the registered migrations would create (incl.
484 /// `schema_migrations`), preserving any user-created tables.
485 ///
486 /// Folds all registered migrations to compute the migration-owned set, intersects
487 /// with the live schema (via `SqlSchema::ReadAllTables`), then drops the matching
488 /// live tables in **reverse** creation order with `cascade=true ifExists=true`. The
489 /// `schema_migrations` table is dropped explicitly because it's created outside the
490 /// registered-migrations stream.
491 ///
492 /// Tables present in the live DB but not in the migration plan are left alone and
493 /// reported under `preservedTables` so operators can spot them.
494 ///
495 /// @param dryRun When true, returns the would-be plan without writing anything.
496 [[nodiscard]] LIGHTWEIGHT_API HardResetResult HardReset(bool dryRun = false);
497
498 /// @brief One column upgrade entry in `UnicodeUpgradeResult`.
500 {
501 /// Fully-qualified name of the table that owns the column.
502 SqlSchema::FullyQualifiedTableName table;
503 /// Name of the column being upgraded.
504 std::string column;
505 /// Live byte-counted type the column currently has.
506 SqlColumnTypeDefinition liveType;
507 /// Char-counted type the migrations now declare for this column.
508 SqlColumnTypeDefinition intendedType;
509 /// Whether the column is nullable (preserved across the type rewrite).
510 bool nullable = true;
511 };
512
513 /// @brief Result of an `UnicodeUpgradeTables` call.
515 {
516 /// True when the populating call was a dry-run; the result describes the
517 /// would-be diff and no DDL was issued.
518 bool wasDryRun = false;
519 /// Columns whose live type drifted from the intended type and were upgraded
520 /// (or would be on a real run).
521 std::vector<ColumnUpgradeEntry> columns;
522 /// Foreign keys that had to be dropped + re-added to upgrade their
523 /// participating columns. Reported so operators see the FK churn.
524 std::vector<SqlCompositeForeignKeyConstraint> rebuiltForeignKeys;
525 };
526
527 /// @brief Rewrites legacy `VARCHAR/CHAR` columns to `NVARCHAR/NCHAR` where the
528 /// registered migrations now declare wide types.
529 ///
530 /// Compares the folded plan's intended column types against `SqlSchema::ReadAllTables`
531 /// output; an upgrade is triggered iff intended is `NVarchar`/`NChar` AND live is
532 /// `Varchar`/`Char` with the same `size`. Foreign keys that touch any upgrade column
533 /// are dropped before the alter and re-added afterwards. Cross-backend; SQLite
534 /// uses the in-tree `RebuildSqliteTable` recipe under the hood.
535 ///
536 /// @param dryRun When true, returns the would-be diff without writing anything.
537 [[nodiscard]] LIGHTWEIGHT_API UnicodeUpgradeResult UnicodeUpgradeTables(bool dryRun = false);
538
539 /// @brief Re-stamps `schema_migrations.checksum` rows that have drifted.
540 ///
541 /// Applied migrations whose stored checksum no longer matches the current
542 /// `MigrationBase::ComputeChecksum` output are updated in-place. Migrations that
543 /// match are left alone. Rows that reference a migration which is no longer
544 /// registered (e.g. removed from the codebase) are surfaced via
545 /// `RewriteChecksumsResult.unregisteredTimestamps` and *not* touched.
546 ///
547 /// This is a recovery tool used when a regen of generated migrations changes
548 /// their byte-level shape but not their logical effect — running it without
549 /// understanding *why* the checksum drifted would defeat the integrity check.
550 ///
551 /// @param dryRun When true, returns the would-be diff without writing anything.
552 [[nodiscard]] LIGHTWEIGHT_API RewriteChecksumsResult RewriteChecksums(bool dryRun = false);
553
554 /// Preview SQL statements for all pending migrations without executing.
555 ///
556 /// This is useful for dry-run mode to see what SQL would be executed.
557 ///
558 /// @param feedbackCallback Optional callback to be called for each migration.
559 /// @return Vector of all SQL statements that would be executed.
560 [[nodiscard]] LIGHTWEIGHT_API std::vector<std::string> PreviewPendingMigrations(
561 ExecuteCallback const& feedbackCallback = {}) const;
562
563 /// Preview SQL for pending migrations whose timestamp is <= `targetInclusive`.
564 ///
565 /// Bounded counterpart of `PreviewPendingMigrations`. Same dependency
566 /// rules as `ApplyPendingMigrationsUpTo`: if any included migration
567 /// depends on an excluded pending migration, this throws.
568 ///
569 /// @param targetInclusive Highest timestamp to preview (inclusive).
570 /// @param feedbackCallback Optional callback to be called for each migration.
571 /// @return Vector of all SQL statements that would be executed.
572 /// @throws std::runtime_error if a dependency would cross the boundary.
573 [[nodiscard]] LIGHTWEIGHT_API std::vector<std::string> PreviewPendingMigrationsUpTo(
574 MigrationTimestamp targetInclusive, ExecuteCallback const& feedbackCallback = {}) const;
575
576 /// Verify checksums of all applied migrations.
577 ///
578 /// Compares the stored checksums in the database with the computed checksums
579 /// of the current migration definitions. This helps detect if migrations
580 /// have been modified after they were applied.
581 ///
582 /// @return Vector of verification results for migrations with mismatched or missing checksums.
583 [[nodiscard]] LIGHTWEIGHT_API std::vector<ChecksumVerificationResult> VerifyChecksums() const;
584
585 /// Mark a migration as applied without executing its Up() method.
586 ///
587 /// This is useful for:
588 /// - Baseline migrations when setting up an existing database
589 /// - Marking migrations that were applied manually or through other means
590 /// - Skipping migrations that are not applicable to a specific environment
591 ///
592 /// @param migration The migration to mark as applied.
593 /// @throws std::runtime_error if the migration is already applied.
594 LIGHTWEIGHT_API void MarkMigrationAsApplied(MigrationBase const& migration);
595
596 /// Revert all migrations applied after the target timestamp.
597 ///
598 /// This method reverts migrations in reverse chronological order,
599 /// rolling back from the most recent to just after the target.
600 /// The target migration itself is NOT reverted.
601 ///
602 /// @param target Target timestamp to revert to. Migrations > target are reverted.
603 /// @param feedbackCallback Optional callback for progress updates.
604 /// @return Result containing list of reverted timestamps or error information.
605 /// @note Stops on first error. Previously reverted migrations in this call are NOT rolled back.
606 [[nodiscard]] LIGHTWEIGHT_API RevertResult RevertToMigration(MigrationTimestamp target,
607 ExecuteCallback const& feedbackCallback = {});
608
609 /// Get a summary status of all migrations.
610 ///
611 /// This method provides a quick overview of the migration state without
612 /// needing to iterate through individual migrations.
613 ///
614 /// @return Status struct with counts of applied, pending, and mismatched migrations.
615 [[nodiscard]] LIGHTWEIGHT_API MigrationStatus GetMigrationStatus() const;
616
617 /// Validate that all registered migrations have satisfiable dependencies.
618 ///
619 /// For each pending migration, verifies that every declared dependency is either
620 /// already applied or itself pending (so it will be applied first due to topological
621 /// ordering). Also detects cycles among pending migrations.
622 ///
623 /// @throws std::runtime_error if any dependency is unresolved or a cycle is found.
624 LIGHTWEIGHT_API void ValidateDependencies() const;
625
626 /// Register a release marker for a software version.
627 ///
628 /// Typically called from `LIGHTWEIGHT_SQL_RELEASE(version, timestamp)` at static init time.
629 /// Releases are ordered by `highestTimestamp`; two releases may not share the same
630 /// `highestTimestamp`, and the same version string may not be registered twice.
631 ///
632 /// @param version Human-readable version, e.g. "6.7.0".
633 /// @param highestTimestamp Highest migration timestamp (inclusive) that belongs to this release.
634 /// @throws std::runtime_error on duplicate version or duplicate timestamp.
635 LIGHTWEIGHT_API void RegisterRelease(std::string version, MigrationTimestamp highestTimestamp);
636
637 /// Remove all registered releases. Useful for resetting state in tests.
638 LIGHTWEIGHT_API void RemoveAllReleases();
639
640 /// Get all registered releases, sorted ascending by `highestTimestamp`.
641 [[nodiscard]] LIGHTWEIGHT_API std::vector<MigrationRelease> const& GetAllReleases() const noexcept;
642
643 /// Find a release by exact version string match.
644 ///
645 /// @return Pointer to the matching release, or nullptr if no release with that version is registered.
646 [[nodiscard]] LIGHTWEIGHT_API MigrationRelease const* FindReleaseByVersion(std::string_view version) const noexcept;
647
648 /// Find the release whose timestamp range contains `timestamp`.
649 ///
650 /// Returns the release with the smallest `highestTimestamp` that is `>= timestamp`.
651 /// Returns nullptr if `timestamp` is greater than every registered release's highestTimestamp
652 /// (i.e., the migration is post-all-releases / unreleased).
653 [[nodiscard]] LIGHTWEIGHT_API MigrationRelease const* FindReleaseForTimestamp(
654 MigrationTimestamp timestamp) const noexcept;
655
656 /// Get all registered migrations belonging to a given release.
657 ///
658 /// A migration `M` belongs to release `R` iff
659 /// `prev_release_ts < M.timestamp <= R.highestTimestamp`, where `prev_release_ts` is the
660 /// previous release's timestamp (or 0 if `R` is the first release).
661 ///
662 /// @param version The version string to look up.
663 /// @return Migrations in the release, ordered by timestamp. Empty if the version is unknown.
664 [[nodiscard]] LIGHTWEIGHT_API MigrationList GetMigrationsForRelease(std::string_view version) const;
665
666 private:
667 /// Return the pending list in dependency-respecting order.
668 ///
669 /// Dependencies among pending migrations are resolved via topological sort.
670 /// Migrations with no dependency between them keep timestamp order.
671 /// Throws on missing deps or cycles.
672 [[nodiscard]] MigrationList TopoSortPending(MigrationList pending,
673 std::vector<MigrationTimestamp> const& applied) const;
674
675 /// @brief Builds a fresh, policy-agnostic render context. The per-migration
676 /// compat knobs are layered on by `ApplySingleMigration` / `PreviewMigrationWithContext`
677 /// before rendering a given migration's steps.
678 [[nodiscard]] static MigrationRenderContext MakeRenderContext();
679
680 MigrationList _migrations;
681 std::vector<MigrationRelease> _releases;
682 mutable DataMapper* _dataMapper { nullptr };
683 CompatPolicy _compatPolicy;
684 };
685
686/// Requires the user to call LIGHTWEIGHT_MIGRATION_PLUGIN() in exactly one CPP file of the migration plugin.
687///
688/// @ingroup SqlMigration
689#define LIGHTWEIGHT_MIGRATION_PLUGIN() \
690 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
691 extern "C" LIGHTWEIGHT_EXPORT Lightweight::SqlMigration::MigrationManager* AcquireMigrationManager() \
692 { \
693 return &Lightweight::SqlMigration::MigrationManager::GetInstance(); \
694 }
695
696 /// Represents a single unique SQL migration.
697 ///
698 /// @ingroup SqlMigration
700 {
701 public:
702 /// Default copy constructor.
703 MigrationBase(MigrationBase const&) = default;
704 MigrationBase(MigrationBase&&) = delete;
705 /// Default copy assignment operator.
708 /// Constructs a migration with the given timestamp and title.
709 MigrationBase(MigrationTimestamp timestamp, std::string_view title):
710 _timestamp { timestamp },
711 _title { title }
712 {
714 }
715
716 virtual ~MigrationBase() = default;
717
718 /// Apply the migration.
719 ///
720 /// @param plan Query builder to use for building the migration plan.
721 virtual void Up(SqlMigrationQueryBuilder& plan) const = 0;
722
723 /// Revert the migration.
724 ///
725 /// @param plan Query builder to use for building the migration plan.
726 virtual void Down(SqlMigrationQueryBuilder& plan) const
727 {
728 (void) plan;
729 }
730
731 /// Check if this migration has a Down() implementation for rollback.
732 ///
733 /// This method determines whether the migration can be safely reverted.
734 /// The default implementation returns false. Derived classes that implement
735 /// Down() should override this to return true.
736 ///
737 /// @return true if Down() is implemented and can revert this migration.
738 [[nodiscard]] virtual bool HasDownImplementation() const noexcept
739 {
740 return false;
741 }
742
743 /// Get the timestamps of migrations that this migration depends on.
744 ///
745 /// Dependencies are enforced at apply time: each declared dependency must be
746 /// registered and applied (or pending in the same run, in dependency order)
747 /// before this migration will run. The default implementation returns no
748 /// dependencies, preserving timestamp-ordered apply behavior.
749 ///
750 /// @return Vector of dependency timestamps. Empty if this migration has none.
751 [[nodiscard]] virtual std::vector<MigrationTimestamp> GetDependencies() const
752 {
753 return {};
754 }
755
756 /// Get the author of the migration, if any.
757 ///
758 /// @return Author string, empty if not set.
759 [[nodiscard]] virtual std::string_view GetAuthor() const noexcept
760 {
761 return {};
762 }
763
764 /// Get the long-form description of the migration, if any.
765 ///
766 /// This is a multi-line description in addition to the short title.
767 ///
768 /// @return Description string, empty if not set.
769 [[nodiscard]] virtual std::string_view GetDescription() const noexcept
770 {
771 return {};
772 }
773
774 /// Get the timestamp of the migration.
775 ///
776 /// @return Timestamp of the migration.
777 [[nodiscard]] MigrationTimestamp GetTimestamp() const noexcept
778 {
779 return _timestamp;
780 }
781
782 /// Get the title of the migration.
783 ///
784 /// @return Title of the migration.
785 [[nodiscard]] std::string_view GetTitle() const noexcept
786 {
787 return _title;
788 }
789
790 /// Compute SHA-256 checksum of migration's Up() SQL statements.
791 ///
792 /// The checksum is computed from the SQL statements that would be executed
793 /// by this migration. This allows detecting if a migration has been modified
794 /// after it was applied.
795 ///
796 /// @param formatter The SQL query formatter to use for generating SQL.
797 /// @return SHA-256 hex string (64 characters).
798 [[nodiscard]] LIGHTWEIGHT_API std::string ComputeChecksum(SqlQueryFormatter const& formatter) const;
799
800 private:
801 MigrationTimestamp _timestamp;
802 std::string_view _title;
803 };
804
805 /// Represents a single unique SQL migration.
806 ///
807 /// This class is a convenience class that can be used to create a migration.
808 ///
809 /// @ingroup SqlMigration
810 /// Optional metadata attached to a Migration at construction time.
811 ///
812 /// All fields are optional. Unset fields behave as if the feature
813 /// were not used (e.g. empty dependencies preserves timestamp order).
814 ///
815 /// @ingroup SqlMigration
817 {
818 /// Migrations that must be applied before this one.
819 std::vector<MigrationTimestamp> dependencies {};
820 /// Author of the migration. Recorded in schema_migrations when the migration is applied.
821 std::string_view author {};
822 /// Long-form description. Recorded in schema_migrations when the migration is applied.
823 std::string_view description {};
824 };
825
826 template <uint64_t TsValue>
827 class Migration: public MigrationBase
828 {
829 public:
830 /// The migration's timestamp, available at compile time from the type itself.
831 ///
832 /// Exposed so @ref TimestampOf can extract the timestamp without
833 /// having to repeat the literal at every use site (e.g. in dependency lists).
834 static constexpr MigrationTimestamp TimeStamp { TsValue };
835
836 /// Create a new migration.
837 ///
838 /// @param title Title of the migration.
839 /// @param up Function to apply the migration.
840 /// @param down Function to revert the migration (optional).
841 Migration(std::string_view title,
842 std::function<void(SqlMigrationQueryBuilder&)> const& up,
843 std::function<void(SqlMigrationQueryBuilder&)> const& down = {}):
844 MigrationBase(TimeStamp, title),
845 _up { up },
846 _down { down }
847 {
848 }
849
850 /// Create a new migration with optional metadata (dependencies, author, description).
851 ///
852 /// @param title Title of the migration.
853 /// @param metadata Optional metadata including dependencies, author, and description.
854 /// @param up Function to apply the migration.
855 /// @param down Function to revert the migration (optional).
856 Migration(std::string_view title,
857 MigrationMetadata metadata,
858 std::function<void(SqlMigrationQueryBuilder&)> const& up,
859 std::function<void(SqlMigrationQueryBuilder&)> const& down = {}):
860 MigrationBase(TimeStamp, title),
861 _up { up },
862 _down { down },
863 _metadata { std::move(metadata) }
864 {
865 }
866
867 /// Apply the migration.
868 ///
869 /// @param builder Query builder to use for building the migration plan.
870 void Up(SqlMigrationQueryBuilder& builder) const override
871 {
872 _up(builder);
873 }
874
875 /// Revert the migration.
876 ///
877 /// @param builder Query builder to use for building the migration plan.
878 void Down(SqlMigrationQueryBuilder& builder) const override
879 {
880 if (_down)
881 _down(builder);
882 }
883
884 /// Check if this migration has a Down() implementation.
885 ///
886 /// @return true if a down function was provided.
887 [[nodiscard]] bool HasDownImplementation() const noexcept override
888 {
889 return static_cast<bool>(_down);
890 }
891
892 /// Get the declared dependencies for this migration.
893 [[nodiscard]] std::vector<MigrationTimestamp> GetDependencies() const override
894 {
895 return _metadata.dependencies;
896 }
897
898 /// Get the author of this migration.
899 [[nodiscard]] std::string_view GetAuthor() const noexcept override
900 {
901 return _metadata.author;
902 }
903
904 /// Get the long-form description of this migration.
905 [[nodiscard]] std::string_view GetDescription() const noexcept override
906 {
907 return _metadata.description;
908 }
909
910 private:
911 std::function<void(SqlMigrationQueryBuilder&)> _up;
912 std::function<void(SqlMigrationQueryBuilder&)> _down;
913 MigrationMetadata _metadata {};
914 };
915
916 /// Extracts the @ref MigrationTimestamp from a migration type that exposes a static
917 /// constexpr `TimeStamp` member.
918 ///
919 /// Works with both the class template @ref Migration and the struct generated by the
920 /// @ref LIGHTWEIGHT_SQL_MIGRATION macro. Use via `decltype`:
921 ///
922 /// @code
923 /// auto migrationA = SqlMigration::Migration<202601010001>("dep base", [](auto&){ ... });
924 /// auto tsA = TimestampOf<decltype(migrationA)>; // MigrationTimestamp { 202601010001 }
925 /// @endcode
926 ///
927 /// @tparam T A migration type exposing `static constexpr MigrationTimestamp TimeStamp`.
928 template <typename T>
929 inline constexpr MigrationTimestamp TimestampOf = T::TimeStamp;
930
931 namespace detail
932 {
933 /// RAII registrar used by `LIGHTWEIGHT_SQL_RELEASE` to register a release with the
934 /// migration manager at static-initialization time. Not intended for direct use.
935 ///
936 /// @ingroup SqlMigration
937 struct ReleaseRegistrar
938 {
939 /// Registers `{version, highestTimestamp}` with the singleton manager.
940 ReleaseRegistrar(std::string version, MigrationTimestamp highestTimestamp)
941 {
942 MigrationManager::GetInstance().RegisterRelease(std::move(version), highestTimestamp);
943 }
944 };
945 } // namespace detail
946
947} // namespace SqlMigration
948
949} // namespace Lightweight
950
951#define _LIGHTWEIGHT_CONCATENATE(s1, s2) s1##s2
952#define _LIGHTWEIGHT_CONCATENATE_INNER(s1, s2) _LIGHTWEIGHT_CONCATENATE(s1, s2)
953
954/// @brief Represents the C++ migration object for a given timestamped migration.
955/// @param timestamp Timestamp of the migration.
956///
957/// @ingroup SqlMigration
958#define LIGHTWEIGHT_MIGRATION_INSTANCE(timestamp) migration_##timestamp
959
960/// @brief Creates a new migration.
961/// @param timestamp Timestamp of the migration.
962/// @param description Description of the migration.
963///
964/// @note The migration will be registered with the migration manager automatically.
965///
966/// @code
967/// #include <Lightweight/SqlMigration.hpp>
968///
969/// LIGHTWEIGHT_SQL_MIGRATION(20260117234120, "Create table 'MyTable'")
970/// {
971/// // Use 'plan' to define the migration steps, for example creating tables.
972/// }
973/// @endcode
974///
975/// @see Lightweight::SqlMigrationQueryBuilder
976///
977/// @ingroup SqlMigration
978#define LIGHTWEIGHT_SQL_MIGRATION(timestamp, description) \
979 struct Migration_##timestamp: public Lightweight::SqlMigration::MigrationBase \
980 { \
981 /** The migration's timestamp, exposed so @ref TimestampOf can extract it from the type. */ \
982 static constexpr Lightweight::SqlMigration::MigrationTimestamp TimeStamp { static_cast<uint64_t>(timestamp) }; \
983 explicit Migration_##timestamp(): \
984 Lightweight::SqlMigration::MigrationBase(TimeStamp, description) \
985 { \
986 } \
987 \
988 void Up(Lightweight::SqlMigrationQueryBuilder& plan) const override; \
989 void Down(Lightweight::SqlMigrationQueryBuilder& /*plan*/) const override {} \
990 }; \
991 \
992 static Migration_##timestamp _LIGHTWEIGHT_CONCATENATE(migration_, timestamp); \
993 \
994 void Migration_##timestamp::Up(Lightweight::SqlMigrationQueryBuilder& plan) const
995
996/// @brief Associates a software release (version string) with the highest migration timestamp
997/// present at the time of that release.
998///
999/// Declare one `LIGHTWEIGHT_SQL_RELEASE` per cut release, alongside the migrations that belong to it.
1000/// The macro registers with the migration manager at static-initialization time. Multiple releases
1001/// may coexist in the same translation unit.
1002///
1003/// @param version A string literal, e.g. `"6.7.0"`.
1004/// @param highestTimestamp An unsigned integer literal matching the timestamp format used by migrations.
1005///
1006/// @code
1007/// LIGHTWEIGHT_SQL_MIGRATION(20260101120000, "Initial schema") { ... }
1008/// LIGHTWEIGHT_SQL_RELEASE("6.6.0", 20260101120000);
1009///
1010/// LIGHTWEIGHT_SQL_MIGRATION(20260501120000, "Add orders table") { ... }
1011/// LIGHTWEIGHT_SQL_RELEASE("6.7.0", 20260501120000);
1012/// @endcode
1013///
1014/// @ingroup SqlMigration
1015#define LIGHTWEIGHT_SQL_RELEASE(version, highestTimestamp) \
1016 static ::Lightweight::SqlMigration::detail::ReleaseRegistrar _LIGHTWEIGHT_CONCATENATE_INNER(_lw_release_, __COUNTER__) \
1017 { \
1018 (version), ::Lightweight::SqlMigration::MigrationTimestamp \
1019 { \
1020 (highestTimestamp) \
1021 } \
1022 }
Main API for mapping records to and from the database using high level C++ syntax.
Query builder for building SQL migration queries.
Definition Migrate.hpp:469
virtual void Up(SqlMigrationQueryBuilder &plan) const =0
MigrationTimestamp GetTimestamp() const noexcept
std::string_view GetTitle() const noexcept
virtual std::vector< MigrationTimestamp > GetDependencies() const
virtual std::string_view GetAuthor() const noexcept
virtual std::string_view GetDescription() const noexcept
MigrationBase(MigrationBase const &)=default
Default copy constructor.
LIGHTWEIGHT_API std::string ComputeChecksum(SqlQueryFormatter const &formatter) const
MigrationBase(MigrationTimestamp timestamp, std::string_view title)
Constructs a migration with the given timestamp and title.
virtual void Down(SqlMigrationQueryBuilder &plan) const
virtual bool HasDownImplementation() const noexcept
MigrationBase & operator=(MigrationBase const &)=default
Default copy assignment operator.
std::string const & GetMigrationTitle() const noexcept
Human-readable title of the failing migration.
Operation GetOperation() const noexcept
Whether the failure occurred while applying or reverting.
MigrationException(Operation operation, MigrationTimestamp timestamp, std::string title, std::size_t stepIndex, std::string failedSql, SqlErrorInfo driverError)
std::string const & GetFailedSql() const noexcept
The exact SQL statement that the driver rejected.
std::string const & GetDriverMessage() const noexcept
Operation
Whether the failure happened while applying (Up) or reverting (Down).
MigrationTimestamp GetMigrationTimestamp() const noexcept
Timestamp of the failing migration.
std::size_t GetStepIndex() const noexcept
Zero-based step index inside the plan of the failing migration.
LIGHTWEIGHT_API void MarkMigrationAsApplied(MigrationBase const &migration)
LIGHTWEIGHT_API void ComposeCompatPolicy(CompatPolicy policy)
Composes an additional policy with the currently installed one. If no policy is installed,...
std::function< void(MigrationBase const &, size_t, size_t)> ExecuteCallback
Callback type invoked during migration execution to report progress.
LIGHTWEIGHT_API DataMapper & GetDataMapper()
Get the data mapper used for migrations.
LIGHTWEIGHT_API RevertResult RevertToMigration(MigrationTimestamp target, ExecuteCallback const &feedbackCallback={})
LIGHTWEIGHT_API void AddMigration(MigrationBase const *migration)
LIGHTWEIGHT_API HardResetResult HardReset(bool dryRun=false)
Drops every table the registered migrations would create (incl. schema_migrations),...
std::list< MigrationBase const * > MigrationList
Type alias for a list of migration pointers.
LIGHTWEIGHT_API MigrationList const & GetAllMigrations() const noexcept
LIGHTWEIGHT_API std::vector< std::string > PreviewPendingMigrationsUpTo(MigrationTimestamp targetInclusive, ExecuteCallback const &feedbackCallback={}) const
LIGHTWEIGHT_API size_t ApplyPendingMigrationsUpTo(MigrationTimestamp targetInclusive, ExecuteCallback const &feedbackCallback={})
LIGHTWEIGHT_API std::vector< std::string > PreviewPendingMigrations(ExecuteCallback const &feedbackCallback={}) const
LIGHTWEIGHT_API void RevertSingleMigration(MigrationBase const &migration)
LIGHTWEIGHT_API DataMapper & GetDataMapper() const
Get the data mapper used for migrations.
LIGHTWEIGHT_API void RemoveAllReleases()
Remove all registered releases. Useful for resetting state in tests.
LIGHTWEIGHT_API PlanFoldingResult FoldRegisteredMigrations(SqlQueryFormatter const &formatter, std::optional< MigrationTimestamp > upToInclusive=std::nullopt) const
Pure plan-walk that folds the effect of every registered migration.
LIGHTWEIGHT_API SqlTransaction Transaction()
LIGHTWEIGHT_API void RegisterRelease(std::string version, MigrationTimestamp highestTimestamp)
LIGHTWEIGHT_API MigrationBase const * GetMigration(MigrationTimestamp timestamp) const noexcept
LIGHTWEIGHT_API std::set< std::string > CompatFlagsFor(MigrationBase const &migration) const
Returns the compat flags the current policy assigns to migration, or an empty set if no policy is ins...
LIGHTWEIGHT_API std::list< MigrationBase const * > GetPending() const noexcept
LIGHTWEIGHT_API std::vector< ChecksumVerificationResult > VerifyChecksums() const
LIGHTWEIGHT_API MigrationRelease const * FindReleaseByVersion(std::string_view version) const noexcept
LIGHTWEIGHT_API RewriteChecksumsResult RewriteChecksums(bool dryRun=false)
Re-stamps schema_migrations.checksum rows that have drifted.
LIGHTWEIGHT_API CompatPolicy const & GetCompatPolicy() const noexcept
Returns a view of the installed policy so it can be propagated across managers (plugin → central)....
LIGHTWEIGHT_API MigrationRelease const * FindReleaseForTimestamp(MigrationTimestamp timestamp) const noexcept
LIGHTWEIGHT_API MigrationList GetMigrationsForRelease(std::string_view version) const
LIGHTWEIGHT_API std::vector< std::string > PreviewMigration(MigrationBase const &migration) const
LIGHTWEIGHT_API size_t ApplyPendingMigrations(ExecuteCallback const &feedbackCallback={})
LIGHTWEIGHT_API void CreateMigrationHistory()
Create the migration history table if it does not exist.
LIGHTWEIGHT_API MigrationStatus GetMigrationStatus() const
LIGHTWEIGHT_API void SetCompatPolicy(CompatPolicy policy)
Installs a per-migration compat policy. Pass {} to clear.
LIGHTWEIGHT_API void ValidateDependencies() const
std::function< std::set< std::string >(MigrationBase const &)> CompatPolicy
Per-migration compat policy.
LIGHTWEIGHT_API UnicodeUpgradeResult UnicodeUpgradeTables(bool dryRun=false)
Rewrites legacy VARCHAR/CHAR columns to NVARCHAR/NCHAR where the registered migrations now declare wi...
LIGHTWEIGHT_API std::vector< MigrationRelease > const & GetAllReleases() const noexcept
Get all registered releases, sorted ascending by highestTimestamp.
LIGHTWEIGHT_API void ApplySingleMigration(MigrationBase const &migration)
LIGHTWEIGHT_API std::vector< std::string > PreviewMigrationWithContext(MigrationBase const &migration, MigrationRenderContext &context) const
Variant of PreviewMigration that threads a caller-owned render context so the column-width cache accu...
static LIGHTWEIGHT_API MigrationManager & GetInstance()
LIGHTWEIGHT_API std::vector< MigrationTimestamp > GetAppliedMigrationIds() const
API to format SQL queries for different SQL dialects.
std::variant< SqlCreateTablePlan, SqlAlterTablePlan, SqlDropTablePlan, SqlCreateIndexPlan, SqlRawSqlPlan, SqlInsertDataPlan, SqlUpdateDataPlan, SqlDeleteDataPlan > SqlMigrationPlanElement
Represents a single SQL migration plan element.
Opt-in behavioural knobs that the ToSql migration-plan renderer honours.
Represents an ODBC SQL error.
Definition SqlError.hpp:33
MigrationTimestamp timestamp
The timestamp of the verified migration.
std::string computedChecksum
The checksum computed from the current migration definition.
std::string storedChecksum
The checksum stored in the database.
bool matches
Whether the stored and computed checksums match.
std::string_view title
The title of the verified migration.
One row in the RewriteChecksumsResult.entries list.
std::string_view title
Title of the registered migration (or "(Unknown Migration)").
MigrationTimestamp timestamp
The migration whose stored checksum was rewritten.
std::string oldChecksum
Stored checksum before the rewrite. Empty if there was none.
std::string newChecksum
Stored checksum after the rewrite.
One column upgrade entry in UnicodeUpgradeResult.
SqlColumnTypeDefinition liveType
Live byte-counted type the column currently has.
SqlSchema::FullyQualifiedTableName table
Fully-qualified name of the table that owns the column.
SqlColumnTypeDefinition intendedType
Char-counted type the migrations now declare for this column.
bool nullable
Whether the column is nullable (preserved across the type rewrite).
std::string column
Name of the column being upgraded.
std::vector< SqlSchema::FullyQualifiedTableName > absentTables
std::vector< SqlSchema::FullyQualifiedTableName > preservedTables
std::vector< SqlSchema::FullyQualifiedTableName > droppedTables
One data step (INSERT/UPDATE/DELETE/RawSql) tagged with its source migration.
std::string sourceTitle
Title of the migration that contributed this data step.
SqlMigrationPlanElement element
The plan element itself (INSERT, UPDATE, DELETE, or RawSql).
MigrationTimestamp sourceTimestamp
Timestamp of the migration that contributed this data step.
Per-table state: ordered column declarations + per-table FK list.
std::vector< SqlColumnDeclaration > columns
Ordered column declarations as they would be emitted in CREATE TABLE.
std::vector< SqlCompositeForeignKeyConstraint > compositeForeignKeys
Snapshot of the schema the registered migrations intend to produce.
std::vector< SqlCreateIndexPlan > indexes
Indexes that survive folding (created on tables still present at end).
std::map< SqlSchema::FullyQualifiedTableName, TableState > tables
std::vector< MigrationRelease > releases
Releases declared via LIGHTWEIGHT_SQL_RELEASE that fall within the fold range.
std::vector< SqlSchema::FullyQualifiedTableName > creationOrder
std::vector< std::pair< MigrationTimestamp, std::string > > foldedMigrations
std::vector< MigrationTimestamp > unregisteredTimestamps
Applied rows whose migration is no longer registered.
std::vector< ChecksumRewriteEntry > entries
One entry per rewritten or would-be-rewritten row.
std::vector< SqlCompositeForeignKeyConstraint > rebuiltForeignKeys
std::vector< MigrationTimestamp > dependencies
Migrations that must be applied before this one.
std::string_view author
Author of the migration. Recorded in schema_migrations when the migration is applied.
std::string_view description
Long-form description. Recorded in schema_migrations when the migration is applied.
MigrationTimestamp highestTimestamp
Highest migration timestamp contained in this release (inclusive).
std::string version
Human-readable version string, e.g. "6.7.0".
size_t mismatchCount
Number of applied migrations with checksum mismatches.
size_t appliedCount
Number of migrations that have been applied.
size_t totalRegistered
Total number of registered migrations.
size_t pendingCount
Number of migrations waiting to be applied.
size_t unknownAppliedCount
Number of applied migrations not found in registered list.
constexpr std::weak_ordering operator<=>(MigrationTimestamp const &other) const noexcept=default
Three-way comparison operator.
uint64_t value
The numeric timestamp value identifying the migration.
std::vector< MigrationTimestamp > revertedTimestamps
Successfully reverted migrations.
std::optional< MigrationTimestamp > failedAt
Migration that failed, if any.
std::string sqlState
SQLSTATE diagnostic code from the driver, if available.
std::string errorMessage
Short error message if failed (driver message only)
SQLINTEGER nativeErrorCode
Native driver error code, if available.