2024052425_add_slot_template_4ca2e4cc7b95.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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",
  96. sa.Column("required_volunteers", sa.Integer(), nullable=False, server_default="0"),
  97. )
  98. op.alter_column("slots", "required_volunteers", server_default=None)
  99. op.add_column("slots", sa.Column("template_id", sa.UUID(as_uuid=False), nullable=True))
  100. op.create_foreign_key(None, "slots", "slot_templates", ["template_id"], ["id"])
  101. bind = op.get_bind()
  102. session = orm.Session(bind=bind)
  103. # Create 1 template for each slot
  104. for slot in session.query(Slot).all():
  105. template = SlotTemplate(
  106. project_id=slot.project_id,
  107. title="Migration template for " + slot.title,
  108. description=slot.description,
  109. place=slot.place,
  110. responsible_contact=slot.responsible_contact,
  111. )
  112. session.add(template)
  113. slot.template = template
  114. session.commit()
  115. op.drop_column("slots", "description")
  116. op.drop_column("slots", "place")
  117. op.drop_column("slots", "responsible_contact")
  118. # ### end Alembic commands ###
  119. def downgrade():
  120. op.add_column(
  121. "slots",
  122. sa.Column(
  123. "responsible_contact",
  124. sa.VARCHAR(),
  125. server_default=sa.text("''::character varying"),
  126. autoincrement=False,
  127. nullable=False,
  128. ),
  129. )
  130. op.add_column(
  131. "slots",
  132. sa.Column(
  133. "place",
  134. sa.VARCHAR(),
  135. server_default=sa.text("''::character varying"),
  136. autoincrement=False,
  137. nullable=False,
  138. ),
  139. )
  140. op.add_column(
  141. "slots",
  142. sa.Column("description", sa.VARCHAR(), autoincrement=False, nullable=False),
  143. )
  144. # Revert data from template to slot
  145. bind = op.get_bind()
  146. session = orm.Session(bind=bind)
  147. for slot in session.query(Slot).all():
  148. slot.place = slot.template.place
  149. slot.description = slot.template.description
  150. slot.responsible_contact = slot.template.responsible_contact
  151. session.commit()
  152. op.drop_column("slots", "template_id")
  153. op.drop_column("slots", "required_volunteers")
  154. op.drop_table("association_description_tag")
  155. op.drop_table("slot_templates")
  156. op.drop_table("slot_tags")
  157. # ### end Alembic commands ###