Current section

Files

Jump to
erlang_rethinkdb src erlang_rethinkdb_ast.erl
Raw

src/erlang_rethinkdb_ast.erl

-module(erlang_rethinkdb_ast).
-include("term.hrl").
-compile(export_all). %% replace with -export()
make(Query) when is_tuple(Query)->
build(Query);
make([Query | Qs]) ->
Parent = build(Query),
Q = build(Qs, Parent),
Q
.
%build([]) ->
% "";
% Argument can be other ReQL
build_argument(A) when is_tuple(A)->
A
;
build_argument(A) when is_list(A)->
A
.
build(Query) when is_tuple(Query) ->
Params = case Query of
{F} -> [];
{F, A} when is_list(A)-> A;
{F, A} when not is_list(A)-> [A];
{F, A, O} when is_list(A)-> [A, O];
{F, A, O} when not is_list(A)-> [A, O]
end,
case F of
'or' -> apply(?MODULE, F, [Params]) ;
'and' -> apply(?MODULE, F, [Params]) ;
%%% Geospatial command receive variadic parameter
polygon -> apply(?MODULE, F, [Params]) ;
line -> apply(?MODULE, F, [Params]) ;
geojson -> apply(?MODULE, F, [Params]) ;
%%% some document manipulation command receive variadic parameter
object -> apply(?MODULE, F, [Params]) ;
bracket -> apply(?MODULE, F, [Params]) ;
_ -> apply(?MODULE, F, Params)
end;
build(N) when is_number(N) ->
apply(?MODULE, var, [N])
.
build([], Parent) ->
Parent;
build([Query | Qs], Parent) when is_tuple(Query)->
T = case Query of
{Func} -> apply(?MODULE, Func, [Parent]);
{Func, Arguments} when is_list(Arguments)-> apply(?MODULE, Func, [Parent] ++ Arguments);
{Func, Arguments} when not is_list(Arguments)-> apply(?MODULE, Func, [Parent] ++ [Arguments]);
{Func, Arguments, Options} when not is_list(Arguments)-> apply(?MODULE, Func, [Parent] ++ [Arguments] ++ [Options]);
{Func, Arguments, Options} when is_list(Arguments)-> apply(?MODULE, Func, [Parent] ++ Arguments ++ [Options])
end,
build(Qs, T)
.
% We have some function name we
func_name(F) ->
case F of
'and' ->
list_to_atom("r_" ++ atom_to_list(F));
_ ->
F
end
.
var(N) ->
[?VAR, [N]]
.
%%Detail implementation of API
db_create(Name) ->
[
?DB_CREATE,
[Name],
{}
]
.
db(DbName, O) ->
[ ?DB, [DbName], O].
db(DbName) ->
[
?DB,
[DbName]
].
db_list() ->
[
?db_list,
[],
[{}]
].
table_list(Db) ->
[
?table_list,
[Db],
[{}]
].
table_list(Db,Option) ->
[
?table_list,
[Db],
Option
].
table(Name) ->
[
?TABLE,
[Name]
].
table(Db, Name) ->
[
?TABLE,
[Db, Name]
].
get(Table, Key) ->
[
?TERMTYPE_GET,
[Table, Key]
].
get_field(O, F) ->
[
?TERMTYPE_GET_FIELD,
[O, F]
].
bracket(O, [F|T]) ->
[?TERMTYPE_BRACKET, [bracket(O, T), F]]
;
bracket(O, F) ->
[?TERMTYPE_BRACKET, [O, F]]
.
keys(O) ->
[?TERMTYPE_KEYS, [O]].
object(O) ->
[?TERMTYPE_OBJECT, O].
table_create(Name) ->
[
?TABLE_CREATE,
[Name]
].
table_create(Db, Name) ->
[
?TABLE_CREATE,
[Db, Name]
].
table_drop(Name) ->
[
?TERMTYPE_TABLE_DROP,
[Name]
].
table_drop(Db, Name) ->
[
?TERMTYPE_TABLE_DROP,
[Db, Name]
].
insert(Table, Item) ->
[
?TERMTYPE_INSERT,
[Table, Item]
].
update(Table, Update) when is_function(Update)->
Var = gen_var(1),
U = Update(Var),
[
?TERMTYPE_UPDATE,
[Table, wrap_fun(U, Var)]
];
update(Table, Item) ->
[
?TERMTYPE_UPDATE,
[Table, Item]
].
update(Table, Update, Option) when is_function(Update)->
Var = gen_var(1),
U = Update(Var),
[
?TERMTYPE_UPDATE,
[Table, wrap_fun(U, Var)],
Option
];
update(Table, Item, Option) ->
[
?TERMTYPE_UPDATE,
[Table, Item],
Option
].
% changes(Table, Function) ->
changes(Table, _) ->
[
?CHANGE,
[Table],
[{}]
]
% Function(F)
.
%%% For simple filter, we do exactly match only
%%% For complex filter, using anonymous function
filter(Sequence, F) when is_tuple(F) ->
filter(Sequence, [F]);
filter(Sequence, F) when is_list(F) ->
[
?FILTER,
[Sequence,
F]
];
filter(Sequence, F) when is_function(F) ->
[
?FILTER,
[Sequence, wrap_fun(make(F(gen_var(1))), gen_var(1))]
].
eq(Field, Value) ->
[
?EQ,
[make(Field), Value]
%[{}]
]
.
gt(Field, Value) ->
[
?GT,
[make(Field), Value]
%[]
]
.
lt(Field, Value) ->
[
?LT,
[make(Field), Value]
%[]
]
.
le(Field, Value) ->
[
?LE,
[make(Field), Value]
%[]
]
.
match(Field, Value) ->
[
?MATCH,
[make(Field), Value]
]
.
%%% Note: not a part of REQL
%%% @TODO: improve
field(P, F) ->
[?TERMTYPE_BRACKET, [make(P), F]].
nth(Sequence, N) ->
[?TERMTYPE_NTH, [Sequence, N]].
%%% when we pass argument to 'and', because of our recursion
%%% we don't know if an argument is compiled or not.
%%% We therefore use a {c, L} mean that it is compilted.
%%% Otherwise it's not.
%%%
%%% We don't have to do for R, because R is never pre-compile
'and'([L,R]) ->
L_ = case L of
{c, L__} -> L__;
_ -> make(L)
end,
[?TERMTYPE_AND, [L_, make(R)]]
;
'and'(C) ->
[L,R, H|T] = C,
'and'([{c, 'and'([L,R])}] ++
[H] ++ T)
.
'or'([L,R]) ->
L_ = case L of
{c, L__} -> L__;
_ -> make(L)
end,
[?TERMTYPE_OR, [L_, make(R)]]
;
'or'(C) ->
[L,R, H|T] = C,
'or'([
{c, 'or'([L,R])},
[H] ++ T
])
.
now() ->
[
?NOW,
[],
[{}]
]
.
expr([Op | _]) ->
% Ex =
expr(Op)
;
expr([]) -> [];
expr(Op) when is_tuple(Op) ->
expr([Op])
.
add(X, Y) ->
[?ADD,
[X, Y]
].
sub(X, Y) ->
[?SUB,
[X, Y]
].
mul(X, Y) ->
[?MUL,
[X, Y]
].
'div'(X, Y) ->
[?DIV, [X, Y]]
.
mod(X, Y) ->
[?MOD, [X, Y]]
.
during(X, Y) ->
[?DURING, [X, Y]]
.
%Working with filter
row(Q) ->
[?FUNC, [
[?TERMTYPE_MAKE_ARRAY, gen_var(1)],
erlang_rethinkdb_ast:make(Q)
]].
default(Item, Value)->
[?TERMTYPE_DEFAULT, [Item, Value]]
.
row(_, Q) ->
% [69, [
% [2, [17]],
% [67, [
% [17, [
% [170, [
% [10, [17]], "age"
% ]],age 9999
% ]],
% [17, [
% [170, [
% [170, [
% [10, [17]], "name"
% ]], "last"
% ]], "Adama"
% ]]
% ]]
% ]]
[?FUNC, [
[?TERMTYPE_MAKE_ARRAY, gen_var(1)],
erlang_rethinkdb_ast:make(Q)
]]
.
gen_var(_) ->
[20].
count(S) ->
[
?TERMTYPE_COUNT,
[S]
].
%%% [erlang_rethinkdb:connect(), [
%%% ]
inner_join(_,_) ->
10.
%%% @TODO: to make test work, detect environment and always return var number 20
wrap_fun(Q, Var) ->
[?FUNC, [
[?TERMTYPE_MAKE_ARRAY, Var],
Q
]].
zip(Sequence) ->
[?TERMTYPE_ZIP, [Sequence]]
.
%%% [50,[[15,[[14,["foodb"]],"compounds_foods"]],"compound_id",[15,[[14,["foodb"]],"compounds_"]]]]
eq_join(Sequence, LeftField, RightTableQuery, Option) when is_function(LeftField) ->
[
?TERMTYPE_EQ_JOIN,
[Sequence, wrap_fun(make(LeftField(gen_var(1))), gen_var(1)), make(RightTableQuery)],
Option
];
eq_join(Sequence, LeftField, RightTableQuery, Option) ->
[
?TERMTYPE_EQ_JOIN,
[Sequence, LeftField, make(RightTableQuery)],
Option
].
eq_join(Sequence, LeftField, RightTableQuery) when is_function(LeftField) ->
[
?TERMTYPE_EQ_JOIN,
[Sequence, wrap_fun(make(LeftField(gen_var(1))), gen_var(1)), make(RightTableQuery)]
];
eq_join(Sequence, LeftField, RightTableQuery)->
[
?TERMTYPE_EQ_JOIN,
[Sequence, LeftField, make(RightTableQuery)]
]
.
%% Geospartial command
circle({Long, Lat}, Radius) ->
[?TERMTYPE_CIRCLE, [[?TERMTYPE_MAKE_ARRAY, [Long, Lat]], Radius]].
%%% Compute the distance between a point and another geometry object. At least one of the geometry objects specified must be a point.
distance([P1, P2], O) ->
[?TERMTYPE_DISTANCE, [P1, P2], O]
.
%%% Convert a Line object into a Polygon object. If the last point does not specify the same coordinates as the first point, polygon will close the polygon by connecting them.
fill(Object) ->
[?TERMTYPE_FILL, [Object]].
point(Long, Lat) ->
[?TERMTYPE_POINT, [Long, Lat]].
polygon(Polygons) ->
[?TERMTYPE_POLYGON, lists:map(fun(V) -> [?TERMTYPE_MAKE_ARRAY, V] end, Polygons)]
.
line(Lines) ->
[?TERMTYPE_LINE, lists:map(fun(V) -> [?TERMTYPE_MAKE_ARRAY, V] end, Lines)]
.
make_array(A) -> [?TERMTYPE_MAKE_ARRAY, A].
%%% Note: this is not a part of ReQL
%%% We try to turn any array into ReQL MAKE_ARRAY
to_rethinkdb_type(O) when is_list(O)->
A = lists:map(fun(V) ->
case V of
{Key, Val} -> {Key, to_rethinkdb_type(Val)};
_ -> V
end
end, O),
make_array(A)
;
to_rethinkdb_type(O) -> O.
geojson(O) ->
A =
lists:map(
fun(V) ->
case V of
{Key, Val} -> {Key, to_rethinkdb_type(Val)};
_ -> V
end
end, O),
[?TERMTYPE_GEOJSON, [A]].
to_jsongeojson() ->
[?TERMTYPE_TO_GEOJSON,
[]
].