Fact.Query (Fact v0.2.0)

View Source

Provide 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 an event_type contained in a supplied list.
  • from_tags/1 - match events with event_tags containing all given tags.
  • from_data/1 - match events with event_data containing 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 :and or :or boolean operations to produce a compound query.

Summary

Types

t()

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

t()

@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

combine(op, queries)

@spec combine(:and | :or, [t(), ...]) :: {:ok, t()} | {:error, term()}

This combines multiple queries using logical boolean operations returning a new query as a tuple.

combine!(op, queries)

@spec combine!(:and | :or, [t(), ...]) :: t()

This combines multiple queries using logical boolean operations returning a new query.

from(types \\ [], tags \\ [], data \\ [])

@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")

from_all()

@spec from_all() :: t()

Create a query which matches all events.

from_data(data)

@spec from_data(keyword()) :: {:ok, t()} | {:error, term()}

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                                                                                                                                                                                                                                                                           
  }                                                                                                                                                                                                                                                                                                                 
]

from_data!(data)

@spec from_data!(keyword()) :: t()

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.

from_none()

@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()
[]

from_tags(tags)

@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                                                                                                                                                                                                                                                                           
  }                                                                                                                                                                                                                                                                                                                 
]

from_tags!(tags)

@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.

from_types(types)

@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                                                                                                                                                                                                                                                                          
  }                                                                                                                                                                                                                                                                                                                 
]

from_types!(types)

@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.