c29facfe716b_update_file_table_path.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. """Update file table path
  2. Revision ID: c29facfe716b
  3. Revises: c69f45358db4
  4. Create Date: 2024-10-20 17:02:35.241684
  5. """
  6. from alembic import op
  7. import sqlalchemy as sa
  8. import json
  9. from sqlalchemy.sql import table, column
  10. from sqlalchemy import String, Text, JSON, and_
  11. revision = "c29facfe716b"
  12. down_revision = "c69f45358db4"
  13. branch_labels = None
  14. depends_on = None
  15. def upgrade():
  16. # 1. Add the `path` column to the "file" table.
  17. op.add_column("file", sa.Column("path", sa.Text(), nullable=True))
  18. # 2. Convert the `meta` column from Text/JSONField to `JSON()`
  19. # Use Alembic's default batch_op for dialect compatibility.
  20. with op.batch_alter_table("file", schema=None) as batch_op:
  21. batch_op.alter_column(
  22. "meta",
  23. type_=sa.JSON(),
  24. existing_type=sa.Text(),
  25. existing_nullable=True,
  26. nullable=True,
  27. postgresql_using="meta::json",
  28. )
  29. # 3. Migrate legacy data from `meta` JSONField
  30. # Fetch and process `meta` data from the table, add values to the new `path` column as necessary.
  31. # We will use SQLAlchemy core bindings to ensure safety across different databases.
  32. file_table = table(
  33. "file", column("id", String), column("meta", JSON), column("path", Text)
  34. )
  35. # Create connection to the database
  36. connection = op.get_bind()
  37. # Get the rows where `meta` has a path and `path` column is null (new column)
  38. # Loop through each row in the result set to update the path
  39. results = connection.execute(
  40. sa.select(file_table.c.id, file_table.c.meta).where(
  41. and_(file_table.c.path.is_(None), file_table.c.meta.isnot(None))
  42. )
  43. ).fetchall()
  44. # Iterate over each row to extract and update the `path` from `meta` column
  45. for row in results:
  46. if "path" in row.meta:
  47. # Extract the `path` field from the `meta` JSON
  48. path = row.meta.get("path")
  49. # Update the `file` table with the new `path` value
  50. connection.execute(
  51. file_table.update()
  52. .where(file_table.c.id == row.id)
  53. .values({"path": path})
  54. )
  55. def downgrade():
  56. # 1. Remove the `path` column
  57. op.drop_column("file", "path")
  58. # 2. Revert the `meta` column back to Text/JSONField
  59. with op.batch_alter_table("file", schema=None) as batch_op:
  60. batch_op.alter_column(
  61. "meta", type_=sa.Text(), existing_type=sa.JSON(), existing_nullable=True
  62. )