fix(search): use in-memory sort for SENDER to include documents with null sender
INNER JOIN from Sort.by("sender.lastName") was excluding docs without a sender.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -291,11 +291,15 @@ public class DocumentService {
|
|||||||
.and(hasTagPartial(tagQ))
|
.and(hasTagPartial(tagQ))
|
||||||
.and(hasStatus(status));
|
.and(hasStatus(status));
|
||||||
|
|
||||||
Sort springSort = resolveSort(sort, dir);
|
|
||||||
if (sort == DocumentSort.RECEIVER) {
|
if (sort == DocumentSort.RECEIVER) {
|
||||||
List<Document> results = documentRepository.findAll(spec);
|
List<Document> results = documentRepository.findAll(spec);
|
||||||
return sortByFirstReceiver(results, dir);
|
return sortByFirstReceiver(results, dir);
|
||||||
}
|
}
|
||||||
|
if (sort == DocumentSort.SENDER) {
|
||||||
|
List<Document> results = documentRepository.findAll(spec);
|
||||||
|
return sortBySender(results, dir);
|
||||||
|
}
|
||||||
|
Sort springSort = resolveSort(sort, dir);
|
||||||
return documentRepository.findAll(spec, springSort);
|
return documentRepository.findAll(spec, springSort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,6 +316,22 @@ public class DocumentService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Document> sortBySender(List<Document> documents, String dir) {
|
||||||
|
boolean ascending = "ASC".equalsIgnoreCase(dir);
|
||||||
|
Comparator<String> nullSafeComparator = (a, b) -> {
|
||||||
|
if (a.isEmpty() && b.isEmpty()) return 0;
|
||||||
|
if (a.isEmpty()) return ascending ? 1 : -1;
|
||||||
|
if (b.isEmpty()) return ascending ? -1 : 1;
|
||||||
|
return ascending ? a.compareTo(b) : b.compareTo(a);
|
||||||
|
};
|
||||||
|
return documents.stream()
|
||||||
|
.sorted(Comparator.comparing(doc -> {
|
||||||
|
Person s = doc.getSender();
|
||||||
|
return s != null ? s.getLastName() + " " + s.getFirstName() : "";
|
||||||
|
}, nullSafeComparator))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
private List<Document> sortByFirstReceiver(List<Document> documents, String dir) {
|
private List<Document> sortByFirstReceiver(List<Document> documents, String dir) {
|
||||||
boolean ascending = "ASC".equalsIgnoreCase(dir);
|
boolean ascending = "ASC".equalsIgnoreCase(dir);
|
||||||
Comparator<String> nullSafeComparator = (a, b) -> {
|
Comparator<String> nullSafeComparator = (a, b) -> {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.raddatz.familienarchiv.dto.DocumentUpdateDTO;
|
|||||||
import org.raddatz.familienarchiv.dto.IncompleteDocumentDTO;
|
import org.raddatz.familienarchiv.dto.IncompleteDocumentDTO;
|
||||||
import org.raddatz.familienarchiv.exception.DomainException;
|
import org.raddatz.familienarchiv.exception.DomainException;
|
||||||
import org.raddatz.familienarchiv.model.Document;
|
import org.raddatz.familienarchiv.model.Document;
|
||||||
|
import org.raddatz.familienarchiv.model.DocumentSort;
|
||||||
import org.raddatz.familienarchiv.model.DocumentStatus;
|
import org.raddatz.familienarchiv.model.DocumentStatus;
|
||||||
import org.raddatz.familienarchiv.model.Person;
|
import org.raddatz.familienarchiv.model.Person;
|
||||||
import org.raddatz.familienarchiv.model.Tag;
|
import org.raddatz.familienarchiv.model.Tag;
|
||||||
@@ -1273,4 +1274,23 @@ class DocumentServiceTest {
|
|||||||
verify(documentRepository).findConversation(eq(senderId), eq(receiverId), any(), any(), eq(sort));
|
verify(documentRepository).findConversation(eq(senderId), eq(receiverId), any(), any(), eq(sort));
|
||||||
verify(documentRepository, never()).findSinglePersonCorrespondence(any(), any(), any(), any());
|
verify(documentRepository, never()).findSinglePersonCorrespondence(any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── searchDocuments — SENDER sort includes documents with null sender ─────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void searchDocuments_senderSort_includesDocumentsWithNullSender() {
|
||||||
|
Person alice = Person.builder().id(UUID.randomUUID()).firstName("Alice").lastName("Ziegler").build();
|
||||||
|
Document withSender = Document.builder().id(UUID.randomUUID()).title("Has Sender").sender(alice).build();
|
||||||
|
Document noSender = Document.builder().id(UUID.randomUUID()).title("No Sender").build();
|
||||||
|
|
||||||
|
// The repository returns both documents (no filtering by sender)
|
||||||
|
when(documentRepository.findAll(any(org.springframework.data.jpa.domain.Specification.class)))
|
||||||
|
.thenReturn(List.of(withSender, noSender));
|
||||||
|
|
||||||
|
List<Document> result = documentService.searchDocuments(
|
||||||
|
null, null, null, null, null, null, null, null, DocumentSort.SENDER, "asc");
|
||||||
|
|
||||||
|
assertThat(result).hasSize(2);
|
||||||
|
assertThat(result).extracting(Document::getTitle).containsExactly("Has Sender", "No Sender");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user