aboutsummaryrefslogtreecommitdiffstats
path: root/thallium-backend
diff options
context:
space:
mode:
authorGravatar Chris Lovering <[email protected]>2024-08-24 23:39:22 +0100
committerGravatar Chris Lovering <[email protected]>2024-08-25 00:14:41 +0100
commit3cca55156acb9b25e996f3702d6260345811707c (patch)
tree1ffdb1a2d8d2551f83c3e1fbcc8c09b03a107274 /thallium-backend
parentMove 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.py98
-rw-r--r--thallium-backend/src/orm/__init__.py5
-rw-r--r--thallium-backend/src/orm/products.py18
-rw-r--r--thallium-backend/src/orm/templates.py62
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})"