Lightweight 0.1.0
Loading...
Searching...
No Matches
SqlServerFormatter.hpp
1// SPDX-License-Identifier: Apache-2.0
2#pragma once
3
4#include "../SqlQueryFormatter.hpp"
5#include "SQLiteFormatter.hpp"
6
7#include <reflection-cpp/reflection.hpp>
8
9#include <cassert>
10#include <format>
11
12class SqlServerQueryFormatter final: public SQLiteQueryFormatter
13{
14 public:
15 [[nodiscard]] std::string QueryLastInsertId(std::string_view /*tableName*/) const override
16 {
17 // TODO: Figure out how to get the last insert id in SQL Server for a given table.
18 return std::format("SELECT @@IDENTITY");
19 }
20
21 [[nodiscard]] std::string_view BooleanLiteral(bool literalValue) const noexcept override
22 {
23 return literalValue ? "1" : "0";
24 }
25
26 [[nodiscard]] std::string SelectFirst(bool distinct,
27 std::string_view fields,
28 std::string_view fromTable,
29 std::string_view fromTableAlias,
30 std::string_view tableJoins,
31 std::string_view whereCondition,
32 std::string_view orderBy,
33 size_t count) const override
34 {
35 std::stringstream sqlQueryString;
36 sqlQueryString << "SELECT";
37 if (distinct)
38 sqlQueryString << " DISTINCT";
39 sqlQueryString << " TOP " << count;
40 sqlQueryString << ' ' << fields;
41 sqlQueryString << " FROM \"" << fromTable << '"';
42 if (!fromTableAlias.empty())
43 sqlQueryString << " AS \"" << fromTableAlias << '"';
44 sqlQueryString << tableJoins;
45 sqlQueryString << whereCondition;
46 sqlQueryString << orderBy;
47 ;
48 return sqlQueryString.str();
49 }
50
51 [[nodiscard]] std::string SelectRange(bool distinct,
52 std::string_view fields,
53 std::string_view fromTable,
54 std::string_view fromTableAlias,
55 std::string_view tableJoins,
56 std::string_view whereCondition,
57 std::string_view orderBy,
58 std::string_view groupBy,
59 std::size_t offset,
60 std::size_t limit) const override
61 {
62 assert(!orderBy.empty());
63 std::stringstream sqlQueryString;
64 sqlQueryString << "SELECT " << fields;
65 if (distinct)
66 sqlQueryString << " DISTINCT";
67 sqlQueryString << " FROM \"" << fromTable << "\"";
68 if (!fromTableAlias.empty())
69 sqlQueryString << " AS \"" << fromTableAlias << "\"";
70 sqlQueryString << tableJoins;
71 sqlQueryString << whereCondition;
72 sqlQueryString << groupBy;
73 sqlQueryString << orderBy;
74 sqlQueryString << " OFFSET " << offset << " ROWS FETCH NEXT " << limit << " ROWS ONLY";
75 return sqlQueryString.str();
76 }
77
78 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition const& type) const override
79 {
80 using namespace SqlColumnTypeDefinitions;
81 return std::visit(detail::overloaded {
82 [](Bigint const&) -> std::string { return "BIGINT"; },
83 [](Binary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
84 [](Bool const&) -> std::string { return "BIT"; },
85 [](Char const& type) -> std::string { return std::format("CHAR({})", type.size); },
86 [](Date const&) -> std::string { return "DATE"; },
87 [](DateTime const&) -> std::string { return "DATETIME"; },
88 [](Decimal const& type) -> std::string {
89 return std::format("DECIMAL({}, {})", type.precision, type.scale);
90 },
91 [](Guid const&) -> std::string { return "UNIQUEIDENTIFIER"; },
92 [](Integer const&) -> std::string { return "INTEGER"; },
93 [](NChar const& type) -> std::string { return std::format("NCHAR({})", type.size); },
94 [](NVarchar const& type) -> std::string {
95 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
96 return "NVARCHAR(MAX)";
97 else
98 return std::format("NVARCHAR({})", type.size);
99 },
100 [](Real const&) -> std::string { return "REAL"; },
101 [](Smallint const&) -> std::string { return "SMALLINT"; },
102 [](Text const&) -> std::string { return "VARCHAR(MAX)"; },
103 [](Time const&) -> std::string { return "TIME"; },
104 [](Timestamp const&) -> std::string { return "TIMESTAMP"; },
105 [](Tinyint const&) -> std::string { return "TINYINT"; },
106 [](VarBinary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
107 [](Varchar const& type) -> std::string {
108 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
109 return "VARCHAR(MAX)";
110 else
111 return std::format("VARCHAR({})", type.size);
112 },
113 },
114 type);
115 }
116
117 [[nodiscard]] std::string BuildColumnDefinition(SqlColumnDeclaration const& column) const override
118 {
119 std::stringstream sqlQueryString;
120 sqlQueryString << '"' << column.name << "\" " << ColumnType(column.type);
121
122 if (column.required)
123 sqlQueryString << " NOT NULL";
124
125 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
126 sqlQueryString << " IDENTITY(1,1) PRIMARY KEY";
127 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
128 sqlQueryString << " UNIQUE";
129
130 return sqlQueryString.str();
131 }
132
133 [[nodiscard]] StringList AlterTable(std::string_view tableName,
134 std::vector<SqlAlterTableCommand> const& commands) const override
135 {
136 std::stringstream sqlQueryString;
137
138 int currentCommand = 0;
139 for (SqlAlterTableCommand const& command: commands)
140 {
141 if (currentCommand > 0)
142 sqlQueryString << '\n';
143 ++currentCommand;
144
145 using namespace SqlAlterTableCommands;
146 sqlQueryString << std::visit(
147 detail::overloaded {
148 [tableName](RenameTable const& actualCommand) -> std::string {
149 return std::format(R"(ALTER TABLE "{}" RENAME TO "{}";)", tableName, actualCommand.newTableName);
150 },
151 [tableName, this](AddColumn const& actualCommand) -> std::string {
152 return std::format(R"(ALTER TABLE "{}" ADD "{}" {} {};)",
153 tableName,
154 actualCommand.columnName,
155 ColumnType(actualCommand.columnType),
156 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" : "NULL");
157 },
158 [tableName, this](AlterColumn const& actualCommand) -> std::string {
159 return std::format(R"(ALTER TABLE "{}" ALTER COLUMN "{}" {} {};)",
160 tableName,
161 actualCommand.columnName,
162 ColumnType(actualCommand.columnType),
163 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" : "NULL");
164 },
165 [tableName](RenameColumn const& actualCommand) -> std::string {
166 return std::format(R"(ALTER TABLE "{}" RENAME COLUMN "{}" TO "{}";)",
167 tableName,
168 actualCommand.oldColumnName,
169 actualCommand.newColumnName);
170 },
171 [tableName](DropColumn const& actualCommand) -> std::string {
172 return std::format(R"(ALTER TABLE "{}" DROP COLUMN "{}";)", tableName, actualCommand.columnName);
173 },
174 [tableName](AddIndex const& actualCommand) -> std::string {
175 using namespace std::string_view_literals;
176 auto const uniqueStr = actualCommand.unique ? "UNIQUE "sv : ""sv;
177 return std::format(R"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}"("{1}");)",
178 tableName,
179 actualCommand.columnName,
180 uniqueStr);
181 },
182 [tableName](DropIndex const& actualCommand) -> std::string {
183 return std::format(R"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
184 },
185 [tableName](AddForeignKey const& actualCommand) -> std::string {
186 return std::format(
187 R"(ALTER TABLE "{}" ADD {};)",
188 tableName,
189 BuildForeignKeyConstraint(actualCommand.columnName, actualCommand.referencedColumn));
190 },
191 [tableName](DropForeignKey const& actualCommand) -> std::string {
192 return std::format(R"(ALTER TABLE "{}" DROP CONSTRAINT "{}";)",
193 tableName,
194 std::format("FK_{}", actualCommand.columnName));
195 },
196 },
197 command);
198 }
199
200 return { sqlQueryString.str() };
201 }
202};
std::variant< SqlAlterTableCommands::RenameTable, SqlAlterTableCommands::AddColumn, SqlAlterTableCommands::AlterColumn, SqlAlterTableCommands::AddIndex, SqlAlterTableCommands::RenameColumn, SqlAlterTableCommands::DropColumn, SqlAlterTableCommands::DropIndex, SqlAlterTableCommands::AddForeignKey, SqlAlterTableCommands::DropForeignKey > SqlAlterTableCommand
Represents a single SQL ALTER TABLE command.
Represents a SQL column declaration.
bool index
Indicates if the column is indexed.
SqlColumnTypeDefinition type
The type of the column.
bool required
Indicates if the column is required (non-nullable).
SqlPrimaryKeyType primaryKey
The primary key type of the column.
bool unique
Indicates if the column is unique.
std::string name
The name of the column.