diff options
author | Marco Bubke <marco.bubke@qt.io> | 2020-05-13 20:29:49 +0200 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@qt.io> | 2020-05-14 09:15:00 +0000 |
commit | c4bbc74e37ab74e000ba6979474d281f203feba2 (patch) | |
tree | 878288e8c0fffc6fd4218bab4f20e800a84f4ad3 | |
parent | a86fd58e40ea8b1a1a80f69d878b2073ad9ebef0 (diff) | |
download | qt-creator-c4bbc74e37ab74e000ba6979474d281f203feba2.tar.gz |
Sqlite: Improve constraint support
Now you can add more than one constraint. And we added some
new constraints too.
Change-Id: I849d2d2ef6e44c897a65ff2bdfe8d172a345c991
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
-rw-r--r-- | src/libs/clangsupport/refactoringdatabaseinitializer.h | 16 | ||||
-rw-r--r-- | src/libs/sqlite/createtablesqlstatementbuilder.cpp | 116 | ||||
-rw-r--r-- | src/libs/sqlite/createtablesqlstatementbuilder.h | 4 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitecolumn.h | 139 | ||||
-rw-r--r-- | src/libs/sqlite/sqliteglobal.h | 2 | ||||
-rw-r--r-- | src/libs/sqlite/sqlitetable.h | 49 | ||||
-rw-r--r-- | src/tools/clangrefactoringbackend/source/symbolstorage.h | 2 | ||||
-rw-r--r-- | tests/unit/unittest/createtablesqlstatementbuilder-test.cpp | 206 | ||||
-rw-r--r-- | tests/unit/unittest/google-using-declarations.h | 18 | ||||
-rw-r--r-- | tests/unit/unittest/sqlitecolumn-test.cpp | 74 | ||||
-rw-r--r-- | tests/unit/unittest/sqlitedatabasebackend-test.cpp | 2 | ||||
-rw-r--r-- | tests/unit/unittest/sqlitetable-test.cpp | 111 |
12 files changed, 497 insertions, 242 deletions
diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index 426485a1fd..b26bd4ef04 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -66,7 +66,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("symbols"); - table.addColumn("symbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("symbolId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text); const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text); const Sqlite::Column &symbolKindColumn = table.addColumn("symbolKind", Sqlite::ColumnType::Integer); @@ -100,7 +100,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("sources"); - table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); const Sqlite::Column &directoryIdColumn = table.addColumn("directoryId", Sqlite::ColumnType::Integer); const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text); table.addUniqueIndex({directoryIdColumn, sourceNameColumn}); @@ -113,7 +113,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("directories"); - table.addColumn("directoryId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("directoryId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); const Sqlite::Column &directoryPathColumn = table.addColumn("directoryPath", Sqlite::ColumnType::Text); table.addUniqueIndex({directoryPathColumn}); @@ -125,7 +125,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("projectParts"); - table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("projectPartId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text); table.addColumn("toolChainArguments", Sqlite::ColumnType::Text); table.addColumn("compilerMacros", Sqlite::ColumnType::Text); @@ -160,7 +160,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("usedMacros"); - table.addColumn("usedMacroId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("usedMacroId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); const Sqlite::Column ¯oNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text); table.addIndex({sourceIdColumn, macroNameColumn}); @@ -174,9 +174,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("fileStatuses"); - table.addColumn("sourceId", - Sqlite::ColumnType::Integer, - Sqlite::Contraint::PrimaryKey); + table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); table.addColumn("size", Sqlite::ColumnType::Integer); table.addColumn("lastModified", Sqlite::ColumnType::Integer); table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer); @@ -201,7 +199,7 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("precompiledHeaders"); - table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("projectPartId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); table.addColumn("projectPchPath", Sqlite::ColumnType::Text); table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer); table.addColumn("systemPchPath", Sqlite::ColumnType::Text); diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.cpp b/src/libs/sqlite/createtablesqlstatementbuilder.cpp index c02169d2fd..aee797f8d4 100644 --- a/src/libs/sqlite/createtablesqlstatementbuilder.cpp +++ b/src/libs/sqlite/createtablesqlstatementbuilder.cpp @@ -41,16 +41,11 @@ void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName, ColumnType columnType, - Contraint constraint, - ForeignKey &&foreignKey) + Constraints &&constraints) { m_sqlStatementBuilder.clear(); - m_columns.emplace_back(Utils::SmallStringView{}, - columnName, - columnType, - constraint, - std::move(foreignKey)); + m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints)); } void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns) @@ -121,30 +116,90 @@ Utils::SmallStringView actionToText(ForeignKeyAction action) return ""; } -void appendForeignKey(Utils::SmallString &columnDefinitionString, const ForeignKey &foreignKey) +class ContraintsVisiter { - columnDefinitionString.append(" REFERENCES "); - columnDefinitionString.append(foreignKey.table); +public: + ContraintsVisiter(Utils::SmallString &columnDefinitionString) + : columnDefinitionString(columnDefinitionString) + {} - if (foreignKey.column.hasContent()) { - columnDefinitionString.append("("); - columnDefinitionString.append(foreignKey.column); + void operator()(const Unique &) { columnDefinitionString.append(" UNIQUE"); } + + void operator()(const PrimaryKey &) { columnDefinitionString.append(" PRIMARY KEY"); } + + 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 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; + } + } + + void operator()(const DefaultExpression &defaultexpression) + { + columnDefinitionString.append(" DEFAULT ("); + columnDefinitionString.append(defaultexpression.expression); columnDefinitionString.append(")"); } - if (foreignKey.updateAction != ForeignKeyAction::NoAction) { - columnDefinitionString.append(" ON UPDATE "); - columnDefinitionString.append(actionToText(foreignKey.updateAction)); + void operator()(const Collate &collate) + { + columnDefinitionString.append(" COLLATE "); + columnDefinitionString.append(collate.collation); } - if (foreignKey.deleteAction != ForeignKeyAction::NoAction) { - columnDefinitionString.append(" ON DELETE "); - columnDefinitionString.append(actionToText(foreignKey.deleteAction)); + 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"); } - if (foreignKey.enforcement == Enforment::Deferred) - columnDefinitionString.append(" DEFERRABLE INITIALLY DEFERRED"); -} + Utils::SmallString &columnDefinitionString; +}; } // namespace void CreateTableSqlStatementBuilder::bindColumnDefinitions() const { @@ -154,19 +209,10 @@ void CreateTableSqlStatementBuilder::bindColumnDefinitions() const for (const Column &column : m_columns) { Utils::SmallString columnDefinitionString = {column.name, " ", column.typeString()}; - switch (column.constraint) { - case Contraint::PrimaryKey: - columnDefinitionString.append(" PRIMARY KEY"); - break; - case Contraint::Unique: - columnDefinitionString.append(" UNIQUE"); - break; - case Contraint::ForeignKey: - appendForeignKey(columnDefinitionString, column.foreignKey); - break; - case Contraint::NoConstraint: - break; - } + ContraintsVisiter visiter{columnDefinitionString}; + + for (const Constraint &constraint : column.constraints) + mpark::visit(visiter, constraint); columnDefinitionStrings.push_back(columnDefinitionString); } diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.h b/src/libs/sqlite/createtablesqlstatementbuilder.h index a62f1f4adb..786753fdfa 100644 --- a/src/libs/sqlite/createtablesqlstatementbuilder.h +++ b/src/libs/sqlite/createtablesqlstatementbuilder.h @@ -36,10 +36,10 @@ public: CreateTableSqlStatementBuilder(); void setTableName(Utils::SmallString &&tableName); + void addColumn(Utils::SmallStringView columnName, ColumnType columnType, - Contraint constraint = Contraint::NoConstraint, - ForeignKey &&foreignKey = {}); + Constraints &&constraints = {}); void setColumns(const SqliteColumns &columns); void setUseWithoutRowId(bool useWithoutRowId); void setUseIfNotExists(bool useIfNotExists); diff --git a/src/libs/sqlite/sqlitecolumn.h b/src/libs/sqlite/sqlitecolumn.h index fd31998f44..aae8230421 100644 --- a/src/libs/sqlite/sqlitecolumn.h +++ b/src/libs/sqlite/sqlitecolumn.h @@ -27,56 +27,135 @@ #include "sqliteforeignkey.h" +#include <sqlitevalue.h> #include <utils/smallstring.h> +#include <utils/variant.h> #include <functional> namespace Sqlite { -class Column +class Unique +{ + friend bool operator==(Unique, Unique) { return true; } +}; + +class PrimaryKey +{ + friend bool operator==(PrimaryKey, PrimaryKey) { return true; } +}; + +class NotNull +{ + friend bool operator==(NotNull, NotNull) { return true; } +}; + +class DefaultValue { public: - Column() = default; + DefaultValue(long long value) + : value(value) + {} - Column(Utils::SmallStringView tableName, - Utils::SmallStringView name, - ColumnType type = ColumnType::Numeric, - Contraint constraint = Contraint::NoConstraint, - ForeignKey &&foreignKey = {}) - : foreignKey(std::move(foreignKey)) - , name(name) - , tableName(tableName) - , type(type) - , constraint(constraint) + DefaultValue(double value) + : value(value) {} + DefaultValue(Utils::SmallStringView value) + : value(value) + {} + + friend bool operator==(const DefaultValue &first, const DefaultValue &second) + { + return first.value == second.value; + } + +public: + Sqlite::Value value; +}; + +class DefaultExpression +{ +public: + DefaultExpression(Utils::SmallStringView expression) + : expression(expression) + {} + + friend bool operator==(const DefaultExpression &first, const DefaultExpression &second) + { + return first.expression == second.expression; + } + +public: + Utils::SmallString expression; +}; + +class Collate +{ +public: + Collate(Utils::SmallStringView collation) + : collation(collation) + {} + + friend bool operator==(const Collate &first, const Collate &second) + { + return first.collation == second.collation; + } + +public: + Utils::SmallString collation; +}; + +enum class GeneratedAlwaysStorage { Stored, Virtual }; + +class GeneratedAlways +{ +public: + GeneratedAlways(Utils::SmallStringView expression, GeneratedAlwaysStorage storage) + : expression(expression) + , storage(storage) + {} + + friend bool operator==(const GeneratedAlways &first, const GeneratedAlways &second) + { + return first.expression == second.expression; + } + +public: + Utils::SmallString expression; + GeneratedAlwaysStorage storage = {}; +}; + +using Constraint = Utils::variant<Unique, + PrimaryKey, + ForeignKey, + NotNull, + DefaultValue, + DefaultExpression, + Collate, + GeneratedAlways>; +using Constraints = std::vector<Constraint>; + +class Column +{ +public: + Column() = default; + Column(Utils::SmallStringView tableName, Utils::SmallStringView name, ColumnType type, - Contraint constraint, - Utils::SmallStringView foreignKeyTable, - Utils::SmallStringView foreignKeycolumn, - ForeignKeyAction foreignKeyUpdateAction, - ForeignKeyAction foreignKeyDeleteAction, - Enforment foreignKeyEnforcement) - : foreignKey(foreignKeyTable, - foreignKeycolumn, - foreignKeyUpdateAction, - foreignKeyDeleteAction, - foreignKeyEnforcement) + Constraints &&constraints = {}) + : constraints(std::move(constraints)) , name(name) , tableName(tableName) , type(type) - , constraint(constraint) - {} void clear() { name.clear(); type = ColumnType::Numeric; - constraint = Contraint::NoConstraint; - foreignKey = {}; + constraints = {}; } Utils::SmallString typeString() const @@ -100,16 +179,14 @@ public: friend bool operator==(const Column &first, const Column &second) { return first.name == second.name && first.type == second.type - && first.constraint - == second.constraint /* && first.foreignKey == second.foreignKey*/; + && first.constraints == second.constraints && first.tableName == second.tableName; } public: - ForeignKey foreignKey; + Constraints constraints; Utils::SmallString name; Utils::SmallString tableName; ColumnType type = ColumnType::Numeric; - Contraint constraint = Contraint::NoConstraint; }; // namespace Sqlite using SqliteColumns = std::vector<Column>; diff --git a/src/libs/sqlite/sqliteglobal.h b/src/libs/sqlite/sqliteglobal.h index 625c45a9ee..ed2b15e8b4 100644 --- a/src/libs/sqlite/sqliteglobal.h +++ b/src/libs/sqlite/sqliteglobal.h @@ -48,7 +48,7 @@ enum class ColumnType : char None }; -enum class Contraint : char { NoConstraint, PrimaryKey, Unique, ForeignKey }; +enum class ConstraintType : char { NoConstraint, PrimaryKey, Unique, ForeignKey }; enum class ForeignKeyAction : char { NoAction, Restrict, SetNull, SetDefault, Cascade }; diff --git a/src/libs/sqlite/sqlitetable.h b/src/libs/sqlite/sqlitetable.h index 8c98959ef9..a7b524cd3b 100644 --- a/src/libs/sqlite/sqlitetable.h +++ b/src/libs/sqlite/sqlitetable.h @@ -73,9 +73,9 @@ public: Column &addColumn(Utils::SmallStringView name, ColumnType type = ColumnType::Numeric, - Contraint constraint = Contraint::NoConstraint) + Constraints &&constraints = {}) { - m_sqliteColumns.emplace_back(m_tableName, name, type, constraint); + m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints)); return m_sqliteColumns.back(); } @@ -85,17 +85,16 @@ public: ForeignKeyAction foreignKeyupdateAction = {}, ForeignKeyAction foreignKeyDeleteAction = {}, Enforment foreignKeyEnforcement = {}, + Constraints &&constraints = {}, ColumnType type = ColumnType::Integer) { - m_sqliteColumns.emplace_back(m_tableName, - name, - type, - Contraint::ForeignKey, - referencedTable.name(), - "", - foreignKeyupdateAction, - foreignKeyDeleteAction, - foreignKeyEnforcement); + constraints.emplace_back(ForeignKey{referencedTable.name(), + "", + foreignKeyupdateAction, + foreignKeyDeleteAction, + foreignKeyEnforcement}); + + m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints)); return m_sqliteColumns.back(); } @@ -104,20 +103,22 @@ public: const Column &referencedColumn, ForeignKeyAction foreignKeyupdateAction = {}, ForeignKeyAction foreignKeyDeleteAction = {}, - Enforment foreignKeyEnforcement = {}) + Enforment foreignKeyEnforcement = {}, + Constraints &&constraints = {}) { - if (referencedColumn.constraint != Contraint::Unique) + if (!constainsUniqueIndex(referencedColumn.constraints)) throw ForeignKeyColumnIsNotUnique("Foreign column key must be unique!"); + constraints.emplace_back(ForeignKey{referencedColumn.tableName, + referencedColumn.name, + foreignKeyupdateAction, + foreignKeyDeleteAction, + foreignKeyEnforcement}); + m_sqliteColumns.emplace_back(m_tableName, name, referencedColumn.type, - Contraint::ForeignKey, - referencedColumn.tableName, - referencedColumn.name, - foreignKeyupdateAction, - foreignKeyDeleteAction, - foreignKeyEnforcement); + std::move(constraints)); return m_sqliteColumns.back(); } @@ -181,6 +182,16 @@ public: && first.m_sqliteColumns == second.m_sqliteColumns; } + static bool constainsUniqueIndex(const Constraints &constraints) + { + return std::find_if(constraints.begin(), + constraints.end(), + [](const Constraint &constraint) { + return Utils::holds_alternative<Unique>(constraint); + }) + != constraints.end(); + } + private: Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns) { diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index f61dc0557d..89855b98cb 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -123,7 +123,7 @@ public: Sqlite::Table table; table.setName("newSymbols"); table.setUseTemporaryTable(true); - table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); const Sqlite::Column &symbolIdColumn = table.addColumn("symbolId", Sqlite::ColumnType::Integer); const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text); const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text); diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index 39e927797b..c8ff7b47b2 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -32,19 +32,38 @@ namespace { using Sqlite::Column; using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::Enforment; +using Sqlite::ForeignKey; using Sqlite::ForeignKeyAction; using Sqlite::JournalMode; using Sqlite::OpenMode; +using Sqlite::PrimaryKey; using Sqlite::SqliteColumns; using Sqlite::SqlStatementBuilderException; +using Sqlite::Unique; class CreateTableSqlStatementBuilder : public ::testing::Test { protected: - void bindValues(); - static SqliteColumns createColumns(); + void bindValues() + { + builder.clear(); + builder.setTableName("test"); + builder.addColumn("id", ColumnType::Integer, {PrimaryKey{}}); + builder.addColumn("name", ColumnType::Text); + builder.addColumn("number", ColumnType::Numeric); + } + + static SqliteColumns createColumns() + { + SqliteColumns columns; + columns.emplace_back("", "id", ColumnType::Integer, Sqlite::Constraints{PrimaryKey{}}); + columns.emplace_back("", "name", ColumnType::Text); + columns.emplace_back("", "number", ColumnType::Numeric); + + return columns; + } protected: Sqlite::CreateTableSqlStatementBuilder builder; @@ -158,7 +177,7 @@ TEST_F(CreateTableSqlStatementBuilder, UniqueContraint) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::Unique); + builder.addColumn("id", ColumnType::Integer, {Unique{}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER UNIQUE)"); @@ -168,7 +187,7 @@ TEST_F(CreateTableSqlStatementBuilder, IfNotExitsModifier) { builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::NoConstraint); + builder.addColumn("id", ColumnType::Integer, {}); builder.setUseIfNotExists(true); @@ -180,7 +199,7 @@ TEST_F(CreateTableSqlStatementBuilder, TemporaryTable) { builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::NoConstraint); + builder.addColumn("id", ColumnType::Integer, {}); builder.setUseTemporaryTable(true); @@ -188,31 +207,12 @@ TEST_F(CreateTableSqlStatementBuilder, TemporaryTable) "CREATE TEMPORARY TABLE test(id INTEGER)"); } -void CreateTableSqlStatementBuilder::bindValues() -{ - builder.clear(); - builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::PrimaryKey); - builder.addColumn("name", ColumnType::Text); - builder.addColumn("number",ColumnType:: Numeric); -} - -SqliteColumns CreateTableSqlStatementBuilder::createColumns() -{ - SqliteColumns columns; - columns.emplace_back("", "id", ColumnType::Integer, Contraint::PrimaryKey); - columns.emplace_back("", "name", ColumnType::Text); - columns.emplace_back("", "number", ColumnType::Numeric); - - return columns; -} - TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn) { builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", ""}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", ""}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable)"); } @@ -222,7 +222,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithColumn) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))"); @@ -233,7 +233,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateNoAction) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))"); @@ -246,8 +246,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateRestrict) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::Restrict}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Restrict}}); ASSERT_THAT( builder.sqlStatement(), @@ -261,8 +260,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetNull) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::SetNull}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetNull}}); ASSERT_THAT( builder.sqlStatement(), @@ -276,8 +274,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetDefault) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::SetDefault}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetDefault}}); ASSERT_THAT( builder.sqlStatement(), @@ -291,8 +288,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::Cascade}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Cascade}}); ASSERT_THAT( builder.sqlStatement(), @@ -304,7 +300,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteNoAction) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))"); @@ -317,8 +313,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteRestrict) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict}}); ASSERT_THAT( builder.sqlStatement(), @@ -332,8 +327,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetNull) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull}}); ASSERT_THAT( builder.sqlStatement(), @@ -347,8 +341,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetDefault) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault}}); ASSERT_THAT( builder.sqlStatement(), @@ -362,8 +355,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteCascade) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade}}); ASSERT_THAT( builder.sqlStatement(), @@ -377,11 +369,10 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", - "otherColumn", - ForeignKeyAction::SetDefault, - ForeignKeyAction::Cascade}); + {ForeignKey{"otherTable", + "otherColumn", + ForeignKeyAction::SetDefault, + ForeignKeyAction::Cascade}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " @@ -395,15 +386,118 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeferred) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", - "otherColumn", - ForeignKeyAction::SetDefault, - ForeignKeyAction::Cascade, - Enforment::Deferred}); + {ForeignKey{"otherTable", + "otherColumn", + ForeignKeyAction::SetDefault, + ForeignKeyAction::Cascade, + Enforment::Deferred}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " "DEFAULT ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"); } + +TEST_F(CreateTableSqlStatementBuilder, NotNullConstraint) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Integer, {Sqlite::NotNull{}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER NOT NULL)"); +} + +TEST_F(CreateTableSqlStatementBuilder, NotNullAndUniqueConstraint) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Integer, {Sqlite::Unique{}, Sqlite::NotNull{}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER UNIQUE NOT NULL)"); +} + +TEST_F(CreateTableSqlStatementBuilder, DefaultValueInt) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Integer, {Sqlite::DefaultValue{1LL}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER DEFAULT 1)"); +} + +TEST_F(CreateTableSqlStatementBuilder, DefaultValueFloat) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Real, {Sqlite::DefaultValue{1.1}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id REAL DEFAULT 1.100000)"); +} + +TEST_F(CreateTableSqlStatementBuilder, DefaultValueString) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Text, {Sqlite::DefaultValue{"foo"}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT DEFAULT \"foo\")"); +} + +TEST_F(CreateTableSqlStatementBuilder, DefaultExpression) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", + ColumnType::Integer, + {Sqlite::DefaultExpression{"SELECT name FROM foo WHERE id=?"}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER DEFAULT (SELECT name FROM foo WHERE id=?))"); +} + +TEST_F(CreateTableSqlStatementBuilder, Collation) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Text, {Sqlite::Collate{"unicode"}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT COLLATE unicode)"); +} + +TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysStored) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", + ColumnType::Text, + {Sqlite::GeneratedAlways{"SELECT name FROM foo WHERE id=?", + Sqlite::GeneratedAlwaysStorage::Stored}}); + + ASSERT_THAT( + builder.sqlStatement(), + "CREATE TABLE test(id TEXT GENERATED ALWAYS AS (SELECT name FROM foo WHERE id=?) STORED)"); +} + +TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysVirtual) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", + ColumnType::Text, + {Sqlite::GeneratedAlways{"SELECT name FROM foo WHERE id=?", + Sqlite::GeneratedAlwaysStorage::Virtual}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id TEXT GENERATED ALWAYS AS (SELECT name FROM foo WHERE id=?) " + "VIRTUAL)"); +} + } // namespace diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index e8bbd52800..a1975ae7a8 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -37,21 +37,27 @@ using testing::AnyOf; using testing::Assign; using testing::ByMove; using testing::ByRef; -using testing::Contains; using testing::ContainerEq; +using testing::Contains; using testing::ElementsAre; +using testing::Eq; using testing::Field; +using testing::Ge; +using testing::Gt; using testing::HasSubstr; using testing::InSequence; using testing::Invoke; using testing::IsEmpty; using testing::IsNull; +using testing::Le; +using testing::Lt; using testing::Matcher; using testing::Mock; using testing::MockFunction; +using testing::Ne; using testing::NiceMock; -using testing::NotNull; using testing::Not; +using testing::NotNull; using testing::Pair; using testing::PrintToString; using testing::Property; @@ -64,10 +70,4 @@ using testing::StrEq; using testing::Throw; using testing::TypedEq; using testing::UnorderedElementsAre; - -using testing::Eq; -using testing::Ge; -using testing::Gt; -using testing::Le; -using testing::Lt; -using testing::Ne; +using testing::VariantWith; diff --git a/tests/unit/unittest/sqlitecolumn-test.cpp b/tests/unit/unittest/sqlitecolumn-test.cpp index 0d6b1401ad..9753457c94 100644 --- a/tests/unit/unittest/sqlitecolumn-test.cpp +++ b/tests/unit/unittest/sqlitecolumn-test.cpp @@ -30,7 +30,7 @@ namespace { using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::JournalMode; using Sqlite::OpenMode; using Column = Sqlite::Column; @@ -51,13 +51,7 @@ TEST_F(SqliteColumn, DefaultConstruct) AllOf(Field(&Column::name, IsEmpty()), Field(&Column::tableName, IsEmpty()), Field(&Column::type, ColumnType::Numeric), - Field(&Column::constraint, Contraint::NoConstraint), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, IsEmpty()), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::enforcement, Enforment::Immediate))))); + Field(&Column::constraints, IsEmpty()))); } TEST_F(SqliteColumn, Clear) @@ -65,11 +59,7 @@ TEST_F(SqliteColumn, Clear) column.name = "foo"; column.name = "foo"; column.type = ColumnType::Text; - column.constraint = Contraint::ForeignKey; - column.foreignKey.table = "bar"; - column.foreignKey.column = "hmm"; - column.foreignKey.updateAction = ForeignKeyAction::Cascade; - column.foreignKey.deleteAction = ForeignKeyAction::SetNull; + column.constraints = {Sqlite::PrimaryKey{}}; column.clear(); @@ -77,13 +67,7 @@ TEST_F(SqliteColumn, Clear) AllOf(Field(&Column::name, IsEmpty()), Field(&Column::tableName, IsEmpty()), Field(&Column::type, ColumnType::Numeric), - Field(&Column::constraint, Contraint::NoConstraint), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, IsEmpty()), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::enforcement, Enforment::Immediate))))); + Field(&Column::constraints, IsEmpty()))); } TEST_F(SqliteColumn, Constructor) @@ -91,24 +75,23 @@ TEST_F(SqliteColumn, Constructor) column = Sqlite::Column{"table", "column", ColumnType::Text, - Contraint::ForeignKey, - {"referencedTable", - "referencedColumn", - ForeignKeyAction::SetNull, - ForeignKeyAction::Cascade, - Enforment::Deferred}}; + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("column")), Field(&Column::tableName, Eq("table")), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, Eq("referencedTable")), - Field(&ForeignKey::column, Eq("referencedColumn")), - Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), - Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), - Field(&ForeignKey::enforcement, Enforment::Deferred))))); + Field(&Column::constraints, + ElementsAre(VariantWith<ForeignKey>( + AllOf(Field(&ForeignKey::table, Eq("referencedTable")), + Field(&ForeignKey::column, Eq("referencedColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); } TEST_F(SqliteColumn, FlatConstructor) @@ -116,24 +99,23 @@ TEST_F(SqliteColumn, FlatConstructor) column = Sqlite::Column{"table", "column", ColumnType::Text, - Contraint::ForeignKey, - "referencedTable", - "referencedColumn", - ForeignKeyAction::SetNull, - ForeignKeyAction::Cascade, - Enforment::Deferred}; + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("column")), Field(&Column::tableName, Eq("table")), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, Eq("referencedTable")), - Field(&ForeignKey::column, Eq("referencedColumn")), - Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), - Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), - Field(&ForeignKey::enforcement, Enforment::Deferred))))); + Field(&Column::constraints, + ElementsAre(VariantWith<ForeignKey>( + AllOf(Field(&ForeignKey::table, Eq("referencedTable")), + Field(&ForeignKey::column, Eq("referencedColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); } } // namespace diff --git a/tests/unit/unittest/sqlitedatabasebackend-test.cpp b/tests/unit/unittest/sqlitedatabasebackend-test.cpp index 40227148bc..9957d3d4c7 100644 --- a/tests/unit/unittest/sqlitedatabasebackend-test.cpp +++ b/tests/unit/unittest/sqlitedatabasebackend-test.cpp @@ -39,7 +39,7 @@ namespace { using Backend = Sqlite::DatabaseBackend; using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::JournalMode; using Sqlite::OpenMode; using Sqlite::TextEncoding; diff --git a/tests/unit/unittest/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp index 89dfb7f867..05d3e73462 100644 --- a/tests/unit/unittest/sqlitetable-test.cpp +++ b/tests/unit/unittest/sqlitetable-test.cpp @@ -34,7 +34,7 @@ namespace { using Sqlite::Column; using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::Database; using Sqlite::Enforment; using Sqlite::ForeignKey; @@ -136,9 +136,7 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls) { Sqlite::Table foreignTable; foreignTable.setName("foreignTable"); - auto &foreignColumn = foreignTable.addColumn("foreignColumn", - ColumnType::Text, - Sqlite::Contraint::Unique); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}}); table.setName(tableName); table.addForeignKeyColumn("name", foreignColumn, @@ -159,19 +157,14 @@ TEST_F(SqliteTable, AddColumn) { table.setName(tableName); - auto &column = table.addColumn("name", ColumnType::Text, Sqlite::Contraint::Unique); + auto &column = table.addColumn("name", ColumnType::Text, {Sqlite::Unique{}}); ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("name")), Field(&Column::tableName, Eq(tableName)), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::Unique), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, IsEmpty()), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::enforcement, Enforment::Immediate))))); + Field(&Column::constraints, + ElementsAre(VariantWith<Sqlite::Unique>(Eq(Sqlite::Unique{})))))); } TEST_F(SqliteTable, AddForeignKeyColumnWithTable) @@ -191,22 +184,20 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithTable) AllOf(Field(&Column::name, Eq("name")), Field(&Column::tableName, Eq(tableName)), Field(&Column::type, ColumnType::Integer), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, Eq("foreignTable")), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), - Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), - Field(&ForeignKey::enforcement, Enforment::Deferred))))); + Field(&Column::constraints, + ElementsAre(VariantWith<ForeignKey>( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); } TEST_F(SqliteTable, AddForeignKeyColumnWithColumn) { Sqlite::Table foreignTable; foreignTable.setName("foreignTable"); - auto &foreignColumn = foreignTable.addColumn("foreignColumn", - ColumnType::Text, - Sqlite::Contraint::Unique); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}}); table.setName(tableName); auto &column = table.addForeignKeyColumn("name", @@ -219,22 +210,20 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumn) AllOf(Field(&Column::name, Eq("name")), Field(&Column::tableName, Eq(tableName)), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, Eq("foreignTable")), - Field(&ForeignKey::column, Eq("foreignColumn")), - Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), - Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), - Field(&ForeignKey::enforcement, Enforment::Deferred))))); + Field(&Column::constraints, + ElementsAre(VariantWith<ForeignKey>( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, Eq("foreignColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); } TEST_F(SqliteTable, AddForeignKeyWhichIsNotUniqueThrowsAnExceptions) { Sqlite::Table foreignTable; foreignTable.setName("foreignTable"); - auto &foreignColumn = foreignTable.addColumn("foreignColumn", - ColumnType::Text, - Sqlite::Contraint::NoConstraint); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text); table.setName(tableName); ASSERT_THROW(table.addForeignKeyColumn("name", @@ -245,4 +234,62 @@ TEST_F(SqliteTable, AddForeignKeyWhichIsNotUniqueThrowsAnExceptions) Sqlite::ForeignKeyColumnIsNotUnique); } +TEST_F(SqliteTable, AddForeignKeyColumnWithTableAndNotNull) +{ + Sqlite::Table foreignTable; + foreignTable.setName("foreignTable"); + + table.setName(tableName); + + auto &column = table.addForeignKeyColumn("name", + foreignTable, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred, + {Sqlite::NotNull{}}); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, ColumnType::Integer), + Field(&Column::constraints, + UnorderedElementsAre( + VariantWith<ForeignKey>( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))), + VariantWith<Sqlite::NotNull>(Eq(Sqlite::NotNull{})))))); +} + +TEST_F(SqliteTable, AddForeignKeyColumnWithColumnAndNotNull) +{ + Sqlite::Table foreignTable; + foreignTable.setName("foreignTable"); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}}); + table.setName(tableName); + + auto &column = table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred, + {Sqlite::NotNull{}}); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, ColumnType::Text), + Field(&Column::constraints, + UnorderedElementsAre( + VariantWith<ForeignKey>( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, Eq("foreignColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))), + VariantWith<Sqlite::NotNull>(Eq(Sqlite::NotNull{})))))); +} + } // namespace |