Skip to content

Commit 14c00e1

Browse files
committed
update enrollment docs
1 parent 7140fbd commit 14c00e1

File tree

1 file changed

+51
-19
lines changed

1 file changed

+51
-19
lines changed

docsrc/enrolling.qmd

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,68 @@ title: "Enrolling an existing db"
33
order: 2
44
---
55

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
77

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.
99

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.
1111

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.
1313

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.
1519

16-
But if you are enrolling an existing db into fastmigrate, then you need to do three things.
20+
``` python
21+
import fastmigrate
22+
fastmigrate.create_db("/path/to/database.db")
23+
fastmigrate.run_migrations("/path/to/database.db")
24+
# application code continues from here
25+
```
1726

18-
- 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.
1930

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 is correct, and your can move your real database back into place.
2132

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.
2334

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 long as 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) is 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`).*
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.
2746

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 not 100% automatic?
52+
53+
The tool generates the migration script based on the _schema_ of your existing database. In many cases, that is all that matters for defining the version of a database, because the schema is all 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+
CREATE TABLE user (id INTEGER, settings TEXT);
3261
```
3362

34-
- Third, update your application code.
63+
But if your application code also required that the database start with one row in that table, defining a user with an ID of 1 and settings which were an empty pair of brances, then you would also add a line like so:
3564

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+
INSERT INTO user VALUES (1, 0, '{}');
67+
```
68+
69+
This subltety is a reason why it is not 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.
3870

0 commit comments

Comments
 (0)