-
Notifications
You must be signed in to change notification settings - Fork 688
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Schema migrations #1419
Comments
Getting this done is blocking some new and frequently requested features (e.g. #1422 - the tagging of sources and submissions and #1359 - the assignment of particular users to address a given source), so I've been testing how to go about doing this in the feature branch Requirements
How it currently works
Potential IssuesWe should enumerate as many possible issues that could arise and handle them if we can:
When to migrateOne thing I'm trying to figure out is when to best attempt to perform a migration. It could be done during |
After discussion, we are going to push this until the next release. |
(Again, this requires the backing out of changes from |
I would like to add a second proposition instead of using
Also, since it's possible we might only ever support Postgres (#2225), using the SQLAlchemy automagic isn't even necessary. For example, the Rust ORM (
And the DB is versioned by the numeric prefix. I actually wrote this once for an app because we kept having problems with import os
from flask_sqlalchemy import SQLAlchemy
from os import path
from sqlalchemy import text
from sqlalchemy.exc import InternalError, OperationalError, ProgrammingError
db = SQLAlchemy()
def migrate(migrations_dir):
version = _initialize_db()
migrations = [(v, s)
for (v, s) in _list_migrations(migrations_dir)
if v > version]
for (version, sql) in migrations:
try:
db.session.execute(sql)
sql = text('UPDATE db_version SET version = :version') \
.bindparams(version=version)
db.session.execute(sql)
db.session.commit()
except Exception:
db.session.rollback()
raise
def _initialize_db() -> int:
version = None
try:
sql = text('SELECT version FROM db_version')
version = list(db.session.execute(sql))[0][0]
except (InternalError, OperationalError, ProgrammingError):
db.session.rollback()
sql = text('CREATE TABLE db_version (version INT)')
db.session.execute(sql)
if version is None:
sql = text('INSERT INTO db_version (version) VALUES (0)')
db.session.execute(sql)
version = 0
db.session.commit()
return version
def _list_migrations(migrations_dir) -> list:
migrations = []
for migration in os.listdir(migrations_dir):
full_path = path.join(migrations_dir, migration)
try:
version = int(migration.split('-')[0])
except ValueError:
continue
with open(full_path, 'r') as f:
sql = f.read()
migrations.append((version, sql))
return list(sorted(migrations, key=lambda x: x[0])) This is one of those times we have to ask about whether or not it makes sense to add a dependency or if we want to just roll our own code. This is only 60 lines of Python + SQL versus having to fiddle with a DSL to get it to generate the code we actually want. The downside to this method is that it doesn't allow arbitrary Python code in the migrations, but realistically, if you need that you're probably doing something overly complicated with your migration. i can't think of a time at work we (at work) have actually needed code for a migration. |
Pinging @redshiftzero for thoughts on this. |
I'm working on this now, and will be using Alembic. I'm also setting it up so that the first migration will optionally dump everything into Postgres if the SQLite database exists. This will cover new and existing instances. |
Blocked by #2866. |
Here's a proposed breakdown for this ticket:
|
Where do we want the database backups saved? What's the naming scheme. I propose gzipped backups as |
Also this may go in to the current PR or may be a second PR since it will be even larger than the original, but the gist is. For each revision We have a test the does all the migrations up to This would mean that every migration would need to have a set up dummy data generated for it as well some manual tests written. |
Further note. Should we do a DB downgrade when we downgrade the SD app version? This could be in the maintainer scripts. |
NB: We've moved this off the 0.7 (May 8) milestone, given that we don't think we'll have quite enough time to properly QA this for the release, but we should be able to ship it with 0.8, and will continue to work on it through this sprint and following ones. |
Some new features (e.g. #1170) are going to require schema migrations. We should integrate e.g.
sqlalchemy-migrate
to make it easier for us to make changes to the databases on the production instances.The text was updated successfully, but these errors were encountered: