Lightweight 0.20250904.0
Loading...
Searching...
No Matches
SqlSchema.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "Api.hpp"
6#include "SqlQuery/MigrationPlan.hpp"
7
8#include <format>
9#include <string_view>
10#include <tuple>
11#include <vector>
12
13namespace Lightweight
14{
15
16class SqlStatement;
17
18namespace SqlSchema
19{
20
21 namespace detail
22 {
23 // NOLINTNEXTLINE(readability-identifier-naming)
24 constexpr std::string_view rtrim(std::string_view value) noexcept
25 {
26 while (!value.empty() && (std::isspace(value.back()) || value.back() == '\0'))
27 value.remove_suffix(1);
28 return value;
29 }
30 } // namespace detail
31
32 struct FullyQualifiedTableName
33 {
34 std::string catalog;
35 std::string schema;
36 std::string table;
37
38 bool operator==(FullyQualifiedTableName const& other) const noexcept
39 {
40 return catalog == other.catalog && schema == other.schema && table == other.table;
41 }
42
43 bool operator!=(FullyQualifiedTableName const& other) const noexcept
44 {
45 return !(*this == other);
46 }
47
48 bool operator<(FullyQualifiedTableName const& other) const noexcept
49 {
50 return std::tie(catalog, schema, table) < std::tie(other.catalog, other.schema, other.table);
51 }
52 };
53
54 struct FullyQualifiedTableColumn
55 {
56 FullyQualifiedTableName table;
57 std::string column;
58
59 bool operator==(FullyQualifiedTableColumn const& other) const noexcept
60 {
61 return table == other.table && column == other.column;
62 }
63
64 bool operator!=(FullyQualifiedTableColumn const& other) const noexcept
65 {
66 return !(*this == other);
67 }
68
69 bool operator<(FullyQualifiedTableColumn const& other) const noexcept
70 {
71 return std::tie(table, column) < std::tie(other.table, other.column);
72 }
73 };
74
75 struct FullyQualifiedTableColumnSequence
76 {
77 FullyQualifiedTableName table;
78 std::vector<std::string> columns;
79 };
80
81 inline bool operator<(FullyQualifiedTableColumnSequence const& a, FullyQualifiedTableColumnSequence const& b) noexcept
82 {
83 return std::tie(a.table, a.columns) < std::tie(b.table, b.columns);
84 }
85
86 struct ForeignKeyConstraint
87 {
88 FullyQualifiedTableColumnSequence foreignKey;
89 FullyQualifiedTableColumnSequence primaryKey;
90 };
91
92 inline bool operator<(ForeignKeyConstraint const& a, ForeignKeyConstraint const& b) noexcept
93 {
94 return std::tie(a.foreignKey, a.primaryKey) < std::tie(b.foreignKey, b.primaryKey);
95 }
96
97 /// Holds the definition of a column in a SQL table as read from the database schema.
98 struct Column
99 {
100 std::string name = {};
101 SqlColumnTypeDefinition type = {};
102 std::string dialectDependantTypeString = {};
103 bool isNullable = true;
104 bool isUnique = false;
105 size_t size = 0;
106 unsigned short decimalDigits = 0;
107 bool isAutoIncrement = false;
108 bool isPrimaryKey = false;
109 bool isForeignKey = false;
110 std::optional<ForeignKeyConstraint> foreignKeyConstraint {};
111 std::string defaultValue = {};
112 };
113
114 /// Callback interface for handling events while reading a database schema.
116 {
117 public:
118 EventHandler() = default;
119 EventHandler(EventHandler&&) = default;
120 EventHandler(EventHandler const&) = default;
121 EventHandler& operator=(EventHandler&&) = default;
122 EventHandler& operator=(EventHandler const&) = default;
123 virtual ~EventHandler() = default;
124
125 /// Called when the names of all tables are read.
126 virtual void OnTables(std::vector<std::string> const& tables) = 0;
127
128 virtual bool OnTable(std::string_view table) = 0;
129 virtual void OnPrimaryKeys(std::string_view table, std::vector<std::string> const& columns) = 0;
130 virtual void OnForeignKey(ForeignKeyConstraint const& foreignKeyConstraint) = 0;
131 virtual void OnColumn(Column const& column) = 0;
132 virtual void OnExternalForeignKey(ForeignKeyConstraint const& foreignKeyConstraint) = 0;
133 virtual void OnTableEnd() = 0;
134 };
135
136 /// Reads all tables in the given database and schema and calls the event handler for each table.
137 LIGHTWEIGHT_API void ReadAllTables(std::string_view database, std::string_view schema, EventHandler& eventHandler);
138
139 /// Holds the definition of a table in a SQL database as read from the database schema.
140 struct Table
141 {
142 // FullyQualifiedTableName name;
143
144 /// The name of the table.
145 std::string name;
146
147 /// The columns of the table.
148 std::vector<Column> columns {};
149
150 /// The foreign keys of the table.
151 std::vector<ForeignKeyConstraint> foreignKeys {};
152
153 /// The foreign keys of other tables that reference this table.
154 std::vector<ForeignKeyConstraint> externalForeignKeys {};
155
156 /// The primary keys of the table.
157 std::vector<std::string> primaryKeys {};
158 };
159
160 /// A list of tables.
161 using TableList = std::vector<Table>;
162
163 using ReadAllTablesCallback = std::function<void(std::string_view /*tableName*/, size_t /*current*/, size_t /*total*/)>;
164
165 /// Retrieves all tables in the given @p database and @p schema.
166 LIGHTWEIGHT_API TableList ReadAllTables(std::string_view database,
167 std::string_view schema = {},
168 ReadAllTablesCallback callback = {});
169
170 /// Retrieves all tables in the given database and schema that have a foreign key to the given table.
171 LIGHTWEIGHT_API std::vector<ForeignKeyConstraint> AllForeignKeysTo(SqlStatement& stmt,
172 FullyQualifiedTableName const& table);
173
174 /// Retrieves all tables in the given database and schema that have a foreign key from the given table.
175 LIGHTWEIGHT_API std::vector<ForeignKeyConstraint> AllForeignKeysFrom(SqlStatement& stmt,
176 FullyQualifiedTableName const& table);
177
178} // namespace SqlSchema
179
180} // namespace Lightweight
181
182template <>
183struct std::formatter<Lightweight::SqlSchema::FullyQualifiedTableName>: std::formatter<std::string>
184{
185 auto format(Lightweight::SqlSchema::FullyQualifiedTableName const& value, format_context& ctx) const
186 -> format_context::iterator
187 {
188 string output = std::string(Lightweight::SqlSchema::detail::rtrim(value.schema));
189 if (!output.empty())
190 output += '.';
191 auto const trimmedSchema = Lightweight::SqlSchema::detail::rtrim(value.catalog);
192 output += trimmedSchema;
193 if (!output.empty() && !trimmedSchema.empty())
194 output += '.';
195 output += Lightweight::SqlSchema::detail::rtrim(value.table);
196 return formatter<string>::format(output, ctx);
197 }
198};
199
200template <>
201struct std::formatter<Lightweight::SqlSchema::FullyQualifiedTableColumn>: std::formatter<std::string>
202{
203 auto format(Lightweight::SqlSchema::FullyQualifiedTableColumn const& value, format_context& ctx) const
204 -> format_context::iterator
205 {
206 auto const table = std::format("{}", value.table);
207 if (table.empty())
208 return formatter<string>::format(std::format("{}", value.column), ctx);
209 else
210 return formatter<string>::format(std::format("{}.{}", value.table, value.column), ctx);
211 }
212};
213
214template <>
215struct std::formatter<Lightweight::SqlSchema::FullyQualifiedTableColumnSequence>: std::formatter<std::string>
216{
217 auto format(Lightweight::SqlSchema::FullyQualifiedTableColumnSequence const& value, format_context& ctx) const
218 -> format_context::iterator
219 {
220 auto const resolvedTableName = std::format("{}", value.table);
221 string output;
222 output += resolvedTableName;
223 output += '(';
224
225#if !defined(__cpp_lib_ranges_enumerate)
226 int i { -1 };
227 for (auto const& column: value.columns)
228 {
229 ++i;
230#else
231 for (auto const [i, column]: value.columns | std::views::enumerate)
232 {
233#endif
234 if (i != 0)
235 output += ", ";
236 output += column;
237 }
238 output += ')';
239
240 return formatter<string>::format(output, ctx);
241 }
242};
Callback interface for handling events while reading a database schema.
virtual void OnTables(std::vector< std::string > const &tables)=0
Called when the names of all tables are read.
Holds the definition of a column in a SQL table as read from the database schema.
Definition SqlSchema.hpp:99
Holds the definition of a table in a SQL database as read from the database schema.
std::vector< ForeignKeyConstraint > foreignKeys
The foreign keys of the table.
std::vector< std::string > primaryKeys
The primary keys of the table.
std::vector< ForeignKeyConstraint > externalForeignKeys
The foreign keys of other tables that reference this table.
std::string name
The name of the table.
std::vector< Column > columns
The columns of the table.