barrel_query (barrel_docdb v1.1.1)

View Source

Query compiler and executor for barrel_docdb

Provides functions to compile Datalog-style query specifications into query plans, and execute them against the path index.

Query Syntax:

   #{
       where => [
           {path, [<<"type">>], <<"user">>},           % equality
           {path, [<<"tags">>], <<"erlang">>},         % list => membership
           {path, [<<"org_id">>], '?Org'},              % bind variable
           {compare, [<<"age">>], '>', 18},            % comparison
           {'and', [...]},                              % conjunction
           {'or', [...]}                                % disjunction
       ],
       select => ['?Org', '?Name'],   % fields/variables to return
       order_by => '?Name',           % ordering
       limit => 100,                   % max results
       offset => 0                     % skip first N
   }

Summary

Functions

Compile a query specification into a query plan. Returns {ok, QueryPlan} or {error, Reason}.

Dump profiling data to console

Execute a compiled query plan against a database. Returns {ok, Results, LastSeq} or {error, Reason}. Uses a snapshot for read consistency across all index and document reads.

Execute a compiled query plan with chunked execution options. Returns {ok, Results, ResultMeta} where ResultMeta includes: - last_seq: sequence number for change tracking - has_more: true if more results available - continuation: opaque token to resume (only if has_more = true)

Explain a query plan (for debugging/optimization). Returns a map describing the execution strategy.

Extract all paths referenced in a query plan. Used for subscription optimization - only evaluate query when a change affects one of these paths. Returns MQTT-style path patterns for use with barrel_sub.

Get current profiling counters

Check if a value is a logic variable (atom starting with '?')

Check if a document matches a compiled query plan. This is useful for filtering documents in-memory without index access.

Check if a document matches a list of conditions. Simpler API for filtering without needing a compiled query plan.

Normalize a condition to canonical form

Reset profiling counters

Validate a query specification. Returns ok or {error, Reason}.

Types

att_info/0

-type att_info() ::
          #{name := binary(),
            content_type := binary(),
            length := non_neg_integer(),
            digest := binary(),
            chunked => boolean(),
            chunk_size => pos_integer(),
            chunk_count => pos_integer()}.

change/0

-type change() :: map().

chunk_opts/0

-type chunk_opts() ::
          #{chunk_size => pos_integer(),
            continuation => binary() | undefined,
            eventual_consistency => boolean()}.

compare_op/0

-type compare_op() :: '>' | '<' | '>=' | '=<' | '=/=' | '=='.

condition/0

-type condition() ::
          {path, path(), value()} |
          {compare, path(), compare_op(), value()} |
          {'and', [condition()]} |
          {'or', [condition()]} |
          {'not', condition()} |
          {in, path(), [value()]} |
          {contains, path(), value()} |
          {exists, path()} |
          {missing, path()} |
          {regex, path(), binary()} |
          {prefix, path(), binary()}.

db_config/0

-type db_config() :: #{path => string(), store => module(), atom() => term()}.

db_name/0

-type db_name() :: binary().

db_ref/0

-type db_ref() :: pid() | atom().

doc/0

-type doc() :: #{binary() => term()}.

doc_info/0

-type doc_info() :: #{id := docid(), rev := revid(), deleted := boolean(), revtree := revtree()}.

docid/0

-type docid() :: binary().

endpoint/0

-type endpoint() :: db_name() | {node(), db_name()} | {module(), term()}.

logic_var/0

-type logic_var() :: atom().

Atoms starting with '?'

order_spec/0

-type order_spec() :: logic_var() | path() | {logic_var() | path(), asc | desc}.

path/0

-type path() :: [binary() | integer()].

projection/0

-type projection() :: logic_var() | path() | '*'.

query_plan/0

-type query_plan() ::
          #query_plan{conditions :: [condition()],
                      bindings :: #{logic_var() => path()},
                      projections :: [projection()],
                      order :: [{path() | logic_var(), asc | desc}],
                      limit :: pos_integer() | undefined,
                      offset :: non_neg_integer(),
                      include_docs :: boolean(),
                      doc_format :: binary | map | json,
                      decoder_fun :: undefined | fun((binary()) -> term()),
                      strategy :: index_seek | index_scan | multi_index | full_scan,
                      flat :: boolean(),
                      id_scan ::
                          undefined |
                          {prefix, binary()} |
                          {range, binary() | undefined, binary() | undefined}}.

query_spec/0

-type query_spec() ::
          #{where => [condition()],
            select => [projection()],
            order_by => order_spec() | [order_spec()],
            limit => pos_integer(),
            offset => non_neg_integer(),
            include_docs => boolean(),
            flat => boolean(),
            id_prefix => binary(),
            id_range => {binary() | undefined, binary() | undefined},
            doc_format => binary | map | json,
            decoder_fun => fun((binary()) -> term())}.

rep_options/0

-type rep_options() ::
          #{continuous => boolean(),
            since => seq_string(),
            filter => fun((doc()) -> boolean()),
            atom() => term()}.

result_meta/0

-type result_meta() :: #{last_seq := seq(), has_more := boolean(), continuation => binary()}.

rev_info/0

-type rev_info() ::
          #{id := revid(),
            parent := revid() | undefined,
            deleted := boolean(),
            attachments => #{binary() => att_info()}}.

revid/0

-type revid() :: binary().

revtree/0

-type revtree() :: #{revid() => rev_info()}.

seq/0

-type seq() :: barrel_hlc:timestamp().

seq_string/0

-type seq_string() :: binary().

value/0

-type value() :: binary() | number() | boolean() | null | logic_var().

view_name/0

-type view_name() :: binary().

view_result/0

-type view_result() :: #{key := term(), value := term(), id := docid()}.

Functions

compile(Spec)

-spec compile(query_spec()) -> {ok, query_plan()} | {error, term()}.

Compile a query specification into a query plan. Returns {ok, QueryPlan} or {error, Reason}.

dump_profile()

Dump profiling data to console

execute(StoreRef, DbName, Query_plan)

-spec execute(barrel_store_rocksdb:db_ref(), db_name(), query_plan()) ->
                 {ok, [map()], seq()} | {error, term()}.

Execute a compiled query plan against a database. Returns {ok, Results, LastSeq} or {error, Reason}. Uses a snapshot for read consistency across all index and document reads.

For unbounded include_docs queries, automatically paginates internally to avoid excessive memory usage from large MultiGet operations.

execute(StoreRef, DbName, Query_plan, Opts)

-spec execute(barrel_store_rocksdb:db_ref(), db_name(), query_plan(), chunk_opts()) ->
                 {ok, [map()], result_meta()} | {error, term()}.

Execute a compiled query plan with chunked execution options. Returns {ok, Results, ResultMeta} where ResultMeta includes: - last_seq: sequence number for change tracking - has_more: true if more results available - continuation: opaque token to resume (only if has_more = true)

Options: - chunk_size: max results per chunk (default 1000) - continuation: resume token from previous call - eventual_consistency: if true, each chunk sees current data (default false)

Example:

  %% First chunk
  {ok, R1, #{has_more := true, continuation := Token}} =
      barrel_query:execute(Store, Db, Plan, #{chunk_size => 100}),
 
  %% Next chunk
  {ok, R2, #{has_more := false}} =
      barrel_query:execute(Store, Db, Plan, #{continuation => Token}).

explain(Query_plan)

-spec explain(query_plan()) -> map().

Explain a query plan (for debugging/optimization). Returns a map describing the execution strategy.

extract_paths(Query_plan)

-spec extract_paths(query_plan()) -> [binary()].

Extract all paths referenced in a query plan. Used for subscription optimization - only evaluate query when a change affects one of these paths. Returns MQTT-style path patterns for use with barrel_sub.

get_profile()

Get current profiling counters

is_logic_var(Atom)

-spec is_logic_var(term()) -> boolean().

Check if a value is a logic variable (atom starting with '?')

match(Query_plan, Doc)

-spec match(query_plan(), map()) -> boolean().

Check if a document matches a compiled query plan. This is useful for filtering documents in-memory without index access.

matches(Doc, Conditions)

-spec matches(map(), list()) -> boolean().

Check if a document matches a list of conditions. Simpler API for filtering without needing a compiled query plan.

normalize_condition(Other)

Normalize a condition to canonical form

reset_profile()

Reset profiling counters

validate_spec(Spec)

-spec validate_spec(query_spec()) -> ok | {error, term()}.

Validate a query specification. Returns ok or {error, Reason}.