Add migrations for the whole schema

This commit is contained in:
Paul Bienkowski 2022-04-02 12:26:19 +02:00
parent 850b907995
commit 959cb7d2b7
12 changed files with 386 additions and 34 deletions

View file

@ -5,6 +5,22 @@ Simple migrations, e.g. for adding schema changes, are not documented
explicitly. Their general usage is described in the [README](./README.md) (for
development) and [deployment/README.md](deployment/README.md) (for production).
## 0.5.2
**Make sure to upgrade to `0.5.1` first, by checking out that version tag and
running migrations, then coming back to this version.** This is required
because the migrations have been edited to create the initial database schema,
but if you run the 0.5.1 migrations first, your database will remember that it
already has all the tables created. This is not required if you set up a new
installation.
For this update, run these steps:
- Build new images
- Stop portal and worker services
- Migrate with alembic (see note above, this should be a no-op if done right)
- Start portal and worker services
## 0.5.0
The upgrade requires the following steps in the given order

16
api/migrations/utils.py Normal file
View file

@ -0,0 +1,16 @@
import sqlalchemy as sa
def dbtype(name):
"""
Create a UserDefinedType for use in migrations as the type of a column,
when the type already exists in the database, but isn't available as a
proper sqlalchemy type.
"""
class TheType(sa.types.UserDefinedType):
def get_col_spec(self):
return name
TheType.__name__ = name
return TheType

View file

@ -0,0 +1,36 @@
"""create table road
Revision ID: 35e7f1768f9b
Revises: 5d75febe2d59
Create Date: 2022-03-30 21:36:48.157457
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from migrations.utils import dbtype
# revision identifiers, used by Alembic.
revision = "35e7f1768f9b"
down_revision = "920aed1450c9"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"road",
sa.Column(
"way_id", sa.BIGINT, autoincrement=True, primary_key=True, index=True
),
sa.Column("zone", dbtype("zone_type")),
sa.Column("name", sa.String),
sa.Column("geometry", dbtype("GEOMETRY"), index=True),
sa.Column("directionality", sa.Integer),
sa.Column("oenway", sa.Boolean),
)
def downgrade():
op.drop_table("road")

View file

@ -0,0 +1,28 @@
"""create extensions
Revision ID: 3856f240bb6d
Revises: a9627f63fbed
Create Date: 2022-03-30 21:31:06.282725
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "3856f240bb6d"
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.execute('CREATE EXTENSION IF NOT EXISTS "hstore";')
op.execute('CREATE EXTENSION IF NOT EXISTS "postgis";')
op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')
def downgrade():
op.execute('DROP EXTENSION "hstore";')
op.execute('DROP EXTENSION "postgis";')
op.execute('DROP EXTENSION "uuid-ossp";')

View file

@ -0,0 +1,43 @@
"""create table overtaking_event
Revision ID: 5d75febe2d59
Revises: 920aed1450c9
Create Date: 2022-03-30 21:36:37.687080
"""
from alembic import op
import sqlalchemy as sa
from migrations.utils import dbtype
# revision identifiers, used by Alembic.
revision = "5d75febe2d59"
down_revision = "9336eef458e7"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"overtaking_event",
sa.Column("id", sa.Integer, autoincrement=True, primary_key=True, index=True),
sa.Column(
"track_id", sa.Integer, sa.ForeignKey("track.id", ondelete="CASCADE")
),
sa.Column("hex_hash", sa.String, unique=True, index=True),
sa.Column("way_id", sa.BIGINT, index=True),
sa.Column("direction_reversed", sa.Boolean),
sa.Column("geometry", dbtype("GEOMETRY")),
sa.Column("latitude", sa.Float),
sa.Column("longitude", sa.Float),
sa.Column("time", sa.DateTime),
sa.Column("distance_overtaker", sa.Float),
sa.Column("distance_stationary", sa.Float),
sa.Column("course", sa.Float),
sa.Column("speed", sa.Float),
sa.Index("road_segment", "way_id", "direction_reversed"),
)
def downgrade():
op.drop_table("overtaking_event")

View file

@ -0,0 +1,31 @@
"""create enum processing_status
Revision ID: 920aed1450c9
Revises: 986c6953e431
Create Date: 2022-03-30 21:36:25.896192
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "920aed1450c9"
down_revision = "986c6953e431"
branch_labels = None
depends_on = None
def _get_enum_type():
return postgresql.ENUM(
"created", "queued", "processing", "complete", "error", name="processing_status"
)
def upgrade():
_get_enum_type().create(op.get_bind(), checkfirst=True)
def downgrade():
_get_enum_type().drop(op.get_bind())

View file

@ -0,0 +1,42 @@
"""create table comment
Revision ID: 9336eef458e7
Revises: 9d8c8c38a1d0
Create Date: 2022-03-30 21:37:02.080429
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID
# revision identifiers, used by Alembic.
revision = "9336eef458e7"
down_revision = "d66baafab5ec"
branch_labels = None
depends_on = None
def upgrade():
NOW = sa.text("NOW()")
op.create_table(
"comment",
sa.Column("id", sa.Integer, autoincrement=True, primary_key=True),
sa.Column("uid", UUID, server_default=sa.func.uuid_generate_v4()),
sa.Column("created_at", sa.DateTime, nullable=False, server_default=NOW),
sa.Column(
"updated_at", sa.DateTime, nullable=False, server_default=NOW, onupdate=NOW
),
sa.Column("body", sa.TEXT),
sa.Column(
"author_id", sa.Integer, sa.ForeignKey("user.id", ondelete="CASCADE")
),
sa.Column(
"track_id", sa.Integer, sa.ForeignKey("track.id", ondelete="CASCADE")
),
)
def downgrade():
op.drop_table("comment")

View file

@ -0,0 +1,29 @@
"""create enum zone_type
Revision ID: 986c6953e431
Revises: 3856f240bb6d
Create Date: 2022-03-30 21:36:19.888268
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "986c6953e431"
down_revision = "3856f240bb6d"
branch_labels = None
depends_on = None
def _get_enum_type():
return postgresql.ENUM("rural", "urban", "motorway", name="zone_type")
def upgrade():
_get_enum_type().create(op.get_bind(), checkfirst=True)
def downgrade():
_get_enum_type().drop(op.get_bind())

View file

@ -0,0 +1,45 @@
"""create table user
Revision ID: 9d8c8c38a1d0
Revises: d66baafab5ec
Create Date: 2022-03-30 21:36:59.375149
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "9d8c8c38a1d0"
down_revision = "35e7f1768f9b"
branch_labels = None
depends_on = None
def upgrade():
NOW = sa.text("NOW()")
op.create_table(
"user",
sa.Column("id", sa.Integer, autoincrement=True, primary_key=True),
sa.Column("created_at", sa.DateTime, nullable=False, server_default=NOW),
sa.Column(
"updated_at", sa.DateTime, nullable=False, server_default=NOW, onupdate=NOW
),
sa.Column("sub", sa.String, unique=True, nullable=False),
sa.Column("username", sa.String, unique=True, nullable=False),
sa.Column("email", sa.String, nullable=False),
sa.Column("bio", sa.TEXT),
sa.Column("image", sa.String),
sa.Column(
"are_tracks_visible_for_all",
sa.Boolean,
server_default=sa.false(),
nullable=False,
),
sa.Column("api_key", sa.String),
sa.Column("match_by_username_email", sa.Boolean, server_default=sa.false()),
)
def downgrade():
op.drop_table("user")

View file

@ -1,34 +0,0 @@
"""create road_usage table
Revision ID: a9627f63fbed
Revises:
Create Date: 2022-03-16 20:26:17.449569
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy import Column, Integer, String, ForeignKey, Index, DateTime, Boolean
from sqlalchemy.types import BIGINT
# revision identifiers, used by Alembic.
revision = "a9627f63fbed"
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"road_usage",
Column("id", Integer, autoincrement=True, primary_key=True, index=True),
Column("track_id", Integer, ForeignKey("track.id", ondelete="CASCADE")),
Column("hex_hash", String, unique=True, index=True),
Column("way_id", BIGINT, index=True),
Column("time", DateTime),
Column("direction_reversed", Boolean),
Index("road_usage_segment", "way_id", "direction_reversed"),
)
def downgrade():
op.drop_table("road_usage")

View file

@ -0,0 +1,34 @@
"""create table road_usage
Revision ID: a9627f63fbed
Revises:
Create Date: 2022-03-16 20:26:17.449569
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "a9627f63fbed"
down_revision = "5d75febe2d59"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"road_usage",
sa.Column("id", sa.Integer, autoincrement=True, primary_key=True, index=True),
sa.Column(
"track_id", sa.Integer, sa.ForeignKey("track.id", ondelete="CASCADE")
),
sa.Column("hex_hash", sa.String, unique=True, index=True),
sa.Column("way_id", sa.BIGINT, index=True),
sa.Column("time", sa.DateTime),
sa.Column("direction_reversed", sa.Boolean),
sa.Index("road_usage_segment", "way_id", "direction_reversed"),
)
def downgrade():
op.drop_table("road_usage")

View file

@ -0,0 +1,66 @@
"""create table track
Revision ID: d66baafab5ec
Revises: 35e7f1768f9b
Create Date: 2022-03-30 21:36:54.848452
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from migrations.utils import dbtype
# revision identifiers, used by Alembic.
revision = "d66baafab5ec"
down_revision = "9d8c8c38a1d0"
branch_labels = None
depends_on = None
def upgrade():
NOW = sa.text("NOW()")
op.create_table(
"track",
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
sa.Column("slug", sa.String, unique=True, nullable=False, index=True),
sa.Column("created_at", sa.DateTime, nullable=False, server_default=NOW),
sa.Column(
"updated_at", sa.DateTime, nullable=False, server_default=NOW, onupdate=NOW
),
sa.Column("title", sa.String),
sa.Column(
"processing_status",
dbtype("processing_status"),
server_default=sa.literal("created"),
),
sa.Column("processing_queued_at", sa.DateTime),
sa.Column("processed_at", sa.DateTime),
sa.Column("processing_log", sa.TEXT),
sa.Column(
"customized_title", sa.Boolean, server_default=sa.false(), nullable=False
),
sa.Column("description", sa.TEXT),
sa.Column("public", sa.Boolean, server_default=sa.false()),
sa.Column("uploaded_by_user_agent", sa.String),
sa.Column("original_file_name", sa.String),
sa.Column("original_file_hash", sa.String, nullable=False),
sa.Column(
"author_id",
sa.Integer,
sa.ForeignKey("user.id", ondelete="CASCADE"),
nullable=False,
),
sa.Column("recorded_at", sa.DateTime),
sa.Column("recorded_until", sa.DateTime),
sa.Column("duration", sa.Float),
sa.Column("length", sa.Float),
sa.Column("segments", sa.Integer),
sa.Column("num_events", sa.Integer),
sa.Column("num_measurements", sa.Integer),
sa.Column("num_valid", sa.Integer),
)
def downgrade():
op.drop_table("track")