%% @private -module(boto_query). -export([query/2]). query(Args, Query) -> Graph = boto_server:graph(), do_query(Graph, Args, Query). do_query(Graph, Args, Query) -> ArgsKeys = maps:keys(Args), {QueryClean, NestedQuery} = extract_nested(Query), Plan = planner(Graph, ArgsKeys, QueryClean), RawResolved = lists:foldl(fun do_resolve/2, Args, Plan), CleanResolved = maps:filter(fun(K, _V) -> lists:member(K, QueryClean) end, RawResolved), nested_query(Graph, CleanResolved, NestedQuery). planner(Graph, ArgsKeys, Query) -> Fun = fun(Requested) -> FlatFun = fun(Arg) -> boto_graph:path(Graph, Arg, Requested) end, case lists:flatmap(FlatFun, ArgsKeys) of [] -> boto_graph:path(Graph, noarg, Requested); Plan -> Plan end end, ResultPlan = lists:flatmap(Fun, Query), lists:uniq(ResultPlan). do_resolve({Mod, Name}, Args) -> Resolved = apply(Mod, resolve, [Name, Args]), maps:merge(Args, Resolved). nested_query(Graph, Resolved, NestedQuery) -> Fun = fun({ArgKey, Query}, Resolving) -> Update = case maps:get(ArgKey, Resolving) of One when is_map(One) -> do_query(Graph, One, Query); Many when is_list(Many) -> lists:map(fun(One) -> do_query(Graph, One, Query) end, Many) end, maps:put(ArgKey, Update, Resolving) end, lists:foldl(Fun, Resolved, NestedQuery). extract_nested(Query) -> NestedQuery = lists:filter(fun is_tuple/1, Query), QueryClean = lists:map(fun extract_nested_field/1, Query), {QueryClean, NestedQuery}. extract_nested_field({K, _V}) -> K; extract_nested_field(K) -> K.