You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: GRDB/Documentation.docc/Migrations.md
+53-54Lines changed: 53 additions & 54 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,13 +14,16 @@ You setup migrations in a ``DatabaseMigrator`` instance. For example:
14
14
var migrator =DatabaseMigrator()
15
15
16
16
// 1st migration
17
-
migrator.registerMigration("createLibrary") { db in
17
+
migrator.registerMigration("Create authors") { db in
18
18
try db.create(table: "author") { t in
19
19
t.autoIncrementedPrimaryKey("id")
20
20
t.column("creationDate", .datetime)
21
21
t.column("name", .text)
22
22
}
23
+
}
23
24
25
+
// 2nd migration
26
+
migrator.registerMigration("Add books and author.birthYear") { db in
24
27
try db.create(table: "book") { t in
25
28
t.autoIncrementedPrimaryKey("id")
26
29
t.column("authorId", .integer)
@@ -29,10 +32,7 @@ migrator.registerMigration("createLibrary") { db in
29
32
.references("author", onDelete: .cascade)
30
33
t.column("title", .text).notNull()
31
34
}
32
-
}
33
35
34
-
// 2nd migration
35
-
migrator.registerMigration("AddBirthYearToAuthors") { db in
36
36
try db.alter(table: "author") { t
37
37
t.add(column: "birthYear", .integer)
38
38
}
@@ -83,14 +83,55 @@ try dbQueue.read { db in
83
83
84
84
**The memory of applied migrations is stored in the database itself** (in a reserved table).
85
85
86
+
## Defining the Database Schema
87
+
88
+
SQLite directly supports a [limited set of schema alterations](https://www.sqlite.org/lang.html). Many of them are available as `Database` methods such as ``Database/create(table:options:body:)``, ``Database/alter(table:body:)``, etc.
89
+
90
+
> Tip: When you use a Swift API instead of a raw SQL query, GRDB can check its availability on the SQLite version that ships on the target operating system.
91
+
92
+
Other changes to the schema are still possible, by recreating tables. For example:
93
+
94
+
```swift
95
+
migrator.registerMigration("Add NOT NULL check on author.name") { db in
96
+
try db.create(table: "new_author") { t in
97
+
t.autoIncrementedPrimaryKey("id")
98
+
t.column("creationDate", .datetime)
99
+
t.column("name", .text).notNull()
100
+
}
101
+
try db.execute(sql: "INSERT INTO new_author SELECT * FROM author")
102
+
try db.drop(table: "author")
103
+
try db.rename(table: "new_author", to: "author")
104
+
}
105
+
```
106
+
107
+
This technique is described in the [Making Other Kinds Of Table Schema Changes](https://www.sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes) section of the SQLite documentation.
108
+
109
+
The detailed sequence of operations for recreating a database table is:
110
+
111
+
1. Remember the format of all indexes, triggers, and views associated with table X. This information will be needed in step 5 below. One way to do this is to run a query like the following: `SELECT type, sql FROM sqlite_schema WHERE tbl_name='X'`.
112
+
113
+
2. Use `CREATE TABLE` to construct a new table "new_X" that is in the desired revised format of table X. Make sure that the name "new_X" does not collide with any existing table name, of course.
114
+
115
+
2. Transfer content from X into new_X using a statement like: `INSERT INTO new_X SELECT ... FROM X`.
116
+
117
+
3. Drop the old table X: `DROP TABLE X`.
118
+
119
+
4. Change the name of new_X to X using: `ALTER TABLE new_X RENAME TO X`.
120
+
121
+
5. Use `CREATE INDEX`, `CREATE TRIGGER`, and `CREATE VIEW` to reconstruct indexes, triggers, and views associated with table X. Perhaps use the old format of the triggers, indexes, and views saved from step 3 above as a guide, making changes as appropriate for the alteration.
122
+
123
+
6. If any views refer to table X in a way that is affected by the schema change, then drop those views using `DROP VIEW` and recreate them with whatever changes are necessary to accommodate the schema change using `CREATE VIEW`.
124
+
125
+
> Important: When recreating a table, be sure to follow the above procedure exactly, in the given order, or you might corrupt triggers, views, and foreign key constraints.
126
+
86
127
## Good Practices for Defining Migrations
87
128
88
129
**A good migration is a migration that is never modified once it has shipped.**
89
130
90
131
It is must easier to control the schema of all databases deployed on users' devices when migrations define a stable timeline of schema versions. For this reason, it is recommended that migrations define the database schema with **strings**:
91
132
92
133
```swift
93
-
migrator.registerMigration("createLibrary") { db in
134
+
migrator.registerMigration("Create authors") { db in
94
135
// 👍 RECOMMENDED
95
136
try db.create(table: "author") { t in
96
137
t.autoIncrementedPrimaryKey("id")
@@ -120,7 +161,7 @@ Setting ``DatabaseMigrator/eraseDatabaseOnSchemaChange`` is useful during applic
120
161
121
162
> Warning: This option can destroy your precious users' data!
122
163
123
-
It is recommended that this option does not ship in the released application. Hide it behind `#if DEBUG`:
164
+
It is recommended that this option does not ship in the released application: hide it behind `#if DEBUG` as below.
SQLite directly supports a [limited set of schema alterations](https://www.sqlite.org/lang.html). Many of them are available as `Database` methods such as ``Database/create(table:options:body:)``, etc.
136
-
137
-
> You should prefer the Swift API, because GRDB only enables apis that are available on SQLite version that ships on the target operating system.
138
-
139
-
Arbitrary changes to the schema design of any table are still possible, by recreating the table. For example:
140
-
141
-
```swift
142
-
migrator.registerMigration("Add NOT NULL check on author.name") { db in
143
-
try db.create(table: "new_author") { t in
144
-
t.autoIncrementedPrimaryKey("id")
145
-
t.column("creationDate", .datetime)
146
-
t.column("name", .text).notNull()
147
-
}
148
-
try db.execute(sql: "INSERT INTO new_author SELECT * FROM author")
149
-
try db.drop(table: "author")
150
-
try db.rename(table: "new_author", to: "author")
151
-
}
152
-
```
153
-
154
-
This technique is described in the [Making Other Kinds Of Table Schema Changes](https://www.sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes) section of the SQLite documentation.
155
-
156
-
The detailed sequence of operations for recreating a database table is:
157
-
158
-
1. Remember the format of all indexes, triggers, and views associated with table X. This information will be needed in step 5 below. One way to do this is to run a query like the following: `SELECT type, sql FROM sqlite_schema WHERE tbl_name='X'`.
159
-
160
-
2. Use `CREATE TABLE` to construct a new table "new_X" that is in the desired revised format of table X. Make sure that the name "new_X" does not collide with any existing table name, of course.
161
-
162
-
2. Transfer content from X into new_X using a statement like: `INSERT INTO new_X SELECT ... FROM X`.
163
-
164
-
3. Drop the old table X: `DROP TABLE X`.
165
-
166
-
4. Change the name of new_X to X using: `ALTER TABLE new_X RENAME TO X`.
167
-
168
-
5. Use `CREATE INDEX`, `CREATE TRIGGER`, and `CREATE VIEW` to reconstruct indexes, triggers, and views associated with table X. Perhaps use the old format of the triggers, indexes, and views saved from step 3 above as a guide, making changes as appropriate for the alteration.
169
-
170
-
6. If any views refer to table X in a way that is affected by the schema change, then drop those views using `DROP VIEW` and recreate them with whatever changes are necessary to accommodate the schema change using `CREATE VIEW`.
171
-
172
-
> Warning: Be sure to follow the above procedure exactly, in the given order, or you might corrupt triggers, views, and foreign key constraints.
173
-
174
174
## Foreign Key Checks
175
175
176
-
The technique described in the previous <doc:Migrations#Advanced-Database-Schema-Changes> chapter creates very undesired churn w.r.t. foreign keys:
177
-
by default, each migration temporarily disables foreign keys, and performs a full check of all foreign keys in the database before it is committed on disk.
176
+
By default, each migration temporarily disables foreign keys, and performs a full check of all foreign keys in the database before it is committed on disk.
178
177
179
178
When the database becomes very big, those checks may have a noticeable impact on migration performances. You'll know this by profiling migrations, and looking for the time spent in the `checkForeignKeys` method.
180
179
@@ -188,7 +187,7 @@ When you register a migration with `.immediate` foreign key checks, the migratio
188
187
migrator.registerMigration("Faster migration", foreignKeyChecks: .immediate) { db in... }
189
188
```
190
189
191
-
Such a migration is much faster, and it still guarantees database integrity. But it must only execute schema alterations directly supported by SQLite. Migrations that recreate tables as described in <doc:Migrations#Advanced-Database-Schema-Changes>**must not** run with immediate foreign keys checks. You'll need to use the second mitigation technique:
190
+
Such a migration is much faster, and it still guarantees database integrity. But it must only execute schema alterations directly supported by SQLite. Migrations that recreate tables as described in <doc:Migrations#Defining-the-Database-Schema>**must not** run with immediate foreign keys checks. You'll need to use the second mitigation technique:
192
191
193
192
**Your second mitigation technique is to disable deferred foreign key checks.**
In order to prevent foreign key violations from being committed to disk, you can:
204
203
205
-
- Register migrations with immediate foreign key checks, as long as they do not recreate tables as described in <doc:Migrations#Advanced-Database-Schema-Changes>:
204
+
- Register migrations with immediate foreign key checks, as long as they do not recreate tables as described in <doc:Migrations#Defining-the-Database-Schema>:
0 commit comments