barrel_bql_lower (barrel_docdb v1.0.0)

View Source

Canonicalize and validate BQL ASTs; lower them to executable plans (lowering lands with the planner step).

Canonical form: - paths are range-variable tagged: {path, Loc, base | unnest, Comps} with Comps in the engine shape [binary() | integer() | '*'] and the leading alias stripped (PartiQL name resolution for one binding: the range variable shadows same-named document fields); - parameters are substituted; - operands are normalized (literal OP path is flipped, constant and path-to-path predicates are rejected); - BETWEEN is expanded to comparisons; - NOT is eliminated by dualization, so downstream code never sees a 'not' node. The engine evaluates leaves as exists-and-satisfies (absent path => false), which matches SQL WHERE except under NOT; dualizing keeps PartiQL's missing-is-filtered semantics. Negations survive only as flags on in/like/contains, which the planner guards with {exists, Path}; - the top-level conjunction is flattened to a list.

Summary

Types

canon/0

-type canon() ::
          #{select := star | [projection()],
            source :=
                {collection, loc(), binary()} | {table_fn, loc(), binary(), [barrel_bql_ast:fn_arg()]},
            alias := binary(),
            unnest := undefined | #{path := cpath(), alias := binary(), loc := loc()},
            where := [cexpr()],
            order_by := [{cpath(), asc | desc}],
            limit := undefined | {integer, loc(), non_neg_integer()},
            offset := undefined | {integer, loc(), non_neg_integer()},
            subscribe := boolean()}.

cexpr/0

-type cexpr() ::
          {cmp, loc(), '=' | '!=' | '<' | '<=' | '>' | '>=', cpath(), clit()} |
          {is_null, loc(), cpath(), boolean()} |
          {is_missing, loc(), cpath(), boolean()} |
          {in, loc(), cpath(), [clit()], boolean()} |
          {like, loc(), cpath(), binary(), boolean()} |
          {contains, loc(), cpath(), clit(), boolean()} |
          {'and', loc(), cexpr(), cexpr()} |
          {'or', loc(), cexpr(), cexpr()}.

clit/0

-type clit() :: {lit, loc(), binary() | number() | boolean() | null}.

comps/0

-type comps() :: [binary() | integer() | '*'].

cpath/0

-type cpath() :: {path, loc(), var(), comps()}.

loc/0

-type loc() :: barrel_bql_ast:loc().

plan/0

-type plan() ::
          #{spec := map(),
            source :=
                {collection, binary()} |
                {table_fn,
                 vector_top_k | bm25_top_k | hybrid_top_k,
                 #{query := binary(), k := pos_integer(), ef_search => pos_integer()}},
            unnest := undefined | #{path := comps(), alias := binary()},
            post :=
                #{residual := [term()],
                  doc_where := [term()],
                  order := undefined | {project_key(), asc | desc},
                  offset := non_neg_integer(),
                  limit := undefined | pos_integer(),
                  project := star | [{b | u | score, comps() | binary(), binary()}],
                  empty := boolean()},
            subscribe := boolean(),
            streamable := boolean(),
            warnings := [term()]}.

project_key/0

-type project_key() :: {b, comps()} | {u, comps()} | {score, binary()}.

projection/0

-type projection() :: #{path := cpath(), name := binary() | undefined, loc := loc()}.

tagged_path/0

-type tagged_path() :: {b, comps()} | {u, comps()}.

var/0

-type var() :: base | unnest.

Functions

canonicalize(Ast, Params)

-spec canonicalize(barrel_bql_ast:ast(), #{binary() => term()}) ->
                      {ok, canon()} | {error, {invalid_query, loc() | undefined, tuple()}}.

lower(Canon)

-spec lower(canon()) -> {ok, plan()} | {error, {invalid_query, loc() | undefined, tuple()}}.

validate(Canon)

-spec validate(canon()) -> ok | {error, {invalid_query, loc() | undefined, tuple()}}.