Skip to content

feat(events): carry the previous state on OnObjectUpdate - #52

Open
herbie-bot wants to merge 1 commit into
mainfrom
feat/update-event-previous-state
Open

herbie-bot wants to merge 1 commit into
mainfrom
feat/update-event-previous-state

Conversation

@herbie-bot

Copy link
Copy Markdown
Collaborator

What

Extends the existing events API so applications can react to what changed on an update. This is the generic part of open-tasks#36 (TaskSnapshot / TaskChangedEvent). It extends OnObjectUpdate rather than adding a parallel event type. Spec: docs/specs/022-update-event-previous-state.

  • OnObjectUpdate: new constructor (previous, current) plus isPreviousKnown() and Optional<T> getPrevious(). It rejects a previous of a different class or with a different id. The one-arg constructor is unchanged, for publishers that cannot know the previous state (e.g. external systems). There is deliberately no diff and no actor in the event.
  • AbstractDbBackedDataService / AbstractMultitenantDbBackedDataService:
    • snapshot toData(entity) before updateEntity
    • replace postSave(boolean, D) with postInsert(D) / postUpdate(D previous, D current)
    • no longer publish an update event when previous.equals(current)
    • the tenant variant also loses a duplicated save call
  • Bug fix: GenericDataEvent implements ResolvableTypeProvider. Before this, a typed listener such as @EventListener OnObjectUpdate<BookDto> was invoked for every DTO type. A probe test confirmed that, and the new TypedEventListenerTest covers it.

Breaking / behaviour changes (documented in upgrade-to-1.5.md)

  • Source break: any override of postSave(boolean, D) no longer compiles. This is intentional: a silent change would be worse.
  • An update that changes nothing no longer produces an audit row or a webhook call.
  • Typed listeners receive only their own DTO type.
  • toData must return a snapshot. A DTO that shares an entity collection would swallow update events. All toData implementations in this repository comply.

Tests

New and extended unit tests for the event constructors, the resolvable type, typed dispatch in a real Spring context, and update / no-op behaviour in both data service base classes. A full mvn verify passes locally, including the Testcontainers integration tests.

🤖 Generated with Claude Code

OnObjectUpdate gets a second constructor (previous, current) plus
isPreviousKnown() and Optional<T> getPrevious(). The one-argument
constructor stays for publishers that cannot know the previous state.
The event carries no diff and no actor; listeners compare themselves.

AbstractDbBackedDataService and AbstractMultitenantDbBackedDataService
snapshot toData(entity) before updateEntity, replace postSave(boolean, D)
with postInsert(D) / postUpdate(D, D) and publish no event for an update
where previous equals current.

GenericDataEvent now implements ResolvableTypeProvider: typed listeners
such as OnObjectUpdate<BookDto> previously received events for every
DTO type.

Spec 022; origin open-tasks#36 (TaskChangedEvent).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants