refactor(importer): single _apply_post_fields predicate for both ingest paths (#842/#753)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 27s
CI / backend-lint-and-test (push) Successful in 42s
CI / integration (push) Successful in 3m22s

The per-media path (_apply_sidecar) and the post-record path (upsert_post_record)
each carried a VERBATIM copy of the post-field write (url/title/date/description/
attachment_count/raw_metadata + external-link sync). Two copies of one concept =
the divergence risk #753 targets. Consolidate into one _apply_post_fields(post,
sd) helper both call — a single predicate for how a post body/links get stored,
so the two sources can't drift. Behavior identical (fill-with-non-empty); both
paths already covered by existing importer tests.

Groundwork for the planned post-first ingest model (single authoritative post
record; media attaches to it) as more platforms move onto the native ingester.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 23:39:30 -04:00
parent eb811e11f6
commit 0d51b93aa7
+25 -24
View File
@@ -739,6 +739,29 @@ class Importer:
self.session.commit()
return ImportResult(status="refreshed", image_id=existing.id)
def _apply_post_fields(self, post: Post, sd) -> None:
"""Write a parsed sidecar's post-level fields onto a Post — the SINGLE
predicate shared by BOTH ingest paths: the per-media path (_apply_sidecar)
and the post-record path (upsert_post_record). Fill-with-non-empty:
parse_sidecar yields None for empty values, so a None field is left
untouched (an empty feed body never wipes a populated one). raw_metadata +
external-link sync always run (latest snapshot). Keeping ONE copy stops
the two paths from diverging on how a post body/links get stored — they
were verbatim duplicates (#842 DRY pass; see [[feedback_preview_apply_parity]]).
"""
if sd.post_url is not None:
post.post_url = sd.post_url
if sd.post_title is not None:
post.post_title = sd.post_title
if sd.post_date is not None:
post.post_date = sd.post_date
if sd.description is not None:
post.description = sd.description
if sd.attachment_count is not None:
post.attachment_count = sd.attachment_count
post.raw_metadata = sd.raw
self._sync_external_links(post)
def upsert_post_record(
self, sidecar: Path, *, artist: Artist | None = None,
source: Source | None = None,
@@ -785,18 +808,7 @@ class Importer:
)
if post.artist_id is None:
post.artist_id = artist.id
if sd.post_url is not None:
post.post_url = sd.post_url
if sd.post_title is not None:
post.post_title = sd.post_title
if sd.post_date is not None:
post.post_date = sd.post_date
if sd.description is not None:
post.description = sd.description
if sd.attachment_count is not None:
post.attachment_count = sd.attachment_count
post.raw_metadata = sd.raw
self._sync_external_links(post)
self._apply_post_fields(post, sd)
self.session.commit()
return True
@@ -1098,18 +1110,7 @@ class Importer:
external_post_id=epid,
artist_id=artist.id,
)
if sd.post_url is not None:
post.post_url = sd.post_url
if sd.post_title is not None:
post.post_title = sd.post_title
if sd.post_date is not None:
post.post_date = sd.post_date
if sd.description is not None:
post.description = sd.description
if sd.attachment_count is not None:
post.attachment_count = sd.attachment_count
post.raw_metadata = sd.raw
self._sync_external_links(post)
self._apply_post_fields(post, sd)
# Race-safe (image_record_id, post_id) upsert — mirrors the
# _find_or_create_source/post savepoint pattern. The plain