1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of Qt Creator. 7 ** 8 ** Commercial License Usage 9 ** Licensees holding valid commercial Qt licenses may use this file in 10 ** accordance with the commercial license agreement provided with the 11 ** Software or, alternatively, in accordance with the terms contained in 12 ** a written agreement between you and The Qt Company. For licensing terms 13 ** and conditions see https://www.qt.io/terms-conditions. For further 14 ** information use the contact form at https://www.qt.io/contact-us. 15 ** 16 ** GNU General Public License Usage 17 ** Alternatively, this file may be used under the terms of the GNU 18 ** General Public License version 3 as published by the Free Software 19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 ** included in the packaging of this file. Please review the following 21 ** information to ensure the GNU General Public License requirements will 22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 ** 24 ****************************************************************************/ 25 26 #pragma once 27 28 #include "createtablesqlstatementbuilder.h" 29 #include "sqliteglobal.h" 30 #include "sqlitecolumn.h" 31 #include "sqliteindex.h" 32 #include "sqliteexception.h" 33 34 namespace Sqlite { 35 36 class Database; 37 38 class Table 39 { 40 public: 41 Table(std::size_t reserve = 10) 42 { 43 m_sqliteColumns.reserve(reserve); 44 m_sqliteIndices.reserve(reserve); 45 } 46 setName(Utils::SmallStringView name)47 void setName(Utils::SmallStringView name) { m_tableName = name; } 48 name()49 Utils::SmallStringView name() const 50 { 51 return m_tableName; 52 } 53 setUseWithoutRowId(bool useWithoutWorId)54 void setUseWithoutRowId(bool useWithoutWorId) 55 { 56 m_withoutRowId = useWithoutWorId; 57 } 58 useWithoutRowId()59 bool useWithoutRowId() const 60 { 61 return m_withoutRowId; 62 } 63 setUseIfNotExists(bool useIfNotExists)64 void setUseIfNotExists(bool useIfNotExists) 65 { 66 m_useIfNotExists = useIfNotExists; 67 } 68 setUseTemporaryTable(bool useTemporaryTable)69 void setUseTemporaryTable(bool useTemporaryTable) 70 { 71 m_useTemporaryTable = useTemporaryTable; 72 } 73 74 Column &addColumn(Utils::SmallStringView name, 75 ColumnType type = ColumnType::None, 76 Constraints &&constraints = {}) 77 { 78 m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints)); 79 80 return m_sqliteColumns.back(); 81 } 82 83 Column &addForeignKeyColumn(Utils::SmallStringView name, 84 const Table &referencedTable, 85 ForeignKeyAction foreignKeyupdateAction = {}, 86 ForeignKeyAction foreignKeyDeleteAction = {}, 87 Enforment foreignKeyEnforcement = {}, 88 Constraints &&constraints = {}, 89 ColumnType type = ColumnType::Integer) 90 { 91 constraints.emplace_back(ForeignKey{referencedTable.name(), 92 "", 93 foreignKeyupdateAction, 94 foreignKeyDeleteAction, 95 foreignKeyEnforcement}); 96 97 m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints)); 98 99 return m_sqliteColumns.back(); 100 } 101 102 Column &addForeignKeyColumn(Utils::SmallStringView name, 103 const Column &referencedColumn, 104 ForeignKeyAction foreignKeyupdateAction = {}, 105 ForeignKeyAction foreignKeyDeleteAction = {}, 106 Enforment foreignKeyEnforcement = {}, 107 Constraints &&constraints = {}) 108 { 109 if (!constainsUniqueIndex(referencedColumn.constraints)) 110 throw ForeignKeyColumnIsNotUnique("Foreign column key must be unique!"); 111 112 constraints.emplace_back(ForeignKey{referencedColumn.tableName, 113 referencedColumn.name, 114 foreignKeyupdateAction, 115 foreignKeyDeleteAction, 116 foreignKeyEnforcement}); 117 118 m_sqliteColumns.emplace_back(m_tableName, 119 name, 120 referencedColumn.type, 121 std::move(constraints)); 122 123 return m_sqliteColumns.back(); 124 } 125 addPrimaryKeyContraint(const SqliteColumnConstReferences & columns)126 void addPrimaryKeyContraint(const SqliteColumnConstReferences &columns) 127 { 128 Utils::SmallStringVector columnNames; 129 columnNames.reserve(columns.size()); 130 131 for (const auto &column : columns) 132 columnNames.emplace_back(column.get().name); 133 134 m_tableConstraints.emplace_back(TablePrimaryKey{std::move(columnNames)}); 135 } 136 137 Index &addIndex(const SqliteColumnConstReferences &columns, Utils::SmallStringView condition = {}) 138 { 139 return m_sqliteIndices.emplace_back(m_tableName, 140 sqliteColumnNames(columns), 141 IndexType::Normal, 142 condition); 143 } 144 145 Index &addUniqueIndex(const SqliteColumnConstReferences &columns, 146 Utils::SmallStringView condition = {}) 147 { 148 return m_sqliteIndices.emplace_back(m_tableName, 149 sqliteColumnNames(columns), 150 IndexType::Unique, 151 condition); 152 } 153 columns()154 const SqliteColumns &columns() const 155 { 156 return m_sqliteColumns; 157 } 158 isReady()159 bool isReady() const 160 { 161 return m_isReady; 162 } 163 164 template <typename Database> initialize(Database & database)165 void initialize(Database &database) 166 { 167 CreateTableSqlStatementBuilder builder; 168 169 builder.setTableName(m_tableName.clone()); 170 builder.setUseWithoutRowId(m_withoutRowId); 171 builder.setUseIfNotExists(m_useIfNotExists); 172 builder.setUseTemporaryTable(m_useTemporaryTable); 173 builder.setColumns(m_sqliteColumns); 174 builder.setConstraints(m_tableConstraints); 175 176 database.execute(builder.sqlStatement()); 177 178 initializeIndices(database); 179 180 m_isReady = true; 181 } 182 template <typename Database> initializeIndices(Database & database)183 void initializeIndices(Database &database) 184 { 185 for (const Index &index : m_sqliteIndices) 186 database.execute(index.sqlStatement()); 187 } 188 189 friend bool operator==(const Table &first, const Table &second) 190 { 191 return first.m_tableName == second.m_tableName 192 && first.m_withoutRowId == second.m_withoutRowId 193 && first.m_useIfNotExists == second.m_useIfNotExists 194 && first.m_isReady == second.m_isReady 195 && first.m_sqliteColumns == second.m_sqliteColumns; 196 } 197 constainsUniqueIndex(const Constraints & constraints)198 static bool constainsUniqueIndex(const Constraints &constraints) 199 { 200 return std::find_if(constraints.begin(), 201 constraints.end(), 202 [](const Constraint &constraint) { 203 return Utils::holds_alternative<Unique>(constraint) 204 || Utils::holds_alternative<PrimaryKey>(constraint); 205 }) 206 != constraints.end(); 207 } 208 209 private: sqliteColumnNames(const SqliteColumnConstReferences & columns)210 Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns) 211 { 212 Utils::SmallStringVector columnNames; 213 214 for (const Column &column : columns) 215 columnNames.push_back(column.name); 216 217 return columnNames; 218 } 219 220 private: 221 Utils::SmallString m_tableName; 222 SqliteColumns m_sqliteColumns; 223 SqliteIndices m_sqliteIndices; 224 TableConstraints m_tableConstraints; 225 bool m_withoutRowId = false; 226 bool m_useIfNotExists = false; 227 bool m_useTemporaryTable = false; 228 bool m_isReady = false; 229 }; 230 231 } // namespace Sqlite 232