Lightweight 0.20250904.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 "SqlQuery.hpp"
8#include "SqlTransaction.hpp"
9
10#include <functional>
11#include <list>
12#include <optional>
13
14namespace Lightweight
15{
16
17class SqlConnection;
18
19namespace SqlMigration
20{
21 class MigrationBase;
22
23 struct MigrationTimestamp
24 {
25 uint64_t value {};
26
27 constexpr bool operator==(MigrationTimestamp const& other) const noexcept
28 {
29 return value == other.value;
30 }
31
32 constexpr bool operator!=(MigrationTimestamp const& other) const noexcept
33 {
34 return !(*this == other);
35 }
36 };
37
38 // Interface to be implemented by the user to execute SQL migrations
39 class SqlMigrationExecutor
40 {
41 public:
42 SqlMigrationExecutor(SqlMigrationExecutor const&) = default;
43 SqlMigrationExecutor(SqlMigrationExecutor&&) = delete;
44 SqlMigrationExecutor& operator=(SqlMigrationExecutor const&) = default;
45 SqlMigrationExecutor& operator=(SqlMigrationExecutor&&) = delete;
46 virtual ~SqlMigrationExecutor() = default;
47
48 virtual void OnCreateTable(SqlCreateTablePlan const& createTable) = 0;
49 virtual void OnAlterTable(SqlAlterTablePlan const& alterTable) = 0;
50
51 virtual void OnDropTable(std::string_view tableName) = 0;
52 };
53
54 // Main API to use for managing SQL migrations
55 class MigrationManager
56 {
57 public:
58 using MigrationList = std::list<MigrationBase const*>;
59
60 LIGHTWEIGHT_API static MigrationManager& GetInstance()
61 {
62 static MigrationManager instance;
63 return instance;
64 }
65
66 LIGHTWEIGHT_API void AddMigration(MigrationBase const* migration);
67
68 [[nodiscard]] LIGHTWEIGHT_API MigrationList const& GetAllMigrations() const noexcept;
69
70 [[nodiscard]] LIGHTWEIGHT_API MigrationBase const* GetMigration(MigrationTimestamp timestamp) const;
71
72 LIGHTWEIGHT_API void RemoveAllMigrations();
73
74 [[nodiscard]] LIGHTWEIGHT_API std::list<MigrationBase const*> GetPending() const noexcept;
75
76 using ExecuteCallback =
77 std::function<void(MigrationBase const& /*migration*/, size_t /*current*/, size_t /*total*/)>;
78
79 LIGHTWEIGHT_API void ApplySingleMigration(MigrationTimestamp timestamp);
80 LIGHTWEIGHT_API void ApplySingleMigration(MigrationBase const& migration);
81 LIGHTWEIGHT_API size_t ApplyPendingMigrations(ExecuteCallback const& feedbackCallback = {});
82
83 LIGHTWEIGHT_API void CreateMigrationHistory();
84 [[nodiscard]] LIGHTWEIGHT_API std::vector<MigrationTimestamp> GetAppliedMigrationIds() const;
85
86 [[nodiscard]] LIGHTWEIGHT_API DataMapper& GetDataMapper();
87
88 [[nodiscard]] LIGHTWEIGHT_API DataMapper& GetDataMapper() const
89 {
90 return const_cast<MigrationManager*>(this)->GetDataMapper();
91 }
92
93 LIGHTWEIGHT_API void CloseDataMapper();
94
95 LIGHTWEIGHT_API SqlTransaction Transaction();
96
97 private:
98 MigrationList _migrations;
99 mutable std::optional<DataMapper> _mapper;
100 };
101
102 // Represents a single unique SQL migration
103 class MigrationBase
104 {
105 public:
106 MigrationBase(MigrationBase const&) = default;
107 MigrationBase(MigrationBase&&) = delete;
108 MigrationBase& operator=(MigrationBase const&) = default;
109 MigrationBase& operator=(MigrationBase&&) = delete;
110 MigrationBase(MigrationTimestamp timestamp, std::string_view title):
111 _timestamp { timestamp },
112 _title { title }
113 {
114 MigrationManager::GetInstance().AddMigration(this);
115 }
116
117 virtual ~MigrationBase() = default;
118
119 virtual void Execute(SqlMigrationQueryBuilder& planer) const = 0;
120
121 [[nodiscard]] MigrationTimestamp GetTimestamp() const noexcept
122 {
123 return _timestamp;
124 }
125
126 [[nodiscard]] std::string_view GetTitle() const noexcept
127 {
128 return _title;
129 }
130
131 private:
132 MigrationTimestamp _timestamp;
133 std::string_view _title;
134 };
135
136 class Migration: public MigrationBase
137 {
138 public:
139 Migration(MigrationTimestamp timestamp,
140 std::string_view title,
141 std::function<void(SqlMigrationQueryBuilder&)> const& plan):
142 MigrationBase(timestamp, title),
143 _plan { plan }
144 {
145 }
146
147 void Execute(SqlMigrationQueryBuilder& planer) const override
148 {
149 _plan(planer);
150 }
151
152 private:
153 std::function<void(SqlMigrationQueryBuilder&)> _plan;
154 };
155
156} // namespace SqlMigration
157
158} // namespace Lightweight
159
160#define LIGHTWEIGHT_CONCATENATE(s1, s2) s1##s2
161
162#define LIGHTWEIGHT_MIGRATION_INSTANCE(timestamp) migration_##timestamp
163
164// Example use:
165//
166// LIGHTWEIGHT_SQL_MIGRATION(std::chrono::system_clock(...), "Create table 'MyTable'")
167// {
168// // ...
169// }
170#define LIGHTWEIGHT_SQL_MIGRATION(timestamp, description) \
171 struct Migration_##timestamp: public Lightweight::SqlMigration::MigrationBase \
172 { \
173 explicit Migration_##timestamp(): \
174 Lightweight::SqlMigration::MigrationBase(Lightweight::SqlMigration::MigrationTimestamp { timestamp }, \
175 description) \
176 { \
177 } \
178 \
179 void Execute(Lightweight::SqlMigrationQueryBuilder& planer) const override; \
180 }; \
181 \
182 static Migration_##timestamp LIGHTWEIGHT_CONCATENATE(migration_, timestamp); \
183 \
184 void Migration_##timestamp::Execute(Lightweight::SqlMigrationQueryBuilder& plan) const