Closed ilslv closed 3 years ago
Check that every combination of event::Name and event::Version correspond to single Rust type (#3, #1)
Additionally:
- extend support for event::Initial in derive macros
please, add also some examples with
Initial<_>
in#[derive(Event)]
. It seems that we haven't covered this situation, which may result to be quite tricky one.
Quite tricky one, indeed. As we discussed, we want to express, that some state can be Initialized
pretty strictly.
// Compiles just fine
#[derive(Event)]
enum ChatEvent {
Created(Init<ChatCreated>),
MessagePosted(ChatMessagePosted),
}
// Failed to compile, as we forgot the `Init<...>` wrapper
#[derive(Event)]
enum ChatEvent {
Created(ChatCreated),
MessagePosted(ChatMessagePosted),
}
Initial
trait, which will be the same as Versioned
, but with special blanket impl.pub trait Initial {
fn name() -> Name;
fn version() -> Version;
}
impl<Ev: Initial + ?Sized> Event for Init<Ev> {
fn name(&self) -> Name {
Ev::name()
}
fn version(&self) -> Version {
Ev::version()
}
}
// ⌄ wrong
impl<Ev: Event + ?Sized, S: Sourced<Ev>> Sourced<Ev> for Option<S> {
fn apply(&mut self, event: &Ev) {
if let Some(state) = self {
state.apply(event);
}
}
}
If we want to store Init<Event>
inside enum variant, this blanket impl needs small change:
// ⌄ was `Event`, became `Versioned`
impl<Ev: Versioned + ?Sized, S: Sourced<Ev>> Sourced<Ev> for Option<S> {
fn apply(&mut self, event: &Ev) {
if let Some(state) = self {
state.apply(event);
}
}
}
And add new blanket
impl<Ev: Initial + ?Sized, S: Initialized<Ev>> Sourced<Init<Ev>> for Option<S> {
fn apply(&mut self, event: &Initial<Ev>) {
*self = Some(S::init(&event.0));
}
}
Initial
derive macro, that works similar to Versioned
Main idea of those changes is to separate Initial
events from Versioned
(maybe rename it to reflect that separation?).
ack @tyranron
@ilslv Event
s are primary thing in event sourcing, while the state is secondary. It should be OK for the same Event
to be initial for one state and not initial for another. Initial
ity is responsibility of event::Sourced
/event::Initialized
traits which express relation between an Event
and the state. It's not the reposnibility of an Event
itself.
I don't see why se should introduce an additional trait/macro to handle the case. It should be possible with current setup by either specializing over Initial
wrapper (giving it some additonal type machinery) or introducing #[event(initial)]
attribute for the variant which will consider that sitouation in code generation.
Discussed: we don't try to derive Event
on Initial
, but rather write our own copy of Borrow
trait (but sealed) with blanket impl for Self
and use it in codegen
Part of #1, #2
Synopsis
As discussed we should check that every combination of
event::Name
andevent::Version
correspond to singleRust
type.Solution
As
TypeId::of()
isconst fn
yet (tracking issue), we use codegen location to uniquely identifyRust
type.Checklist
Draft:
prefixk::
labels appliedDraft:
prefix is removed