diff options
Diffstat (limited to 'src/libs/sqlite/createtablesqlstatementbuilder.h')
-rw-r--r-- | src/libs/sqlite/createtablesqlstatementbuilder.h | 323 |
1 files changed, 303 insertions, 20 deletions
diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.h b/src/libs/sqlite/createtablesqlstatementbuilder.h index 3e3743e9da..fb53e68a42 100644 --- a/src/libs/sqlite/createtablesqlstatementbuilder.h +++ b/src/libs/sqlite/createtablesqlstatementbuilder.h @@ -29,43 +29,326 @@ #include "sqlstatementbuilder.h" #include "tableconstraints.h" +#include <type_traits> + namespace Sqlite { +template<typename ColumnType> class SQLITE_EXPORT CreateTableSqlStatementBuilder { public: - CreateTableSqlStatementBuilder(); + CreateTableSqlStatementBuilder() + : m_sqlStatementBuilder(templateText()) + {} + + void setTableName(Utils::SmallString &&tableName) + { + m_sqlStatementBuilder.clear(); - void setTableName(Utils::SmallString &&tableName); + this->m_tableName = std::move(tableName); + } void addColumn(Utils::SmallStringView columnName, ColumnType columnType, - Constraints &&constraints = {}); - void addConstraint(TableConstraint &&constraint); - void setConstraints(TableConstraints constraints); - void setColumns(SqliteColumns columns); - void setUseWithoutRowId(bool useWithoutRowId); - void setUseIfNotExists(bool useIfNotExists); - void setUseTemporaryTable(bool useTemporaryTable); + Constraints &&constraints = {}) + { + m_sqlStatementBuilder.clear(); + + m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints)); + } + void addConstraint(TableConstraint &&constraint) + { + m_tableConstraints.push_back(std::move(constraint)); + } + void setConstraints(TableConstraints constraints) + { + m_tableConstraints = std::move(constraints); + } + void setColumns(BasicColumns<ColumnType> columns) + { + m_sqlStatementBuilder.clear(); + + m_columns = std::move(columns); + } + + void setUseWithoutRowId(bool useWithoutRowId) { m_useWithoutRowId = useWithoutRowId; } + + void setUseIfNotExists(bool useIfNotExists) { m_useIfNotExits = useIfNotExists; } + + void setUseTemporaryTable(bool useTemporaryTable) { m_useTemporaryTable = useTemporaryTable; } + + void clear() + { + m_sqlStatementBuilder.clear(); + m_columns.clear(); + m_tableName.clear(); + m_useWithoutRowId = false; + } + + void clearColumns() + { + m_sqlStatementBuilder.clear(); + m_columns.clear(); + } + + Utils::SmallStringView sqlStatement() const + { + if (!m_sqlStatementBuilder.isBuild()) + bindAll(); + + return m_sqlStatementBuilder.sqlStatement(); + } + + bool isValid() const { return m_tableName.hasContent() && !m_columns.empty(); } + +private: + static Utils::SmallStringView templateText() + { + if constexpr (std::is_same_v<ColumnType, ::Sqlite::ColumnType>) { + return "CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId"; + } + + return "CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId STRICT"; + } + + static Utils::SmallString columnTypeToString(ColumnType columnType) + { + if constexpr (std::is_same_v<ColumnType, ::Sqlite::ColumnType>) { + switch (columnType) { + case ColumnType::Numeric: + return " NUMERIC"; + case ColumnType::Integer: + return " INTEGER"; + case ColumnType::Real: + return " REAL"; + case ColumnType::Text: + return " TEXT"; + case ColumnType::Blob: + return " BLOB"; + case ColumnType::None: + return {}; + } + } else { + switch (columnType) { + case ColumnType::Any: + return " ANY"; + case ColumnType::Int: + return " INT"; + case ColumnType::Integer: + return " INTEGER"; + case ColumnType::Real: + return " REAL"; + case ColumnType::Text: + return " TEXT"; + case ColumnType::Blob: + return " BLOB"; + } + } + + return ""; + } + + static Utils::SmallStringView actionToText(ForeignKeyAction action) + { + switch (action) { + case ForeignKeyAction::NoAction: + return "NO ACTION"; + case ForeignKeyAction::Restrict: + return "RESTRICT"; + case ForeignKeyAction::SetNull: + return "SET NULL"; + case ForeignKeyAction::SetDefault: + return "SET DEFAULT"; + case ForeignKeyAction::Cascade: + return "CASCADE"; + } + + return ""; + } + + class ContraintsVisiter + { + public: + ContraintsVisiter(Utils::SmallString &columnDefinitionString) + : columnDefinitionString(columnDefinitionString) + {} + + void operator()(const Unique &) { columnDefinitionString.append(" UNIQUE"); } + + void operator()(const PrimaryKey &primaryKey) + { + columnDefinitionString.append(" PRIMARY KEY"); + if (primaryKey.autoincrement == AutoIncrement::Yes) + columnDefinitionString.append(" AUTOINCREMENT"); + } + + void operator()(const ForeignKey &foreignKey) + { + columnDefinitionString.append(" REFERENCES "); + columnDefinitionString.append(foreignKey.table); + + if (foreignKey.column.hasContent()) { + columnDefinitionString.append("("); + columnDefinitionString.append(foreignKey.column); + columnDefinitionString.append(")"); + } + + if (foreignKey.updateAction != ForeignKeyAction::NoAction) { + columnDefinitionString.append(" ON UPDATE "); + columnDefinitionString.append(actionToText(foreignKey.updateAction)); + } + + if (foreignKey.deleteAction != ForeignKeyAction::NoAction) { + columnDefinitionString.append(" ON DELETE "); + columnDefinitionString.append(actionToText(foreignKey.deleteAction)); + } + + if (foreignKey.enforcement == Enforment::Deferred) + columnDefinitionString.append(" DEFERRABLE INITIALLY DEFERRED"); + } + + void operator()(const NotNull &) { columnDefinitionString.append(" NOT NULL"); } + + void operator()(const Check &check) + { + columnDefinitionString.append(" CHECK ("); + columnDefinitionString.append(check.expression); + columnDefinitionString.append(")"); + } + + void operator()(const DefaultValue &defaultValue) + { + columnDefinitionString.append(" DEFAULT "); + switch (defaultValue.value.type()) { + case Sqlite::ValueType::Integer: + columnDefinitionString.append( + Utils::SmallString::number(defaultValue.value.toInteger())); + break; + case Sqlite::ValueType::Float: + columnDefinitionString.append(Utils::SmallString::number(defaultValue.value.toFloat())); + break; + case Sqlite::ValueType::String: + columnDefinitionString.append("'"); + columnDefinitionString.append(defaultValue.value.toStringView()); + columnDefinitionString.append("'"); + break; + default: + break; + } + } + + void operator()(const DefaultExpression &defaultexpression) + { + columnDefinitionString.append(" DEFAULT ("); + columnDefinitionString.append(defaultexpression.expression); + columnDefinitionString.append(")"); + } + + void operator()(const Collate &collate) + { + columnDefinitionString.append(" COLLATE "); + columnDefinitionString.append(collate.collation); + } + + void operator()(const GeneratedAlways &generatedAlways) + { + columnDefinitionString.append(" GENERATED ALWAYS AS ("); + columnDefinitionString.append(generatedAlways.expression); + columnDefinitionString.append(")"); + + if (generatedAlways.storage == Sqlite::GeneratedAlwaysStorage::Virtual) + columnDefinitionString.append(" VIRTUAL"); + else + columnDefinitionString.append(" STORED"); + } + + Utils::SmallString &columnDefinitionString; + }; + + class TableContraintsVisiter + { + public: + TableContraintsVisiter(Utils::SmallString &columnDefinitionString) + : columnDefinitionString(columnDefinitionString) + {} + + void operator()(const TablePrimaryKey &primaryKey) + { + columnDefinitionString.append("PRIMARY KEY("); + columnDefinitionString.append(primaryKey.columns.join(", ")); + columnDefinitionString.append(")"); + } + + Utils::SmallString &columnDefinitionString; + }; + + void bindColumnDefinitionsAndTableConstraints() const + { + Utils::SmallStringVector columnDefinitionStrings; + columnDefinitionStrings.reserve(m_columns.size()); + + for (const BasicColumn<ColumnType> &column : m_columns) { + auto columnDefinitionString = Utils::SmallString::join( + {column.name, columnTypeToString(column.type)}); + + ContraintsVisiter visiter{columnDefinitionString}; + + for (const Constraint &constraint : column.constraints) + Utils::visit(visiter, constraint); + + columnDefinitionStrings.push_back(std::move(columnDefinitionString)); + } + + for (const TableConstraint &constraint : m_tableConstraints) { + Utils::SmallString columnDefinitionString; + + TableContraintsVisiter visiter{columnDefinitionString}; + Utils::visit(visiter, constraint); + + columnDefinitionStrings.push_back(std::move(columnDefinitionString)); + } + + m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings); + } + + void bindAll() const + { + m_sqlStatementBuilder.bind("$table", m_tableName.clone()); - void clear(); - void clearColumns(); + bindTemporary(); + bindIfNotExists(); + bindColumnDefinitionsAndTableConstraints(); + bindWithoutRowId(); + } - Utils::SmallStringView sqlStatement() const; + void bindWithoutRowId() const + { + if (m_useWithoutRowId) + m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID"); + else + m_sqlStatementBuilder.bindEmptyText("$withoutRowId"); + } - bool isValid() const; + void bindIfNotExists() const + { + if (m_useIfNotExits) + m_sqlStatementBuilder.bind("$ifNotExits", "IF NOT EXISTS "); + else + m_sqlStatementBuilder.bindEmptyText("$ifNotExits"); + } -protected: - void bindColumnDefinitionsAndTableConstraints() const; - void bindAll() const; - void bindWithoutRowId() const; - void bindIfNotExists() const; - void bindTemporary() const; + void bindTemporary() const + { + if (m_useTemporaryTable) + m_sqlStatementBuilder.bind("$temporary", "TEMPORARY "); + else + m_sqlStatementBuilder.bindEmptyText("$temporary"); + } private: mutable SqlStatementBuilder m_sqlStatementBuilder; Utils::SmallString m_tableName; - SqliteColumns m_columns; + BasicColumns<ColumnType> m_columns; TableConstraints m_tableConstraints; bool m_useWithoutRowId = false; bool m_useIfNotExits = false; |