%% @doc Built in operators. -module(glc_ops). -export([ lt/2, eq/2, gt/2, wc/1, nf/1 ]). -export([ all/1, any/1, null/1, with/2 ]). -export([ union/1 ]). -type op() :: {atom(), '<', term()} | {atom(), '=', term()} | {atom(), '>', term()} | {atom(), '*'} | {atom(), '!'} | {any, [op(), ...]} | {all, [op(), ...]} | {null, true|false}. -export_type([op/0]). %% @doc Test that a field value is less than a term. -spec lt(atom(), term()) -> op(). lt(Key, Term) when is_atom(Key) -> {Key, '<', Term}; lt(Key, Term) -> erlang:error(badarg, [Key, Term]). %% @doc Test that a field value is equal to a term. -spec eq(atom(), term()) -> op(). eq(Key, Term) when is_atom(Key) -> {Key, '=', Term}; eq(Key, Term) -> erlang:error(badarg, [Key, Term]). %% @doc Test that a field value is greater than a term. -spec gt(atom(), term()) -> op(). gt(Key, Term) when is_atom(Key) -> {Key, '>', Term}; gt(Key, Term) -> erlang:error(badarg, [Key, Term]). %% @doc Test that a field exists. -spec wc(atom()) -> op(). wc(Key) when is_atom(Key) -> {Key, '*'}; wc(Key) -> erlang:error(badarg, [Key]). %% @doc Test that a field is not found. -spec nf(atom()) -> op(). nf(Key) when is_atom(Key) -> {Key, '!'}; nf(Key) -> erlang:error(badarg, [Key]). %% @doc Filter the input using multiple filters. %% %% For an input to be considered valid output the all filters specified %% in the list must hold for the input event. The list is expected to %% be a non-empty list. If the list of filters is an empty list a `badarg' %% error will be thrown. -spec all([op()]) -> op(). all([_|_]=Conds) -> {all, Conds}; all(Other) -> erlang:error(badarg, [Other]). %% @doc Filter the input using one of multiple filters. %% %% For an input to be considered valid output on of the filters specified %% in the list must hold for the input event. The list is expected to be %% a non-empty list. If the list of filters is an empty list a `badarg' %% error will be thrown. -spec any([op()]) -> op(). any([_|_]=Conds) -> {any, Conds}; any(Other) -> erlang:error(badarg, [Other]). %% @doc Always return `true' or `false'. -spec null(boolean()) -> op(). null(Result) when is_boolean(Result) -> {null, Result}; null(Result) -> erlang:error(badarg, [Result]). %% @doc Apply a function to each output of a query. %% %% Updating the output action of a query finalizes it. Attempting %% to use a finalized query to construct a new query will result %% in a `badarg' error. -spec with(op(), fun((gre:event()) -> term())) -> op(). with(Query, Fun) when is_function(Fun, 1) -> {with, Query, Fun}; with(Query, Fun) -> erlang:error(badarg, [Query, Fun]). %% @doc Return a union of multiple queries. %% %% The union of multiple queries is the equivalent of executing multiple %% queries separately on the same input event. The advantage is that filter %% conditions that are common to all or some of the queries only need to %% be tested once. %% %% All queries are expected to be valid and have an output action other %% than the default which is `output'. If these expectations don't hold %% a `badarg' error will be thrown. -spec union([op()]) -> op(). union(Queries) -> case [Query || Query <- Queries, glc_lib:onoutput(Query) =:= output] of [] -> {union, Queries}; [_|_] -> erlang:error(badarg, [Queries]) end.