From 10f6b0c0c95b1954cd9926e41bbe09fb6f6073ee Mon Sep 17 00:00:00 2001 From: gluap Date: Wed, 29 Mar 2023 23:35:23 +0200 Subject: [PATCH] make sure we generate the right geometry column type and stay with the types we had from osm2psql (and thus compatible with older installations). I believe retrofitting the migrations is OK as these were overwritten by osm2pgsql in the past anyhow. Now at least we create the schema everyone is using already. --- .../35e7f1768f9b_create_table_road.py | 7 +-- .../a049e5eb24dd_create_table_region.py | 7 +-- api/obs/api/db.py | 47 +++++++++++++++---- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/api/migrations/versions/35e7f1768f9b_create_table_road.py b/api/migrations/versions/35e7f1768f9b_create_table_road.py index 9268101..5972624 100644 --- a/api/migrations/versions/35e7f1768f9b_create_table_road.py +++ b/api/migrations/versions/35e7f1768f9b_create_table_road.py @@ -22,14 +22,15 @@ def upgrade(): op.create_table( "road", sa.Column( - "way_id", sa.BIGINT, autoincrement=True, primary_key=True, index=True + "way_id", sa.BIGINT, primary_key=True, index=True, autoincrement=False ), sa.Column("zone", dbtype("zone_type")), - sa.Column("name", sa.String), - sa.Column("geometry", dbtype("GEOMETRY"), index=True), + sa.Column("name", sa.Text), + sa.Column("geometry", dbtype("geometry(LINESTRING,3857)")), sa.Column("directionality", sa.Integer), sa.Column("oneway", sa.Boolean), ) + op.execute('CREATE INDEX ix_road_geometry ON road USING GIST (geometry) WITH (FILLFACTOR=100);') def downgrade(): diff --git a/api/migrations/versions/a049e5eb24dd_create_table_region.py b/api/migrations/versions/a049e5eb24dd_create_table_region.py index 1970967..e77f324 100644 --- a/api/migrations/versions/a049e5eb24dd_create_table_region.py +++ b/api/migrations/versions/a049e5eb24dd_create_table_region.py @@ -22,13 +22,14 @@ def upgrade(): op.create_table( "region", sa.Column( - "relation_id", sa.BIGINT, autoincrement=True, primary_key=True, index=True + "relation_id", sa.BIGINT, primary_key=True, index=True, autoincrement=False ), - sa.Column("name", sa.String), - sa.Column("geometry", dbtype("GEOMETRY"), index=True), + sa.Column("name", sa.Text), + sa.Column("geometry", dbtype("GEOMETRY(GEOMETRY,3857)"), index=False), sa.Column("admin_level", sa.Integer, index=True), sa.Column("tags", dbtype("HSTORE")), ) + op.execute('CREATE INDEX ix_region_geometry ON region USING GIST (geometry) WITH (FILLFACTOR=100);') def downgrade(): diff --git a/api/obs/api/db.py b/api/obs/api/db.py index 43d0706..b48fa53 100644 --- a/api/obs/api/db.py +++ b/api/obs/api/db.py @@ -34,6 +34,7 @@ from sqlalchemy import ( select, text, literal, + Text ) from sqlalchemy.dialects.postgresql import UUID @@ -107,6 +108,28 @@ class Geometry(UserDefinedType): return func.ST_AsGeoJSON(func.ST_Transform(col, 4326), type_=self) +class LineString(UserDefinedType): + def get_col_spec(self): + return "geometry(LineString, 3857)" + + def bind_expression(self, bindvalue): + return func.ST_GeomFromGeoJSON(bindvalue, type_=self) + + def column_expression(self, col): + return func.ST_AsGeoJSON(func.ST_Transform(col, 4326), type_=self) + + +class GeometryGeometry(UserDefinedType): + def get_col_spec(self): + return "geometry(GEOMETRY, 3857)" + + def bind_expression(self, bindvalue): + return func.ST_GeomFromGeoJSON(bindvalue, type_=self) + + def column_expression(self, col): + return func.ST_AsGeoJSON(func.ST_Transform(col, 4326), type_=self) + + class OvertakingEvent(Base): __tablename__ = "overtaking_event" __table_args__ = (Index("road_segment", "way_id", "direction_reversed"),) @@ -134,14 +157,18 @@ class OvertakingEvent(Base): class Road(Base): __tablename__ = "road" - way_id = Column(BIGINT, primary_key=True, index=True) + way_id = Column(BIGINT, primary_key=True, index=True, autoincrement=False) zone = Column(ZoneType) - name = Column(String) - geometry = Column(Geometry) + name = Column(Text) + geometry = Column(LineString) directionality = Column(Integer) oneway = Column(Boolean) import_group = Column(String) + __table_args__ = ( + Index('ix_road_geometry', 'geometry', postgresql_using='gist', postgresql_with={'fillfactor':100}), + ) + def to_dict(self): return { "way_id": self.way_id, @@ -377,7 +404,7 @@ class User(Base): api_key = Column(String) # This user can be matched by the email address from the auth service - # instead of having to match by `sub`. If a matching user logs in, the + # instead of having to match by `sub`. If a matching user logs in, the # `sub` is updated to the new sub and this flag is disabled. This is for # migrating *to* the external authentication scheme. match_by_username_email = Column(Boolean, server_default=false()) @@ -472,12 +499,16 @@ class Comment(Base): class Region(Base): __tablename__ = "region" - relation_id = Column(BIGINT, primary_key=True, index=True) - name = Column(String) - geometry = Column(Geometry) - admin_level = Column(Integer) + relation_id = Column(BIGINT, primary_key=True, index=True, autoincrement=False) + name = Column(Text) + geometry = Column(GeometryGeometry) + admin_level = Column(Integer, index=True) import_group = Column(String) + __table_args__ = ( + Index('ix_region_geometry', 'geometry', postgresql_using='gist', postgresql_with={'fillfactor':100}), + ) + Comment.author = relationship("User", back_populates="authored_comments") User.authored_comments = relationship(