diff --git a/database/base.py b/database/base.py index be2b1be..d39ac1b 100644 --- a/database/base.py +++ b/database/base.py @@ -1,11 +1,11 @@ import uuid from datetime import datetime -from typing import Optional +from typing import Optional, Tuple from geoalchemy2 import Geometry from shapely.geometry import Polygon from sqlalchemy import ForeignKey -from sqlalchemy.dialects.postgresql import JSONB, UUID +from sqlalchemy.dialects.postgresql import JSONB, NUMRANGE, UUID from sqlalchemy.orm import ( DeclarativeBase, Mapped, @@ -28,6 +28,7 @@ class Base(DeclarativeBase): uuid.UUID: UUID(as_uuid=True), dict[str, str]: JSONB, Polygon: Geometry(geometry_type="POLYGON", srid=PROJECT_SRID), + Tuple[float, float]: NUMRANGE, } @@ -43,6 +44,8 @@ class Base(DeclarativeBase): ] timestamp = Annotated[datetime, mapped_column(server_default=func.now())] +autoincrement_int = Annotated[int, mapped_column(autoincrement=True, index=True)] + metadata = Base.metadata diff --git a/database/migrations/versions/2024_02_08_1648-776ca8ea5a68_add_plan_regulation_table.py b/database/migrations/versions/2024_02_08_1648-776ca8ea5a68_add_plan_regulation_table.py new file mode 100644 index 0000000..868bd19 --- /dev/null +++ b/database/migrations/versions/2024_02_08_1648-776ca8ea5a68_add_plan_regulation_table.py @@ -0,0 +1,88 @@ +"""add_plan_regulation_table + +Revision ID: 776ca8ea5a68 +Revises: 6ee06a6e634a +Create Date: 2024-02-08 16:48:20.346350 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +# import geoalchemy2 +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "776ca8ea5a68" +down_revision: Union[str, None] = "6ee06a6e634a" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "plan_regulation", + sa.Column("plan_regulation_group_id", sa.UUID(), nullable=False), + sa.Column("type_of_plan_regulation_id", sa.UUID(), nullable=False), + sa.Column("type_of_verbal_plan_regulation_id", sa.UUID(), nullable=False), + sa.Column("numeric_range", postgresql.NUMRANGE(), nullable=False), + sa.Column("unit", sa.String(), nullable=False), + sa.Column( + "text_value", + postgresql.JSONB(astext_type=sa.Text()), + server_default='{"fin": "", "swe": "", "eng": ""}', + nullable=False, + ), + sa.Column("numeric_value", sa.Float(), nullable=False), + sa.Column( + "regulation_number", sa.Integer(), autoincrement=True, nullable=False + ), + sa.Column("exported_at", sa.DateTime(), nullable=True), + sa.Column("valid_from", sa.DateTime(), nullable=True), + sa.Column("valid_to", sa.DateTime(), nullable=True), + sa.Column("repealed_at", sa.DateTime(), nullable=True), + sa.Column("lifecycle_status_id", sa.UUID(), nullable=False), + sa.Column( + "id", sa.UUID(), server_default=sa.text("gen_random_uuid()"), nullable=False + ), + sa.Column( + "created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False + ), + sa.Column( + "modified_at", + sa.DateTime(), + server_default=sa.text("now()"), + nullable=False, + ), + sa.ForeignKeyConstraint( + ["lifecycle_status_id"], + ["codes.lifecycle_status.id"], + name="plan_lifecycle_status_id_fkey", + ), + sa.ForeignKeyConstraint( + ["plan_regulation_group_id"], + ["hame.plan_regulation_group.id"], + name="plan_regulation_group_id_fkey", + ), + sa.ForeignKeyConstraint( + ["type_of_plan_regulation_id"], + ["codes.type_of_plan_regulation.id"], + name="type_of_plan_regulation_id_fkey", + ), + sa.ForeignKeyConstraint( + ["type_of_verbal_plan_regulation_id"], + ["codes.type_of_verbal_plan_regulation.id"], + name="type_of_verbal_plan_regulation_id_fkey", + ), + sa.PrimaryKeyConstraint("id"), + schema="hame", + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("plan_regulation", schema="hame") + # ### end Alembic commands ### diff --git a/database/migrations/versions/2024_02_15_0751-e22a66335242_edit_plan_regulation_table.py b/database/migrations/versions/2024_02_15_0751-e22a66335242_edit_plan_regulation_table.py new file mode 100644 index 0000000..d4a89a9 --- /dev/null +++ b/database/migrations/versions/2024_02_15_0751-e22a66335242_edit_plan_regulation_table.py @@ -0,0 +1,111 @@ +"""edit_plan_regulation_table + +Revision ID: e22a66335242 +Revises: 776ca8ea5a68 +Create Date: 2024-02-15 07:51:18.528788 + +""" +from typing import Sequence, Union + +# import geoalchemy2 +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "e22a66335242" +down_revision: Union[str, None] = "776ca8ea5a68" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "plan_regulation", + sa.Column("ordering", sa.Integer(), autoincrement=True, nullable=False), + schema="hame", + ) + op.alter_column( + "plan_regulation", + "type_of_verbal_plan_regulation_id", + existing_type=sa.UUID(), + nullable=True, + schema="hame", + ) + op.alter_column( + "plan_regulation", + "numeric_range", + existing_type=postgresql.NUMRANGE(), + nullable=True, + schema="hame", + ) + op.alter_column( + "plan_regulation", + "unit", + existing_type=sa.VARCHAR(), + nullable=True, + schema="hame", + ) + op.alter_column( + "plan_regulation", + "numeric_value", + existing_type=sa.DOUBLE_PRECISION(precision=53), + nullable=True, + schema="hame", + ) + op.create_index( + op.f("ix_hame_plan_regulation_ordering"), + "plan_regulation", + ["ordering"], + unique=False, + schema="hame", + ) + op.drop_column("plan_regulation", "regulation_number", schema="hame") + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "plan_regulation", + sa.Column( + "regulation_number", sa.INTEGER(), autoincrement=False, nullable=False + ), + schema="hame", + ) + op.drop_index( + op.f("ix_hame_plan_regulation_ordering"), + table_name="plan_regulation", + schema="hame", + ) + op.alter_column( + "plan_regulation", + "numeric_value", + existing_type=sa.DOUBLE_PRECISION(precision=53), + nullable=False, + schema="hame", + ) + op.alter_column( + "plan_regulation", + "unit", + existing_type=sa.VARCHAR(), + nullable=False, + schema="hame", + ) + op.alter_column( + "plan_regulation", + "numeric_range", + existing_type=postgresql.NUMRANGE(), + nullable=False, + schema="hame", + ) + op.alter_column( + "plan_regulation", + "type_of_verbal_plan_regulation_id", + existing_type=sa.UUID(), + nullable=False, + schema="hame", + ) + op.drop_column("plan_regulation", "ordering", schema="hame") + # ### end Alembic commands ### diff --git a/database/models.py b/database/models.py index 237e71c..fcf70bc 100644 --- a/database/models.py +++ b/database/models.py @@ -1,9 +1,11 @@ +import uuid from datetime import datetime -from typing import Optional +from typing import Optional, Tuple -from base import PlanBase, VersionedBase, language_str, unique_str +from base import PlanBase, VersionedBase, autoincrement_int, language_str, unique_str from shapely.geometry import Polygon -from sqlalchemy.orm import Mapped +from sqlalchemy import ForeignKey +from sqlalchemy.orm import Mapped, mapped_column, relationship class Plan(PlanBase): @@ -27,3 +29,55 @@ class PlanRegulationGroup(VersionedBase): short_name: Mapped[unique_str] name: Mapped[language_str] + # värikoodi? + # group_type: oma koodilista + + +class PlanRegulation(PlanBase): + """ + Kaavamääräys + """ + + __tablename__ = "plan_regulation" + + plan_regulation_group_id: Mapped[uuid.UUID] = mapped_column( + ForeignKey( + "hame.plan_regulation_group.id", name="plan_regulation_group_id_fkey" + ) + ) + + type_of_plan_regulation_id: Mapped[uuid.UUID] = mapped_column( + ForeignKey( + "codes.type_of_plan_regulation.id", name="type_of_plan_regulation_id_fkey" + ) + ) + type_of_verbal_plan_regulation_id: Mapped[uuid.UUID] = mapped_column( + ForeignKey( + "codes.type_of_verbal_plan_regulation.id", + name="type_of_verbal_plan_regulation_id_fkey", + ), + nullable=True, + ) + # type_of_additional_information_id: Mapped[uuid.UUID] = mapped_column( + # ForeignKey( + # "codes.type_of_additional_information.id", + # name="type_of_additional_information_id_fkey", + # ) + # ) + + plan_regulation_group = relationship( + "PlanRegulationGroup", back_populates="plan_regulations" + ) + type_of_plan_regulation = relationship( + "TypeOfPlanRegulation", back_populates="plan_regulations" + ) + # plan_theme: kaavoitusteema-koodilista + type_of_verbal_plan_regulation = relationship( + "TypeOfVerbalPlanRegulation", back_populates="plan_regulations" + ) + numeric_range: Mapped[Tuple[float, float]] = mapped_column(nullable=True) + unit: Mapped[str] = mapped_column(nullable=True) + text_value: Mapped[language_str] + numeric_value: Mapped[float] = mapped_column(nullable=True) + ordering: Mapped[autoincrement_int] + # ElinkaaritilaX_pvm? diff --git a/database/test/test_db.py b/database/test/test_db.py index c3f6056..f403f06 100644 --- a/database/test/test_db.py +++ b/database/test/test_db.py @@ -2,7 +2,7 @@ import psycopg2 -hame_count: int = 2 # adjust me when adding tables +hame_count: int = 3 # adjust me when adding tables codes_count: int = 8 # adjust me when adding tables matview_count: int = 0 # adjust me when adding views @@ -88,6 +88,14 @@ def assert_database_is_alright( None, f"CREATE UNIQUE INDEX ix_hame_{table_name}_short_name ON hame.{table_name} USING btree (short_name)", ) in indexes + if ("ordering",) in columns: + assert ( + "hame", + table_name, + f"ix_hame_{table_name}_ordering", + None, + f"CREATE INDEX ix_hame_{table_name}_ordering ON hame.{table_name} USING btree (ordering)", + ) in indexes # Check code tables cur.execute("SELECT tablename, tableowner FROM pg_tables WHERE schemaname='codes';")