diff options
author | 2024-08-24 23:39:22 +0100 | |
---|---|---|
committer | 2024-08-25 00:14:41 +0100 | |
commit | 3cca55156acb9b25e996f3702d6260345811707c (patch) | |
tree | 1ffdb1a2d8d2551f83c3e1fbcc8c09b03a107274 /thallium-backend | |
parent | Move UUIDBase to its own mixin (diff) |
Replace products with templates and variants
Diffstat (limited to 'thallium-backend')
-rw-r--r-- | thallium-backend/migrations/versions/1724540581-8c35ad6bab78_templates_and_variants.py | 98 | ||||
-rw-r--r-- | thallium-backend/src/orm/__init__.py | 5 | ||||
-rw-r--r-- | thallium-backend/src/orm/products.py | 18 | ||||
-rw-r--r-- | thallium-backend/src/orm/templates.py | 62 |
4 files changed, 163 insertions, 20 deletions
diff --git a/thallium-backend/migrations/versions/1724540581-8c35ad6bab78_templates_and_variants.py b/thallium-backend/migrations/versions/1724540581-8c35ad6bab78_templates_and_variants.py new file mode 100644 index 0000000..6c3f683 --- /dev/null +++ b/thallium-backend/migrations/versions/1724540581-8c35ad6bab78_templates_and_variants.py @@ -0,0 +1,98 @@ +""" +Replace products with templates and variants. + +Revision ID: 8c35ad6bab78 +Revises: bd897d0f21e1 +Create Date: 2024-08-24 23:03:01.084903+00:00 +""" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "8c35ad6bab78" +down_revision = "bd897d0f21e1" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + """Apply this migration.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "templates", + sa.Column("template_id", sa.Integer(), nullable=False), + sa.Column("title", sa.String(), nullable=False), + sa.Column("product_id", sa.Integer(), nullable=False), + sa.Column("mockup_file_url", sa.String(), nullable=False), + sa.Column("last_synced", sa.DateTime(timezone=True), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.PrimaryKeyConstraint("template_id", name=op.f("templates_pk")), + ) + op.create_table( + "variants", + sa.Column("variant_id", sa.Integer(), nullable=False), + sa.Column("name", sa.String(), nullable=False), + sa.Column("size", sa.String(), nullable=False), + sa.Column("colour", sa.String(), nullable=False), + sa.Column("colour_code", sa.String(), nullable=False), + sa.Column("price", sa.Numeric(), nullable=False), + sa.Column("last_synced", sa.DateTime(timezone=True), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.PrimaryKeyConstraint("variant_id", name=op.f("variants_pk")), + ) + op.create_table( + "template_variant", + sa.Column("template_id", sa.Integer(), nullable=True), + sa.Column("variant_id", sa.Integer(), nullable=True), + sa.ForeignKeyConstraint( + ["template_id"], + ["templates.template_id"], + name=op.f("template_variant_template_id_templates_fk"), + ondelete="CASCADE", + ), + sa.ForeignKeyConstraint( + ["variant_id"], + ["variants.variant_id"], + name=op.f("template_variant_variant_id_variants_fk"), + ondelete="CASCADE", + ), + ) + op.drop_table("products") + # ### end Alembic commands ### + + +def downgrade() -> None: + """Revert this migration.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "products", + sa.Column("product_id", sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column("name", sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column("description", sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column("price", sa.NUMERIC(), autoincrement=False, nullable=False), + sa.Column("image", postgresql.BYTEA(), autoincrement=False, nullable=False), + sa.Column("id", sa.UUID(), server_default=sa.text("gen_random_uuid()"), autoincrement=False, nullable=False), + sa.Column( + "created_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.Column( + "updated_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.PrimaryKeyConstraint("product_id", "id", name="products_pk"), + ) + op.drop_table("template_variant") + op.drop_table("variants") + op.drop_table("templates") + # ### end Alembic commands ### diff --git a/thallium-backend/src/orm/__init__.py b/thallium-backend/src/orm/__init__.py index cf70ddd..2f94916 100644 --- a/thallium-backend/src/orm/__init__.py +++ b/thallium-backend/src/orm/__init__.py @@ -1,14 +1,15 @@ """Database models.""" from .base import AuditBase, Base -from .products import Product +from .templates import Template, Variant from .users import User from .vouchers import Voucher __all__ = ( "AuditBase", "Base", - "Product", + "Template", + "Variant", "User", "Voucher", ) diff --git a/thallium-backend/src/orm/products.py b/thallium-backend/src/orm/products.py deleted file mode 100644 index 2c07b75..0000000 --- a/thallium-backend/src/orm/products.py +++ /dev/null @@ -1,18 +0,0 @@ -from decimal import Decimal - -from sqlalchemy.orm import Mapped, mapped_column -from sqlalchemy.types import LargeBinary - -from .base import AuditBase, Base - - -class Product(AuditBase, Base): - """A product available to be ordered.""" - - __tablename__ = "products" - - product_id: Mapped[int] = mapped_column(primary_key=True) - name: Mapped[str] - description: Mapped[str] - price: Mapped[Decimal] - image: Mapped[bytes] = mapped_column(LargeBinary, deferred=True) diff --git a/thallium-backend/src/orm/templates.py b/thallium-backend/src/orm/templates.py new file mode 100644 index 0000000..cffd5ca --- /dev/null +++ b/thallium-backend/src/orm/templates.py @@ -0,0 +1,62 @@ +from datetime import datetime +from decimal import Decimal + +from sqlalchemy import Column, DateTime, ForeignKey, Integer, Table +from sqlalchemy.orm import Mapped, mapped_column, relationship + +from .base import AuditBase, Base + +template_variant_association = Table( + "template_variant", + Base.metadata, + Column("template_id", Integer, ForeignKey("templates.template_id", ondelete="CASCADE")), + Column("variant_id", Integer, ForeignKey("variants.variant_id", ondelete="CASCADE")), +) + + +class Template(AuditBase, Base): + """An authenticated user of the service.""" + + __tablename__ = "templates" + + template_id: Mapped[int] = mapped_column(primary_key=True) + title: Mapped[str] + product_id: Mapped[int] + mockup_file_url: Mapped[str] + last_synced: Mapped[datetime] = mapped_column(DateTime(timezone=True)) + + variants: Mapped[list["Variant"]] = relationship( + "Variant", + secondary=template_variant_association, + back_populates="templates", + lazy=True, + ) + + def loggify(self) -> str: + """Human readable repr for logging.""" + return f"{self.__class__.__name__} {self.title} ({self.template_id})" + + +class Variant(AuditBase, Base): + """An authenticated user of the service.""" + + __tablename__ = "variants" + + variant_id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] + size: Mapped[str] + colour: Mapped[str] + colour_code: Mapped[str] + price: Mapped[Decimal] + last_synced: Mapped[datetime] = mapped_column(DateTime(timezone=True)) + + templates: Mapped[list["Template"]] = relationship( + "Template", + secondary=template_variant_association, + back_populates="variants", + lazy=True, + ) + + def loggify(self) -> str: + """Human readable repr for logging.""" + return f"{self.__class__.__name__} {self.name} ({self.variant_id})" |