multi_demand_video_detail_repo.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. from __future__ import annotations
  2. from collections.abc import Iterable
  3. from sqlalchemy import select, update
  4. from sqlalchemy.dialects.mysql import insert
  5. from supply_infra.db.models.multi_demand_video_detail import MultiDemandVideoDetail
  6. from supply_infra.db.repositories.base import BaseRepository
  7. _BATCH_SIZE = 1000
  8. class MultiDemandVideoDetailRepository(BaseRepository[MultiDemandVideoDetail]):
  9. """需求池视频详情表 — 按 vid 唯一键增量写入。"""
  10. model = MultiDemandVideoDetail
  11. def get_existing_vids(self, vids: Iterable[str]) -> set[str]:
  12. """返回 vids 中已存在于表内的视频 id。"""
  13. vid_list = [v for v in vids if v]
  14. if not vid_list:
  15. return set()
  16. existing: set[str] = set()
  17. for i in range(0, len(vid_list), _BATCH_SIZE):
  18. batch = vid_list[i : i + _BATCH_SIZE]
  19. stmt = select(MultiDemandVideoDetail.vid).where(
  20. MultiDemandVideoDetail.vid.in_(batch)
  21. )
  22. existing.update(str(v) for v in self.session.scalars(stmt).all() if v)
  23. return existing
  24. def list_by_vids(self, vids: Iterable[str]) -> dict[str, MultiDemandVideoDetail]:
  25. """按 vid 批量查询,返回 vid → row。"""
  26. vid_list = [v for v in vids if v]
  27. if not vid_list:
  28. return {}
  29. result: dict[str, MultiDemandVideoDetail] = {}
  30. for i in range(0, len(vid_list), _BATCH_SIZE):
  31. batch = vid_list[i : i + _BATCH_SIZE]
  32. stmt = select(MultiDemandVideoDetail).where(
  33. MultiDemandVideoDetail.vid.in_(batch)
  34. )
  35. for row in self.session.scalars(stmt).all():
  36. if row.vid:
  37. result[str(row.vid)] = row
  38. return result
  39. def list_vids_missing_title(self) -> list[str]:
  40. """返回 title 为空的全部 vid。"""
  41. stmt = select(MultiDemandVideoDetail.vid).where(
  42. (MultiDemandVideoDetail.title.is_(None)) | (MultiDemandVideoDetail.title == "")
  43. )
  44. return [str(v) for v in self.session.scalars(stmt).all() if v]
  45. def list_vids_missing_points(self) -> list[str]:
  46. """返回灵感点/目的点/关键点任一字段为空的全部 vid。"""
  47. stmt = select(MultiDemandVideoDetail.vid).where(
  48. MultiDemandVideoDetail.inspiration_points_json.is_(None)
  49. | MultiDemandVideoDetail.purpose_points_json.is_(None)
  50. | MultiDemandVideoDetail.key_points_json.is_(None)
  51. )
  52. return [str(v) for v in self.session.scalars(stmt).all() if v]
  53. def list_vids_missing_urls(self) -> list[str]:
  54. """返回 url1 或 url2 为空的全部 vid。"""
  55. stmt = select(MultiDemandVideoDetail.vid).where(
  56. MultiDemandVideoDetail.url1.is_(None)
  57. | (MultiDemandVideoDetail.url1 == "")
  58. | MultiDemandVideoDetail.url2.is_(None)
  59. | (MultiDemandVideoDetail.url2 == "")
  60. )
  61. return [str(v) for v in self.session.scalars(stmt).all() if v]
  62. def bulk_insert_ignore(self, rows: list[dict]) -> int:
  63. """批量插入,MySQL 自动忽略 vid 重复行。"""
  64. if not rows:
  65. return 0
  66. inserted = 0
  67. for i in range(0, len(rows), _BATCH_SIZE):
  68. batch = rows[i : i + _BATCH_SIZE]
  69. stmt = insert(MultiDemandVideoDetail).values(batch).prefix_with("IGNORE")
  70. result = self.session.execute(stmt)
  71. inserted += result.rowcount
  72. return inserted
  73. def update_titles(self, titles_by_vid: dict[str, str]) -> int:
  74. """按 vid 批量更新 title。"""
  75. if not titles_by_vid:
  76. return 0
  77. updated = 0
  78. for vid, title in titles_by_vid.items():
  79. stmt = (
  80. update(MultiDemandVideoDetail)
  81. .where(MultiDemandVideoDetail.vid == vid)
  82. .values(title=title)
  83. )
  84. result = self.session.execute(stmt)
  85. updated += result.rowcount or 0
  86. return updated
  87. def update_urls(self, urls_by_vid: dict[str, dict[str, str | None]]) -> int:
  88. """按 vid 批量更新 url1/url2(values 为落库字段名 → URL 文本)。"""
  89. if not urls_by_vid:
  90. return 0
  91. updated = 0
  92. for vid, values in urls_by_vid.items():
  93. if not values:
  94. continue
  95. stmt = (
  96. update(MultiDemandVideoDetail)
  97. .where(MultiDemandVideoDetail.vid == vid)
  98. .values(**values)
  99. )
  100. result = self.session.execute(stmt)
  101. updated += result.rowcount or 0
  102. return updated
  103. def update_points(self, points_by_vid: dict[str, dict[str, str | None]]) -> int:
  104. """按 vid 批量更新灵感点/目的点/关键点(values 为落库字段名 → JSON 文本)。"""
  105. if not points_by_vid:
  106. return 0
  107. updated = 0
  108. for vid, values in points_by_vid.items():
  109. if not values:
  110. continue
  111. stmt = (
  112. update(MultiDemandVideoDetail)
  113. .where(MultiDemandVideoDetail.vid == vid)
  114. .values(**values)
  115. )
  116. result = self.session.execute(stmt)
  117. updated += result.rowcount or 0
  118. return updated