Repository navigation
Run upcasters only for the versions they were written for - #238
Open
DavidBadura wants to merge 1 commit into
Open
DavidBadura wants to merge 1 commit into
DavidBadura wants to merge 1 commit into
Conversation
An upcaster can declare the version of the data it expects with from, in the UpcasterFor attribute or as argument of the CallbackUpcaster. The version of the hydrated data is passed per class in the context with UpcastExtension::VERSIONS. Versioned upcasters only run for data of their version or older, without a version the data is treated as up to date. Upcasters without a version run for every version as before. The versioned upcasters of a class have to be registered in the order of their versions, the middleware throws an exception otherwise.
|
Hello 👋 Here are the most recent benchmark results, compared against GeneratedHydrator
StackHydrator
StackHydratorWithLazy
StackHydratorWithCryptography
GeneratedHydratorWithCryptography
This comment gets updated every time a new commit comes in. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upcasters have to find out the shape of the stored data themselves today, usually by checking which fields exist. If the version of the data is stored with it, they can rely on that instead. An upcaster now declares the version of the data it expects with
fromand returns the data of the next version:The
CallbackUpcastertakes the version as third argument. The version of the hydrated data is passed per class in the context withUpcastExtension::VERSIONS, for example[ProfileCreated::class => 1]. A versioned upcaster only runs for data of its version or older, so data of the current version skips all of them. Without a version in the context the data is treated as up to date and only the upcasters without a version run, they keep running for every version as before. The version is keyed by class so it doesn't leak to nested objects, whose data belongs to the shape of the outer class.The versioned upcasters of a class have to be registered in the order of their versions, otherwise the middleware throws
UpcastersNotInVersionOrderwhen it is built. Running a chain in the wrong order would silently produce broken data.What event-sourcing would need
In event-sourcing the version is a custom header of the message, so the stores keep it in
custom_headerswithout a schema change. A sketch for 4.0 once it uses hydrator 3. New would be the version on#[Event]and in the event metadata, theEventVersionHeader, theEventVersionDecoratorand theOPTION_EVENT_VERSIONof the serializer. The version comes from the event attribute:A message decorator adds the header when the event is recorded, like the
SplitStreamDecoratordoes with its header:The stores write the header with the other custom headers, nothing changes there. While loading, they have to deserialize the custom headers before the payload, today they do it afterwards, and pass the version on to the serializer. Events stored before the header existed have no header and count as version 1:
The
DefaultEventSerializerhands the version to the hydrator. Without the option it doesn't pass a version at all, so the data counts as up to date. Defaulting to 1 there would run the upcasters on current data whenever an event is deserialized somewhere without its headers:The upcasters then target the event class with the version they upcast from,
#[UpcasterFor(ProfileCreated::class, from: 1)].