Sqlite: Add primary key table constraint to table builder

Change-Id: I60c158eb76db2217a2d045053bb8e47eef75ff7a
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2020-06-02 22:16:06 +02:00
committed by Tim Jenssen
parent a61eff0079
commit cf441e8198
8 changed files with 139 additions and 7 deletions

View File

@@ -42,7 +42,10 @@ enum class AutoIncrement { No, Yes };
class PrimaryKey class PrimaryKey
{ {
friend bool operator==(PrimaryKey, PrimaryKey) { return true; } friend bool operator==(PrimaryKey first, PrimaryKey second)
{
return first.autoincrement == second.autoincrement;
}
public: public:
AutoIncrement autoincrement = AutoIncrement::No; AutoIncrement autoincrement = AutoIncrement::No;

View File

@@ -48,7 +48,17 @@ void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName
m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints)); m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints));
} }
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns) void CreateTableSqlStatementBuilder::addConstraint(TableConstraint &&constraint)
{
m_tableConstraints.push_back(std::move(constraint));
}
void CreateTableSqlStatementBuilder::setConstraints(TableConstraints constraints)
{
m_tableConstraints = std::move(constraints);
}
void CreateTableSqlStatementBuilder::setColumns(SqliteColumns columns)
{ {
m_sqlStatementBuilder.clear(); m_sqlStatementBuilder.clear();
@@ -212,8 +222,25 @@ public:
Utils::SmallString &columnDefinitionString; 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;
};
} // namespace } // namespace
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const void CreateTableSqlStatementBuilder::bindColumnDefinitionsAndTableConstraints() const
{ {
Utils::SmallStringVector columnDefinitionStrings; Utils::SmallStringVector columnDefinitionStrings;
columnDefinitionStrings.reserve(m_columns.size()); columnDefinitionStrings.reserve(m_columns.size());
@@ -226,7 +253,16 @@ void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
for (const Constraint &constraint : column.constraints) for (const Constraint &constraint : column.constraints)
Utils::visit(visiter, constraint); Utils::visit(visiter, constraint);
columnDefinitionStrings.push_back(columnDefinitionString); 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); m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings);
@@ -238,7 +274,7 @@ void CreateTableSqlStatementBuilder::bindAll() const
bindTemporary(); bindTemporary();
bindIfNotExists(); bindIfNotExists();
bindColumnDefinitions(); bindColumnDefinitionsAndTableConstraints();
bindWithoutRowId(); bindWithoutRowId();
} }

View File

@@ -27,6 +27,7 @@
#include "sqlitecolumn.h" #include "sqlitecolumn.h"
#include "sqlstatementbuilder.h" #include "sqlstatementbuilder.h"
#include "tableconstraints.h"
namespace Sqlite { namespace Sqlite {
@@ -40,7 +41,9 @@ public:
void addColumn(Utils::SmallStringView columnName, void addColumn(Utils::SmallStringView columnName,
ColumnType columnType, ColumnType columnType,
Constraints &&constraints = {}); Constraints &&constraints = {});
void setColumns(const SqliteColumns &columns); void addConstraint(TableConstraint &&constraint);
void setConstraints(TableConstraints constraints);
void setColumns(SqliteColumns columns);
void setUseWithoutRowId(bool useWithoutRowId); void setUseWithoutRowId(bool useWithoutRowId);
void setUseIfNotExists(bool useIfNotExists); void setUseIfNotExists(bool useIfNotExists);
void setUseTemporaryTable(bool useTemporaryTable); void setUseTemporaryTable(bool useTemporaryTable);
@@ -53,7 +56,7 @@ public:
bool isValid() const; bool isValid() const;
protected: protected:
void bindColumnDefinitions() const; void bindColumnDefinitionsAndTableConstraints() const;
void bindAll() const; void bindAll() const;
void bindWithoutRowId() const; void bindWithoutRowId() const;
void bindIfNotExists() const; void bindIfNotExists() const;
@@ -63,6 +66,7 @@ private:
mutable SqlStatementBuilder m_sqlStatementBuilder; mutable SqlStatementBuilder m_sqlStatementBuilder;
Utils::SmallString m_tableName; Utils::SmallString m_tableName;
SqliteColumns m_columns; SqliteColumns m_columns;
TableConstraints m_tableConstraints;
bool m_useWithoutRowId = false; bool m_useWithoutRowId = false;
bool m_useIfNotExits = false; bool m_useIfNotExits = false;
bool m_useTemporaryTable = false; bool m_useTemporaryTable = false;

View File

@@ -27,6 +27,7 @@ SOURCES += \
$$PWD/sqlitebasestatement.cpp $$PWD/sqlitebasestatement.cpp
HEADERS += \ HEADERS += \
$$PWD/constraints.h \ $$PWD/constraints.h \
$$PWD/tableconstraints.h \
$$PWD/createtablesqlstatementbuilder.h \ $$PWD/createtablesqlstatementbuilder.h \
$$PWD/lastchangedrowid.h \ $$PWD/lastchangedrowid.h \
$$PWD/sqlitedatabasebackend.h \ $$PWD/sqlitedatabasebackend.h \

View File

@@ -123,6 +123,17 @@ public:
return m_sqliteColumns.back(); return m_sqliteColumns.back();
} }
void addPrimaryKeyContraint(const SqliteColumnConstReferences &columns)
{
Utils::SmallStringVector columnNames;
columnNames.reserve(columns.size());
for (const auto &column : columns)
columnNames.emplace_back(column.get().name);
m_tableConstraints.emplace_back(TablePrimaryKey{std::move(columnNames)});
}
Index &addIndex(const SqliteColumnConstReferences &columns) Index &addIndex(const SqliteColumnConstReferences &columns)
{ {
m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns)); m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns));
@@ -159,6 +170,7 @@ public:
builder.setUseIfNotExists(m_useIfNotExists); builder.setUseIfNotExists(m_useIfNotExists);
builder.setUseTemporaryTable(m_useTemporaryTable); builder.setUseTemporaryTable(m_useTemporaryTable);
builder.setColumns(m_sqliteColumns); builder.setColumns(m_sqliteColumns);
builder.setConstraints(m_tableConstraints);
database.execute(builder.sqlStatement()); database.execute(builder.sqlStatement());
@@ -207,6 +219,7 @@ private:
Utils::SmallString m_tableName; Utils::SmallString m_tableName;
SqliteColumns m_sqliteColumns; SqliteColumns m_sqliteColumns;
SqliteIndices m_sqliteIndices; SqliteIndices m_sqliteIndices;
TableConstraints m_tableConstraints;
bool m_withoutRowId = false; bool m_withoutRowId = false;
bool m_useIfNotExists = false; bool m_useIfNotExists = false;
bool m_useTemporaryTable = false; bool m_useTemporaryTable = false;

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** 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 <sqlitevalue.h>
#include <utils/smallstringvector.h>
#include <utils/variant.h>
namespace Sqlite {
class TablePrimaryKey
{
friend bool operator==(TablePrimaryKey first, TablePrimaryKey second)
{
return first.columns == second.columns;
}
public:
Utils::SmallStringVector columns;
};
using TableConstraint = Utils::variant<TablePrimaryKey>;
using TableConstraints = std::vector<TableConstraint>;
} // namespace Sqlite

View File

@@ -530,4 +530,17 @@ TEST_F(CreateTableSqlStatementBuilder, BlobType)
ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(data BLOB)"); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(data BLOB)");
} }
TEST_F(CreateTableSqlStatementBuilder, TablePrimaryKeyConstaint)
{
builder.clear();
builder.setTableName("test");
builder.addColumn("id", ColumnType::Integer);
builder.addColumn("text", ColumnType::Text);
builder.addConstraint(Sqlite::TablePrimaryKey{{"id, text"}});
auto statement = builder.sqlStatement();
ASSERT_THAT(statement, "CREATE TABLE test(id INTEGER, text TEXT, PRIMARY KEY(id, text))");
}
} // namespace } // namespace

View File

@@ -292,4 +292,17 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumnAndNotNull)
VariantWith<Sqlite::NotNull>(Eq(Sqlite::NotNull{})))))); VariantWith<Sqlite::NotNull>(Eq(Sqlite::NotNull{}))))));
} }
TEST_F(SqliteTable, AddPrimaryTableContraint)
{
table.setName(tableName.clone());
const auto &idColumn = table.addColumn("id");
const auto &nameColumn = table.addColumn("name");
table.addPrimaryKeyContraint({idColumn, nameColumn});
EXPECT_CALL(mockDatabase,
execute(
Eq("CREATE TABLE testTable(id NUMERIC, name NUMERIC, PRIMARY KEY(id, name))")));
table.initialize(mockDatabase);
}
} // namespace } // namespace