1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AFFILIATIONS_CORE_BROWSER_SQL_TABLE_BUILDER_H_
#define COMPONENTS_AFFILIATIONS_CORE_BROWSER_SQL_TABLE_BUILDER_H_
#include <limits>
#include <string>
#include <string_view>
#include <vector>
#include "base/functional/callback_helpers.h"
namespace sql {
class Database;
}
namespace affiliations {
// Use this class to represent the versioned evolution of a SQLite table
// structure and generate creating and migrating statements for it.
//
// Usage example:
//
// SQLTableBuilder builder("logins");
//
// // First describe a couple of versions:
// builder.AddColumnToPrimaryKey("id", "INTEGER");
// builder.AddColumn("name", "VARCHAR");
// builder.AddColumn("icon", "VARCHAR");
// builder.AddColumn("password", "VARCHAR NOT NULL");
// unsigned version = builder.SealVersion(); // Version 0 is sealed.
// DCHECK_EQ(0u, version);
// builder.RenameColumn("icon", "avatar");
// version = builder.SealVersion(); // Version 1 is sealed.
// DCHECK_EQ(1u, version);
//
// // Now, assuming that |db| has a table "logins" in a state corresponding
// // version 0, this will migrate it to the latest version:
// sql::Database* db = ...;
// builder.MigrateFrom(0, db);
//
// // And assuming |db| has no table called "logins", this will create one
// // in a state corresponding the latest sealed version:
// builder.CreateTable(db);
class SQLTableBuilder {
public:
// Create the builder for an arbitrary table name.
explicit SQLTableBuilder(const std::string& table_name);
SQLTableBuilder(const SQLTableBuilder& rhs) = delete;
SQLTableBuilder& operator=(const SQLTableBuilder& rhs) = delete;
~SQLTableBuilder();
// Adds a column in the table description, with |name| and |type|. |name|
// must not have been added to the table in this version before.
void AddColumn(std::string name, std::string type);
// As AddColumn but also adds column |name| to the primary key of the table.
// The column must be of type "INTEGER" and will be AUTO INCREMENT. This
// method can be called only once.
void AddPrimaryKeyColumn(std::string name);
// As AddColumn but also adds column |name| to the unique key of the table.
void AddColumnToUniqueKey(std::string name, std::string type);
// As AddColumn but also adds column |name| to the unique key of the table.
// The column |name| is a foreign key to 'parent_table' and an implicit index
// is created.
void AddColumnToUniqueKey(std::string name,
std::string type,
std::string parent_table,
std::string index_name);
// Renames column |old_name| to |new_name|. |new_name| can not exist already.
// |old_name| must have been added in the past. Furthermore, there must be no
// index in this version referencing |old_name|.
void RenameColumn(const std::string& old_name, const std::string& new_name);
// Removes column |name|. |name| must have been added in the past.
// Furthermore, there must be no index in this version referencing |name|.
void DropColumn(const std::string& name);
// Adds an index in the table description, with |name| and on columns
// |columns|. |name| must not have been added to the table in this version
// before. Furthermore, |columns| must be non-empty, and every column
// referenced in |columns| must be unique and exist in the current version.
void AddIndex(std::string name, std::vector<std::string> columns);
// Increments the internal version counter and marks the current state of the
// table as that version. Returns the sealed version. Calling any of the
// *Column* and *Index* methods above will result in starting a new version
// which is not considered sealed.
unsigned SealVersion();
// Assuming that the database connected through |db| contains a table called
// |table_name_| in a state described by version |old_version|, migrates it to
// the current version, which must be sealed. Returns true on success.
// |post_migration_step_callback| is executed after each migration step in to
// allow the calling site to inject custom logic to run upon each migration
// step from |old_version| to the current version. The passed parameter
// corresponds to database to be migrated and the new version number that has
// been reached after the migration step. |post_migration_step_callback|
// returns true on success, otherwise the migration is aborted.
bool MigrateFrom(
unsigned old_version,
sql::Database* db,
const base::RepeatingCallback<bool(sql::Database*, unsigned)>&
post_migration_step_callback = base::NullCallback()) const;
// If |db| connects to a database where table |table_name_| already exists,
// this is a no-op and returns true. Otherwise, |table_name_| is created in a
// state described by the current version known to the builder. The current
// version must be sealed. Returns true on success. At least one call
// to AddColumnToUniqueKey must have been done before this is called the first
// time.
bool CreateTable(sql::Database* db) const;
// Returns the comma-separated list of all column names present in the last
// version. The last version must be sealed.
std::string ListAllColumnNames() const;
// Same as ListAllColumnNames, but for non-unique key names only (i.e. keys
// that are part of neither the PRIMARY KEY nor the UNIQUE constraint), and
// with names followed by " = ?".
std::string ListAllNonuniqueKeyNames() const;
// Same as ListAllNonuniqueKeyNames, but for unique key names without the
// primary key names and separated by " AND ".
std::string ListAllUniqueKeyNames() const;
// Returns a vector of all PRIMARY KEY names that are present in the last
// version. The last version must be sealed.
std::vector<std::string_view> AllPrimaryKeyNames() const;
// Returns the number of all columns present in the last version. The last
// version must be sealed.
size_t NumberOfColumns() const;
// Returns the table name.
std::string TableName() const;
private:
// Stores the information about one column (name, type, etc.).
struct Column;
// Stores the information about one index (name, columns, etc.).
struct Index;
static unsigned constexpr kInvalidVersion =
std::numeric_limits<unsigned>::max();
// Computes the SQL CREATE TABLE constraints for given |version|.
std::string ComputeConstraints(unsigned version) const;
// Assuming that the database connected through |db| contains a table called
// |table_name_| in a state described by version |old_version|, migrates it to
// version |old_version + 1|. The current version known to the builder must be
// at least |old_version + 1| and sealed. Returns true on success.
bool MigrateToNextFrom(unsigned old_version, sql::Database* db) const;
// Assuming that the database connected through |db| contains a table called
// |table_name_| in a state described by version |old_version|, migrates it
// indices to version |old_version + 1|. The current version known to the
// builder must be at least |old_version + 1| and sealed. Returns true on
// success.
bool MigrateIndicesToNextFrom(unsigned old_version, sql::Database* db) const;
// Looks up column named |name| in |columns_|. If present, returns the last
// one.
std::vector<Column>::reverse_iterator FindLastColumnByName(
const std::string& name);
// Looks up index named |name| in |indices_|. If present, returns the last
// one.
std::vector<Index>::reverse_iterator FindLastIndexByName(
const std::string& name);
// Returns whether the last version is |version| and whether it was sealed
// (by calling SealVersion with no table modifications afterwards).
bool IsVersionLastAndSealed(unsigned version) const;
// Whether |column| is present in the last version. The last version must be
// sealed.
bool IsColumnInLastVersion(const Column& column) const;
// Whether |index| is present in the last version. The last version must be
// sealed.
bool IsIndexInLastVersion(const Index& index) const;
// Last sealed version, kInvalidVersion means "none".
unsigned sealed_version_ = kInvalidVersion;
std::vector<Column> columns_; // Columns of the table, across all versions.
std::vector<Index> indices_; // Indices of the table, across all versions.
// The name of the table.
const std::string table_name_;
};
} // namespace affiliations
#endif // COMPONENTS_AFFILIATIONS_CORE_BROWSER_SQL_TABLE_BUILDER_H_
|