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