refactor(document): address review concerns from PR #660
All checks were successful
CI / Semgrep Security Scan (pull_request) Successful in 21s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m2s
nightly / deploy-staging (push) Successful in 2m2s
CI / Unit & Component Tests (push) Successful in 3m58s
CI / OCR Service Tests (push) Successful in 20s
CI / Backend Unit Tests (push) Successful in 3m50s
CI / fail2ban Regex (push) Successful in 44s
CI / Unit & Component Tests (pull_request) Successful in 3m29s
CI / Semgrep Security Scan (push) Successful in 21s
CI / OCR Service Tests (pull_request) Successful in 21s
CI / Backend Unit Tests (pull_request) Successful in 3m43s
CI / Compose Bucket Idempotency (push) Successful in 59s
CI / fail2ban Regex (pull_request) Successful in 45s

- Restore JavaDoc on DocumentSearchResult.of() and .paged() factory methods
- Remove redundant null guards on @Builder.Default collections in toListItem()
- Map DocumentListItem fields explicitly in DocumentMultiSelect before cast
- Add DocumentListItem required fields to docFactory in spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #660.
This commit is contained in:
Marcel
2026-05-22 19:27:31 +02:00
parent 627fc44d99
commit 8e9e3bba06
4 changed files with 28 additions and 4 deletions

View File

@@ -17,11 +17,19 @@ public record DocumentSearchResult(
@Schema(requiredMode = Schema.RequiredMode.REQUIRED) @Schema(requiredMode = Schema.RequiredMode.REQUIRED)
int totalPages int totalPages
) { ) {
/**
* Single-page convenience factory used by empty-result shortcuts and by tests that
* don't care about paging. Treats the whole list as page 0 of itself.
*/
public static DocumentSearchResult of(List<DocumentListItem> items) { public static DocumentSearchResult of(List<DocumentListItem> items) {
int size = items.size(); int size = items.size();
return new DocumentSearchResult(items, size, 0, size, size == 0 ? 0 : 1); return new DocumentSearchResult(items, size, 0, size, size == 0 ? 0 : 1);
} }
/**
* Paged factory used by the service when it has a real Pageable + full match count
* (e.g. from Spring's Page&lt;T&gt; or from an in-memory sort-then-slice).
*/
public static DocumentSearchResult paged(List<DocumentListItem> slice, Pageable pageable, long totalElements) { public static DocumentSearchResult paged(List<DocumentListItem> slice, Pageable pageable, long totalElements) {
int pageSize = pageable.getPageSize(); int pageSize = pageable.getPageSize();
int totalPages = pageSize == 0 ? 0 : (int) ((totalElements + pageSize - 1) / pageSize); int totalPages = pageSize == 0 ? 0 : (int) ((totalElements + pageSize - 1) / pageSize);

View File

@@ -759,8 +759,8 @@ public class DocumentService {
doc.getThumbnailUrl(), doc.getThumbnailUrl(),
doc.getDocumentDate(), doc.getDocumentDate(),
doc.getSender(), doc.getSender(),
doc.getReceivers() != null ? List.copyOf(doc.getReceivers()) : List.of(), List.copyOf(doc.getReceivers()),
doc.getTags() != null ? List.copyOf(doc.getTags()) : List.of(), List.copyOf(doc.getTags()),
doc.getArchiveBox(), doc.getArchiveBox(),
doc.getArchiveFolder(), doc.getArchiveFolder(),
doc.getLocation(), doc.getLocation(),

View File

@@ -46,7 +46,11 @@ function handleInput() {
const res = await fetch(`/api/documents/search?q=${encodeURIComponent(searchTerm)}&size=10`); const res = await fetch(`/api/documents/search?q=${encodeURIComponent(searchTerm)}&size=10`);
if (res.ok) { if (res.ok) {
const body: { items: DocumentListItem[] } = await res.json(); const body: { items: DocumentListItem[] } = await res.json();
const docs = body.items as unknown as Document[]; const docs = body.items.map((it) => ({
id: it.id,
title: it.title,
documentDate: it.documentDate
})) as unknown as Document[];
results = docs.filter((d) => !selectedDocuments.some((s) => s.id === d.id)); results = docs.filter((d) => !selectedDocuments.some((s) => s.id === d.id));
} }
} catch { } catch {

View File

@@ -10,7 +10,19 @@ const docFactory = (id: string, title: string, date = '1880-01-01') => ({
title, title,
documentDate: date, documentDate: date,
originalFilename: `${title}.pdf`, originalFilename: `${title}.pdf`,
status: 'UPLOADED', receivers: [],
tags: [],
completionPercentage: 0,
contributors: [],
matchData: {
titleOffsets: [],
senderMatched: false,
matchedReceiverIds: [],
matchedTagIds: [],
snippetOffsets: [],
summaryOffsets: []
},
status: 'UPLOADED' as const,
metadataComplete: false, metadataComplete: false,
scriptType: 'UNKNOWN' as const, scriptType: 'UNKNOWN' as const,
createdAt: '2024-01-01T00:00:00', createdAt: '2024-01-01T00:00:00',