@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { return delegate.readEvents(aggregateIdentifier, firstSequenceNumber); }
@Override public Stream<? extends TrackedEventMessage<?>> readEvents(TrackingToken trackingToken, boolean mayBlock) { return delegate.readEvents(trackingToken, mayBlock); }
@Override public DomainEventStream readEvents(String aggregateIdentifier) { return delegate.readEvents(aggregateIdentifier); }
/** * Get a {@link DomainEventStream} containing all events published by the aggregate with given {@code * aggregateIdentifier}. By default calling this method is shorthand for an invocation of * {@link #readEvents(String, long)} with a sequence number of 0. * <p> * The returned stream is finite, i.e. it should not block to wait for further events if the end of the event stream * of the aggregate is reached. * * @param aggregateIdentifier The identifier of the aggregate to return an event stream for * @return A non-blocking DomainEventStream of the given aggregate */ default DomainEventStream readEvents(String aggregateIdentifier) { return readEvents(aggregateIdentifier, 0L); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { DomainEventStream historic = historicStorage.readEvents(aggregateIdentifier, firstSequenceNumber); return new ConcatenatingDomainEventStream(historic, aggregateIdentifier, (id, seq) -> activeStorage.readEvents(aggregateIdentifier, seq)); }
/** * Returns the last known sequence number for the given {@code aggregateIdentifier}. * <p> * While it's recommended to use the sequence numbers from the {@link DomainEventStream}, there are cases where * knowing the sequence number is required, without having read the actual events. In such case, this method is a * viable alternative. * * @param aggregateIdentifier The identifier to find the last sequence number for * @return an optional with the highest sequence number, or an empty optional if the aggregate identifier wasn't * found */ default Optional<Long> lastSequenceNumberFor(String aggregateIdentifier) { return readEvents(aggregateIdentifier).asStream().map(DomainEventMessage::getSequenceNumber).max(Long::compareTo); }
@Override public Stream<? extends TrackedEventMessage<?>> readEvents(TrackingToken trackingToken, boolean mayBlock) { Spliterator<? extends TrackedEventMessage<?>> historicSpliterator = historicStorage.readEvents(trackingToken, mayBlock).spliterator(); Spliterator<? extends TrackedEventMessage<?>> merged = new ConcatenatingSpliterator( historicSpliterator, mayBlock, token -> activeStorage.readEvents(token, mayBlock).spliterator()); return StreamSupport.stream(merged, false); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { return DomainEventStream.concat(storageEngine.readEvents(aggregateIdentifier, firstSequenceNumber), DomainEventStream.of( stagedDomainEventMessages(aggregateIdentifier) .filter(m -> m.getSequenceNumber() >= firstSequenceNumber))); }
@Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void testLoadPartialStreamOfTrackedEvents() { List<DomainEventMessage<?>> events = createEvents(4); testSubject.appendEvents(events); TrackingToken token = testSubject.readEvents(null, false).findFirst().get().trackingToken(); assertEquals(3, testSubject.readEvents(token, false).count()); assertEquals(events.subList(1, events.size()).stream().map(EventMessage::getIdentifier).collect(toList()), testSubject.readEvents(token, false).map(EventMessage::getIdentifier).collect(toList())); }
@Test public void testLoadNonExistent() { assertEquals(0L, testSubject.readEvents(randomUUID().toString()).asStream().count()); }
@Test public void testCreateTokenAt() { DomainEventMessage<String> event1 = createEvent(0, Instant.parse("2007-12-03T10:15:00.00Z")); DomainEventMessage<String> event2 = createEvent(1, Instant.parse("2007-12-03T10:15:40.00Z")); DomainEventMessage<String> event3 = createEvent(2, Instant.parse("2007-12-03T10:15:35.00Z")); testSubject.appendEvents(event1, event2, event3); TrackingToken tokenAt = testSubject.createTokenAt(Instant.parse("2007-12-03T10:15:30.00Z")); List<EventMessage<?>> readEvents = testSubject.readEvents(tokenAt, false) .collect(toList()); assertEventStreamsById(Arrays.asList(event2, event3), readEvents); }
@Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void testReadPartialStream() { testSubject.appendEvents(createEvents(5)); assertEquals(2L, testSubject.readEvents(AGGREGATE, 2).asStream().findFirst().get().getSequenceNumber()); assertEquals(4L, testSubject.readEvents(AGGREGATE, 2).asStream().reduce((a, b) -> b).get().getSequenceNumber()); assertEquals(3L, testSubject.readEvents(AGGREGATE, 2).asStream().count()); }
@Test public void testCreateTailToken() { DomainEventMessage<String> event1 = createEvent(0, Instant.parse("2007-12-03T10:15:00.00Z")); DomainEventMessage<String> event2 = createEvent(1, Instant.parse("2007-12-03T10:15:40.00Z")); DomainEventMessage<String> event3 = createEvent(2, Instant.parse("2007-12-03T10:15:35.00Z")); testSubject.appendEvents(event1, event2, event3); TrackingToken headToken = testSubject.createTailToken(); List<EventMessage<?>> readEvents = testSubject.readEvents(headToken, false) .collect(toList()); assertEventStreamsById(Arrays.asList(event1, event2, event3), readEvents); }
@Test public void testCreateHeadToken() { DomainEventMessage<String> event1 = createEvent(0, Instant.parse("2007-12-03T10:15:00.00Z")); DomainEventMessage<String> event2 = createEvent(1, Instant.parse("2007-12-03T10:15:40.00Z")); DomainEventMessage<String> event3 = createEvent(2, Instant.parse("2007-12-03T10:15:35.00Z")); testSubject.appendEvents(event1, event2, event3); TrackingToken headToken = testSubject.createHeadToken(); List<EventMessage<?>> readEvents = testSubject.readEvents(headToken, false) .collect(toList()); assertTrue(readEvents.isEmpty()); }
@Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void testLoadTrackedEvents() throws InterruptedException { testSubject.appendEvents(createEvents(4)); assertEquals(4, testSubject.readEvents(null, false).count()); // give the clock some time to make sure the last message is really last Thread.sleep(10); DomainEventMessage<?> eventMessage = createEvent("otherAggregate", 0); testSubject.appendEvents(eventMessage); assertEquals(5, testSubject.readEvents(null, false).count()); assertEquals(eventMessage.getIdentifier(), testSubject.readEvents(null, false).reduce((a, b) -> b).get().getIdentifier()); }
@Test public void testCreateTokenWithUnorderedEvents() { DomainEventMessage<String> event1 = createEvent(0, Instant.parse("2007-12-03T10:15:30.00Z")); DomainEventMessage<String> event2 = createEvent(1, Instant.parse("2007-12-03T10:15:40.00Z")); DomainEventMessage<String> event3 = createEvent(2, Instant.parse("2007-12-03T10:15:50.00Z")); DomainEventMessage<String> event4 = createEvent(3, Instant.parse("2007-12-03T10:15:45.00Z")); DomainEventMessage<String> event5 = createEvent(4, Instant.parse("2007-12-03T10:15:42.00Z")); testSubject.appendEvents(event1, event2, event3, event4, event5); TrackingToken tokenAt = testSubject.createTokenAt(Instant.parse("2007-12-03T10:15:45.00Z")); List<EventMessage<?>> readEvents = testSubject.readEvents(tokenAt, false) .collect(toList()); assertEventStreamsById(Arrays.asList(event3, event4, event5), readEvents); }
@Test public void testCreateTokenAtExactTime() { DomainEventMessage<String> event1 = createEvent(0, Instant.parse("2007-12-03T10:15:30.00Z")); DomainEventMessage<String> event2 = createEvent(1, Instant.parse("2007-12-03T10:15:40.00Z")); DomainEventMessage<String> event3 = createEvent(2, Instant.parse("2007-12-03T10:15:35.00Z")); testSubject.appendEvents(event1, event2, event3); TrackingToken tokenAt = testSubject.createTokenAt(Instant.parse("2007-12-03T10:15:30.00Z")); List<EventMessage<?>> readEvents = testSubject.readEvents(tokenAt, false) .collect(toList()); assertEventStreamsById(Arrays.asList(event1, event2, event3), readEvents); }
@Test public void testStoreAndLoadEvents() { testSubject.appendEvents(createEvents(4)); assertEquals(4, testSubject.readEvents(AGGREGATE).asStream().count()); testSubject.appendEvents(createEvent("otherAggregate", 0)); assertEquals(4, testSubject.readEvents(AGGREGATE).asStream().count()); assertEquals(1, testSubject.readEvents("otherAggregate").asStream().count()); }
@Test public void testStoreAndLoadApplicationEvent() { testSubject.appendEvents(new GenericEventMessage<>("application event", MetaData.with("key", "value"))); assertEquals(1, testSubject.readEvents(null, false).count()); EventMessage<?> message = testSubject.readEvents(null, false).findFirst().get(); assertEquals("application event", message.getPayload()); assertEquals(MetaData.with("key", "value"), message.getMetaData()); }
@Test public void testStoreAndLoadEventsArray() { testSubject.appendEvents(createEvent(0), createEvent(1)); assertEquals(2, testSubject.readEvents(AGGREGATE).asStream().count()); }