Fact.Query (Fact v0.2.0)
View SourceProvide utilities for constructing event queries for defining consistency boundaries and projection sources.
A query in the Fact system is a higher-order function that takes a database context and returns a predicate
function. This predicate is used by Fact.read/2 and related functions to determine whether each event in the
database should be included in the result set.
Query Construction
This module offers several ways to build queries:
from_types/1- match events with anevent_typecontained in a supplied list.from_tags/1- match events withevent_tagscontaining all given tags.from_data/1- match events withevent_datacontaining specific key-value pairs.from_all/0- match all events.from_none/0- match no events.from/3- a convenience wrapper that combines types, tags, and data into a single compound query.combine/2- combines a list of queries using:andor:orboolean operations to produce a compound query.
Summary
Types
A query is function which takes a database context and returns an event_id predicate function.
Functions
This combines multiple queries using logical boolean operations returning a new query as a tuple.
This combines multiple queries using logical boolean operations returning a new query.
This is a helper function for creating compound queries.
Create a query which matches all events.
Creates a query which matches events with all the supplied key value pairs and returns it in a tuple. When duplicate keys are provided, the query will match events with any supplied values.
Creates a query which matches events with all the supplied key value pairs. When duplicate keys are provided, the query will match events with any supplied values.
Create a query which matches no events.
Creates a query which matches events tagged with all the supplied tags and returns it in a tuple.
Creates a query which matches events tagged with all the supplied tags.
Creates a query which matches events with any of the supplied event types and returns it in a tuple.
Creates a query which matches events with any of the supplied event types
Types
@type t() :: (Fact.database_id() -> (Fact.record_id() -> boolean()))
A query is function which takes a database context and returns an event_id predicate function.
Functions
This combines multiple queries using logical boolean operations returning a new query as a tuple.
This combines multiple queries using logical boolean operations returning a new query.
@spec from( Fact.event_type() | [Fact.event_type(), ...], Fact.event_tag() | [Fact.event_tag(), ...], keyword() ) :: {:ok, t()} | {:error, term()}
This is a helper function for creating compound queries.
This provides a shortcut for writing:
Fact.Query.combine(:and, [
Fact.Query.from_types("StudentSubscribedToCourse"),
Fact.Query.from_tags("course:c1"),
Fact.Query.from_data(student_id: "s1")
])Which could be shortened to:
Fact.Query.from("StudentSubscribedToCourse", "course:c1", student_id: "s1")
@spec from_all() :: t()
Create a query which matches all events.
Creates a query which matches events with all the supplied key value pairs and returns it in a tuple. When duplicate keys are provided, the query will match events with any supplied values.
Examples
Get all events with a capacity of 10.
iex> {:ok, query} = Fact.Query.from_data(capacity: 10)
iex> Fact.read(:mydb, query) |> Enum.to_list()
[
%{
"event_data" => %{"capacity" => 10, "course_id" => "c1"},
"event_id" => "a7f82f20b49549748a412797ef6b3c3d",
"event_metadata" => %{},
"event_tags" => ["course:c1"],
"event_type" => "CourseDefined",
"store_position" => 1,
"store_timestamp" => 1765222610917506
},
%{
"event_data" => %{"capacity" => 10, "course_id" => "c4"},
"event_id" => "b7a5c4b71f4649e78a2a3347a23331df",
"event_metadata" => %{},
"event_tags" => ["course:c4"],
"event_type" => "CourseDefined",
"store_position" => 4,
"store_timestamp" => 1765224048824117
}
]Get all events with a matching course_id and capacity of 10.
iex> {:ok, query} = Fact.Query.from_data(capacity: 10, course_id: "c1")
iex> Fact.read(:mydb, query) |> Enum.to_list()
[
%{
"event_data" => %{"capacity" => 10, "course_id" => "c1"},
"event_id" => "a7f82f20b49549748a412797ef6b3c3d",
"event_metadata" => %{},
"event_tags" => ["course:c1"],
"event_type" => "CourseDefined",
"store_position" => 1,
"store_timestamp" => 1765222610917506
}
]Get all events with a matching course_id and a capacity of 10 or 15.
iex> {:ok, query} = Fact.Query.from_data(course_id: "c1", capacity: 10, capacity: 15)
iex> Fact.read(:mydb, query) |> Enum.to_list()
[
%{
"event_data" => %{"capacity" => 10, "course_id" => "c1"},
"event_id" => "a7f82f20b49549748a412797ef6b3c3d",
"event_metadata" => %{},
"event_tags" => ["course:c1"],
"event_type" => "CourseDefined",
"store_position" => 1,
"store_timestamp" => 1765222610917506
},
%{
"event_data" => %{"capacity" => 15, "course_id" => "c1"},
"event_id" => "2f575ea536a84b348b5738fd8785dbc7",
"event_metadata" => %{},
"event_tags" => ["course:c1"],
"event_type" => "CourseCapacityChanged",
"store_position" => 12,
"store_timestamp" => 1765301503964237
}
]
Creates a query which matches events with all the supplied key value pairs. When duplicate keys are provided, the query will match events with any supplied values.
Raises ArgumentError when no keywords are supplied.
@spec from_none() :: t()
Create a query which matches no events.
Examples
iex> query = Fact.Query.from_none()
iex> Fact.read(:mydb, query) |> Enum.to_list()
[]
@spec from_tags(Fact.event_tag() | [Fact.event_tag(), ...]) :: {:ok, t()} | {:error, term()}
Creates a query which matches events tagged with all the supplied tags and returns it in a tuple.
Examples
Get all events tagged with student:s1.
iex> {:ok, query} = Fact.Query.from_tags(["student:s1"])
iex> Fact.read(:mydb, query) |> Enum.to_list()
[
%{
"event_data" => %{"student_id" => "s1"},
"event_id" => "ead3e5c6a78b493fade1b9fbad68ee35",
"event_metadata" => %{},
"event_tags" => ["student:s1"],
"event_type" => "StudentRegistered",
"store_position" => 6,
"store_timestamp" => 1765224325494777
},
%{
"event_data" => %{"course_id" => "c1", "student_id" => "s1"},
"event_id" => "90441ac451c74a82ba0e643b510ad429",
"event_metadata" => %{},
"event_tags" => ["course:c1", "student:s1"],
"event_type" => "StudentSubscribedToCourse",
"store_position" => 10,
"store_timestamp" => 1765242156981475
},
%{
"event_data" => %{"course_id" => "c3", "student_id" => "s1"},
"event_id" => "7ddcbe4fc32f40ac943661a69066f4ef",
"event_metadata" => %{},
"event_tags" => ["student:s1", "course:c3"],
"event_type" => "StudentSubscribedToCourse",
"store_position" => 11,
"store_timestamp" => 1765242258559384
}
]Get all events tagged with both course:c1 and student:s1
iex> {:ok, query} = Fact.Query.from_tags(["course:c1","student:s1"])
iex> Fact.read(:mydb, query) |> Enum.to_list()
[
%{
"event_data" => %{"course_id" => "c1", "student_id" => "s1"},
"event_id" => "90441ac451c74a82ba0e643b510ad429",
"event_metadata" => %{},
"event_tags" => ["course:c1", "student:s1"],
"event_type" => "StudentSubscribedToCourse",
"store_position" => 10,
"store_timestamp" => 1765242156981475
}
]
@spec from_tags!(Fact.event_tag() | [Fact.event_tag(), ...]) :: t()
Creates a query which matches events tagged with all the supplied tags.
Raises ArgumentError when no event tags are supplied.
Raises ArgumentError if any supplied event tag is not a string.
@spec from_types(Fact.event_type() | [Fact.event_type(), ...]) :: {:ok, t()} | {:error, term()}
Creates a query which matches events with any of the supplied event types and returns it in a tuple.
Examples
iex> {:ok, query} = Fact.Query.from_types(["CourseDefined","StudentRegistered"])
iex> Fact.read(:mydb, query) |> Enum.to_list()
[
%{
"event_data" => %{"capacity" => 10, "course_id" => "c1"},
"event_id" => "a7f82f20b49549748a412797ef6b3c3d",
"event_metadata" => %{},
"event_tags" => ["course:c1"],
"event_type" => "CourseDefined",
"store_position" => 1,
"store_timestamp" => 1765222610917506
},
%{
"event_data" => %{"student_id" => "s1"},
"event_id" => "ead3e5c6a78b493fade1b9fbad68ee35",
"event_metadata" => %{},
"event_tags" => ["student:s1"],
"event_type" => "StudentRegistered",
"store_position" => 3,
"store_timestamp" => 1765224325494777
}
]
@spec from_types!(Fact.event_type() | [Fact.event_type(), ...]) :: t()
Creates a query which matches events with any of the supplied event types
Raises ArgumentError when no event types are supplied.
Raises ArgumentError if any supplied event type is not a string.