diff --git a/UPGRADING.md b/UPGRADING.md index 1ad5426..2e599eb 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -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 diff --git a/api/migrations/utils.py b/api/migrations/utils.py new file mode 100644 index 0000000..021e12c --- /dev/null +++ b/api/migrations/utils.py @@ -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 diff --git a/api/migrations/versions/35e7f1768f9b_create_table_road.py b/api/migrations/versions/35e7f1768f9b_create_table_road.py new file mode 100644 index 0000000..17d2582 --- /dev/null +++ b/api/migrations/versions/35e7f1768f9b_create_table_road.py @@ -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") diff --git a/api/migrations/versions/3856f240bb6d_create_extensions.py b/api/migrations/versions/3856f240bb6d_create_extensions.py new file mode 100644 index 0000000..f4dd489 --- /dev/null +++ b/api/migrations/versions/3856f240bb6d_create_extensions.py @@ -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";') diff --git a/api/migrations/versions/5d75febe2d59_create_table_overtaking_event.py b/api/migrations/versions/5d75febe2d59_create_table_overtaking_event.py new file mode 100644 index 0000000..2bb96b8 --- /dev/null +++ b/api/migrations/versions/5d75febe2d59_create_table_overtaking_event.py @@ -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") diff --git a/api/migrations/versions/920aed1450c9_create_enum_processing_status.py b/api/migrations/versions/920aed1450c9_create_enum_processing_status.py new file mode 100644 index 0000000..99c57b0 --- /dev/null +++ b/api/migrations/versions/920aed1450c9_create_enum_processing_status.py @@ -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()) diff --git a/api/migrations/versions/9336eef458e7_create_table_comment.py b/api/migrations/versions/9336eef458e7_create_table_comment.py new file mode 100644 index 0000000..6fa7d82 --- /dev/null +++ b/api/migrations/versions/9336eef458e7_create_table_comment.py @@ -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") diff --git a/api/migrations/versions/986c6953e431_create_enum_zone_type.py b/api/migrations/versions/986c6953e431_create_enum_zone_type.py new file mode 100644 index 0000000..341b12f --- /dev/null +++ b/api/migrations/versions/986c6953e431_create_enum_zone_type.py @@ -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()) diff --git a/api/migrations/versions/9d8c8c38a1d0_create_table_user.py b/api/migrations/versions/9d8c8c38a1d0_create_table_user.py new file mode 100644 index 0000000..79dbf08 --- /dev/null +++ b/api/migrations/versions/9d8c8c38a1d0_create_table_user.py @@ -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") diff --git a/api/migrations/versions/a9627f63fbed_create_road_usage_table.py b/api/migrations/versions/a9627f63fbed_create_road_usage_table.py deleted file mode 100644 index cfbf302..0000000 --- a/api/migrations/versions/a9627f63fbed_create_road_usage_table.py +++ /dev/null @@ -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") diff --git a/api/migrations/versions/a9627f63fbed_create_table_road_usage.py b/api/migrations/versions/a9627f63fbed_create_table_road_usage.py new file mode 100644 index 0000000..508501d --- /dev/null +++ b/api/migrations/versions/a9627f63fbed_create_table_road_usage.py @@ -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") diff --git a/api/migrations/versions/d66baafab5ec_create_table_track.py b/api/migrations/versions/d66baafab5ec_create_table_track.py new file mode 100644 index 0000000..68ba3f8 --- /dev/null +++ b/api/migrations/versions/d66baafab5ec_create_table_track.py @@ -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")