4#include "../SqlQueryFormatter.hpp"
5#include "SQLiteFormatter.hpp"
7#include <reflection-cpp/reflection.hpp>
14class PostgreSqlFormatter final:
public SQLiteQueryFormatter
17 using SQLiteQueryFormatter::CreateTable;
19 [[nodiscard]]
bool RequiresTableRebuildForSchemaChange() const noexcept
override
24 [[nodiscard]]
StringList DropTable(std::string_view schemaName,
25 std::string_view
const& tableName,
26 bool ifExists =
false,
27 bool cascade =
false)
const override
29 std::string sql = ifExists ? std::format(
"DROP TABLE IF EXISTS {}",
FormatTableName(schemaName, tableName))
37 [[nodiscard]] std::string BinaryLiteral(std::span<uint8_t const> data)
const override
40 result.reserve((data.size() * 2) + 4);
42 for (uint8_t
byte: data)
43 result += std::format(
"{:02X}", byte);
48 [[nodiscard]] std::string QueryLastInsertId(std::string_view )
const override
53 return std::format(
"SELECT lastval();");
56 [[nodiscard]] std::string_view DateFunction() const noexcept
override
58 return "CURRENT_DATE";
66 [[nodiscard]] std::string SetDefaultSchemaStatement(std::string_view schema)
const override
70 return std::format(R
"(SET search_path TO "{}", public)", schema);
73 [[nodiscard]] std::string BuildColumnDefinition(SqlColumnDeclaration const& column)
const override
75 std::stringstream sqlQueryString;
77 sqlQueryString <<
'"' << column.name <<
"\" ";
82 bool const isAutoIncrementViaDefault = column.defaultValue.contains(
"nextval(");
83 bool const isAutoIncrement = column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT || isAutoIncrementViaDefault;
86 sqlQueryString << SerialColumnType(column.type);
88 sqlQueryString << ColumnType(column.type);
91 sqlQueryString <<
" NOT NULL";
96 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
97 sqlQueryString <<
" PRIMARY KEY";
98 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
99 sqlQueryString <<
" UNIQUE";
102 if (!column.defaultValue.empty() && !isAutoIncrement)
103 sqlQueryString <<
" DEFAULT " << column.defaultValue;
105 return sqlQueryString.str();
126 [[nodiscard]]
static std::string_view SerialColumnType(SqlColumnTypeDefinition
const& type)
128 using namespace SqlColumnTypeDefinitions;
130 return std::visit(detail::overloaded {
131 [](Bigint
const&) -> std::string_view {
return "BIGSERIAL"; },
132 [](Smallint
const&) -> std::string_view {
return "SMALLSERIAL"; },
135 [](Tinyint
const&) -> std::string_view {
return "SMALLSERIAL"; },
136 [](
auto const&) -> std::string_view {
return "SERIAL"; },
141 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition
const& type)
const override
143 using namespace SqlColumnTypeDefinitions;
146 return std::visit(detail::overloaded {
147 [](Bigint
const&) -> std::string {
return "BIGINT"; },
148 [](Binary
const& type) -> std::string {
return std::format(
"BYTEA", type.size); },
149 [](Bool
const&) -> std::string {
return "BOOLEAN"; },
150 [](Char
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
151 [](Date
const&) -> std::string {
return "DATE"; },
152 [](DateTime
const&) -> std::string {
return "TIMESTAMP"; },
153 [](Decimal
const& type) -> std::string {
154 return std::format(
"DECIMAL({}, {})", type.precision, type.scale);
156 [](Guid
const&) -> std::string {
return "UUID"; },
157 [](Integer
const&) -> std::string {
return "INTEGER"; },
158 [](NChar
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
159 [](NVarchar
const& type) -> std::string {
162 return std::format(
"VARCHAR({})", type.size);
164 [](Real
const& type) -> std::string {
168 return type.precision > 24 ?
"DOUBLE PRECISION" :
"REAL";
170 [](Smallint
const&) -> std::string {
return "SMALLINT"; },
171 [](Text
const&) -> std::string {
return "TEXT"; },
172 [](Time
const&) -> std::string {
return "TIME"; },
173 [](Timestamp
const&) -> std::string {
return "TIMESTAMP"; },
175 [](Tinyint
const&) -> std::string {
return "SMALLINT"; },
176 [](VarBinary
const& ) -> std::string {
return std::format(
"BYTEA"); },
177 [](Varchar
const& type) -> std::string {
180 return std::format(
"VARCHAR({})", type.size);
187 [[nodiscard]]
StringList AlterTable(std::string_view schemaName,
188 std::string_view tableName,
189 std::vector<SqlAlterTableCommand>
const& commands)
const override
191 std::stringstream sqlQueryString;
193 int currentCommand = 0;
196 if (currentCommand > 0)
197 sqlQueryString <<
'\n';
200 using namespace SqlAlterTableCommands;
201 sqlQueryString << std::visit(
203 [schemaName, tableName](RenameTable
const& actualCommand) -> std::string {
204 return std::format(R
"(ALTER TABLE {} RENAME TO "{}";)",
206 actualCommand.newTableName);
208 [schemaName, tableName, this](AddColumn
const& actualCommand) -> std::string {
209 return std::format(R
"(ALTER TABLE {} ADD COLUMN "{}" {} {};)",
211 actualCommand.columnName,
212 ColumnType(actualCommand.columnType),
213 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
215 [schemaName, tableName,
this](AlterColumn
const& actualCommand) -> std::string {
217 R
"(ALTER TABLE {0} ALTER COLUMN "{1}" TYPE {2}, ALTER COLUMN "{1}" {3} NOT NULL;)",
219 actualCommand.columnName,
220 ColumnType(actualCommand.columnType),
221 actualCommand.nullable == SqlNullable::NotNull ? "SET" :
"DROP");
223 [schemaName, tableName](RenameColumn
const& actualCommand) -> std::string {
224 return std::format(R
"(ALTER TABLE {} RENAME COLUMN "{}" TO "{}";)",
226 actualCommand.oldColumnName,
227 actualCommand.newColumnName);
229 [schemaName, tableName](DropColumn const& actualCommand) -> std::string {
230 return std::format(R
"(ALTER TABLE {} DROP COLUMN "{}";)",
232 actualCommand.columnName);
234 [schemaName, tableName](AddIndex const& actualCommand) -> std::string {
235 using namespace std::string_view_literals;
236 auto const uniqueStr = actualCommand.unique ?
"UNIQUE "sv :
""sv;
237 if (schemaName.empty())
238 return std::format(R
"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}" ("{1}");)",
240 actualCommand.columnName,
243 return std::format(R
"(CREATE {3}INDEX "{0}_{1}_{2}_index" ON "{0}"."{1}" ("{2}");)",
246 actualCommand.columnName,
249 [schemaName, tableName](DropIndex const& actualCommand) -> std::string {
250 if (schemaName.empty())
251 return std::format(R
"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
254 R
"(DROP INDEX "{0}_{1}_{2}_index";)", schemaName, tableName, actualCommand.columnName);
256 [schemaName, tableName](AddForeignKey const& actualCommand) -> std::string {
261 "DO $$ BEGIN ALTER TABLE {} ADD {}; EXCEPTION WHEN duplicate_object THEN NULL; END $$;",
263 BuildForeignKeyConstraint(tableName, actualCommand.columnName, actualCommand.referencedColumn));
265 [schemaName, tableName](DropForeignKey
const& actualCommand) -> std::string {
266 return std::format(R
"(ALTER TABLE {} DROP CONSTRAINT "{}";)",
269 tableName, std::array { std::string_view { actualCommand.columnName } }));
271 [schemaName, tableName](AddCompositeForeignKey const& actualCommand) -> std::string {
272 std::stringstream ss;
273 ss <<
"ALTER TABLE " <<
FormatTableName(schemaName, tableName) <<
" ADD CONSTRAINT \""
277 for (
auto const& col: actualCommand.columns)
281 ss <<
'"' << col <<
'"';
283 ss <<
") REFERENCES " <<
FormatTableName(schemaName, actualCommand.referencedTableName) <<
" (";
286 for (
auto const& col: actualCommand.referencedColumns)
290 ss <<
'"' << col <<
'"';
295 [schemaName, tableName,
this](AddColumnIfNotExists
const& actualCommand) -> std::string {
297 return std::format(R
"(ALTER TABLE {} ADD COLUMN IF NOT EXISTS "{}" {} {};)",
299 actualCommand.columnName,
300 ColumnType(actualCommand.columnType),
301 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
303 [schemaName, tableName](DropColumnIfExists
const& actualCommand) -> std::string {
305 return std::format(R
"(ALTER TABLE {} DROP COLUMN IF EXISTS "{}";)",
307 actualCommand.columnName);
309 [schemaName, tableName](DropIndexIfExists const& actualCommand) -> std::string {
311 if (schemaName.empty())
313 R
"(DROP INDEX IF EXISTS "{0}_{1}_index";)", tableName, actualCommand.columnName);
315 return std::format(R
"(DROP INDEX IF EXISTS "{0}_{1}_{2}_index";)",
318 actualCommand.columnName);
324 return { sqlQueryString.str() };
327 [[nodiscard]] std::string QueryServerVersion()
const override
329 return "SELECT version()";
335 [[nodiscard]] SqlAdvisoryLockHandler
const& AdvisoryLockOps()
const override
337 return PostgreSqlAdvisoryLockOps();
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.