4#include "../SqlQueryFormatter.hpp"
5#include "SQLiteFormatter.hpp"
7#include <reflection-cpp/reflection.hpp>
15class SqlServerQueryFormatter final:
public SQLiteQueryFormatter
18 [[nodiscard]]
static std::string FormatFromTable(std::string_view table)
21 if (!table.empty() && (table.front() ==
'[' || table.front() ==
'"'))
22 return std::string(table);
25 return std::format(R
"("{}")", table);
29 [[nodiscard]]
bool RequiresTableRebuildForForeignKeyChange() const noexcept
override
34 [[nodiscard]]
StringList DropTable(std::string_view schemaName,
35 std::string_view
const& tableName,
36 bool ifExists =
false,
37 bool cascade =
false)
const override
44 std::string
const schemaFilter = schemaName.empty() ?
"dbo" : std::string(schemaName);
46 result.emplace_back(std::format(
47 R
"(DECLARE @sql NVARCHAR(MAX) = N'';
48SELECT @sql = @sql + 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id)) + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + '; '
49FROM sys.foreign_keys fk
50WHERE OBJECT_NAME(fk.referenced_object_id) = '{}' AND OBJECT_SCHEMA_NAME(fk.referenced_object_id) = '{}';
51EXEC sp_executesql @sql;)",
58 result.emplace_back(std::format(
"DROP TABLE IF EXISTS {};",
FormatTableName(schemaName, tableName)));
60 result.emplace_back(std::format(
"DROP TABLE {};",
FormatTableName(schemaName, tableName)));
65 [[nodiscard]] std::string BinaryLiteral(std::span<uint8_t const> data)
const override
68 result.reserve((data.size() * 2) + 2);
70 for (uint8_t
byte: data)
71 result += std::format(
"{:02X}", byte);
75 [[nodiscard]] std::string QualifiedTableName(std::string_view schema, std::string_view table)
const override
78 return std::format(
"[{}]", table);
79 return std::format(
"[{}].[{}]", schema, table);
82 [[nodiscard]] std::string QueryLastInsertId(std::string_view )
const override
85 return std::format(
"SELECT @@IDENTITY");
88 [[nodiscard]] std::string_view BooleanLiteral(
bool literalValue)
const noexcept override
90 return literalValue ?
"1" :
"0";
93 [[nodiscard]] std::string_view DateFunction() const noexcept
override
98 [[nodiscard]] std::string SelectFirst(
bool distinct,
100 std::string_view fields,
101 std::string_view fromTable,
102 std::string_view fromTableAlias,
103 std::string_view tableJoins,
104 std::string_view whereCondition,
105 std::string_view orderBy,
106 size_t count)
const override
108 std::stringstream sqlQueryString;
109 sqlQueryString <<
"SELECT";
111 sqlQueryString <<
" DISTINCT";
112 sqlQueryString <<
" TOP " << count;
113 sqlQueryString <<
' ' << fields;
114 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
115 if (!fromTableAlias.empty())
116 sqlQueryString <<
" AS [" << fromTableAlias <<
']';
117 sqlQueryString << tableJoins;
118 sqlQueryString << whereCondition;
119 sqlQueryString << orderBy;
120 return sqlQueryString.str();
123 [[nodiscard]] std::string SelectRange(
bool distinct,
125 std::string_view fields,
126 std::string_view fromTable,
127 std::string_view fromTableAlias,
128 std::string_view tableJoins,
129 std::string_view whereCondition,
130 std::string_view orderBy,
131 std::string_view groupBy,
133 std::size_t limit)
const override
135 assert(!orderBy.empty());
136 std::stringstream sqlQueryString;
137 sqlQueryString <<
"SELECT " << fields;
139 sqlQueryString <<
" DISTINCT";
140 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
141 if (!fromTableAlias.empty())
142 sqlQueryString <<
" AS [" << fromTableAlias <<
']';
143 sqlQueryString << tableJoins;
144 sqlQueryString << whereCondition;
145 sqlQueryString << groupBy;
146 sqlQueryString << orderBy;
147 sqlQueryString <<
" OFFSET " << offset <<
" ROWS FETCH NEXT " << limit <<
" ROWS ONLY";
148 return sqlQueryString.str();
151 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition
const& type)
const override
153 using namespace SqlColumnTypeDefinitions;
154 return std::visit(detail::overloaded {
155 [](Bigint
const&) -> std::string {
return "BIGINT"; },
156 [](Binary
const& type) -> std::string {
157 if (type.size == 0 || type.size > 8000)
158 return "VARBINARY(MAX)";
160 return std::format(
"VARBINARY({})", type.size);
162 [](Bool
const&) -> std::string {
return "BIT"; },
163 [](Char
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
164 [](Date
const&) -> std::string {
return "DATE"; },
165 [](DateTime
const&) -> std::string {
return "DATETIME"; },
166 [](Decimal
const& type) -> std::string {
167 return std::format(
"DECIMAL({}, {})", type.precision, type.scale);
169 [](Guid
const&) -> std::string {
return "UNIQUEIDENTIFIER"; },
170 [](Integer
const&) -> std::string {
return "INTEGER"; },
171 [](NChar
const& type) -> std::string {
return std::format(
"NCHAR({})", type.size); },
172 [](NVarchar
const& type) -> std::string {
173 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
174 return "NVARCHAR(MAX)";
176 return std::format(
"NVARCHAR({})", type.size);
178 [](Real
const&) -> std::string {
return "REAL"; },
179 [](Smallint
const&) -> std::string {
return "SMALLINT"; },
180 [](Text
const&) -> std::string {
return "VARCHAR(MAX)"; },
181 [](Time
const&) -> std::string {
return "TIME"; },
182 [](Timestamp
const&) -> std::string {
return "TIMESTAMP"; },
183 [](Tinyint
const&) -> std::string {
return "TINYINT"; },
184 [](VarBinary
const& type) -> std::string {
185 if (type.size == 0 || type.size > 8000)
186 return "VARBINARY(MAX)";
188 return std::format(
"VARBINARY({})", type.size);
190 [](Varchar
const& type) -> std::string {
191 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
192 return "VARCHAR(MAX)";
194 return std::format(
"VARCHAR({})", type.size);
200 [[nodiscard]] std::string BuildColumnDefinition(SqlColumnDeclaration
const& column)
const override
202 std::stringstream sqlQueryString;
203 sqlQueryString <<
'"' << column.name <<
"\" " << ColumnType(column.type);
206 sqlQueryString <<
" NOT NULL";
208 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
209 sqlQueryString <<
" IDENTITY(1,1) PRIMARY KEY";
210 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
211 sqlQueryString <<
" UNIQUE";
213 if (!column.defaultValue.empty())
214 sqlQueryString <<
" DEFAULT " << column.defaultValue;
216 return sqlQueryString.str();
220 [[nodiscard]]
StringList CreateTable(std::string_view schema,
221 std::string_view tableName,
222 std::vector<SqlColumnDeclaration>
const& columns,
223 std::vector<SqlCompositeForeignKeyConstraint>
const& foreignKeys,
224 bool ifNotExists =
false)
const override
226 std::stringstream ss;
231 std::string schemaFilter = schema.empty() ?
"dbo" : std::string(schema);
232 ss << std::format(
"IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = '{}' AND schema_id = SCHEMA_ID('{}'))\n",
237 ss << std::format(
"CREATE TABLE {} (",
FormatTableName(schema, tableName));
240 for (
auto const& column: columns)
245 ss <<
"\n " << BuildColumnDefinition(column);
248 auto const primaryKeys = [&]() -> std::vector<std::string> {
249 std::vector<std::pair<uint16_t, std::string>> indexedPrimaryKeys;
250 for (
auto const& col: columns)
252 indexedPrimaryKeys.emplace_back(col.primaryKeyIndex, col.name);
253 std::ranges::sort(indexedPrimaryKeys, [](
auto const& a,
auto const& b) {
return a.first < b.first; });
255 std::vector<std::string> primaryKeys;
256 primaryKeys.reserve(indexedPrimaryKeys.size());
257 for (
auto const& [index, name]: indexedPrimaryKeys)
258 primaryKeys.push_back(name);
262 if (!primaryKeys.empty())
272 bool hasIdentity =
false;
273 for (
auto const& col: columns)
279 ss <<
",\n PRIMARY KEY (";
281 for (
auto const& pk: primaryKeys)
286 ss <<
'"' << pk <<
'"';
292 if (!foreignKeys.empty())
294 for (
auto const& fk: foreignKeys)
300 for (
auto const& col: fk.columns)
304 ss <<
'"' << col <<
'"';
307 ss <<
") REFERENCES " <<
FormatTableName(schema, fk.referencedTableName) <<
" (";
310 for (
auto const& col: fk.referencedColumns)
314 ss <<
'"' << col <<
'"';
322 for (
auto const& column: columns)
324 if (column.foreignKey)
326 ss <<
",\n " << BuildForeignKeyConstraint(tableName, column.name, *column.foreignKey);
333 result.emplace_back(ss.str());
336 for (SqlColumnDeclaration
const& column: columns)
338 if (column.index && column.primaryKey == SqlPrimaryKeyType::NONE)
344 result.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}" ("{}");)",
350 result.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}"."{}" ("{}");)",
360 result.emplace_back(std::format(R
"(CREATE INDEX "{}_{}_index" ON "{}" ("{}");)",
366 result.emplace_back(std::format(R
"(CREATE INDEX "{}_{}_index" ON "{}"."{}" ("{}");)",
380 [[nodiscard]]
StringList AlterTable(std::string_view schemaName,
381 std::string_view tableName,
382 std::vector<SqlAlterTableCommand>
const& commands)
const override
384 std::stringstream sqlQueryString;
386 int currentCommand = 0;
389 if (currentCommand > 0)
390 sqlQueryString <<
'\n';
393 using namespace SqlAlterTableCommands;
394 sqlQueryString << std::visit(
396 [schemaName, tableName](RenameTable
const& actualCommand) -> std::string {
397 return std::format(R
"(ALTER TABLE {} RENAME TO "{}";)",
399 actualCommand.newTableName);
401 [schemaName, tableName, this](AddColumn
const& actualCommand) -> std::string {
402 return std::format(R
"(ALTER TABLE {} ADD "{}" {} {};)",
404 actualCommand.columnName,
405 ColumnType(actualCommand.columnType),
406 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
408 [schemaName, tableName,
this](AlterColumn
const& actualCommand) -> std::string {
409 return std::format(R
"(ALTER TABLE {} ALTER COLUMN "{}" {} {};)",
411 actualCommand.columnName,
412 ColumnType(actualCommand.columnType),
413 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
415 [schemaName, tableName](RenameColumn
const& actualCommand) -> std::string {
416 return std::format(R
"(ALTER TABLE {} RENAME COLUMN "{}" TO "{}";)",
418 actualCommand.oldColumnName,
419 actualCommand.newColumnName);
421 [schemaName, tableName](DropColumn const& actualCommand) -> std::string {
422 return std::format(R
"(ALTER TABLE {} DROP COLUMN "{}";)",
424 actualCommand.columnName);
426 [schemaName, tableName](AddIndex const& actualCommand) -> std::string {
427 using namespace std::string_view_literals;
428 auto const uniqueStr = actualCommand.unique ?
"UNIQUE "sv :
""sv;
429 if (schemaName.empty())
430 return std::format(R
"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}" ("{1}");)",
432 actualCommand.columnName,
435 return std::format(R
"(CREATE {3}INDEX "{0}_{1}_{2}_index" ON "{0}"."{1}" ("{2}");)",
438 actualCommand.columnName,
441 [schemaName, tableName](DropIndex const& actualCommand) -> std::string {
442 if (schemaName.empty())
443 return std::format(R
"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
446 R
"(DROP INDEX "{0}_{1}_{2}_index";)", schemaName, tableName, actualCommand.columnName);
448 [schemaName, tableName](AddForeignKey const& actualCommand) -> std::string {
453 tableName, std::array { std::string_view { actualCommand.columnName } });
455 R
"(IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '{0}') ALTER TABLE {1} ADD {2};)",
458 BuildForeignKeyConstraint(tableName, actualCommand.columnName, actualCommand.referencedColumn));
460 [schemaName, tableName](DropForeignKey const& actualCommand) -> std::string {
461 return std::format(R
"(ALTER TABLE {} DROP CONSTRAINT "{}";)",
464 tableName, std::array { std::string_view { actualCommand.columnName } }));
466 [schemaName, tableName](AddCompositeForeignKey const& actualCommand) -> std::string {
467 std::stringstream ss;
468 ss <<
"ALTER TABLE " <<
FormatTableName(schemaName, tableName) <<
" ADD CONSTRAINT \""
472 for (
auto const& col: actualCommand.columns)
476 ss <<
'"' << col <<
'"';
478 ss <<
") REFERENCES " <<
FormatTableName(schemaName, actualCommand.referencedTableName) <<
" (";
481 for (
auto const& col: actualCommand.referencedColumns)
485 ss <<
'"' << col <<
'"';
490 [schemaName, tableName,
this](AddColumnIfNotExists
const& actualCommand) -> std::string {
493 R
"(IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('{}') AND name = '{}')
494ALTER TABLE {} ADD "{}" {} {};)",
496 actualCommand.columnName,
498 actualCommand.columnName,
499 ColumnType(actualCommand.columnType),
500 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
502 [schemaName, tableName](DropColumnIfExists
const& actualCommand) -> std::string {
505 R
"(IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('{}') AND name = '{}')
506ALTER TABLE {} DROP COLUMN "{}";)",
508 actualCommand.columnName,
510 actualCommand.columnName);
512 [schemaName, tableName](DropIndexIfExists const& actualCommand) -> std::string {
513 if (schemaName.empty())
515 R
"(IF EXISTS (SELECT * FROM sys.indexes WHERE name = '{0}_{1}_index' AND object_id = OBJECT_ID('{0}'))
516DROP INDEX "{0}_{1}_index" ON "{0}";)",
518 actualCommand.columnName);
521 R
"(IF EXISTS (SELECT * FROM sys.indexes WHERE name = '{0}_{1}_{2}_index')
522DROP INDEX "{0}_{1}_{2}_index" ON "{0}"."{1}";)",
525 actualCommand.columnName);
531 return { sqlQueryString.str() };
534 [[nodiscard]] std::string QueryServerVersion()
const override
536 return "SELECT @@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.
SqlPrimaryKeyType
Represents a primary key type.