4#include "../SqlQueryFormatter.hpp"
6#include <reflection-cpp/reflection.hpp>
13class SQLiteQueryFormatter:
public SqlQueryFormatter
19 [[nodiscard]]
static std::string FormatFromTable(std::string_view table)
21 if (!table.empty() && (table.front() ==
'"' || table.front() ==
'['))
22 return std::string(table);
23 return std::format(R
"("{}")", table);
27 [[nodiscard]]
bool RequiresTableRebuildForForeignKeyChange() const noexcept
override
42 [[nodiscard]]
static std::string BuildColumnExistsQuery(std::string_view tableName, std::string_view columnName)
44 return std::format(R
"(SELECT COUNT(*) FROM pragma_table_info('{}') WHERE name = '{}';)", tableName, columnName);
47 [[nodiscard]] std::string Insert(std::string_view intoTable,
48 std::string_view fields,
49 std::string_view values) const override
51 return std::format(R
"(INSERT INTO "{}" ({}) VALUES ({}))", intoTable, fields, values);
54 [[nodiscard]] std::string Insert(std::string_view ,
55 std::string_view intoTable,
56 std::string_view fields,
57 std::string_view values)
const override
60 return std::format(R
"(INSERT INTO "{}" ({}) VALUES ({}))", intoTable, fields, values);
63 [[nodiscard]] std::string QueryLastInsertId(std::string_view )
const override
66 return "SELECT LAST_INSERT_ROWID()";
69 [[nodiscard]] std::string_view BooleanLiteral(
bool literalValue)
const noexcept override
71 return literalValue ?
"TRUE" :
"FALSE";
74 [[nodiscard]] std::string_view DateFunction() const noexcept
override
79 [[nodiscard]] std::string StringLiteral(std::string_view value)
const noexcept override
85 escaped.reserve(value.size() + 2);
87 for (
char const c: value)
98 [[nodiscard]] std::string StringLiteral(
char value)
const noexcept override
102 return std::format(
"'{}'", value);
105 [[nodiscard]] std::string BinaryLiteral(std::span<uint8_t const> data)
const override
108 result.reserve((data.size() * 2) + 3);
110 for (uint8_t
byte: data)
111 result += std::format(
"{:02X}", byte);
116 [[nodiscard]] std::string QualifiedTableName(std::string_view schema, std::string_view table)
const override
120 return std::format(R
"("{}")", table);
122 return std::format(R
"("{}"."{}")", schema, table);
125 [[nodiscard]] std::string SelectCount(bool distinct,
126 std::string_view fromTable,
127 std::string_view fromTableAlias,
128 std::string_view tableJoins,
129 std::string_view whereCondition)
const override
131 auto const formattedTable = FormatFromTable(fromTable);
132 if (fromTableAlias.empty())
134 "SELECT{} COUNT(*) FROM {}{}{}", distinct ?
" DISTINCT" :
"", formattedTable, tableJoins, whereCondition);
136 return std::format(R
"(SELECT{} COUNT(*) FROM {} AS "{}"{}{})",
137 distinct ? " DISTINCT" :
"",
144 [[nodiscard]] std::string SelectAll(
bool distinct,
146 std::string_view fields,
147 std::string_view fromTable,
148 std::string_view fromTableAlias,
149 std::string_view tableJoins,
150 std::string_view whereCondition,
151 std::string_view orderBy,
152 std::string_view groupBy)
const override
154 std::stringstream sqlQueryString;
155 sqlQueryString <<
"SELECT ";
157 sqlQueryString <<
"DISTINCT ";
158 sqlQueryString << fields;
159 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
160 if (!fromTableAlias.empty())
161 sqlQueryString <<
" AS \"" << fromTableAlias <<
'"';
162 sqlQueryString << tableJoins;
163 sqlQueryString << whereCondition;
164 sqlQueryString << groupBy;
165 sqlQueryString << orderBy;
167 return sqlQueryString.str();
170 [[nodiscard]] std::string SelectFirst(
bool distinct,
172 std::string_view fields,
173 std::string_view fromTable,
174 std::string_view fromTableAlias,
175 std::string_view tableJoins,
176 std::string_view whereCondition,
177 std::string_view orderBy,
178 size_t count)
const override
180 std::stringstream sqlQueryString;
181 sqlQueryString <<
"SELECT " << fields;
183 sqlQueryString <<
" DISTINCT";
184 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
185 if (!fromTableAlias.empty())
186 sqlQueryString <<
" AS \"" << fromTableAlias <<
"\"";
187 sqlQueryString << tableJoins;
188 sqlQueryString << whereCondition;
189 sqlQueryString << orderBy;
190 sqlQueryString <<
" LIMIT " << count;
191 return sqlQueryString.str();
194 [[nodiscard]] std::string SelectRange(
bool distinct,
196 std::string_view fields,
197 std::string_view fromTable,
198 std::string_view fromTableAlias,
199 std::string_view tableJoins,
200 std::string_view whereCondition,
201 std::string_view orderBy,
202 std::string_view groupBy,
204 std::size_t limit)
const override
206 std::stringstream sqlQueryString;
207 sqlQueryString <<
"SELECT " << fields;
209 sqlQueryString <<
" DISTINCT";
210 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
211 if (!fromTableAlias.empty())
212 sqlQueryString <<
" AS \"" << fromTableAlias <<
"\"";
213 sqlQueryString << tableJoins;
214 sqlQueryString << whereCondition;
215 sqlQueryString << groupBy;
216 sqlQueryString << orderBy;
217 sqlQueryString <<
" LIMIT " << limit <<
" OFFSET " << offset;
218 return sqlQueryString.str();
221 [[nodiscard]] std::string Update(std::string_view table,
222 std::string_view tableAlias,
223 std::string_view setFields,
224 std::string_view whereCondition)
const override
226 auto const formattedTable = FormatFromTable(table);
227 if (tableAlias.empty())
228 return std::format(
"UPDATE {} SET {}{}", formattedTable, setFields, whereCondition);
230 return std::format(R
"(UPDATE {} AS "{}" SET {}{})", formattedTable, tableAlias, setFields, whereCondition);
233 [[nodiscard]] std::string Delete(std::string_view fromTable,
234 std::string_view fromTableAlias,
235 std::string_view tableJoins,
236 std::string_view whereCondition) const override
238 auto const formattedTable = FormatFromTable(fromTable);
239 if (fromTableAlias.empty())
240 return std::format(
"DELETE FROM {}{}{}", formattedTable, tableJoins, whereCondition);
242 return std::format(R
"(DELETE FROM {} AS "{}"{}{})", formattedTable, fromTableAlias, tableJoins, whereCondition);
245 [[nodiscard]] virtual std::string BuildColumnDefinition(SqlColumnDeclaration
const& column)
const
247 std::stringstream sqlQueryString;
249 sqlQueryString <<
'"' << column.name <<
"\" ";
251 if (column.primaryKey != SqlPrimaryKeyType::AUTO_INCREMENT)
252 sqlQueryString << ColumnType(column.type);
254 sqlQueryString << ColumnType(SqlColumnTypeDefinitions::Integer {});
257 sqlQueryString <<
" NOT NULL";
259 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
260 sqlQueryString <<
" PRIMARY KEY AUTOINCREMENT";
261 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
262 sqlQueryString <<
" UNIQUE";
264 if (!column.defaultValue.empty())
265 sqlQueryString <<
" DEFAULT " << column.defaultValue;
267 return sqlQueryString.str();
270 [[nodiscard]]
static std::string BuildForeignKeyConstraint(std::string_view tableName,
271 std::string_view columnName,
272 SqlForeignKeyReferenceDefinition
const& referencedColumn)
277 return std::format(R
"(CONSTRAINT "{}" FOREIGN KEY ("{}") REFERENCES "{}"("{}"))",
280 referencedColumn.tableName,
281 referencedColumn.columnName);
285 [[nodiscard]]
StringList CreateTable(std::string_view schema,
286 std::string_view tableName,
287 std::vector<SqlColumnDeclaration>
const& columns,
288 std::vector<SqlCompositeForeignKeyConstraint>
const& foreignKeys,
289 bool ifNotExists =
false)
const override
294 sqlQueries.emplace_back([&]() {
295 std::stringstream sqlQueryString;
296 sqlQueryString <<
"CREATE TABLE ";
298 sqlQueryString <<
"IF NOT EXISTS ";
301 sqlQueryString <<
"\"" << tableName <<
"\" (";
302 std::vector<SqlColumnDeclaration const*> pks;
303 size_t currentColumn = 0;
304 std::string foreignKeyConstraints;
305 for (SqlColumnDeclaration
const& column: columns)
307 if (currentColumn > 0)
308 sqlQueryString <<
",";
310 sqlQueryString <<
"\n ";
311 sqlQueryString << BuildColumnDefinition(column);
313 if (column.primaryKey != SqlPrimaryKeyType::NONE)
314 pks.push_back(&column);
316 if (column.foreignKey)
318 foreignKeyConstraints +=
",\n ";
319 foreignKeyConstraints += BuildForeignKeyConstraint(tableName, column.name, *column.foreignKey);
323 for (SqlCompositeForeignKeyConstraint
const& fk: foreignKeys)
329 foreignKeyConstraints +=
",\n CONSTRAINT \"";
331 foreignKeyConstraints +=
"\" FOREIGN KEY (";
332 for (
size_t i = 0; i < fk.columns.size(); ++i)
335 foreignKeyConstraints +=
", ";
336 foreignKeyConstraints +=
'"' + fk.columns[i] +
'"';
338 foreignKeyConstraints +=
") REFERENCES \"";
339 foreignKeyConstraints += fk.referencedTableName;
340 foreignKeyConstraints +=
"\" (";
341 for (
size_t i = 0; i < fk.referencedColumns.size(); ++i)
344 foreignKeyConstraints +=
", ";
345 foreignKeyConstraints +=
'"' + fk.referencedColumns[i] +
'"';
347 foreignKeyConstraints +=
")";
357 pks, [](SqlColumnDeclaration
const* col) {
return col->primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT; });
361 std::ranges::sort(pks, [](SqlColumnDeclaration
const* a, SqlColumnDeclaration
const* b) {
366 if (a->primaryKeyIndex != 0 && b->primaryKeyIndex != 0)
367 return a->primaryKeyIndex < b->primaryKeyIndex;
368 if (a->primaryKeyIndex != 0)
370 if (b->primaryKeyIndex != 0)
375 sqlQueryString <<
",\n PRIMARY KEY (";
376 for (
size_t i = 0; i < pks.size(); ++i)
379 sqlQueryString <<
", ";
380 sqlQueryString <<
'"' << pks[i]->name <<
'"';
382 sqlQueryString <<
")";
385 sqlQueryString << foreignKeyConstraints;
387 sqlQueryString <<
"\n);";
388 return sqlQueryString.str();
391 for (SqlColumnDeclaration
const& column: columns)
393 if (column.index && column.primaryKey == SqlPrimaryKeyType::NONE)
397 sqlQueries.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}" ("{}");)",
403 sqlQueries.emplace_back(std::format(
404 R
"(CREATE INDEX "{}_{}_index" ON "{}" ("{}");)", tableName, column.name, tableName, column.name));
411 [[nodiscard]]
StringList AlterTable(std::string_view ,
412 std::string_view tableName,
413 std::vector<SqlAlterTableCommand>
const& commands)
const override
416 auto const formatTable = [tableName]() {
417 return std::format(R
"("{}")", tableName);
426 using namespace SqlAlterTableCommands;
429 std::string sql = std::visit(
431 [&formatTable](RenameTable
const& actualCommand) -> std::string {
432 return std::format(R
"(ALTER TABLE {} RENAME TO "{}";)", formatTable(), actualCommand.newTableName);
434 [&formatTable, this](AddColumn
const& actualCommand) -> std::string {
435 return std::format(R
"(ALTER TABLE {} ADD COLUMN "{}" {} {};)",
437 actualCommand.columnName,
438 ColumnType(actualCommand.columnType),
439 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
441 [&formatTable,
this](AlterColumn
const& actualCommand) -> std::string {
442 return std::format(R
"(ALTER TABLE {} ALTER COLUMN "{}" {} {};)",
444 actualCommand.columnName,
445 ColumnType(actualCommand.columnType),
446 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
448 [&formatTable](RenameColumn
const& actualCommand) -> std::string {
449 return std::format(R
"(ALTER TABLE {} RENAME COLUMN "{}" TO "{}";)",
451 actualCommand.oldColumnName,
452 actualCommand.newColumnName);
454 [&formatTable](DropColumn const& actualCommand) -> std::string {
455 return std::format(R
"(ALTER TABLE {} DROP COLUMN "{}";)", formatTable(), actualCommand.columnName);
457 [tableName](AddIndex const& actualCommand) -> std::string {
458 using namespace std::string_view_literals;
459 auto const uniqueStr = actualCommand.unique ?
"UNIQUE "sv :
""sv;
460 return std::format(R
"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}" ("{1}");)",
462 actualCommand.columnName,
465 [tableName](DropIndex const& actualCommand) -> std::string {
466 return std::format(R
"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
468 [tableName](AddForeignKey const& actualCommand) -> std::string {
475 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: ADD_FOREIGN_KEY "{0}" "{1}" "{2}" "{3}"
476-- ALTER TABLE "{0}" ADD {4};)",
478 actualCommand.columnName,
479 actualCommand.referencedColumn.tableName,
480 actualCommand.referencedColumn.columnName,
481 BuildForeignKeyConstraint(tableName, actualCommand.columnName, actualCommand.referencedColumn));
483 [tableName](DropForeignKey const& actualCommand) -> std::string {
487 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: DROP_FOREIGN_KEY "{0}" "{1}"
488-- ALTER TABLE "{0}" DROP CONSTRAINT "{2}";)",
490 actualCommand.columnName,
492 std::array { std::string_view { actualCommand.columnName } }));
494 [tableName](AddCompositeForeignKey const& ) -> std::string {
497 return std::format(R
"(-- AddCompositeForeignKey not supported for {};)", tableName);
499 [&formatTable, tableName, this](AddColumnIfNotExists
const& actualCommand) -> std::string {
504 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: ADD_COLUMN_IF_NOT_EXISTS "{0}" "{1}"
505ALTER TABLE {2} ADD COLUMN "{1}" {3} {4};)",
507 actualCommand.columnName,
509 ColumnType(actualCommand.columnType),
510 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
512 [&formatTable, tableName](DropColumnIfExists
const& actualCommand) -> std::string {
515 R
"(-- LIGHTWEIGHT_SQLITE_GUARD: DROP_COLUMN_IF_EXISTS "{0}" "{1}"
516ALTER TABLE {2} DROP COLUMN "{1}";)",
518 actualCommand.columnName,
521 [tableName](DropIndexIfExists const& actualCommand) -> std::string {
522 return std::format(R
"(DROP INDEX IF EXISTS "{0}_{1}_index";)", tableName, actualCommand.columnName);
528 result.push_back(std::move(sql));
534 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition
const& type)
const override
536 using namespace SqlColumnTypeDefinitions;
537 return std::visit(detail::overloaded {
538 [](Bigint
const&) -> std::string {
return "BIGINT"; },
539 [](Binary
const&) -> std::string {
return "BLOB"; },
540 [](Bool
const&) -> std::string {
return "BOOLEAN"; },
541 [](Char
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
542 [](Date
const&) -> std::string {
return "DATE"; },
543 [](DateTime
const&) -> std::string {
return "DATETIME"; },
544 [](Decimal
const& type) -> std::string {
545 return std::format(
"DECIMAL({}, {})", type.precision, type.scale);
547 [](Guid
const&) -> std::string {
return "GUID"; },
548 [](Integer
const&) -> std::string {
return "INTEGER"; },
549 [](NChar
const& type) -> std::string {
return std::format(
"NCHAR({})", type.size); },
550 [](NVarchar
const& type) -> std::string {
return std::format(
"NVARCHAR({})", type.size); },
551 [](Real
const&) -> std::string {
return "REAL"; },
552 [](Smallint
const&) -> std::string {
return "SMALLINT"; },
553 [](Text
const&) -> std::string {
return "TEXT"; },
554 [](Time
const&) -> std::string {
return "TIME"; },
555 [](Timestamp
const&) -> std::string {
return "TIMESTAMP"; },
556 [](Tinyint
const&) -> std::string {
return "TINYINT"; },
557 [](VarBinary
const& type) -> std::string {
return std::format(
"VARBINARY({})", type.size); },
558 [](Varchar
const& type) -> std::string {
return std::format(
"VARCHAR({})", type.size); },
563 [[nodiscard]]
StringList DropTable(std::string_view ,
564 std::string_view
const& tableName,
565 bool ifExists =
false,
566 bool cascade =
false)
const override
573 return { std::format(R
"(DROP TABLE IF EXISTS "{}";)", tableName) };
575 return { std::format(R
"(DROP TABLE "{}";)", tableName) };
578 [[nodiscard]] std::string QueryServerVersion() const override
580 return "SELECT sqlite_version()";
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.