Expects a StreamQuery and an optional starting SequenceNumber and returns an EventStream.
Note: The EventStore should also allow for backwards iteration on the EventStream in order to support cursor based pagination.
Expects a set of Events and an AppendCondition and returns the last appended SequenceNumber.
EventStore {
read(query: StreamQuery, from?: SequenceNumber): EventStream
readBackwards(query: StreamQuery, from?: SequenceNumber): EventStream
append(events: Events, condition: AppendCondition): SequenceNumber
}
The StreamQuery
describes constraints that must be matched by Events in the EventStore.
- It MAY contain a set of StreamQuery Criteria
Note: All criteria of a StreamQuery are merged into a logical disjunction, so the example below matches all events, that match the first OR the second criterion.
{
"version": "1.0",
"criteria": [{
"type": "EventTypes",
"properties": {
"event_types": ["EventType1", "EventType2"]
}
}, {
"type": "Tags",
"properties": {
"tags": ["foo:bar", "baz:foos"],
}
}, {
"type": "EventTypesAndTags",
"properties": {
"event_types": ["EventType2", "EventType3"],
"tags": ["foo:bar", "foo:baz"],
}
}]
}
In v1 the only supported criteria types are:
Tags
– allows to target one or more TagsEventTypes
– allows to target one or more EventTypesEventTypesAndTags
– allows to target one or more Tags and one or more EventTypes
When an Event is appended to the EventStore a SequenceNumber
is assigned to it.
It...
- MUST be unique for one EventStore
- MUST be monotonic increasing
- MUST have an allowed minimum value of
1
- CAN contain gaps
- SHOULD have a reasonably high maximum value (depending on programming language and environment)
When reading from the EventStore an EventStream
is returned.
It...
- It MUST be iterable
- It MUST return an EventEnvelope for every iteration
- It CAN include new events if they occur during iteration
- Individual EventEnvelope instances MAY be converted during iteration for performance optimization
- Batches of events MAY be loaded from the underlying storage at once for performance optimization
Each item in the EventStream is an EventEnvelope
that consists of the underlying event and metadata, like the SequenceNumber that was added during the append()
call.
{
"event": {
"id": "15aaa216-4179-46d9-999a-75516e21a1c6",
"type": "SomeEventType",
"data": "{\"some\":\"data\"}"
"tags": ["type1:value1", "type2:value2"]
},
"sequence_number": 1234
}
A set of Event instances that is passed to the append()
method of the EventStore
It...
- MUST not be empty
- MUST be iterable, each iteration returning an Event
- It MUST contain a globally unique EventId
- It MUST contain an EventType
- It MUST contain EventData
- It MAY contain Tags
{
"id": "15aaa216-4179-46d9-999a-75516e21a1c6",
"type": "SomeEventType",
"data": "{\"some\":\"data\"}"
"tags": ["key1:value1", "key1:value2"]
}
String based globally unique identifier of an Event
- It MUST satisfy the regular expression
^[\w\-]{1,100}$
- It MAY be implemented as a UUID
String based type of an event
- It MUST satisfy the regular expression
^[\w\.\:\-]{1,200}$
String based, opaque payload of an Event
- It SHOULD have a reasonable large enough maximum length (depending on language and environment)
- It MAY contain JSON
- It MAY be serialized into an empty string
A set of Tag instances.
- It MUST contain at least one Tag
- It MAY contain multiple Tags with the same value
- It SHOULD not contain muliple Tags with the same key/value pair
A Tag
can add domain specific metadata (usually the ids of an entity or concept of the core domain) to an event allowing for custom partitioning
NOTE: If the value
is not specified, all tags of the given key
will match (wildcard)
- It MUST contain a
key
that satisfies the regular expression^[a-zA-Z0-9\-\_]{1,50}$
- It CAN contain a
value
that satisfies the regular expression^[a-zA-Z0-9\-\_]{1,50}$
- It MUST contain a StreamQuery
- It MUST contain a ExpectedHighestSequenceNumber
Can either be an instance of SequenceNumber Or one of:
NONE
– No event must match the specified StreamQueryANY
– Any event matches (= wildcard AppendCondition)