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(
82 detail::overloaded {
83 [](Bigint const&) -> std::string { return "BIGINT"; },
84 [](Binary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
85 [](Bool const&) -> std::string { return "BIT"; },
86 [](Char const& type) -> std::string { return std::format("CHAR({})", type.size); },
87 [](Date const&) -> std::string { return "DATE"; },
88 [](DateTime const&) -> std::string { return "DATETIME"; },
89 [](Decimal const& type) -> std::string {
90 return std::format("DECIMAL({}, {})", type.precision, type.scale);
91 },
92 [](Guid const&) -> std::string { return "UNIQUEIDENTIFIER"; },
93 [](Integer const&) -> std::string { return "INTEGER"; },
94 [](NChar const& type) -> std::string { return std::format("NCHAR({})", type.size); },
95 [](NVarchar const& type) -> std::string {
96 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
97 return "NVARCHAR(MAX)";
98 else
99 return std::format("NVARCHAR({})", type.size);
100 },
101 [](Real const&) -> std::string { return "REAL"; },
102 [](Smallint const&) -> std::string { return "SMALLINT"; },
103 [](Text const&) -> std::string { return "VARCHAR(MAX)"; },
104 [](Time const&) -> std::string { return "TIME"; },
105 [](Timestamp const&) -> std::string { return "TIMESTAMP"; },
106 [](Tinyint const&) -> std::string { return "TINYINT"; },
107 [](VarBinary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
108 [](Varchar const& type) -> std::string {
109 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
110 return "VARCHAR(MAX)";
111 else
112 return std::format("VARCHAR({})", type.size);
113 },
114 },
115 type);
116 }
117
118 [[nodiscard]] std::string BuildColumnDefinition(SqlColumnDeclaration const& column) const override
119 {
120 std::stringstream sqlQueryString;
121 sqlQueryString << '"' << column.name << "\" " << ColumnType(column.type);
122
123 if (column.required)
124 sqlQueryString << " NOT NULL";
125
126 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
127 sqlQueryString << " IDENTITY(1,1) PRIMARY KEY";
128 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
129 sqlQueryString << " UNIQUE";
130
131 return sqlQueryString.str();
132 }
133
134 [[nodiscard]] StringList AlterTable(std::string_view tableName,
135 std::vector<SqlAlterTableCommand> const& commands) const override
136 {
137 std::stringstream sqlQueryString;
138
139 int currentCommand = 0;
140 for (SqlAlterTableCommand const& command: commands)
141 {
142 if (currentCommand > 0)
143 sqlQueryString << '\n';
144 ++currentCommand;
145
146 using namespace SqlAlterTableCommands;
147 sqlQueryString << std::visit(
148 detail::overloaded {
149 [tableName](RenameTable const& actualCommand) -> std::string {
150 return std::format(
151 R"(ALTER TABLE "{}" RENAME TO "{}";)", tableName, actualCommand.newTableName);
152 },
153 [tableName, this](AddColumn const& actualCommand) -> std::string {
154 return std::format(R"(ALTER TABLE "{}" ADD "{}" {} {};)",
155 tableName,
156 actualCommand.columnName,
157 ColumnType(actualCommand.columnType),
158 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" : "NULL");
159 },
160 [tableName, this](AlterColumn const& actualCommand) -> std::string {
161 return std::format(R"(ALTER TABLE "{}" ALTER COLUMN "{}" {} {};)",
162 tableName,
163 actualCommand.columnName,
164 ColumnType(actualCommand.columnType),
165 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" : "NULL");
166 },
167 [tableName](RenameColumn const& actualCommand) -> std::string {
168 return std::format(R"(ALTER TABLE "{}" RENAME COLUMN "{}" TO "{}";)",
169 tableName,
170 actualCommand.oldColumnName,
171 actualCommand.newColumnName);
172 },
173 [tableName](DropColumn const& actualCommand) -> std::string {
174 return std::format(
175 R"(ALTER TABLE "{}" DROP COLUMN "{}";)", tableName, actualCommand.columnName);
176 },
177 [tableName](AddIndex const& actualCommand) -> std::string {
178 using namespace std::string_view_literals;
179 auto const uniqueStr = actualCommand.unique ? "UNIQUE "sv : ""sv;
180 return std::format(R"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}"("{1}");)",
181 tableName,
182 actualCommand.columnName,
183 uniqueStr);
184 },
185 [tableName](DropIndex const& actualCommand) -> std::string {
186 return std::format(R"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
187 },
188 [tableName](AddForeignKey const& actualCommand) -> std::string {
189 return std::format(
190 R"(ALTER TABLE "{}" ADD {};)",
191 tableName,
192 BuildForeignKeyConstraint(actualCommand.columnName, actualCommand.referencedColumn));
193 },
194 [tableName](DropForeignKey const& actualCommand) -> std::string {
195 return std::format(R"(ALTER TABLE "{}" DROP CONSTRAINT "{}";)",
196 tableName,
197 std::format("FK_{}", actualCommand.columnName));
198 },
199 },
200 command);
201 }
202
203 return { sqlQueryString.str() };
204 }
205};
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.