20260731_13_version_demand_belong_rel.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. """version and explain legacy demand-belong relation edges
  2. Revision ID: 20260731_13
  3. Revises: 20260731_12
  4. Create Date: 2026-07-31
  5. """
  6. from __future__ import annotations
  7. from collections.abc import Sequence
  8. import sqlalchemy as sa
  9. from alembic import op
  10. revision: str = "20260731_13"
  11. down_revision: str | None = "20260731_12"
  12. branch_labels: str | Sequence[str] | None = None
  13. depends_on: str | Sequence[str] | None = None
  14. def _new_columns() -> tuple[sa.Column, ...]:
  15. return (
  16. sa.Column(
  17. "biz_dt",
  18. sa.String(32),
  19. nullable=False,
  20. server_default="legacy",
  21. ),
  22. sa.Column(
  23. "relation_type",
  24. sa.String(32),
  25. nullable=False,
  26. server_default="explicit_token",
  27. ),
  28. sa.Column(
  29. "relation_source",
  30. sa.String(64),
  31. nullable=False,
  32. server_default="legacy",
  33. ),
  34. sa.Column(
  35. "reason",
  36. sa.Text(),
  37. nullable=False,
  38. ),
  39. sa.Column(
  40. "confidence",
  41. sa.Numeric(6, 5),
  42. nullable=False,
  43. server_default="1",
  44. ),
  45. sa.Column(
  46. "is_inferred",
  47. sa.Boolean(),
  48. nullable=False,
  49. server_default="1",
  50. ),
  51. sa.Column(
  52. "status",
  53. sa.String(24),
  54. nullable=False,
  55. server_default="active",
  56. ),
  57. sa.Column(
  58. "valid_from_biz_dt",
  59. sa.String(32),
  60. nullable=False,
  61. server_default="legacy",
  62. ),
  63. sa.Column("valid_to_biz_dt", sa.String(32), nullable=True),
  64. )
  65. def upgrade() -> None:
  66. inspector = sa.inspect(op.get_bind())
  67. table_names = set(inspector.get_table_names())
  68. if "demand_belong_pool_rel" not in table_names:
  69. op.create_table(
  70. "demand_belong_pool_rel",
  71. sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
  72. sa.Column("demand_belong_category_id", sa.BigInteger(), nullable=False),
  73. sa.Column("multi_demand_pool_di_id", sa.BigInteger(), nullable=False),
  74. *_new_columns(),
  75. sa.Column(
  76. "create_time",
  77. sa.DateTime(),
  78. nullable=False,
  79. server_default=sa.func.now(),
  80. ),
  81. sa.Column(
  82. "update_time",
  83. sa.DateTime(),
  84. nullable=False,
  85. server_default=sa.func.now(),
  86. ),
  87. sa.PrimaryKeyConstraint("id"),
  88. sa.UniqueConstraint(
  89. "demand_belong_category_id",
  90. "multi_demand_pool_di_id",
  91. name="uk_belong_pool",
  92. ),
  93. )
  94. op.create_index(
  95. "idx_belong_category_id",
  96. "demand_belong_pool_rel",
  97. ["demand_belong_category_id"],
  98. )
  99. op.create_index(
  100. "idx_pool_di_id",
  101. "demand_belong_pool_rel",
  102. ["multi_demand_pool_di_id"],
  103. )
  104. else:
  105. existing_columns = {
  106. column["name"]
  107. for column in inspector.get_columns("demand_belong_pool_rel")
  108. }
  109. reason_added = False
  110. for column in _new_columns():
  111. if column.name not in existing_columns:
  112. if column.name == "reason":
  113. op.add_column(
  114. "demand_belong_pool_rel",
  115. sa.Column("reason", sa.Text(), nullable=True),
  116. )
  117. reason_added = True
  118. else:
  119. op.add_column("demand_belong_pool_rel", column)
  120. if "multi_demand_pool_di" in table_names:
  121. op.execute(
  122. sa.text(
  123. "UPDATE demand_belong_pool_rel "
  124. "SET biz_dt = COALESCE(("
  125. "SELECT pool.biz_dt FROM multi_demand_pool_di AS pool "
  126. "WHERE pool.id = demand_belong_pool_rel.multi_demand_pool_di_id"
  127. "), 'legacy'), "
  128. "valid_from_biz_dt = COALESCE(("
  129. "SELECT pool.biz_dt FROM multi_demand_pool_di AS pool "
  130. "WHERE pool.id = demand_belong_pool_rel.multi_demand_pool_di_id"
  131. "), 'legacy'), "
  132. "relation_source = 'legacy_name_match', "
  133. "reason = '历史名称匹配关系,由迁移接管;后续按业务日重建', "
  134. "is_inferred = 1"
  135. )
  136. )
  137. if reason_added:
  138. op.execute(
  139. sa.text(
  140. "UPDATE demand_belong_pool_rel "
  141. "SET reason = 'legacy relation' "
  142. "WHERE reason IS NULL"
  143. )
  144. )
  145. if op.get_bind().dialect.name == "sqlite":
  146. with op.batch_alter_table("demand_belong_pool_rel") as batch_op:
  147. batch_op.alter_column(
  148. "reason",
  149. existing_type=sa.Text(),
  150. nullable=False,
  151. )
  152. else:
  153. op.alter_column(
  154. "demand_belong_pool_rel",
  155. "reason",
  156. existing_type=sa.Text(),
  157. nullable=False,
  158. )
  159. index_names = {
  160. index["name"]
  161. for index in sa.inspect(op.get_bind()).get_indexes(
  162. "demand_belong_pool_rel"
  163. )
  164. }
  165. if "idx_belong_pool_biz_status" not in index_names:
  166. op.create_index(
  167. "idx_belong_pool_biz_status",
  168. "demand_belong_pool_rel",
  169. ["biz_dt", "status"],
  170. )
  171. def downgrade() -> None:
  172. op.drop_index(
  173. "idx_belong_pool_biz_status",
  174. table_name="demand_belong_pool_rel",
  175. )
  176. for column in (
  177. "valid_to_biz_dt",
  178. "valid_from_biz_dt",
  179. "status",
  180. "is_inferred",
  181. "confidence",
  182. "reason",
  183. "relation_source",
  184. "relation_type",
  185. "biz_dt",
  186. ):
  187. op.drop_column("demand_belong_pool_rel", column)