fix(wip-title): count inserts via pre-SELECT, not driver rowcount
apply_wip_image_tags relied on result.rowcount, but psycopg reports -1 for a multi-row INSERT ... ON CONFLICT DO NOTHING (executemany path), so the return count (and the backfill's reported total) was wrong. Compute the count from a pre-SELECT of already-tagged ids within the same transaction; keep ON CONFLICT DO NOTHING as a race-safety belt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,22 +65,37 @@ def resolve_wip_tag_id(session: Session) -> int | None:
|
||||
|
||||
|
||||
def apply_wip_image_tags(session: Session, image_ids, tag_id: int) -> int:
|
||||
"""Attach ``tag_id`` (source='wip_title') to each image id, idempotently
|
||||
(ON CONFLICT DO NOTHING — never disturbs an existing tag or its source).
|
||||
Returns the number of image_tag rows newly inserted. Does NOT commit."""
|
||||
"""Attach ``tag_id`` (source='wip_title') to each image id, idempotently —
|
||||
never disturbs an existing tag or its source. Returns the number of image_tag
|
||||
rows newly inserted. Does NOT commit.
|
||||
|
||||
The insert count is computed from a pre-SELECT of already-tagged ids rather
|
||||
than the statement's ``rowcount``: psycopg reports -1 for a multi-row
|
||||
ON CONFLICT DO NOTHING insert (it runs via an executemany path), so rowcount
|
||||
is unusable here. The SELECT is accurate within this single transaction (no
|
||||
concurrent writer touches these (image, wip) rows); ON CONFLICT DO NOTHING
|
||||
stays as a race-safety belt so a rare concurrent insert can't error."""
|
||||
ids = list({int(i) for i in image_ids})
|
||||
if not ids:
|
||||
return 0
|
||||
inserted = 0
|
||||
for start in range(0, len(ids), _INSERT_CHUNK):
|
||||
chunk = ids[start:start + _INSERT_CHUNK]
|
||||
result = session.execute(
|
||||
already = set(session.execute(
|
||||
select(image_tag.c.image_record_id)
|
||||
.where(image_tag.c.tag_id == tag_id)
|
||||
.where(image_tag.c.image_record_id.in_(chunk))
|
||||
).scalars())
|
||||
to_insert = [iid for iid in chunk if iid not in already]
|
||||
if not to_insert:
|
||||
continue
|
||||
session.execute(
|
||||
pg_insert(image_tag)
|
||||
.values([
|
||||
{"image_record_id": iid, "tag_id": tag_id, "source": WIP_TITLE_SOURCE}
|
||||
for iid in chunk
|
||||
for iid in to_insert
|
||||
])
|
||||
.on_conflict_do_nothing(index_elements=["image_record_id", "tag_id"])
|
||||
)
|
||||
inserted += result.rowcount or 0
|
||||
inserted += len(to_insert)
|
||||
return inserted
|
||||
|
||||
Reference in New Issue
Block a user