* Add tests for the `roll` package to ensure that the new versioned
schema is created on `start` and removed on `rollback`. We already had a
test there to ensure the previous versioned schema is dropped on
`complete`.
* Remove parts of tests for the create table operation that concerned
themselves with checking for the existence/non-existence of the
versioned schema. That is now tested in the `roll` package and we want
the tests for each operation to be focussed on the operation itself, not
schema creation.
* Add one more test for the create table operation to ensure that the
view for the new table is usable after `complete` (we already had a test
to ensure that it's usable on `start`).
Close https://github.com/xataio/pg-roll/issues/15.
Qualify versioned schema with the name of the schema they represent.
For a migration called `01_create_table` running in the `public` schema,
the versioned schema is called `public_01_create_table`.
This change will retrieve and store the resulting schema after a
migration is completed. This schema will be used as the base to execute
the next migration, making it possible to create views that are aware of
the full schema, and not only the one created by the last migration.
We use a function to retrieve the schema directly from Postgres instead
of building it from the migration files. This allows for more features
in the future, like doing an initial sync on top of the existing schema
or automatically detecting and storing out of band migrations from
triggers.
Example JSON stored schema:
```
{
"tables": {
"bills": {
"oid": "18272",
"name": "bills",
"columns": {
"id": {
"name": "id",
"type": "integer",
"comment": null,
"default": null,
"nullable": false
},
"date": {
"name": "date",
"type": "time with time zone",
"comment": null,
"default": null,
"nullable": false
},
"quantity": {
"name": "quantity",
"type": "integer",
"comment": null,
"default": null,
"nullable": false
}
},
"comment": null
},
"products": {
"oid": "18286",
"name": "products",
"columns": {
"id": {
"name": "id",
"type": "integer",
"comment": null,
"default": "nextval(_pgroll_new_products_id_seq::regclass)",
"nullable": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"comment": null,
"default": null,
"nullable": false
},
"price": {
"name": "price",
"type": "numeric(10,2)",
"comment": null,
"default": null,
"nullable": false
}
},
"comment": null
},
"customers": {
"oid": "18263",
"name": "customers",
"columns": {
"id": {
"name": "id",
"type": "integer",
"comment": null,
"default": null,
"nullable": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"comment": null,
"default": null,
"nullable": false
},
"credit_card": {
"name": "credit_card",
"type": "text",
"comment": null,
"default": null,
"nullable": true
}
},
"comment": null
}
}
}
```
After this change, I believe that the `create_table` operation is
feature complete and can be used for many sequential migrations.
Add a sentinel error `ErrNoActiveMigration` for the case where there is
no active migration. This improves the error strings presented to users
by not mentioning SQL errors.
**`pg-roll start` when there is a migration in progess:**
```
Error: a migration for schema "public" is already in progress
```
**`pg-roll rollback` when there is no migration in progress:**
```
Error: unable to get active migration: no active migration
```
**`pg-complete` when there is no active migration:**
```
Error: unable to get active migration: no active migration
```
This migrations introduces state handling by creating a dedicated
`pgroll` schema (name configurable). We will store migrations there, as
well as their state. So we keep some useful information, ie the
migration definition (so we don't need it for the `complete` state).
Schema includes the proper constraints to guarantee that:
* Only a migration is active at a time
* Migration history is linear (all migrations have a unique parent,
except the first one which is NULL)
* We now the current migration at all times
Some helper functions are included:
* `is_active_migration_period()` will return true if there is an active
migration.
* `latest_version()` will return the name of the latest version of the
schema.
Add a `rollback` command to the CLI.
Use the rollback functionality added to the `migrations` package in #5
to perform the rollback.
Example:
```bash
go run . start examples/01_create_tables.json
go run . rollback examples/01_create_tables.json
```
The schema for the `01_create_table` version is removed from the
database along with the underlying tables.
⚠️ We currently don't have a way to ensure that only uncompleted
migrations can be rolled back. Once we have some state in the db
recording with migrations have been applied, we can revisit this command
to ensure completed migrations can't be rolled back ⚠️
Implement rollbacks for the create table operation.
* Delete the new version of the schema and any views it contains.
* Drop the tables created by the operations.
Add an integration test to check that these resources are successfully
dropped.
This PR adds the rollback operation to the `migrations` package;
supporting the operation through the CLI will be in a later PR.