refactor(thumbnails): pack key + aspect + pageCount into ThumbnailResult

persistThumbnailMetadata was a four-arg method signature that mixed
three conceptually related values. Wrapping them in a private
ThumbnailResult record drops the signature to (Document, result),
mirrors the existing SourcePreview record one step earlier in the
pipeline, and keeps generate() reading as a narrative of small
named outputs rather than positional arguments.

Refs #305
Fixes @felixbrandt suggestion 2 from PR review

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-23 20:39:04 +02:00
parent 514f0174e3
commit 78caac8d1a

View File

@@ -99,8 +99,9 @@ public class ThumbnailService {
String thumbnailKey = thumbnailKeyFor(doc.getId()); String thumbnailKey = thumbnailKeyFor(doc.getId());
if (!uploadToStorage(thumbnailKey, jpeg, doc.getId())) return Outcome.FAILED; if (!uploadToStorage(thumbnailKey, jpeg, doc.getId())) return Outcome.FAILED;
ThumbnailAspect aspect = aspectOf(preview.image()); ThumbnailResult result = new ThumbnailResult(
return persistThumbnailMetadata(doc, thumbnailKey, aspect, preview.pageCount()); thumbnailKey, aspectOf(preview.image()), preview.pageCount());
return persistThumbnailMetadata(doc, result);
} }
private static ThumbnailAspect aspectOf(BufferedImage source) { private static ThumbnailAspect aspectOf(BufferedImage source) {
@@ -112,6 +113,10 @@ public class ThumbnailService {
// 1 for image uploads; for PDFs it comes straight from PDDocument. // 1 for image uploads; for PDFs it comes straight from PDDocument.
private record SourcePreview(BufferedImage image, int pageCount) {} private record SourcePreview(BufferedImage image, int pageCount) {}
// Everything the generate pipeline has already committed to storage and
// now wants stamped onto the Document entity in a single save call.
private record ThumbnailResult(String key, ThumbnailAspect aspect, int pageCount) {}
private static String thumbnailKeyFor(UUID documentId) { private static String thumbnailKeyFor(UUID documentId) {
return THUMBNAIL_KEY_PREFIX + documentId + THUMBNAIL_KEY_SUFFIX; return THUMBNAIL_KEY_PREFIX + documentId + THUMBNAIL_KEY_SUFFIX;
} }
@@ -156,13 +161,12 @@ public class ThumbnailService {
} }
} }
private Outcome persistThumbnailMetadata(Document doc, String thumbnailKey, private Outcome persistThumbnailMetadata(Document doc, ThumbnailResult result) {
ThumbnailAspect aspect, int pageCount) {
try { try {
doc.setThumbnailKey(thumbnailKey); doc.setThumbnailKey(result.key());
doc.setThumbnailGeneratedAt(LocalDateTime.now()); doc.setThumbnailGeneratedAt(LocalDateTime.now());
doc.setThumbnailAspect(aspect); doc.setThumbnailAspect(result.aspect());
doc.setPageCount(pageCount); doc.setPageCount(result.pageCount());
documentRepository.save(doc); documentRepository.save(doc);
return Outcome.SUCCESS; return Outcome.SUCCESS;
} catch (Exception e) { } catch (Exception e) {
@@ -172,7 +176,7 @@ public class ThumbnailService {
// overwrite it cleanly. Logging distinctly so an operator tracking // overwrite it cleanly. Logging distinctly so an operator tracking
// backfill totals can spot the database-side issue. // backfill totals can spot the database-side issue.
log.warn("Thumbnail persist failed for doc={} (orphaned in storage as {}): {}", log.warn("Thumbnail persist failed for doc={} (orphaned in storage as {}): {}",
doc.getId(), thumbnailKey, e.getMessage()); doc.getId(), result.key(), e.getMessage());
return Outcome.FAILED; return Outcome.FAILED;
} }
} }