forked from qt-creator/qt-creator
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:
@@ -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;
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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 \
|
||||||
|
@@ -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;
|
||||||
|
49
src/libs/sqlite/tableconstraints.h
Normal file
49
src/libs/sqlite/tableconstraints.h
Normal 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
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user