2024052425_add_slot_template_4ca2e4cc7b95.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. """add_slot_template
  2. Revision ID: 4ca2e4cc7b95
  3. Revises: 2f90ef72e3b9
  4. Create Date: 2024-05-24 09:25:42.163966
  5. """
  6. from datetime import datetime
  7. from typing import List, Optional
  8. from alembic import op
  9. import sqlalchemy as sa
  10. from sqlalchemy import orm
  11. from sqlalchemy.ext.declarative import declarative_base
  12. import uuid
  13. from sqlalchemy.dialects.postgresql import UUID
  14. # revision identifiers, used by Alembic.
  15. revision = "4ca2e4cc7b95"
  16. down_revision = "2f90ef72e3b9"
  17. branch_labels = None
  18. depends_on = None
  19. def uid_column() -> orm.Mapped[str]:
  20. """Returns a postgreSQL UUID column for SQL ORM"""
  21. return orm.mapped_column(
  22. UUID(as_uuid=False), primary_key=True, default=lambda _: str(uuid.uuid4())
  23. )
  24. Base = declarative_base()
  25. class Project(Base):
  26. __tablename__ = "projects"
  27. id: orm.Mapped[str] = uid_column()
  28. class Slot(Base):
  29. __tablename__ = "slots"
  30. id = uid_column()
  31. project_id = orm.mapped_column(sa.ForeignKey("projects.id", ondelete="CASCADE"))
  32. title: orm.Mapped[str] = orm.mapped_column(sa.String(128), nullable=False)
  33. description: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  34. place: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  35. responsible_contact: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  36. template_id: orm.Mapped[Optional[str]] = orm.mapped_column(sa.ForeignKey("slot_templates.id"))
  37. template: orm.Mapped["SlotTemplate"] = orm.relationship(back_populates="slots")
  38. class SlotTemplate(Base):
  39. __tablename__ = "slot_templates"
  40. id = uid_column()
  41. project_id = orm.mapped_column(sa.ForeignKey("projects.id", ondelete="CASCADE"))
  42. created_at = orm.mapped_column(sa.DateTime(timezone=True), server_default=sa.func.now())
  43. updated_at = orm.mapped_column(
  44. sa.DateTime(timezone=True), default=datetime.now, onupdate=sa.func.now()
  45. )
  46. title: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  47. description: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  48. place: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  49. responsible_contact: orm.Mapped[str] = orm.mapped_column(sa.String(), default="")
  50. slots: orm.Mapped[List[Slot]] = orm.relationship(back_populates="template")
  51. def upgrade():
  52. # ### commands auto generated by Alembic - please adjust! ###
  53. op.create_table(
  54. "slot_tags",
  55. sa.Column("id", sa.UUID(as_uuid=False), nullable=False),
  56. sa.Column("project_id", sa.UUID(as_uuid=False), nullable=False),
  57. sa.Column(
  58. "created_at",
  59. sa.DateTime(timezone=True),
  60. server_default=sa.text("now()"),
  61. nullable=False,
  62. ),
  63. sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
  64. sa.Column("title", sa.String(), nullable=False),
  65. sa.ForeignKeyConstraint(["project_id"], ["projects.id"], ondelete="CASCADE"),
  66. sa.PrimaryKeyConstraint("id"),
  67. )
  68. op.create_table(
  69. "slot_templates",
  70. sa.Column("id", sa.UUID(as_uuid=False), nullable=False),
  71. sa.Column("project_id", sa.UUID(as_uuid=False), nullable=False),
  72. sa.Column(
  73. "created_at",
  74. sa.DateTime(timezone=True),
  75. server_default=sa.text("now()"),
  76. nullable=False,
  77. ),
  78. sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
  79. sa.Column("title", sa.String(), nullable=False),
  80. sa.Column("description", sa.String(), nullable=False),
  81. sa.Column("place", sa.String(), nullable=False),
  82. sa.Column("responsible_contact", sa.String(), nullable=False),
  83. sa.ForeignKeyConstraint(["project_id"], ["projects.id"], ondelete="CASCADE"),
  84. sa.PrimaryKeyConstraint("id"),
  85. )
  86. op.create_table(
  87. "association_description_tag",
  88. sa.Column("description_id", sa.UUID(as_uuid=False), nullable=False),
  89. sa.Column("tag_id", sa.UUID(as_uuid=False), nullable=False),
  90. sa.ForeignKeyConstraint(["description_id"], ["slot_templates.id"], ondelete="CASCADE"),
  91. sa.ForeignKeyConstraint(["tag_id"], ["slot_tags.id"], ondelete="CASCADE"),
  92. sa.PrimaryKeyConstraint("description_id", "tag_id"),
  93. )
  94. op.add_column(
  95. "slots", sa.Column("required_volunteers", sa.Integer(), nullable=False, server_default="0")
  96. )
  97. op.alter_column("slots", "required_volunteers", server_default=None)
  98. op.add_column("slots", sa.Column("template_id", sa.UUID(as_uuid=False), nullable=True))
  99. op.create_foreign_key(None, "slots", "slot_templates", ["template_id"], ["id"])
  100. bind = op.get_bind()
  101. session = orm.Session(bind=bind)
  102. # Create 1 template for each slot
  103. for slot in session.query(Slot).all():
  104. template = SlotTemplate(
  105. project_id=slot.project_id,
  106. title="Migration template for " + slot.title,
  107. description=slot.description,
  108. place=slot.place,
  109. responsible_contact=slot.responsible_contact,
  110. )
  111. session.add(template)
  112. slot.template = template
  113. session.commit()
  114. op.drop_column("slots", "description")
  115. op.drop_column("slots", "place")
  116. op.drop_column("slots", "responsible_contact")
  117. # ### end Alembic commands ###
  118. def downgrade():
  119. op.add_column(
  120. "slots",
  121. sa.Column(
  122. "responsible_contact",
  123. sa.VARCHAR(),
  124. server_default=sa.text("''::character varying"),
  125. autoincrement=False,
  126. nullable=False,
  127. ),
  128. )
  129. op.add_column(
  130. "slots",
  131. sa.Column(
  132. "place",
  133. sa.VARCHAR(),
  134. server_default=sa.text("''::character varying"),
  135. autoincrement=False,
  136. nullable=False,
  137. ),
  138. )
  139. op.add_column(
  140. "slots", sa.Column("description", sa.VARCHAR(), autoincrement=False, nullable=False)
  141. )
  142. # Revert data from template to slot
  143. bind = op.get_bind()
  144. session = orm.Session(bind=bind)
  145. for slot in session.query(Slot).all():
  146. slot.place = slot.template.place
  147. slot.description = slot.template.description
  148. slot.responsible_contact = slot.template.responsible_contact
  149. session.commit()
  150. op.drop_column("slots", "template_id")
  151. op.drop_column("slots", "required_volunteers")
  152. op.drop_table("association_description_tag")
  153. op.drop_table("slot_templates")
  154. op.drop_table("slot_tags")
  155. # ### end Alembic commands ###