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: docsrc/enrolling.qmd
+51-19Lines changed: 51 additions & 19 deletions
Original file line number
Diff line number
Diff line change
@@ -3,36 +3,68 @@ title: "Enrolling an existing db"
3
3
order: 2
4
4
---
5
5
6
-
If you use fastmigrate with valid migration scripts, fastmigrate can guarantee the version of your database presented to your application code. This is the value of managed migrations.
6
+
## Enroll an existing db
7
7
8
-
However, to provide this guarantee, you need your database to be managed by fastmigrate. If you created the database with fastmigrate (using `create_db` or the `fastmigrate_create_db` CLI command), then it is managed.
8
+
Here's how to add an existing db to be managed by fastmigrate.
9
9
10
-
But what if you are starting with an application built outside of fastmigrate, and you want to _enroll_ the database in fastmigrate? Here is how to think about it, and how to do it correctly:
10
+
0. Back up your database, of course.
11
11
12
-
To clarify the background: the key invariant which we need to maintain is this: *any database which has a fastmigrate version number (like 1, or like 3) is exactly in the state which would be produced by the migration script with that version number (like by `0001-initialize.sql` or `0003-unify-users.sql`).*
12
+
1. Run `fastmigrate_enroll_db --db /path/to/database.db` against your current database.
13
13
14
-
Now if you create a db with fastmigrate, it is created with version 0, and the version only advances as a result of running migration scripts. So this maintains the invariant.
14
+
This will modify your database, marking it as version 1 by adding a `_meta` table.
15
+
16
+
It will also generate an initial migration script, `0001-initialize.sql`, which is for creating an empty "version 1" database with the same schema as your current database.
17
+
18
+
2. Move your current database to somewhere safe, update your application's db setup code to use fastmigrate, and run it.
15
19
16
-
But if you are enrolling an existing db into fastmigrate, then you need to do three things.
- First, write a migration script `0001-initialize.sql` which will produce the schema of the database which you are working with right now.
27
+
Since you moved your real db, fastmigrate will create a new db at that path based on the initial migration script.
28
+
29
+
3. Check your app, to see if it is working fine.
19
30
20
-
Why? You need this so that, when you are starting fresh instances of your application, fastmigrate can create a database which is equivalent to what you have created now. The easiest way to create this script is to run `sqlite3 data.db .schema > 0001-initialize.sql` on your current database, which will create a sql file `0001-initialize.sql` which creates a fresh db with the same schema as your current db.
31
+
If it is, your initialization script iscorrect, and your can move your real database back into place.
21
32
22
-
This is now your first migration script. Because it matches the current state of your current database, it will not be run on your current database. But it will ensure that newly created databases match your current database.
33
+
If not, then you will need to edit that initialization script, so that it produces a database which is equivalent to your current database.
23
34
24
-
From an abundance of caution, you should use it to create a db and confirm that it is indeed equivalent to your current db.
25
-
26
-
- Second, manually modify your current data to add fastmigrate version tag and set its version to 1. You can do this by using fastmigrate's internal API. Doing this constitutes asserting that the db is in fact in the state which would be produced by the migration script 0001. After doing this, fastmigrate will recognize your db as managed. Here is how to do it:
35
+
## The reason for this procedure
36
+
37
+
As longas you use fastmigrate with valid migration scripts, fastmigrate can guarantee whch version of your database it presented to your application code. This is the value of managed migrations.
38
+
39
+
However, to provide this guarantee, you need your database to be managed by fastmigrate -- that is, to be explicitly marked with a version, in its `_meta` table. If you created the database with fastmigrate (using `create_db`or the `fastmigrate_create_db`CLI command), then it is managed.
40
+
41
+
But what if you are starting with an application built outside of fastmigrate, and you want to _enroll_ the database in fastmigrate?
42
+
43
+
To recap the basic idea of what migrations are, the fundamental guarantee which we need to maintain is this: *any database which has a fastmigrate version number (like 1, or like 3) isin the state which would be produced by the migration script with that version number (like by `0001-initialize.sql`or`0003-unify-users.sql`).*
44
+
45
+
So when enrolling an existing db, you need to assign a version to the db you already have. But since that version number takes its meaning from the migration script which _would_ produce it, you also need to create a migration script which would produce a database like yours. That script is also practically useful. If you ever want to deploy a new instance of your database, or run fresh instancs for debugging, you need that initialization script to create the initial, empty state of a db for your application to use.
27
46
28
-
```python
29
-
from fastmigrate.core import _ensure_meta_table, _set_db_version
30
-
_ensure_meta_table("path/to/data.db")
31
-
_set_db_version("path/to/data.db",1)
47
+
`fastmigrate_enroll_db`is merely a helper for those tasks. It marks your database, and generates an initialization migration script.
48
+
49
+
### One reason enrollment needs manual inspection
50
+
51
+
Why is this not100% automatic?
52
+
53
+
The tool generates the migration script based on the _schema_ of your existing database. In many cases, that isall that matters for defining the version of a database, because the schema isall that the application code depends on.
54
+
55
+
However, this will not be enough if you application requires not only a particular table schema, but also certain _initial data values_ to be present. In that case you will need to add code to your the initialization script which not only creates the necessary tables but also inserts those values.
56
+
57
+
For instance, if your application code merely required a `user` table which tracked settings, you would expect a line like this:
58
+
59
+
``` sql
60
+
CREATETABLE user (idINTEGER, settings TEXT);
32
61
```
33
62
34
-
- Third, update your application code.
63
+
But ifyour application code also required that the database start with one row in that table, defining a user with an ID of 1and settings which were an empty pair of brances, then you would also add a line like so:
35
64
36
-
You should update it so that it no longer manually creates and initializes a database if it is missing by itself (as it might do now), but instead uses fastmigrate to create the db and to run the migrations, as is shown in the readme. You should check the migration scripts into version control alongside your application code. Your application code should now all be written under the assumption that it will find the database in the state defined by the highest-numbered migration script in the repo.
37
-
65
+
``` sql
66
+
INSERTINTO user VALUES (1, 0, '{}');
67
+
```
68
+
69
+
This subltety is a reason why it isnot strictly accurate to say migrations version exist only to track schema schema. In fact, they define versions which should track what application code expects, which likely includes versions but not only versions.
0 commit comments