4#include "../SqlAdvisoryLock.hpp"
5#include "../SqlQueryFormatter.hpp"
7#include <reflection-cpp/reflection.hpp>
14class SQLiteQueryFormatter:
public SqlQueryFormatter
20 [[nodiscard]]
static std::string FormatFromTable(std::string_view table)
22 if (!table.empty() && (table.front() ==
'"' || table.front() ==
'['))
23 return std::string(table);
24 return std::format(R
"("{}")", table);
33 [[nodiscard]]
bool RequiresTableRebuildForSchemaChange() const noexcept
override
48 [[nodiscard]]
static std::string BuildColumnExistsQuery(std::string_view tableName, std::string_view columnName)
50 return std::format(R
"(SELECT COUNT(*) FROM pragma_table_info('{}') WHERE name = '{}';)", tableName, columnName);
53 [[nodiscard]] std::string Insert(std::string_view intoTable,
54 std::string_view fields,
55 std::string_view values) const override
57 return std::format(R
"(INSERT INTO "{}" ({}) VALUES ({}))", intoTable, fields, values);
60 [[nodiscard]] std::string Insert(std::string_view ,
61 std::string_view intoTable,
62 std::string_view fields,
63 std::string_view values)
const override
66 return std::format(R
"(INSERT INTO "{}" ({}) VALUES ({}))", intoTable, fields, values);
69 [[nodiscard]] std::string QueryLastInsertId(std::string_view )
const override
72 return "SELECT LAST_INSERT_ROWID()";
75 [[nodiscard]] std::string_view BooleanLiteral(
bool literalValue)
const noexcept override
77 return literalValue ?
"TRUE" :
"FALSE";
80 [[nodiscard]] std::string_view DateFunction() const noexcept
override
85 [[nodiscard]] std::string StringLiteral(std::string_view value)
const noexcept override
91 escaped.reserve(value.size() + 2);
93 for (
char const c: value)
104 [[nodiscard]] std::string StringLiteral(
char value)
const noexcept override
108 return std::format(
"'{}'", value);
111 [[nodiscard]] std::string BinaryLiteral(std::span<uint8_t const> data)
const override
114 result.reserve((data.size() * 2) + 3);
116 for (uint8_t
byte: data)
117 result += std::format(
"{:02X}", byte);
122 [[nodiscard]] std::string QualifiedTableName(std::string_view schema, std::string_view table)
const override
126 return std::format(R
"("{}")", table);
128 return std::format(R
"("{}"."{}")", schema, table);
131 [[nodiscard]] std::string SelectCount(bool distinct,
132 std::string_view fromTable,
133 std::string_view fromTableAlias,
134 std::string_view tableJoins,
135 std::string_view whereCondition)
const override
137 auto const formattedTable = FormatFromTable(fromTable);
138 if (fromTableAlias.empty())
140 "SELECT{} COUNT(*) FROM {}{}{}", distinct ?
" DISTINCT" :
"", formattedTable, tableJoins, whereCondition);
142 return std::format(R
"(SELECT{} COUNT(*) FROM {} AS "{}"{}{})",
143 distinct ? " DISTINCT" :
"",
150 [[nodiscard]] std::string SelectAll(
bool distinct,
152 std::string_view fields,
153 std::string_view fromTable,
154 std::string_view fromTableAlias,
155 std::string_view tableJoins,
156 std::string_view whereCondition,
157 std::string_view orderBy,
158 std::string_view groupBy)
const override
160 std::stringstream sqlQueryString;
161 sqlQueryString <<
"SELECT ";
163 sqlQueryString <<
"DISTINCT ";
164 sqlQueryString << fields;
165 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
166 if (!fromTableAlias.empty())
167 sqlQueryString <<
" AS \"" << fromTableAlias <<
'"';
168 sqlQueryString << tableJoins;
169 sqlQueryString << whereCondition;
170 sqlQueryString << groupBy;
171 sqlQueryString << orderBy;
173 return sqlQueryString.str();
176 [[nodiscard]] std::string SelectFirst(
bool distinct,
178 std::string_view fields,
179 std::string_view fromTable,
180 std::string_view fromTableAlias,
181 std::string_view tableJoins,
182 std::string_view whereCondition,
183 std::string_view orderBy,
184 size_t count)
const override
186 std::stringstream sqlQueryString;
187 sqlQueryString <<
"SELECT " << fields;
189 sqlQueryString <<
" DISTINCT";
190 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
191 if (!fromTableAlias.empty())
192 sqlQueryString <<
" AS \"" << fromTableAlias <<
"\"";
193 sqlQueryString << tableJoins;
194 sqlQueryString << whereCondition;
195 sqlQueryString << orderBy;
196 sqlQueryString <<
" LIMIT " << count;
197 return sqlQueryString.str();
200 [[nodiscard]] std::string SelectRange(
bool distinct,
202 std::string_view fields,
203 std::string_view fromTable,
204 std::string_view fromTableAlias,
205 std::string_view tableJoins,
206 std::string_view whereCondition,
207 std::string_view orderBy,
208 std::string_view groupBy,
210 std::size_t limit)
const override
212 std::stringstream sqlQueryString;
213 sqlQueryString <<
"SELECT " << fields;
215 sqlQueryString <<
" DISTINCT";
216 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
217 if (!fromTableAlias.empty())
218 sqlQueryString <<
" AS \"" << fromTableAlias <<
"\"";
219 sqlQueryString << tableJoins;
220 sqlQueryString << whereCondition;
221 sqlQueryString << groupBy;
222 sqlQueryString << orderBy;
223 sqlQueryString <<
" LIMIT " << limit <<
" OFFSET " << offset;
224 return sqlQueryString.str();
227 [[nodiscard]] std::string Update(std::string_view table,
228 std::string_view tableAlias,
229 std::string_view setFields,
230 std::string_view whereCondition)
const override
232 auto const formattedTable = FormatFromTable(table);
233 if (tableAlias.empty())
234 return std::format(
"UPDATE {} SET {}{}", formattedTable, setFields, whereCondition);
236 return std::format(R
"(UPDATE {} AS "{}" SET {}{})", formattedTable, tableAlias, setFields, whereCondition);
239 [[nodiscard]] std::string Delete(std::string_view fromTable,
240 std::string_view fromTableAlias,
241 std::string_view tableJoins,
242 std::string_view whereCondition) const override
244 auto const formattedTable = FormatFromTable(fromTable);
245 if (fromTableAlias.empty())
246 return std::format(
"DELETE FROM {}{}{}", formattedTable, tableJoins, whereCondition);
248 return std::format(R
"(DELETE FROM {} AS "{}"{}{})", formattedTable, fromTableAlias, tableJoins, whereCondition);
251 [[nodiscard]] virtual std::string BuildColumnDefinition(SqlColumnDeclaration
const& column)
const
253 std::stringstream sqlQueryString;
255 sqlQueryString <<
'"' << column.name <<
"\" ";
257 if (column.primaryKey != SqlPrimaryKeyType::AUTO_INCREMENT)
258 sqlQueryString << ColumnType(column.type);
260 sqlQueryString << ColumnType(SqlColumnTypeDefinitions::Integer {});
263 sqlQueryString <<
" NOT NULL";
265 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
266 sqlQueryString <<
" PRIMARY KEY AUTOINCREMENT";
267 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
268 sqlQueryString <<
" UNIQUE";
270 if (!column.defaultValue.empty())
271 sqlQueryString <<
" DEFAULT " << column.defaultValue;
273 return sqlQueryString.str();
276 [[nodiscard]]
static std::string BuildForeignKeyConstraint(std::string_view tableName,
277 std::string_view columnName,
278 SqlForeignKeyReferenceDefinition
const& referencedColumn)
285 return std::format(R
"(CONSTRAINT "{}" FOREIGN KEY ("{}") REFERENCES "{}"("{}"))",
288 referencedColumn.tableName,
289 referencedColumn.columnName);
293 [[nodiscard]]
StringList CreateTable(std::string_view schema,
294 std::string_view tableName,
295 std::vector<SqlColumnDeclaration>
const& columns,
296 std::vector<SqlCompositeForeignKeyConstraint>
const& foreignKeys,
297 bool ifNotExists =
false)
const override
302 sqlQueries.emplace_back([&]() {
303 std::stringstream sqlQueryString;
304 sqlQueryString <<
"CREATE TABLE ";
306 sqlQueryString <<
"IF NOT EXISTS ";
309 sqlQueryString <<
"\"" << tableName <<
"\" (";
310 std::vector<SqlColumnDeclaration const*> pks;
311 size_t currentColumn = 0;
312 std::string foreignKeyConstraints;
313 for (SqlColumnDeclaration
const& column: columns)
315 if (currentColumn > 0)
316 sqlQueryString <<
",";
318 sqlQueryString <<
"\n ";
319 sqlQueryString << BuildColumnDefinition(column);
321 if (column.primaryKey != SqlPrimaryKeyType::NONE)
322 pks.push_back(&column);
324 if (column.foreignKey)
326 foreignKeyConstraints +=
",\n ";
327 foreignKeyConstraints += BuildForeignKeyConstraint(tableName, column.name, *column.foreignKey);
331 for (SqlCompositeForeignKeyConstraint
const& fk: foreignKeys)
337 foreignKeyConstraints +=
",\n CONSTRAINT \"";
339 foreignKeyConstraints +=
"\" FOREIGN KEY (";
340 for (
size_t i = 0; i < fk.columns.size(); ++i)
343 foreignKeyConstraints +=
", ";
344 foreignKeyConstraints +=
'"' + fk.columns[i] +
'"';
346 foreignKeyConstraints +=
") REFERENCES \"";
347 foreignKeyConstraints += fk.referencedTableName;
348 foreignKeyConstraints +=
"\" (";
349 for (
size_t i = 0; i < fk.referencedColumns.size(); ++i)
352 foreignKeyConstraints +=
", ";
353 foreignKeyConstraints +=
'"' + fk.referencedColumns[i] +
'"';
355 foreignKeyConstraints +=
")";
365 pks, [](SqlColumnDeclaration
const* col) {
return col->primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT; });
369 std::ranges::sort(pks, [](SqlColumnDeclaration
const* a, SqlColumnDeclaration
const* b) {
374 if (a->primaryKeyIndex != 0 && b->primaryKeyIndex != 0)
375 return a->primaryKeyIndex < b->primaryKeyIndex;
376 if (a->primaryKeyIndex != 0)
378 if (b->primaryKeyIndex != 0)
383 sqlQueryString <<
",\n PRIMARY KEY (";
384 for (
size_t i = 0; i < pks.size(); ++i)
387 sqlQueryString <<
", ";
388 sqlQueryString <<
'"' << pks[i]->name <<
'"';
390 sqlQueryString <<
")";
393 sqlQueryString << foreignKeyConstraints;
395 sqlQueryString <<
"\n);";
396 return sqlQueryString.str();
399 for (SqlColumnDeclaration
const& column: columns)
401 if (column.index && column.primaryKey == SqlPrimaryKeyType::NONE)
405 sqlQueries.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}" ("{}");)",
411 sqlQueries.emplace_back(std::format(
412 R
"(CREATE INDEX "{}_{}_index" ON "{}" ("{}");)", tableName, column.name, tableName, column.name));
425 [[nodiscard]]
static std::string EscapeSentinelField(std::string_view identifier)
428 out.reserve(identifier.size());
429 for (
auto const ch: identifier)
438 [[nodiscard]] std::string FormatAlterTableCommand(std::string_view tableName,
SqlAlterTableCommand const& command)
const
440 auto const formatTable = [tableName]() {
441 return std::format(R
"("{}")", tableName);
444 using namespace SqlAlterTableCommands;
447 [&formatTable](RenameTable
const& actualCommand) -> std::string {
448 return std::format(R
"(ALTER TABLE {} RENAME TO "{}";)", formatTable(), actualCommand.newTableName);
450 [&formatTable, this](AddColumn
const& actualCommand) -> std::string {
451 return std::format(R
"(ALTER TABLE {} ADD COLUMN "{}" {} {};)",
453 actualCommand.columnName,
454 ColumnType(actualCommand.columnType),
455 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
457 [&formatTable, tableName,
this](AlterColumn
const& actualCommand) -> std::string {
465 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: ALTER_COLUMN "{0}" "{1}" "{2}" "{3}"
466-- ALTER TABLE {4} ALTER COLUMN "{1}" {2} {3};)",
467 EscapeSentinelField(tableName),
468 EscapeSentinelField(actualCommand.columnName),
469 ColumnType(actualCommand.columnType),
470 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL",
473 [&formatTable](RenameColumn
const& actualCommand) -> std::string {
474 return std::format(R
"(ALTER TABLE {} RENAME COLUMN "{}" TO "{}";)",
476 actualCommand.oldColumnName,
477 actualCommand.newColumnName);
479 [&formatTable](DropColumn const& actualCommand) -> std::string {
480 return std::format(R
"(ALTER TABLE {} DROP COLUMN "{}";)", formatTable(), actualCommand.columnName);
482 [tableName](AddIndex const& actualCommand) -> std::string {
483 using namespace std::string_view_literals;
484 auto const uniqueStr = actualCommand.unique ?
"UNIQUE "sv :
""sv;
485 return std::format(R
"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}" ("{1}");)",
487 actualCommand.columnName,
490 [tableName](DropIndex const& actualCommand) -> std::string {
491 return std::format(R
"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
493 [tableName](AddForeignKey const& actualCommand) -> std::string {
500 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: ADD_FOREIGN_KEY "{0}" "{1}" "{2}" "{3}"
501-- ALTER TABLE "{0}" ADD {4};)",
503 actualCommand.columnName,
504 actualCommand.referencedColumn.tableName,
505 actualCommand.referencedColumn.columnName,
506 BuildForeignKeyConstraint(tableName, actualCommand.columnName, actualCommand.referencedColumn));
508 [tableName](DropForeignKey const& actualCommand) -> std::string {
512 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: DROP_FOREIGN_KEY "{0}" "{1}"
513-- ALTER TABLE "{0}" DROP CONSTRAINT "{2}";)",
515 actualCommand.columnName,
517 std::array { std::string_view { actualCommand.columnName } }));
519 [tableName](AddCompositeForeignKey const& actualCommand) -> std::string {
526 auto const joinComma = [](std::vector<std::string>
const& v) {
528 for (
size_t i = 0; i < v.size(); ++i)
536 auto const joinQuoted = [](std::vector<std::string>
const& v) {
538 for (
size_t i = 0; i < v.size(); ++i)
550 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: ADD_COMPOSITE_FOREIGN_KEY "{0}" "{1}" "{2}" "{3}"
551-- ALTER TABLE "{0}" ADD CONSTRAINT "{4}" FOREIGN KEY ({5}) REFERENCES "{2}"({6});)",
553 joinComma(actualCommand.columns),
554 actualCommand.referencedTableName,
555 joinComma(actualCommand.referencedColumns),
557 joinQuoted(actualCommand.columns),
558 joinQuoted(actualCommand.referencedColumns));
560 [&formatTable, tableName, this](AddColumnIfNotExists
const& actualCommand) -> std::string {
565 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: ADD_COLUMN_IF_NOT_EXISTS "{0}" "{1}"
566ALTER TABLE {2} ADD COLUMN "{1}" {3} {4};)",
568 actualCommand.columnName,
570 ColumnType(actualCommand.columnType),
571 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
573 [&formatTable, tableName](DropColumnIfExists
const& actualCommand) -> std::string {
576 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: DROP_COLUMN_IF_EXISTS "{0}" "{1}"
577ALTER TABLE {2} DROP COLUMN "{1}";)",
579 actualCommand.columnName,
582 [tableName](DropIndexIfExists const& actualCommand) -> std::string {
583 return std::format(R
"(DROP INDEX IF EXISTS "{0}_{1}_index";)", tableName, actualCommand.columnName);
590 [[nodiscard]]
StringList AlterTable(std::string_view ,
591 std::string_view tableName,
592 std::vector<SqlAlterTableCommand>
const& commands)
const override
601 auto sql = FormatAlterTableCommand(tableName, command);
603 result.push_back(std::move(sql));
608 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition
const& type)
const override
610 using namespace SqlColumnTypeDefinitions;
611 return std::visit(detail::overloaded {
612 [](Bigint
const&) -> std::string {
return "BIGINT"; },
613 [](Binary
const&) -> std::string {
return "BLOB"; },
614 [](Bool
const&) -> std::string {
return "BOOLEAN"; },
615 [](Char
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
616 [](Date
const&) -> std::string {
return "DATE"; },
617 [](DateTime
const&) -> std::string {
return "DATETIME"; },
618 [](Decimal
const& type) -> std::string {
619 return std::format(
"DECIMAL({}, {})", type.precision, type.scale);
621 [](Guid
const&) -> std::string {
return "GUID"; },
622 [](Integer
const&) -> std::string {
return "INTEGER"; },
623 [](NChar
const& type) -> std::string {
return std::format(
"NCHAR({})", type.size); },
624 [](NVarchar
const& type) -> std::string {
return std::format(
"NVARCHAR({})", type.size); },
625 [](Real
const&) -> std::string {
return "REAL"; },
626 [](Smallint
const&) -> std::string {
return "SMALLINT"; },
627 [](Text
const&) -> std::string {
return "TEXT"; },
628 [](Time
const&) -> std::string {
return "TIME"; },
629 [](Timestamp
const&) -> std::string {
return "TIMESTAMP"; },
630 [](Tinyint
const&) -> std::string {
return "TINYINT"; },
631 [](VarBinary
const& type) -> std::string {
return std::format(
"VARBINARY({})", type.size); },
632 [](Varchar
const& type) -> std::string {
return std::format(
"VARCHAR({})", type.size); },
637 [[nodiscard]]
StringList DropTable(std::string_view ,
638 std::string_view
const& tableName,
639 bool ifExists =
false,
640 bool cascade =
false)
const override
647 return { std::format(R
"(DROP TABLE IF EXISTS "{}";)", tableName) };
649 return { std::format(R
"(DROP TABLE "{}";)", tableName) };
652 [[nodiscard]] std::string QueryServerVersion() const override
654 return "SELECT sqlite_version()";
665 [[nodiscard]] SqlAdvisoryLockHandler
const& AdvisoryLockOps()
const override
667 return SqliteAdvisoryLockOps();
std::variant< SqlAlterTableCommands::RenameTable, SqlAlterTableCommands::AddColumn, SqlAlterTableCommands::AddColumnIfNotExists, SqlAlterTableCommands::AlterColumn, SqlAlterTableCommands::AddIndex, SqlAlterTableCommands::RenameColumn, SqlAlterTableCommands::DropColumn, SqlAlterTableCommands::DropColumnIfExists, SqlAlterTableCommands::DropIndex, SqlAlterTableCommands::DropIndexIfExists, SqlAlterTableCommands::AddForeignKey, SqlAlterTableCommands::AddCompositeForeignKey, SqlAlterTableCommands::DropForeignKey > SqlAlterTableCommand
Represents a single SQL ALTER TABLE command.