/** * Appends events, provided explicitly, to a given existing or new aggregate, optionally * requiring the current version to match the specified requirements. * * @param aggregateId The id of the aggregate to append events do. * @param events The list of events to append. * @param expectedVersion The expected version of the aggregate at the time the new events are * appended to its underlying stream of events. If the version at the * time the append is attempted differs from the one provided, an * UnexpectedVersionException will be thrown. */ default int append( final String aggregateId, final Iterable<? extends TEvent> events, final ExpectedVersion expectedVersion) { return append(aggregateId, events, expectedVersion, null); }
/** * Persists a given existing or new aggregate with a list of events taken from an aggregate * state. The id of the aggregate and expected version (if used) will be taken from the details * of the aggregate state, and all pending events on the state will be persisted. * * @param aggregate The aggregate to apply updates for. */ default ImmutableAggregate<TState, TEvent> save( @NotNull Aggregate<TState, TEvent> aggregate) { return save(aggregate, true, null); }
when(repository.load(any())) .thenReturn(DefaultImmutableAggregate.fromExisting( mock(AggregateProjection.class), 42, new TestState("test"))); when(repository.append(any(), any(), any(), any())).thenReturn(newVersion); verify(repository).append(eq(AGGREGATE_ID), passedEvents.capture(), any(), any()); Assert.assertThat( passedEvents.getValue(),
@Test @SuppressWarnings("unchecked") public void aggregateReadWhenStateRequired() { Operation operation = new OperationHandlerOperation( (x, y) -> ImmutableList.of(new TestEvent("test")), true, false, ExpectedVersion.any()); DefaultCommand command = new DefaultCommand(repository, operation); when(repository.load(any())) .thenReturn(DefaultImmutableAggregate.fromExisting( mock(AggregateProjection.class), AGGREGATE_ID, 42, new TestState("test"))); command.setAggregateId(AGGREGATE_ID); command.run(); verify(repository).load(AGGREGATE_ID); }
DefaultImmutableAggregate sourceAggregate = DefaultImmutableAggregate.createNew(projection, AGGREGATE_ID); when(repository.load(any())).thenReturn(sourceAggregate); when(repository.append(any(), any(), any(), any())).thenReturn(newVersion); DefaultCommand command = new DefaultCommand(repository, operation); command.setAggregateId(AGGREGATE_ID); verify(repository).append(eq(AGGREGATE_ID), passedEvents.capture(), any(), any()); Assert.assertThat( passedEvents.getValue(),
@NotNull private ImmutableAggregate<TState, TEvent> readAndValidateAggregate( final ExpectedVersion effectiveExpectedVersion) { ImmutableAggregate<TState, TEvent> aggregate = repository.load(aggregateId);
when(repository.load(any())) .thenReturn(DefaultImmutableAggregate.fromExisting( mock(AggregateProjection.class), 42, new TestState("test"))); when(repository.append(any(), any(), any(), any())).thenReturn(newVersion); verify(repository).append(eq(AGGREGATE_ID), any(), any(), passedMetadata.capture()); Assert.assertEquals( "value1",
/** * Appends events, provided explicitly, to a given existing or new aggregate, optionally * requiring the current version to match the specified requirements. * * @param aggregateId The id of the aggregate to append events do. * @param events The list of events to append. * @param expectedVersion The expected version of the aggregate at the time the new events are * appended to its underlying stream of events. If the version at the * time the append is attempted differs from the one provided, an * UnexpectedVersionException will be thrown. */ default int append( final String aggregateId, final Iterable<? extends TEvent> events, final ExpectedVersion expectedVersion) { return append(aggregateId, events, expectedVersion, null); }
@NotNull private ImmutableAggregate<TState, TEvent> readAndValidateAggregate( final ExpectedVersion effectiveExpectedVersion) { ImmutableAggregate<TState, TEvent> aggregate = repository.load(aggregateId);
/** * Persists a given existing or new aggregate with a list of events taken from an aggregate * state. The id of the aggregate and expected version (if used) will be taken from the details * of the aggregate state, and all pending events on the state will be persisted. * * @param aggregate The aggregate to apply updates for. */ default ImmutableAggregate<TState, TEvent> save( @NotNull Aggregate<TState, TEvent> aggregate) { return save(aggregate, true, null); }
@Test @SuppressWarnings("unchecked") public void idempotentCreateWorksIfConflictOnSave() { Operation operation = new OperationHandlerOperation( (x, y) -> ImmutableList.of("hello"), false, false, ExpectedVersion.notCreated()); when(repository.load(any())) .thenReturn(DefaultImmutableAggregate.fromExisting( mock(AggregateProjection.class), AGGREGATE_ID, 42, new TestState("test"))); DefaultCommand command = new DefaultCommand(repository, operation); command.setAggregateId(AGGREGATE_ID); command.setIdempotentCreate(true); command.setAtomic(false); when(repository.append(any(), any(), any(), any())) .thenThrow(new UnexpectedVersionException(42, ExpectedVersion.notCreated())); CommandResult commandResult = command.run(); Assert.assertTrue(commandResult.getEvents().isEmpty()); }
/** * Appends an event, provided explicitly, to a given existing or new aggregate, optionally * requiring the current version to match the specified requirements. * * @param aggregateId The id of the aggregate to append events do. * @param event The event to append. * @param expectedVersion The expected version of the aggregate at the time the new events are * appended to its underlying stream of events. If the version at the * time the append is attempted differs from the one provided, an * UnexpectedVersionException will be thrown. */ default int append( final String aggregateId, final TEvent event, final ExpectedVersion expectedVersion) { return append(aggregateId, ImmutableList.of(event), expectedVersion, null); } }
@Test @SuppressWarnings("unchecked") public void idempotentCreateMeansNoOpIfExisting() { Operation operation = new OperationHandlerOperation( (x, y) -> ImmutableList.of(new TestEvent("xxx")), false, false, ExpectedVersion.notCreated()); when(repository.load(any())) .thenReturn(DefaultImmutableAggregate.fromExisting( mock(AggregateProjection.class), AGGREGATE_ID, 42, new TestState("test"))); DefaultCommand command = new DefaultCommand(repository, operation); command.setAggregateId(AGGREGATE_ID); command.setIdempotentCreate(true); CommandResult commandResult = command.run(); Assert.assertTrue(commandResult.getEvents().isEmpty()); }
/** * Persists a given existing or new aggregate with a list of events taken from an aggregate * state. The id of the aggregate and expected version (if used) will be taken from the details * of the aggregate state, and all pending events on the state will be persisted. * * @param aggregate The aggregate to apply updates for. * @param atomic If true, the original version of the aggregate will be used as the expected * version, failing the operation if other changes have taken place in * between. */ default ImmutableAggregate<TState, TEvent> save( @NotNull Aggregate<TState, TEvent> aggregate, boolean atomic) { return save(aggregate, atomic, null); }
/** * Appends an event, provided explicitly, to a given existing or new aggregate, optionally * requiring the current version to match the specified requirements. * * @param aggregateId The id of the aggregate to append events do. * @param event The event to append. * @param expectedVersion The expected version of the aggregate at the time the new events are * appended to its underlying stream of events. If the version at the * time the append is attempted differs from the one provided, an * UnexpectedVersionException will be thrown. */ default int append( final String aggregateId, final TEvent event, final ExpectedVersion expectedVersion) { return append(aggregateId, ImmutableList.of(event), expectedVersion, null); } }
/** * Persists a given existing or new aggregate with a list of events taken from an aggregate * state. The id of the aggregate and expected version (if used) will be taken from the details * of the aggregate state, and all pending events on the state will be persisted. * * @param aggregate The aggregate to apply updates for. * @param atomic If true, the original version of the aggregate will be used as the expected * version, failing the operation if other changes have taken place in * between. */ default ImmutableAggregate<TState, TEvent> save( @NotNull Aggregate<TState, TEvent> aggregate, boolean atomic) { return save(aggregate, atomic, null); }
/** * Appends an event, provided explicitly, to a given existing or new aggregate, optionally * requiring the current version to match the specified requirements. * * @param aggregateId The id of the aggregate to append events do. * @param event The event to append. * @param expectedVersion The expected version of the aggregate at the time the new events are * appended to its underlying stream of events. If the version at the * time the append is attempted differs from the one provided, an * UnexpectedVersionException will be thrown. * @param metadata Metadata in the form of string key/value pairs used to annotate each * event as persisted. Metadata will not be used to reconstruct the * aggregate from events, but can be used to append diagnostic * information to the operation, such as who performed the action that * triggered it, or which system that submitted the events. */ default int append( final String aggregateId, final TEvent event, final ExpectedVersion expectedVersion, final Map<String, String> metadata) { return append(aggregateId, ImmutableList.of(event), expectedVersion, metadata); }
/** * Appends an event, provided explicitly, to a given existing or new aggregate, optionally * requiring the current version to match the specified requirements. * * @param aggregateId The id of the aggregate to append events do. * @param event The event to append. * @param expectedVersion The expected version of the aggregate at the time the new events are * appended to its underlying stream of events. If the version at the * time the append is attempted differs from the one provided, an * UnexpectedVersionException will be thrown. * @param metadata Metadata in the form of string key/value pairs used to annotate each * event as persisted. Metadata will not be used to reconstruct the * aggregate from events, but can be used to append diagnostic * information to the operation, such as who performed the action that * triggered it, or which system that submitted the events. */ default int append( final String aggregateId, final TEvent event, final ExpectedVersion expectedVersion, final Map<String, String> metadata) { return append(aggregateId, ImmutableList.of(event), expectedVersion, metadata); }
int newVersion = repository.append( aggregateId, events,
int newVersion = repository.append( aggregateId, events,