File: sql_table_builder.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (206 lines) | stat: -rw-r--r-- 8,672 bytes parent folder | download | duplicates (9)
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_