forked from qt-creator/qt-creator
Sqlite: Add foreign key support
It is still only support references in columns but so far it is enough. Change-Id: Iebb4866cf738d651270e54357b5e4a2837f05417 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -39,13 +39,18 @@ void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName
|
|||||||
this->m_tableName = std::move(tableName);
|
this->m_tableName = std::move(tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
|
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName,
|
||||||
ColumnType columnType,
|
ColumnType columnType,
|
||||||
Contraint constraint)
|
Contraint constraint,
|
||||||
|
ForeignKey &&foreignKey)
|
||||||
{
|
{
|
||||||
m_sqlStatementBuilder.clear();
|
m_sqlStatementBuilder.clear();
|
||||||
|
|
||||||
m_columns.emplace_back(std::move(columnName), columnType, constraint);
|
m_columns.emplace_back(Utils::SmallStringView{},
|
||||||
|
columnName,
|
||||||
|
columnType,
|
||||||
|
constraint,
|
||||||
|
std::move(foreignKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns)
|
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns)
|
||||||
@@ -97,17 +102,70 @@ bool CreateTableSqlStatementBuilder::isValid() const
|
|||||||
return m_tableName.hasContent() && !m_columns.empty();
|
return m_tableName.hasContent() && !m_columns.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
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 "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendForeignKey(Utils::SmallString &columnDefinitionString, 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");
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
|
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
|
||||||
{
|
{
|
||||||
Utils::SmallStringVector columnDefinitionStrings;
|
Utils::SmallStringVector columnDefinitionStrings;
|
||||||
|
columnDefinitionStrings.reserve(m_columns.size());
|
||||||
|
|
||||||
for (const Column &columns : m_columns) {
|
for (const Column &column : m_columns) {
|
||||||
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
|
Utils::SmallString columnDefinitionString = {column.name, " ", column.typeString()};
|
||||||
|
|
||||||
switch (columns.constraint()) {
|
switch (column.constraint) {
|
||||||
case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break;
|
case Contraint::PrimaryKey:
|
||||||
case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break;
|
columnDefinitionString.append(" PRIMARY KEY");
|
||||||
case Contraint::NoConstraint: break;
|
break;
|
||||||
|
case Contraint::Unique:
|
||||||
|
columnDefinitionString.append(" UNIQUE");
|
||||||
|
break;
|
||||||
|
case Contraint::ForeignKey:
|
||||||
|
appendForeignKey(columnDefinitionString, column.foreignKey);
|
||||||
|
break;
|
||||||
|
case Contraint::NoConstraint:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
columnDefinitionStrings.push_back(columnDefinitionString);
|
columnDefinitionStrings.push_back(columnDefinitionString);
|
||||||
|
|||||||
@@ -36,9 +36,10 @@ public:
|
|||||||
CreateTableSqlStatementBuilder();
|
CreateTableSqlStatementBuilder();
|
||||||
|
|
||||||
void setTableName(Utils::SmallString &&tableName);
|
void setTableName(Utils::SmallString &&tableName);
|
||||||
void addColumn(Utils::SmallString &&columnName,
|
void addColumn(Utils::SmallStringView columnName,
|
||||||
ColumnType columnType,
|
ColumnType columnType,
|
||||||
Contraint constraint = Contraint::NoConstraint);
|
Contraint constraint = Contraint::NoConstraint,
|
||||||
|
ForeignKey &&foreignKey = {});
|
||||||
void setColumns(const SqliteColumns &columns);
|
void setColumns(const SqliteColumns &columns);
|
||||||
void setUseWithoutRowId(bool useWithoutRowId);
|
void setUseWithoutRowId(bool useWithoutRowId);
|
||||||
void setUseIfNotExists(bool useIfNotExists);
|
void setUseIfNotExists(bool useIfNotExists);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ HEADERS += \
|
|||||||
$$PWD/sqlitedatabasebackend.h \
|
$$PWD/sqlitedatabasebackend.h \
|
||||||
$$PWD/sqlitedatabaseinterface.h \
|
$$PWD/sqlitedatabaseinterface.h \
|
||||||
$$PWD/sqliteexception.h \
|
$$PWD/sqliteexception.h \
|
||||||
|
$$PWD/sqliteforeignkey.h \
|
||||||
$$PWD/sqliteglobal.h \
|
$$PWD/sqliteglobal.h \
|
||||||
$$PWD/sqlitereadstatement.h \
|
$$PWD/sqlitereadstatement.h \
|
||||||
$$PWD/sqlitereadwritestatement.h \
|
$$PWD/sqlitereadwritestatement.h \
|
||||||
@@ -45,7 +46,8 @@ HEADERS += \
|
|||||||
$$PWD/sqlitebasestatement.h
|
$$PWD/sqlitebasestatement.h
|
||||||
|
|
||||||
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS \
|
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS \
|
||||||
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_JSON1
|
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_JSON1 \
|
||||||
|
SQLITE_DEFAULT_FOREIGN_KEYS=1
|
||||||
|
|
||||||
OTHER_FILES += README.md
|
OTHER_FILES += README.md
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sqliteglobal.h"
|
#include "sqliteforeignkey.h"
|
||||||
|
|
||||||
#include <utils/smallstring.h>
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
@@ -38,59 +38,60 @@ class Column
|
|||||||
public:
|
public:
|
||||||
Column() = default;
|
Column() = default;
|
||||||
|
|
||||||
Column(Utils::SmallString &&name,
|
Column(Utils::SmallStringView tableName,
|
||||||
|
Utils::SmallStringView name,
|
||||||
ColumnType type = ColumnType::Numeric,
|
ColumnType type = ColumnType::Numeric,
|
||||||
Contraint constraint = Contraint::NoConstraint)
|
Contraint constraint = Contraint::NoConstraint,
|
||||||
: m_name(std::move(name)),
|
ForeignKey &&foreignKey = {})
|
||||||
m_type(type),
|
: foreignKey(std::move(foreignKey))
|
||||||
m_constraint(constraint)
|
, name(name)
|
||||||
|
, tableName(tableName)
|
||||||
|
, type(type)
|
||||||
|
, constraint(constraint)
|
||||||
|
{}
|
||||||
|
|
||||||
|
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)
|
||||||
|
, name(name)
|
||||||
|
, tableName(tableName)
|
||||||
|
, type(type)
|
||||||
|
, constraint(constraint)
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
m_name.clear();
|
name.clear();
|
||||||
m_type = ColumnType::Numeric;
|
type = ColumnType::Numeric;
|
||||||
m_constraint = Contraint::NoConstraint;
|
constraint = Contraint::NoConstraint;
|
||||||
}
|
foreignKey = {};
|
||||||
|
|
||||||
void setName(Utils::SmallString &&newName)
|
|
||||||
{
|
|
||||||
m_name = newName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Utils::SmallString &name() const
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setType(ColumnType newType)
|
|
||||||
{
|
|
||||||
m_type = newType;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnType type() const
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setContraint(Contraint constraint)
|
|
||||||
{
|
|
||||||
m_constraint = constraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
Contraint constraint() const
|
|
||||||
{
|
|
||||||
return m_constraint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::SmallString typeString() const
|
Utils::SmallString typeString() const
|
||||||
{
|
{
|
||||||
switch (m_type) {
|
switch (type) {
|
||||||
case ColumnType::None: return {};
|
case ColumnType::None:
|
||||||
case ColumnType::Numeric: return "NUMERIC";
|
return {};
|
||||||
case ColumnType::Integer: return "INTEGER";
|
case ColumnType::Numeric:
|
||||||
case ColumnType::Real: return "REAL";
|
return "NUMERIC";
|
||||||
case ColumnType::Text: return "TEXT";
|
case ColumnType::Integer:
|
||||||
|
return "INTEGER";
|
||||||
|
case ColumnType::Real:
|
||||||
|
return "REAL";
|
||||||
|
case ColumnType::Text:
|
||||||
|
return "TEXT";
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
@@ -98,16 +99,18 @@ public:
|
|||||||
|
|
||||||
friend bool operator==(const Column &first, const Column &second)
|
friend bool operator==(const Column &first, const Column &second)
|
||||||
{
|
{
|
||||||
return first.m_name == second.m_name
|
return first.name == second.name && first.type == second.type
|
||||||
&& first.m_type == second.m_type
|
&& first.constraint
|
||||||
&& first.m_constraint == second.m_constraint;
|
== second.constraint /* && first.foreignKey == second.foreignKey*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
public:
|
||||||
Utils::SmallString m_name;
|
ForeignKey foreignKey;
|
||||||
ColumnType m_type = ColumnType::Numeric;
|
Utils::SmallString name;
|
||||||
Contraint m_constraint = Contraint::NoConstraint;
|
Utils::SmallString tableName;
|
||||||
};
|
ColumnType type = ColumnType::Numeric;
|
||||||
|
Contraint constraint = Contraint::NoConstraint;
|
||||||
|
}; // namespace Sqlite
|
||||||
|
|
||||||
using SqliteColumns = std::vector<Column>;
|
using SqliteColumns = std::vector<Column>;
|
||||||
using SqliteColumnConstReference = std::reference_wrapper<const Column>;
|
using SqliteColumnConstReference = std::reference_wrapper<const Column>;
|
||||||
|
|||||||
@@ -272,4 +272,12 @@ public:
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ForeignKeyColumnIsNotUnique : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ForeignKeyColumnIsNotUnique(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
|||||||
65
src/libs/sqlite/sqliteforeignkey.h
Normal file
65
src/libs/sqlite/sqliteforeignkey.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sqliteglobal.h"
|
||||||
|
|
||||||
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
class ForeignKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ForeignKey() = default;
|
||||||
|
ForeignKey(Utils::SmallStringView table,
|
||||||
|
Utils::SmallStringView column,
|
||||||
|
ForeignKeyAction updateAction = {},
|
||||||
|
ForeignKeyAction deleteAction = {},
|
||||||
|
Enforment enforcement = {})
|
||||||
|
: table(table)
|
||||||
|
, column(column)
|
||||||
|
, updateAction(updateAction)
|
||||||
|
, deleteAction(deleteAction)
|
||||||
|
, enforcement(enforcement)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const ForeignKey &first, const ForeignKey &second)
|
||||||
|
{
|
||||||
|
return first.table == second.table && first.column == second.column
|
||||||
|
&& first.updateAction == second.updateAction
|
||||||
|
&& first.deleteAction == second.deleteAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString table;
|
||||||
|
Utils::SmallString column;
|
||||||
|
ForeignKeyAction updateAction = {};
|
||||||
|
ForeignKeyAction deleteAction = {};
|
||||||
|
Enforment enforcement = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
||||||
@@ -48,17 +48,13 @@ enum class ColumnType : char
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Contraint : char
|
enum class Contraint : char { NoConstraint, PrimaryKey, Unique, ForeignKey };
|
||||||
{
|
|
||||||
NoConstraint,
|
|
||||||
PrimaryKey,
|
|
||||||
Unique
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ColumnConstraint : char
|
enum class ForeignKeyAction : char { NoAction, Restrict, SetNull, SetDefault, Cascade };
|
||||||
{
|
|
||||||
PrimaryKey
|
enum class Enforment : char { Immediate, Deferred };
|
||||||
};
|
|
||||||
|
enum class ColumnConstraint : char { PrimaryKey };
|
||||||
|
|
||||||
enum class JournalMode : char
|
enum class JournalMode : char
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ public:
|
|||||||
m_sqliteIndices.reserve(reserve);
|
m_sqliteIndices.reserve(reserve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setName(Utils::SmallString &&name)
|
void setName(Utils::SmallStringView name) { m_tableName = name; }
|
||||||
{
|
|
||||||
m_tableName = std::move(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::SmallStringView name() const
|
Utils::SmallStringView name() const
|
||||||
{
|
{
|
||||||
@@ -74,11 +71,53 @@ public:
|
|||||||
m_useTemporaryTable = useTemporaryTable;
|
m_useTemporaryTable = useTemporaryTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Column &addColumn(Utils::SmallString &&name,
|
Column &addColumn(Utils::SmallStringView name,
|
||||||
ColumnType type = ColumnType::Numeric,
|
ColumnType type = ColumnType::Numeric,
|
||||||
Contraint constraint = Contraint::NoConstraint)
|
Contraint constraint = Contraint::NoConstraint)
|
||||||
{
|
{
|
||||||
m_sqliteColumns.emplace_back(std::move(name), type, constraint);
|
m_sqliteColumns.emplace_back(m_tableName, name, type, constraint);
|
||||||
|
|
||||||
|
return m_sqliteColumns.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
Column &addForeignKeyColumn(Utils::SmallStringView name,
|
||||||
|
const Table &referencedTable,
|
||||||
|
ForeignKeyAction foreignKeyupdateAction = {},
|
||||||
|
ForeignKeyAction foreignKeyDeleteAction = {},
|
||||||
|
Enforment foreignKeyEnforcement = {},
|
||||||
|
ColumnType type = ColumnType::Integer)
|
||||||
|
{
|
||||||
|
m_sqliteColumns.emplace_back(m_tableName,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
referencedTable.name(),
|
||||||
|
"",
|
||||||
|
foreignKeyupdateAction,
|
||||||
|
foreignKeyDeleteAction,
|
||||||
|
foreignKeyEnforcement);
|
||||||
|
|
||||||
|
return m_sqliteColumns.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
Column &addForeignKeyColumn(Utils::SmallStringView name,
|
||||||
|
const Column &referencedColumn,
|
||||||
|
ForeignKeyAction foreignKeyupdateAction = {},
|
||||||
|
ForeignKeyAction foreignKeyDeleteAction = {},
|
||||||
|
Enforment foreignKeyEnforcement = {})
|
||||||
|
{
|
||||||
|
if (referencedColumn.constraint != Contraint::Unique)
|
||||||
|
throw ForeignKeyColumnIsNotUnique("Foreign column key must be unique!");
|
||||||
|
|
||||||
|
m_sqliteColumns.emplace_back(m_tableName,
|
||||||
|
name,
|
||||||
|
referencedColumn.type,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
referencedColumn.tableName,
|
||||||
|
referencedColumn.name,
|
||||||
|
foreignKeyupdateAction,
|
||||||
|
foreignKeyDeleteAction,
|
||||||
|
foreignKeyEnforcement);
|
||||||
|
|
||||||
return m_sqliteColumns.back();
|
return m_sqliteColumns.back();
|
||||||
}
|
}
|
||||||
@@ -148,7 +187,7 @@ private:
|
|||||||
Utils::SmallStringVector columnNames;
|
Utils::SmallStringVector columnNames;
|
||||||
|
|
||||||
for (const Column &column : columns)
|
for (const Column &column : columns)
|
||||||
columnNames.push_back(column.name());
|
columnNames.push_back(column.name);
|
||||||
|
|
||||||
return columnNames;
|
return columnNames;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,14 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using Sqlite::Column;
|
||||||
using Sqlite::ColumnType;
|
using Sqlite::ColumnType;
|
||||||
using Sqlite::Contraint;
|
using Sqlite::Contraint;
|
||||||
|
using Sqlite::Enforment;
|
||||||
|
using Sqlite::ForeignKeyAction;
|
||||||
using Sqlite::JournalMode;
|
using Sqlite::JournalMode;
|
||||||
using Sqlite::OpenMode;
|
using Sqlite::OpenMode;
|
||||||
using Sqlite::Column;
|
|
||||||
using Sqlite::SqliteColumns;
|
using Sqlite::SqliteColumns;
|
||||||
|
|
||||||
using Sqlite::SqlStatementBuilderException;
|
using Sqlite::SqlStatementBuilderException;
|
||||||
|
|
||||||
class CreateTableSqlStatementBuilder : public ::testing::Test
|
class CreateTableSqlStatementBuilder : public ::testing::Test
|
||||||
@@ -199,11 +200,210 @@ void CreateTableSqlStatementBuilder::bindValues()
|
|||||||
SqliteColumns CreateTableSqlStatementBuilder::createColumns()
|
SqliteColumns CreateTableSqlStatementBuilder::createColumns()
|
||||||
{
|
{
|
||||||
SqliteColumns columns;
|
SqliteColumns columns;
|
||||||
columns.emplace_back("id", ColumnType::Integer, Contraint::PrimaryKey);
|
columns.emplace_back("", "id", ColumnType::Integer, Contraint::PrimaryKey);
|
||||||
columns.emplace_back("name", ColumnType::Text);
|
columns.emplace_back("", "name", ColumnType::Text);
|
||||||
columns.emplace_back("number", ColumnType::Numeric);
|
columns.emplace_back("", "number", ColumnType::Numeric);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", ""});
|
||||||
|
|
||||||
|
ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithColumn)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"});
|
||||||
|
|
||||||
|
ASSERT_THAT(builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateNoAction)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"});
|
||||||
|
|
||||||
|
ASSERT_THAT(builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateRestrict)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", ForeignKeyAction::Restrict});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE RESTRICT)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetNull)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", ForeignKeyAction::SetNull});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET NULL)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetDefault)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", ForeignKeyAction::SetDefault});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET DEFAULT)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", ForeignKeyAction::Cascade});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE CASCADE)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteNoAction)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"});
|
||||||
|
|
||||||
|
ASSERT_THAT(builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteRestrict)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE RESTRICT)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetNull)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE SET NULL)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetDefault)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE SET DEFAULT)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteCascade)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade});
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE CASCADE)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::ForeignKey,
|
||||||
|
{"otherTable",
|
||||||
|
"otherColumn",
|
||||||
|
ForeignKeyAction::SetDefault,
|
||||||
|
ForeignKeyAction::Cascade});
|
||||||
|
|
||||||
|
ASSERT_THAT(builder.sqlStatement(),
|
||||||
|
"CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET "
|
||||||
|
"DEFAULT ON DELETE CASCADE)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeferred)
|
||||||
|
{
|
||||||
|
builder.clear();
|
||||||
|
builder.setTableName("test");
|
||||||
|
|
||||||
|
builder.addColumn("id",
|
||||||
|
ColumnType::Integer,
|
||||||
|
Contraint::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)");
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|||||||
@@ -29,70 +29,111 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using testing::AllOf;
|
|
||||||
using testing::Contains;
|
|
||||||
using testing::Property;
|
|
||||||
|
|
||||||
using Sqlite::ColumnType;
|
using Sqlite::ColumnType;
|
||||||
using Sqlite::Contraint;
|
using Sqlite::Contraint;
|
||||||
using Sqlite::JournalMode;
|
using Sqlite::JournalMode;
|
||||||
using Sqlite::OpenMode;
|
using Sqlite::OpenMode;
|
||||||
using Column = Sqlite::Column;
|
using Column = Sqlite::Column;
|
||||||
|
using Sqlite::Enforment;
|
||||||
|
using Sqlite::ForeignKey;
|
||||||
|
using Sqlite::ForeignKeyAction;
|
||||||
using Sqlite::SqliteColumns;
|
using Sqlite::SqliteColumns;
|
||||||
|
|
||||||
class SqliteColumn : public ::testing::Test
|
class SqliteColumn : public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override;
|
|
||||||
|
|
||||||
Sqlite::Column column;
|
Sqlite::Column column;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(SqliteColumn, ChangeName)
|
TEST_F(SqliteColumn, DefaultConstruct)
|
||||||
{
|
{
|
||||||
column.setName("Claudia");
|
ASSERT_THAT(column,
|
||||||
|
AllOf(Field(&Column::name, IsEmpty()),
|
||||||
ASSERT_THAT(column.name(), "Claudia");
|
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)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SqliteColumn, DefaultType)
|
TEST_F(SqliteColumn, Clear)
|
||||||
{
|
{
|
||||||
ASSERT_THAT(column.type(), ColumnType::Numeric);
|
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;
|
||||||
|
|
||||||
TEST_F(SqliteColumn, ChangeType)
|
column.clear();
|
||||||
{
|
|
||||||
column.setType(ColumnType::Text);
|
|
||||||
|
|
||||||
ASSERT_THAT(column.type(), ColumnType::Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SqliteColumn, DefaultConstraint)
|
|
||||||
{
|
|
||||||
ASSERT_THAT(column.constraint(), Contraint::NoConstraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SqliteColumn, SetConstraint)
|
|
||||||
{
|
|
||||||
column.setContraint(Contraint::PrimaryKey);
|
|
||||||
|
|
||||||
ASSERT_THAT(column.constraint(), Contraint::PrimaryKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SqliteColumn, GetColumnDefinition)
|
|
||||||
{
|
|
||||||
column.setName("Claudia");
|
|
||||||
|
|
||||||
ASSERT_THAT(column,
|
ASSERT_THAT(column,
|
||||||
AllOf(
|
AllOf(Field(&Column::name, IsEmpty()),
|
||||||
Property(&Column::name, "Claudia"),
|
Field(&Column::tableName, IsEmpty()),
|
||||||
Property(&Column::type, ColumnType::Numeric),
|
Field(&Column::type, ColumnType::Numeric),
|
||||||
Property(&Column::constraint, Contraint::NoConstraint)));
|
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)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SqliteColumn::SetUp()
|
TEST_F(SqliteColumn, Constructor)
|
||||||
{
|
{
|
||||||
column.clear();
|
column = Sqlite::Column{"table",
|
||||||
|
"column",
|
||||||
|
ColumnType::Text,
|
||||||
|
Contraint::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)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteColumn, FlatConstructor)
|
||||||
|
{
|
||||||
|
column = Sqlite::Column{"table",
|
||||||
|
"column",
|
||||||
|
ColumnType::Text,
|
||||||
|
Contraint::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)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|||||||
@@ -32,11 +32,15 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using Sqlite::Column;
|
||||||
using Sqlite::ColumnType;
|
using Sqlite::ColumnType;
|
||||||
|
using Sqlite::Contraint;
|
||||||
|
using Sqlite::Database;
|
||||||
|
using Sqlite::Enforment;
|
||||||
|
using Sqlite::ForeignKey;
|
||||||
|
using Sqlite::ForeignKeyAction;
|
||||||
using Sqlite::JournalMode;
|
using Sqlite::JournalMode;
|
||||||
using Sqlite::OpenMode;
|
using Sqlite::OpenMode;
|
||||||
using Sqlite::Column;
|
|
||||||
using Sqlite::Database;
|
|
||||||
|
|
||||||
class SqliteTable : public ::testing::Test
|
class SqliteTable : public ::testing::Test
|
||||||
{
|
{
|
||||||
@@ -110,21 +114,135 @@ TEST_F(SqliteTable, InitializeTableWithIndex)
|
|||||||
table.initialize(mockDatabase);
|
table.initialize(mockDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteTable, AddForeignKeyColumnWithTableCalls)
|
||||||
TEST_F(SqliteTable, InitializeTableWithUniqueIndex)
|
|
||||||
{
|
{
|
||||||
InSequence sequence;
|
Sqlite::Table foreignTable;
|
||||||
table.setName(tableName.clone());
|
foreignTable.setName("foreignTable");
|
||||||
auto &column = table.addColumn("name");
|
table.setName(tableName);
|
||||||
auto &column2 = table.addColumn("value");
|
table.addForeignKeyColumn("name",
|
||||||
table.addUniqueIndex({column});
|
foreignTable,
|
||||||
table.addIndex({column2});
|
ForeignKeyAction::SetNull,
|
||||||
|
ForeignKeyAction::Cascade,
|
||||||
|
Enforment::Deferred);
|
||||||
|
|
||||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE testTable(name NUMERIC, value NUMERIC)")));
|
EXPECT_CALL(mockDatabase,
|
||||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_testTable_name ON testTable(name)")));
|
execute(Eq("CREATE TABLE testTable(name INTEGER REFERENCES foreignTable ON UPDATE "
|
||||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_value ON testTable(value)")));
|
"SET NULL ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)")));
|
||||||
|
|
||||||
table.initialize(mockDatabase);
|
table.initialize(mockDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls)
|
||||||
|
{
|
||||||
|
Sqlite::Table foreignTable;
|
||||||
|
foreignTable.setName("foreignTable");
|
||||||
|
auto &foreignColumn = foreignTable.addColumn("foreignColumn",
|
||||||
|
ColumnType::Text,
|
||||||
|
Sqlite::Contraint::Unique);
|
||||||
|
table.setName(tableName);
|
||||||
|
table.addForeignKeyColumn("name",
|
||||||
|
foreignColumn,
|
||||||
|
ForeignKeyAction::SetDefault,
|
||||||
|
ForeignKeyAction::Restrict,
|
||||||
|
Enforment::Deferred);
|
||||||
|
|
||||||
|
EXPECT_CALL(
|
||||||
|
mockDatabase,
|
||||||
|
execute(
|
||||||
|
Eq("CREATE TABLE testTable(name TEXT REFERENCES foreignTable(foreignColumn) ON UPDATE "
|
||||||
|
"SET DEFAULT ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED)")));
|
||||||
|
|
||||||
|
table.initialize(mockDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteTable, AddColumn)
|
||||||
|
{
|
||||||
|
table.setName(tableName);
|
||||||
|
|
||||||
|
auto &column = table.addColumn("name", ColumnType::Text, Sqlite::Contraint::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)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteTable, AddForeignKeyColumnWithTable)
|
||||||
|
{
|
||||||
|
Sqlite::Table foreignTable;
|
||||||
|
foreignTable.setName("foreignTable");
|
||||||
|
|
||||||
|
table.setName(tableName);
|
||||||
|
|
||||||
|
auto &column = table.addForeignKeyColumn("name",
|
||||||
|
foreignTable,
|
||||||
|
ForeignKeyAction::SetNull,
|
||||||
|
ForeignKeyAction::Cascade,
|
||||||
|
Enforment::Deferred);
|
||||||
|
|
||||||
|
ASSERT_THAT(column,
|
||||||
|
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)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteTable, AddForeignKeyColumnWithColumn)
|
||||||
|
{
|
||||||
|
Sqlite::Table foreignTable;
|
||||||
|
foreignTable.setName("foreignTable");
|
||||||
|
auto &foreignColumn = foreignTable.addColumn("foreignColumn",
|
||||||
|
ColumnType::Text,
|
||||||
|
Sqlite::Contraint::Unique);
|
||||||
|
table.setName(tableName);
|
||||||
|
|
||||||
|
auto &column = table.addForeignKeyColumn("name",
|
||||||
|
foreignColumn,
|
||||||
|
ForeignKeyAction::SetNull,
|
||||||
|
ForeignKeyAction::Cascade,
|
||||||
|
Enforment::Deferred);
|
||||||
|
|
||||||
|
ASSERT_THAT(column,
|
||||||
|
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)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteTable, AddForeignKeyWhichIsNotUniqueThrowsAnExceptions)
|
||||||
|
{
|
||||||
|
Sqlite::Table foreignTable;
|
||||||
|
foreignTable.setName("foreignTable");
|
||||||
|
auto &foreignColumn = foreignTable.addColumn("foreignColumn",
|
||||||
|
ColumnType::Text,
|
||||||
|
Sqlite::Contraint::NoConstraint);
|
||||||
|
table.setName(tableName);
|
||||||
|
|
||||||
|
ASSERT_THROW(table.addForeignKeyColumn("name",
|
||||||
|
foreignColumn,
|
||||||
|
ForeignKeyAction::SetNull,
|
||||||
|
ForeignKeyAction::Cascade,
|
||||||
|
Enforment::Deferred),
|
||||||
|
Sqlite::ForeignKeyColumnIsNotUnique);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user