feat(journey-editor): JourneyEditor frontend — issue #753 #792
@@ -30,8 +30,18 @@ public interface JourneyItemRepository extends JpaRepository<JourneyItem, UUID>
|
||||
/** COUNT for the 100-item cap check — COUNT(*)-based, never MAX(position)-derived. */
|
||||
long countByGeschichteId(UUID geschichteId);
|
||||
|
||||
/** Dedup guard: true when the document is already linked to this journey. */
|
||||
boolean existsByGeschichteIdAndDocumentId(UUID geschichteId, UUID documentId);
|
||||
/**
|
||||
* Dedup guard: true when the document is already linked to this journey.
|
||||
* Explicit JPQL, not a derived query: the transient {@code getDocumentId()}
|
||||
* getter on JourneyItem makes Spring Data resolve the derived path as a
|
||||
* direct {@code documentId} attribute, which Hibernate cannot map.
|
||||
*/
|
||||
@Query("""
|
||||
SELECT COUNT(i) > 0 FROM JourneyItem i
|
||||
WHERE i.geschichte.id = :geschichteId AND i.document.id = :documentId
|
||||
""")
|
||||
boolean existsByGeschichteIdAndDocumentId(
|
||||
@Param("geschichteId") UUID geschichteId, @Param("documentId") UUID documentId);
|
||||
|
||||
/**
|
||||
* Loads journey items with their linked Document in a single JOIN FETCH query,
|
||||
|
||||
@@ -258,6 +258,30 @@ class JourneyItemIntegrationTest {
|
||||
assertThat(persisted.get(0).getNote()).isEqualTo("First stop");
|
||||
}
|
||||
|
||||
@Test
|
||||
void append_document_persists_and_rejects_duplicate() {
|
||||
// Covers the document branch of append, including the duplicate guard —
|
||||
// the derived exists query must resolve document.id, which the transient
|
||||
// getDocumentId() getter on JourneyItem shadows for Spring Data.
|
||||
authenticateAs(writer, Permission.BLOG_WRITE);
|
||||
|
||||
JourneyItemCreateDTO dto = new JourneyItemCreateDTO();
|
||||
dto.setDocumentId(doc.getId());
|
||||
|
||||
JourneyItemView view = journeyItemService.append(journey.getId(), dto);
|
||||
em.flush();
|
||||
em.clear();
|
||||
|
||||
assertThat(view.document()).isNotNull();
|
||||
assertThat(view.document().id()).isEqualTo(doc.getId());
|
||||
|
||||
JourneyItemCreateDTO duplicate = new JourneyItemCreateDTO();
|
||||
duplicate.setDocumentId(doc.getId());
|
||||
assertThatThrownBy(() -> journeyItemService.append(journey.getId(), duplicate))
|
||||
.hasFieldOrPropertyWithValue("code",
|
||||
org.raddatz.familienarchiv.exception.ErrorCode.JOURNEY_DOCUMENT_ALREADY_ADDED);
|
||||
}
|
||||
|
||||
// ─── JourneyItemService.reorder — atomicity check ────────────────────────
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user