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]] std::string Insert(std::string_view intoTable,
28 std::string_view fields,
29 std::string_view values)
const override
31 return std::format(R
"(INSERT INTO "{}" ({}) VALUES ({}))", intoTable, fields, values);
34 [[nodiscard]] std::string Insert(std::string_view ,
35 std::string_view intoTable,
36 std::string_view fields,
37 std::string_view values)
const override
40 return std::format(R
"(INSERT INTO "{}" ({}) VALUES ({}))", intoTable, fields, values);
43 [[nodiscard]] std::string QueryLastInsertId(std::string_view )
const override
46 return "SELECT LAST_INSERT_ROWID()";
49 [[nodiscard]] std::string_view BooleanLiteral(
bool literalValue)
const noexcept override
51 return literalValue ?
"TRUE" :
"FALSE";
54 [[nodiscard]] std::string_view DateFunction() const noexcept
override
59 [[nodiscard]] std::string StringLiteral(std::string_view value)
const noexcept override
65 escaped.reserve(value.size() + 2);
67 for (
char const c: value)
78 [[nodiscard]] std::string StringLiteral(
char value)
const noexcept override
82 return std::format(
"'{}'", value);
85 [[nodiscard]] std::string BinaryLiteral(std::span<uint8_t const> data)
const override
88 result.reserve((data.size() * 2) + 3);
90 for (uint8_t
byte: data)
91 result += std::format(
"{:02X}", byte);
96 [[nodiscard]] std::string QualifiedTableName(std::string_view schema, std::string_view table)
const override
100 return std::format(R
"("{}")", table);
102 return std::format(R
"("{}"."{}")", schema, table);
105 [[nodiscard]] std::string SelectCount(bool distinct,
106 std::string_view fromTable,
107 std::string_view fromTableAlias,
108 std::string_view tableJoins,
109 std::string_view whereCondition)
const override
111 auto const formattedTable = FormatFromTable(fromTable);
112 if (fromTableAlias.empty())
114 "SELECT{} COUNT(*) FROM {}{}{}", distinct ?
" DISTINCT" :
"", formattedTable, tableJoins, whereCondition);
116 return std::format(R
"(SELECT{} COUNT(*) FROM {} AS "{}"{}{})",
117 distinct ? " DISTINCT" :
"",
124 [[nodiscard]] std::string SelectAll(
bool distinct,
126 std::string_view fields,
127 std::string_view fromTable,
128 std::string_view fromTableAlias,
129 std::string_view tableJoins,
130 std::string_view whereCondition,
131 std::string_view orderBy,
132 std::string_view groupBy)
const override
134 std::stringstream sqlQueryString;
135 sqlQueryString <<
"SELECT ";
137 sqlQueryString <<
"DISTINCT ";
138 sqlQueryString << fields;
139 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
140 if (!fromTableAlias.empty())
141 sqlQueryString <<
" AS \"" << fromTableAlias <<
'"';
142 sqlQueryString << tableJoins;
143 sqlQueryString << whereCondition;
144 sqlQueryString << groupBy;
145 sqlQueryString << orderBy;
147 return sqlQueryString.str();
150 [[nodiscard]] std::string SelectFirst(
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 size_t count)
const override
160 std::stringstream sqlQueryString;
161 sqlQueryString <<
"SELECT " << fields;
163 sqlQueryString <<
" DISTINCT";
164 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
165 if (!fromTableAlias.empty())
166 sqlQueryString <<
" AS \"" << fromTableAlias <<
"\"";
167 sqlQueryString << tableJoins;
168 sqlQueryString << whereCondition;
169 sqlQueryString << orderBy;
170 sqlQueryString <<
" LIMIT " << count;
171 return sqlQueryString.str();
174 [[nodiscard]] std::string SelectRange(
bool distinct,
176 std::string_view fields,
177 std::string_view fromTable,
178 std::string_view fromTableAlias,
179 std::string_view tableJoins,
180 std::string_view whereCondition,
181 std::string_view orderBy,
182 std::string_view groupBy,
184 std::size_t limit)
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 << groupBy;
196 sqlQueryString << orderBy;
197 sqlQueryString <<
" LIMIT " << limit <<
" OFFSET " << offset;
198 return sqlQueryString.str();
201 [[nodiscard]] std::string Update(std::string_view table,
202 std::string_view tableAlias,
203 std::string_view setFields,
204 std::string_view whereCondition)
const override
206 auto const formattedTable = FormatFromTable(table);
207 if (tableAlias.empty())
208 return std::format(
"UPDATE {} SET {}{}", formattedTable, setFields, whereCondition);
210 return std::format(R
"(UPDATE {} AS "{}" SET {}{})", formattedTable, tableAlias, setFields, whereCondition);
213 [[nodiscard]] std::string Delete(std::string_view fromTable,
214 std::string_view fromTableAlias,
215 std::string_view tableJoins,
216 std::string_view whereCondition) const override
218 auto const formattedTable = FormatFromTable(fromTable);
219 if (fromTableAlias.empty())
220 return std::format(
"DELETE FROM {}{}{}", formattedTable, tableJoins, whereCondition);
222 return std::format(R
"(DELETE FROM {} AS "{}"{}{})", formattedTable, fromTableAlias, tableJoins, whereCondition);
225 [[nodiscard]] virtual std::string BuildColumnDefinition(SqlColumnDeclaration
const& column)
const
227 std::stringstream sqlQueryString;
229 sqlQueryString <<
'"' << column.name <<
"\" ";
231 if (column.primaryKey != SqlPrimaryKeyType::AUTO_INCREMENT)
232 sqlQueryString << ColumnType(column.type);
234 sqlQueryString << ColumnType(SqlColumnTypeDefinitions::Integer {});
237 sqlQueryString <<
" NOT NULL";
239 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
240 sqlQueryString <<
" PRIMARY KEY AUTOINCREMENT";
241 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
242 sqlQueryString <<
" UNIQUE";
244 if (!column.defaultValue.empty())
245 sqlQueryString <<
" DEFAULT " << column.defaultValue;
247 return sqlQueryString.str();
250 [[nodiscard]]
static std::string BuildForeignKeyConstraint(std::string_view tableName,
251 std::string_view columnName,
252 SqlForeignKeyReferenceDefinition
const& referencedColumn)
254 return std::format(R
"(CONSTRAINT {} FOREIGN KEY ("{}") REFERENCES "{}"("{}"))",
255 std::format("FK_{}_{}", tableName, columnName),
257 referencedColumn.tableName,
258 referencedColumn.columnName);
262 [[nodiscard]] StringList CreateTable(std::string_view schema,
263 std::string_view tableName,
264 std::vector<SqlColumnDeclaration>
const& columns,
265 std::vector<SqlCompositeForeignKeyConstraint>
const& foreignKeys,
266 bool ifNotExists =
false)
const override
268 auto sqlQueries = StringList {};
271 sqlQueries.emplace_back([&]() {
272 std::stringstream sqlQueryString;
273 sqlQueryString <<
"CREATE TABLE ";
275 sqlQueryString <<
"IF NOT EXISTS ";
278 sqlQueryString <<
"\"" << tableName <<
"\" (";
279 std::vector<SqlColumnDeclaration const*> pks;
280 size_t currentColumn = 0;
281 std::string foreignKeyConstraints;
282 for (SqlColumnDeclaration
const& column: columns)
284 if (currentColumn > 0)
285 sqlQueryString <<
",";
287 sqlQueryString <<
"\n ";
288 sqlQueryString << BuildColumnDefinition(column);
290 if (column.primaryKey != SqlPrimaryKeyType::NONE)
291 pks.push_back(&column);
293 if (column.foreignKey)
295 foreignKeyConstraints +=
",\n ";
296 foreignKeyConstraints += BuildForeignKeyConstraint(tableName, column.name, *column.foreignKey);
300 for (SqlCompositeForeignKeyConstraint
const& fk: foreignKeys)
302 foreignKeyConstraints +=
",\n FOREIGN KEY (";
303 for (
size_t i = 0; i < fk.columns.size(); ++i)
306 foreignKeyConstraints +=
", ";
307 foreignKeyConstraints +=
'"' + fk.columns[i] +
'"';
309 foreignKeyConstraints +=
") REFERENCES \"";
310 foreignKeyConstraints += fk.referencedTableName;
311 foreignKeyConstraints +=
"\" (";
312 for (
size_t i = 0; i < fk.referencedColumns.size(); ++i)
315 foreignKeyConstraints +=
", ";
316 foreignKeyConstraints +=
'"' + fk.referencedColumns[i] +
'"';
318 foreignKeyConstraints +=
")";
328 pks, [](SqlColumnDeclaration
const* col) {
return col->primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT; });
332 std::ranges::sort(pks, [](SqlColumnDeclaration
const* a, SqlColumnDeclaration
const* b) {
337 if (a->primaryKeyIndex != 0 && b->primaryKeyIndex != 0)
338 return a->primaryKeyIndex < b->primaryKeyIndex;
339 if (a->primaryKeyIndex != 0)
341 if (b->primaryKeyIndex != 0)
346 sqlQueryString <<
",\n PRIMARY KEY (";
347 for (
size_t i = 0; i < pks.size(); ++i)
350 sqlQueryString <<
", ";
351 sqlQueryString <<
'"' << pks[i]->name <<
'"';
353 sqlQueryString <<
")";
356 sqlQueryString << foreignKeyConstraints;
358 sqlQueryString <<
"\n);";
359 return sqlQueryString.str();
362 for (SqlColumnDeclaration
const& column: columns)
364 if (column.index && column.primaryKey == SqlPrimaryKeyType::NONE)
368 sqlQueries.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}" ("{}");)",
374 sqlQueries.emplace_back(std::format(
375 R
"(CREATE INDEX "{}_{}_index" ON "{}" ("{}");)", tableName, column.name, tableName, column.name));
382 [[nodiscard]] StringList AlterTable(std::string_view ,
383 std::string_view tableName,
384 std::vector<SqlAlterTableCommand>
const& commands)
const override
387 auto const formatTable = [tableName]() {
388 return std::format(R
"("{}")", tableName);
391 std::stringstream sqlQueryString;
393 int currentCommand = 0;
394 for (SqlAlterTableCommand
const& command: commands)
396 if (currentCommand > 0)
397 sqlQueryString <<
'\n';
400 using namespace SqlAlterTableCommands;
401 sqlQueryString << std::visit(
403 [&formatTable](RenameTable
const& actualCommand) -> std::string {
404 return std::format(R
"(ALTER TABLE {} RENAME TO "{}";)", formatTable(), actualCommand.newTableName);
406 [&formatTable, this](AddColumn
const& actualCommand) -> std::string {
407 return std::format(R
"(ALTER TABLE {} ADD COLUMN "{}" {} {};)",
409 actualCommand.columnName,
410 ColumnType(actualCommand.columnType),
411 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
413 [&formatTable,
this](AlterColumn
const& actualCommand) -> std::string {
414 return std::format(R
"(ALTER TABLE {} ALTER COLUMN "{}" {} {};)",
416 actualCommand.columnName,
417 ColumnType(actualCommand.columnType),
418 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
420 [&formatTable](RenameColumn
const& actualCommand) -> std::string {
421 return std::format(R
"(ALTER TABLE {} RENAME COLUMN "{}" TO "{}";)",
423 actualCommand.oldColumnName,
424 actualCommand.newColumnName);
426 [&formatTable](DropColumn const& actualCommand) -> std::string {
427 return std::format(R
"(ALTER TABLE {} DROP COLUMN "{}";)", formatTable(), actualCommand.columnName);
429 [tableName](AddIndex const& actualCommand) -> std::string {
430 using namespace std::string_view_literals;
431 auto const uniqueStr = actualCommand.unique ?
"UNIQUE "sv :
""sv;
432 return std::format(R
"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}" ("{1}");)",
434 actualCommand.columnName,
437 [tableName](DropIndex const& actualCommand) -> std::string {
438 return std::format(R
"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
440 [&formatTable, tableName](AddForeignKey const& actualCommand) -> std::string {
442 R
"(ALTER TABLE {} ADD {};)",
444 BuildForeignKeyConstraint(tableName, actualCommand.columnName, actualCommand.referencedColumn));
446 [&formatTable, tableName](DropForeignKey const& actualCommand) -> std::string {
447 return std::format(R
"(ALTER TABLE {} DROP CONSTRAINT "{}";)",
449 std::format("FK_{}_{}", tableName, actualCommand.columnName));
451 [tableName](AddCompositeForeignKey
const& ) -> std::string {
454 return std::format(R
"(-- AddCompositeForeignKey not supported for {};)", tableName);
456 [&formatTable, this](AddColumnIfNotExists
const& actualCommand) -> std::string {
460 R
"(-- AddColumnIfNotExists: SQLite doesn't support IF NOT EXISTS for columns
461ALTER TABLE {} ADD COLUMN "{}" {} {};)",
463 actualCommand.columnName,
464 ColumnType(actualCommand.columnType),
465 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
467 [&formatTable](DropColumnIfExists
const& actualCommand) -> std::string {
470 R
"(-- DropColumnIfExists: SQLite doesn't support IF EXISTS for columns
471ALTER TABLE {} DROP COLUMN "{}";)",
473 actualCommand.columnName);
475 [tableName](DropIndexIfExists const& actualCommand) -> std::string {
476 return std::format(R
"(DROP INDEX IF EXISTS "{0}_{1}_index";)", tableName, actualCommand.columnName);
482 return { sqlQueryString.str() };
485 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition
const& type)
const override
487 using namespace SqlColumnTypeDefinitions;
488 return std::visit(detail::overloaded {
489 [](Bigint
const&) -> std::string {
return "BIGINT"; },
490 [](Binary
const&) -> std::string {
return "BLOB"; },
491 [](Bool
const&) -> std::string {
return "BOOLEAN"; },
492 [](Char
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
493 [](Date
const&) -> std::string {
return "DATE"; },
494 [](DateTime
const&) -> std::string {
return "DATETIME"; },
495 [](Decimal
const& type) -> std::string {
496 return std::format(
"DECIMAL({}, {})", type.precision, type.scale);
498 [](Guid
const&) -> std::string {
return "GUID"; },
499 [](Integer
const&) -> std::string {
return "INTEGER"; },
500 [](NChar
const& type) -> std::string {
return std::format(
"NCHAR({})", type.size); },
501 [](NVarchar
const& type) -> std::string {
return std::format(
"NVARCHAR({})", type.size); },
502 [](Real
const&) -> std::string {
return "REAL"; },
503 [](Smallint
const&) -> std::string {
return "SMALLINT"; },
504 [](Text
const&) -> std::string {
return "TEXT"; },
505 [](Time
const&) -> std::string {
return "TIME"; },
506 [](Timestamp
const&) -> std::string {
return "TIMESTAMP"; },
507 [](Tinyint
const&) -> std::string {
return "TINYINT"; },
508 [](VarBinary
const& type) -> std::string {
return std::format(
"VARBINARY({})", type.size); },
509 [](Varchar
const& type) -> std::string {
return std::format(
"VARCHAR({})", type.size); },
514 [[nodiscard]] StringList DropTable(std::string_view ,
515 std::string_view
const& tableName,
516 bool ifExists =
false,
517 bool cascade =
false)
const override
524 return { std::format(R
"(DROP TABLE IF EXISTS "{}";)", tableName) };
526 return { std::format(R
"(DROP TABLE "{}";)", tableName) };
529 [[nodiscard]] std::string QueryServerVersion() const override
531 return "SELECT sqlite_version()";