2020import java .time .Instant ;
2121import java .time .ZoneOffset ;
2222import java .util .ArrayList ;
23+ import java .util .Collection ;
2324import java .util .List ;
2425import java .util .Map ;
2526import java .util .Objects ;
2627import java .util .Optional ;
2728import java .util .UUID ;
29+ import java .util .function .BiFunction ;
2830import java .util .function .Function ;
2931
3032import org .neo4j .cypherdsl .core .Cypher ;
3133import org .neo4j .cypherdsl .core .Node ;
3234import org .neo4j .cypherdsl .core .ResultStatement ;
3335import org .neo4j .cypherdsl .core .Statement ;
36+ import org .neo4j .cypherdsl .core .StatementBuilder .OrderableOngoingReadingAndWithWithoutWhere ;
3437import org .neo4j .cypherdsl .core .renderer .Configuration ;
3538import org .neo4j .cypherdsl .core .renderer .Renderer ;
3639import org .neo4j .driver .Values ;
@@ -65,11 +68,14 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
6568 private static final String PUBLICATION_DATE = "publicationDate" ;
6669 private static final String COMPLETION_DATE = "completionDate" ;
6770
71+ private static final Collection <String > ALL_PROPERTIES = List .of (ID , EVENT_SERIALIZED , EVENT_HASH , EVENT_TYPE ,
72+ LISTENER_ID , PUBLICATION_DATE , COMPLETION_DATE );
73+
6874 private static final Node EVENT_PUBLICATION_NODE = node ("Neo4jEventPublication" )
6975 .named ("neo4jEventPublication" );
7076
71- private static final Node EVENT_PUBLICATION_COMPLETED_NODE = node ("Neo4jEventPublicationCompleted " )
72- .named ("neo4jEventPublicationCompleted " );
77+ private static final Node EVENT_PUBLICATION_ARCHIVE_NODE = node ("Neo4jEventPublicationArchive " )
78+ .named ("neo4jEventPublicationArchive " );
7379
7480 private static final Statement INCOMPLETE_BY_EVENT_AND_TARGET_IDENTIFIER_STATEMENT = match (EVENT_PUBLICATION_NODE )
7581 .where (EVENT_PUBLICATION_NODE .property (EVENT_HASH ).eq (parameter (EVENT_HASH )))
@@ -114,6 +120,7 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
114120 .set (EVENT_PUBLICATION_NODE .property (EVENT_TYPE ).to (parameter (EVENT_TYPE )))
115121 .set (EVENT_PUBLICATION_NODE .property (LISTENER_ID ).to (parameter (LISTENER_ID )))
116122 .set (EVENT_PUBLICATION_NODE .property (PUBLICATION_DATE ).to (parameter (PUBLICATION_DATE )))
123+ .set (EVENT_PUBLICATION_NODE .property (COMPLETION_DATE ).to (parameter (COMPLETION_DATE )))
117124 .build ();
118125
119126 private static final Statement COMPLETE_STATEMENT = match (EVENT_PUBLICATION_NODE )
@@ -123,29 +130,34 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
123130 .set (EVENT_PUBLICATION_NODE .property (COMPLETION_DATE ).to (parameter (COMPLETION_DATE )))
124131 .build ();
125132
126- private static final Statement COMPLETE_IN_ARCHIVE_BY_ID_STATEMENT = match (EVENT_PUBLICATION_NODE )
133+ private static final Statement COMPLETE_IN_ARCHIVE_BY_ID_STATEMENT = applyProperties ( match (EVENT_PUBLICATION_NODE )
127134 .where (EVENT_PUBLICATION_NODE .property (ID ).eq (parameter (ID )))
128- .and (not (exists (match (EVENT_PUBLICATION_COMPLETED_NODE )
129- .where (EVENT_PUBLICATION_COMPLETED_NODE .property (ID ).eq (parameter (ID )))
130- .returning (literalTrue ()).build ())))
131- .with (EVENT_PUBLICATION_NODE )
132- .create (EVENT_PUBLICATION_COMPLETED_NODE )
133- .set (EVENT_PUBLICATION_COMPLETED_NODE .property (ID ).to (EVENT_PUBLICATION_NODE .property (ID )))
134- .set (EVENT_PUBLICATION_COMPLETED_NODE .property (COMPLETION_DATE ).to (parameter (COMPLETION_DATE )))
135- .build ();
136-
137- private static final Statement COMPLETE_IN_ARCHIVE_BY_EVENT_AND_LISTENER_ID_STATEMENT = match (EVENT_PUBLICATION_NODE )
138- .where (EVENT_PUBLICATION_NODE .property (EVENT_HASH ).eq (parameter (EVENT_HASH )))
139- .and (EVENT_PUBLICATION_NODE .property (LISTENER_ID ).eq (parameter (LISTENER_ID )))
140- .and (not (exists (match (EVENT_PUBLICATION_COMPLETED_NODE )
141- .where (EVENT_PUBLICATION_COMPLETED_NODE .property (EVENT_HASH ).eq (parameter (EVENT_HASH )))
142- .and (EVENT_PUBLICATION_COMPLETED_NODE .property (LISTENER_ID ).eq (parameter (LISTENER_ID )))
135+ .and (not (exists (match (EVENT_PUBLICATION_ARCHIVE_NODE )
136+ .where (EVENT_PUBLICATION_ARCHIVE_NODE .property (ID ).eq (parameter (ID )))
143137 .returning (literalTrue ()).build ())))
144- .with (EVENT_PUBLICATION_NODE )
145- .create (EVENT_PUBLICATION_COMPLETED_NODE )
146- .set (EVENT_PUBLICATION_COMPLETED_NODE .property (ID ).to (EVENT_PUBLICATION_NODE .property (ID )))
147- .set (EVENT_PUBLICATION_COMPLETED_NODE .property (COMPLETION_DATE ).to (parameter (COMPLETION_DATE )))
148- .build ();
138+ .with (EVENT_PUBLICATION_NODE ));
139+
140+ private static final Statement COMPLETE_IN_ARCHIVE_BY_EVENT_AND_LISTENER_ID_STATEMENT = applyProperties (
141+ match (EVENT_PUBLICATION_NODE )
142+ .where (EVENT_PUBLICATION_NODE .property (EVENT_HASH ).eq (parameter (EVENT_HASH )))
143+ .and (EVENT_PUBLICATION_NODE .property (LISTENER_ID ).eq (parameter (LISTENER_ID )))
144+ .and (not (exists (match (EVENT_PUBLICATION_ARCHIVE_NODE )
145+ .where (EVENT_PUBLICATION_ARCHIVE_NODE .property (EVENT_HASH ).eq (parameter (EVENT_HASH )))
146+ .and (EVENT_PUBLICATION_ARCHIVE_NODE .property (LISTENER_ID ).eq (parameter (LISTENER_ID )))
147+ .returning (literalTrue ()).build ())))
148+ .with (EVENT_PUBLICATION_NODE ));
149+
150+ private static Statement applyProperties (OrderableOngoingReadingAndWithWithoutWhere source ) {
151+
152+ var operations = ALL_PROPERTIES .stream ()
153+ .map (it -> EVENT_PUBLICATION_ARCHIVE_NODE .property (it ).to (EVENT_PUBLICATION_NODE .property (it )))
154+ .toList ();
155+
156+ return source .create (EVENT_PUBLICATION_ARCHIVE_NODE )
157+ .set (operations )
158+ .set (EVENT_PUBLICATION_ARCHIVE_NODE .property (COMPLETION_DATE ).to (parameter (COMPLETION_DATE )))
159+ .build ();
160+ }
149161
150162 private static final Function <Node , Statement > COMPLETE_BY_ID_STATEMENT = node -> match (node )
151163 .where (node .property (ID ).eq (parameter (ID )))
@@ -168,6 +180,7 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
168180 private final Renderer renderer ;
169181 private final EventSerializer eventSerializer ;
170182 private final CompletionMode completionMode ;
183+ private final Node completedNode ;
171184
172185 private final Statement deleteCompletedStatement ;
173186 private final Statement deleteCompletedBeforeStatement ;
@@ -187,12 +200,14 @@ class Neo4jEventPublicationRepository implements EventPublicationRepository {
187200 this .eventSerializer = eventSerializer ;
188201 this .completionMode = completionMode ;
189202
190- var archiveNode = completionMode == CompletionMode .ARCHIVE ? EVENT_PUBLICATION_COMPLETED_NODE : EVENT_PUBLICATION_NODE ;
203+ this .completedNode = completionMode == CompletionMode .ARCHIVE
204+ ? EVENT_PUBLICATION_ARCHIVE_NODE
205+ : EVENT_PUBLICATION_NODE ;
191206
192- this .deleteCompletedStatement = DELETE_COMPLETED_STATEMENT .apply (archiveNode );
193- this .deleteCompletedBeforeStatement = DELETE_COMPLETED_BEFORE_STATEMENT .apply (archiveNode );
194- this .completedByIdStatement = COMPLETE_BY_ID_STATEMENT .apply (archiveNode );
195- this .allCompletedStatement = ALL_COMPLETED_STATEMENT .apply (archiveNode );
207+ this .deleteCompletedStatement = DELETE_COMPLETED_STATEMENT .apply (completedNode );
208+ this .deleteCompletedBeforeStatement = DELETE_COMPLETED_BEFORE_STATEMENT .apply (completedNode );
209+ this .completedByIdStatement = COMPLETE_BY_ID_STATEMENT .apply (completedNode );
210+ this .allCompletedStatement = ALL_COMPLETED_STATEMENT .apply (completedNode );
196211 }
197212
198213 /*
@@ -219,7 +234,8 @@ public TargetEventPublication create(TargetEventPublication publication) {
219234 EVENT_HASH , eventHash ,
220235 EVENT_TYPE , eventType ,
221236 LISTENER_ID , listenerId ,
222- PUBLICATION_DATE , Values .value (publicationDate .atOffset (ZoneOffset .UTC ))))
237+ PUBLICATION_DATE , Values .value (publicationDate .atOffset (ZoneOffset .UTC )),
238+ COMPLETION_DATE , Values .NULL ))
223239 .run ();
224240
225241 return publication ;
@@ -249,6 +265,7 @@ public void markCompleted(Object event, PublicationTargetIdentifier identifier,
249265 .bind (identifier .getValue ()).to (LISTENER_ID )
250266 .bind (Values .value (completionDate .atOffset (ZoneOffset .UTC ))).to (COMPLETION_DATE )
251267 .run ();
268+
252269 neo4jClient .query (renderer .render (DELETE_BY_EVENT_AND_LISTENER_ID ))
253270 .bind (eventHash ).to (EVENT_HASH )
254271 .bind (identifier .getValue ()).to (LISTENER_ID )
@@ -279,9 +296,10 @@ public void markCompleted(UUID identifier, Instant completionDate) {
279296 } else if (completionMode == CompletionMode .ARCHIVE ) {
280297
281298 neo4jClient .query (renderer .render (COMPLETE_IN_ARCHIVE_BY_ID_STATEMENT ))
282- .bind ("" ).to (ID )
299+ .bind (Values . value ( identifier . toString ()) ).to (ID )
283300 .bind (Values .value (completionDate .atOffset (ZoneOffset .UTC ))).to (COMPLETION_DATE )
284301 .run ();
302+
285303 deletePublications (List .of (identifier ));
286304
287305 } else {
@@ -304,7 +322,7 @@ public List<TargetEventPublication> findIncompletePublications() {
304322
305323 return List .copyOf (neo4jClient .query (renderer .render (INCOMPLETE_STATEMENT ))
306324 .fetchAs (TargetEventPublication .class )
307- .mappedBy (this :: mapRecordToPublication )
325+ .mappedBy (incompleteMapping () )
308326 .all ());
309327 }
310328
@@ -319,7 +337,7 @@ public List<TargetEventPublication> findIncompletePublicationsPublishedBefore(In
319337 return List .copyOf (neo4jClient .query (renderer .render (INCOMPLETE_PUBLISHED_BEFORE_STATEMENT ))
320338 .bind (Values .value (instant .atOffset (ZoneOffset .UTC ))).to (PUBLICATION_DATE )
321339 .fetchAs (TargetEventPublication .class )
322- .mappedBy (this :: mapRecordToPublication )
340+ .mappedBy (incompleteMapping () )
323341 .all ());
324342 }
325343
@@ -338,7 +356,7 @@ public Optional<TargetEventPublication> findIncompletePublicationsByEventAndTarg
338356 return neo4jClient .query (renderer .render (INCOMPLETE_BY_EVENT_AND_TARGET_IDENTIFIER_STATEMENT ))
339357 .bindAll (Map .of (EVENT_HASH , eventHash , LISTENER_ID , listenerId ))
340358 .fetchAs (TargetEventPublication .class )
341- .mappedBy (this :: mapRecordToPublication )
359+ .mappedBy (incompleteMapping () )
342360 .one ();
343361 }
344362
@@ -351,7 +369,7 @@ public List<TargetEventPublication> findCompletedPublications() {
351369
352370 return new ArrayList <>(neo4jClient .query (renderer .render (allCompletedStatement ))
353371 .fetchAs (TargetEventPublication .class )
354- .mappedBy (this :: mapRecordToPublication )
372+ .mappedBy (completeMapping () )
355373 .all ());
356374 }
357375
@@ -391,21 +409,31 @@ public void deleteCompletedPublicationsBefore(Instant instant) {
391409 .run ();
392410 }
393411
394- private Neo4jEventPublicationAdapter mapRecordToPublication (TypeSystem typeSystem , org .neo4j .driver .Record record ) {
412+ private BiFunction <TypeSystem , org .neo4j .driver .Record , TargetEventPublication > incompleteMapping () {
413+ return (typeSystem , driverRecord ) -> mapRecordToPublication (typeSystem , driverRecord , EVENT_PUBLICATION_NODE );
414+ }
415+
416+ private BiFunction <TypeSystem , org .neo4j .driver .Record , TargetEventPublication > completeMapping () {
417+ return (typeSystem , driverRecord ) -> mapRecordToPublication (typeSystem , driverRecord , completedNode );
418+ }
419+
420+ private Neo4jEventPublicationAdapter mapRecordToPublication (TypeSystem typeSystem , org .neo4j .driver .Record record ,
421+ Node node ) {
395422
396- var publicationNode = record .get (EVENT_PUBLICATION_NODE .getRequiredSymbolicName ().getValue ()).asNode ();
423+ var publicationNode = record .get (node .getRequiredSymbolicName ().getValue ()).asNode ();
397424 var identifier = UUID .fromString (publicationNode .get (ID ).asString ());
398425 var publicationDate = publicationNode .get (PUBLICATION_DATE ).asZonedDateTime ().toInstant ();
399426 var listenerId = publicationNode .get (LISTENER_ID ).asString ();
400427 var eventSerialized = publicationNode .get (EVENT_SERIALIZED ).asString ();
401428 var eventHash = publicationNode .get (EVENT_HASH ).asString ();
402429 var eventType = publicationNode .get (EVENT_TYPE ).asString ();
430+ var completionDate = publicationNode .get (COMPLETION_DATE );
403431
404432 try {
405433
406434 var event = eventSerializer .deserialize (eventSerialized , Class .forName (eventType ));
407435 var publication = new Neo4jEventPublication (identifier , publicationDate , listenerId , event ,
408- eventHash );
436+ eventHash , completionDate . isNull () ? null : completionDate . asZonedDateTime (). toInstant () );
409437
410438 return new Neo4jEventPublicationAdapter (publication );
411439
0 commit comments