Describes which events a store should match.
A query is a plain list of items, as described by the
DCB specification. Each item is a map with
an optional :types and an optional :tags key. An event matches the query
when it matches any of the items (OR). Within an item, the event's type
must be one of the item's types (OR) and the event's tags must contain
all of the item's tags (AND). An omitted or empty list places no
constraint on that dimension, so an item with only tags matches them across
every event type, and one with only types matches those types whatever they
are tagged with.
An empty query ([]) matches every event.
Tags are what makes this work: rather than querying into the payload, events
carry Sourced.StoredEvent.tag/0s naming the domain concepts they concern,
and items match on those. See Sourced.StoredEvent for the tag conventions and
Sourced.Middleware.Domain.Event for deriving them from domain structs.
A query is a matcher and nothing else. Bounding a result to a range of
sequences, or to a number of events, is a property of a particular read rather
than of the set of events being described, so :from, :to and :limit are
options of Sourced.EventStore.Behaviour.query/2 instead. The same matcher
can then be reused for the read, for the append that follows it, and for a
subscription, without one use silently inheriting another's bounds.
Examples
# Every OrderPlaced or OrderShipped tagged for order 1, plus every event
# of any type tagged for customer 42.
[
%{types: ["OrderPlaced", "OrderShipped"], tags: ["order:1"]},
%{tags: ["customer:42"]}
]Note that the performance of any given query will be dependent on the event store and its implementation details.
Summary
Types
A single item of a query, constraining event types, tags, or both.
An event type criterion: a stored type string ("order_placed"), an atom
shorthand for one (:order_placed), or a domain event module
(OrderPlaced). Criteria are kept as given; atoms are resolved to their
stored type by the Sourced.Middleware.Domain middleware.
Functions
Filters events down to the ones matching query.
Returns true if query has no items, i.e. it matches every event.
Returns true if event matches the query.
Types
@type item() :: %{ optional(:types) => [type()], optional(:tags) => [Sourced.StoredEvent.tag()] }
A single item of a query, constraining event types, tags, or both.
@type t() :: [item()]
An event type criterion: a stored type string ("order_placed"), an atom
shorthand for one (:order_placed), or a domain event module
(OrderPlaced). Criteria are kept as given; atoms are resolved to their
stored type by the Sourced.Middleware.Domain middleware.
Functions
@spec apply([Sourced.StoredEvent.t()], t() | nil) :: [Sourced.StoredEvent.t()]
Filters events down to the ones matching query.
Intended for event store implementations that load events into memory before
matching them. Bounding the result is separate; see
Sourced.EventStore.Behaviour.query/2.
Returns true if query has no items, i.e. it matches every event.
Examples
iex> Query.empty?([])
true
iex> Query.empty?(nil)
true
iex> Query.empty?([%{tags: ["order:1"]}])
false
@spec matches?(t() | nil, Sourced.StoredEvent.t()) :: boolean()
Returns true if event matches the query.
An empty query matches every event; otherwise the event must match at least one item.
Matching is exact: criteria are compared against event.type as-is, so an
item holding event modules matches events whose type is a module — which is
what Sourced.Middleware.Domain restores it to on the way out — while one
holding stored type strings matches raw events.