-module(sqlode@query_analyzer). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/sqlode/query_analyzer.gleam"). -export([analysis_error_to_string/1, analyze_queries/4]). -file("src/sqlode/query_analyzer.gleam", 16). -spec analysis_error_to_string(sqlode@query_analyzer@context:analysis_error()) -> binary(). analysis_error_to_string(Error) -> sqlode@query_analyzer@context:analysis_error_to_string(Error). -file("src/sqlode/query_analyzer.gleam", 74). -spec merge_virtual_tables(sqlode@model:catalog(), list(sqlode@model:table())) -> sqlode@model:catalog(). merge_virtual_tables(Catalog, Vtables) -> case Vtables of [] -> Catalog; _ -> {catalog, lists:append(erlang:element(2, Catalog), Vtables), erlang:element(3, Catalog)} end. -file("src/sqlode/query_analyzer.gleam", 179). -spec macro_index(sqlode@model:macro()) -> integer(). macro_index(M) -> case M of {macro_arg, I, _} -> I; {macro_narg, I@1, _} -> I@1; {macro_slice, I@2, _} -> I@2 end. -file("src/sqlode/query_analyzer.gleam", 187). -spec build_macro_dict(list(sqlode@model:macro())) -> gleam@dict:dict(integer(), sqlode@model:macro()). build_macro_dict(Macros) -> gleam@list:fold( Macros, maps:new(), fun(D, M) -> gleam@dict:insert(D, macro_index(M), M) end ). -file("src/sqlode/query_analyzer.gleam", 191). -spec build_inference_dict(list({integer(), sqlode@model:column()})) -> gleam@dict:dict(integer(), sqlode@model:column()). build_inference_dict(Inferences) -> gleam@list:fold( Inferences, maps:new(), fun(D, Entry) -> {Index, Column} = Entry, case gleam@dict:has_key(D, Index) of true -> D; false -> gleam@dict:insert(D, Index, Column) end end ). -file("src/sqlode/query_analyzer.gleam", 88). -spec build_params( sqlode@query_analyzer@context:analyzer_context(), sqlode@model:engine(), sqlode@model:parsed_query(), sqlode@model:catalog(), list(sqlode@query_analyzer@placeholder:placeholder_occurrence()) ) -> {ok, list(sqlode@model:query_param())} | {error, sqlode@query_analyzer@context:analysis_error()}. build_params(Ctx, Engine, Query, Catalog, Occurrences) -> Inferences = begin _pipe = lists:append( sqlode@query_analyzer@param_inferencer:infer_insert_params( Ctx, Engine, Query, Catalog ), sqlode@query_analyzer@param_inferencer:infer_equality_params( Ctx, Engine, Query, Catalog ) ), lists:append( _pipe, sqlode@query_analyzer@param_inferencer:infer_in_params( Ctx, Engine, Query, Catalog ) ) end, gleam@result:'try'( begin _pipe@1 = sqlode@query_analyzer@param_inferencer:extract_type_casts( Ctx, Engine, erlang:element(5, Query) ), gleam@result:map_error( _pipe@1, fun(Err) -> {Index, Cast_type} = Err, {unrecognized_cast_type, erlang:element(2, Query), Index, Cast_type} end ) end, fun(Cast_dict) -> Macro_dict = build_macro_dict(erlang:element(8, Query)), Inference_dict = build_inference_dict(Inferences), _pipe@2 = sqlode@query_analyzer@placeholder:unique(Occurrences), gleam@list:try_map( _pipe@2, fun(Occurrence) -> Macro_info = begin _pipe@3 = gleam_stdlib:map_get( Macro_dict, erlang:element(2, Occurrence) ), gleam@option:from_result(_pipe@3) end, Inferred = begin _pipe@4 = gleam_stdlib:map_get( Inference_dict, erlang:element(2, Occurrence) ), gleam@option:from_result(_pipe@4) end, Cast_type@1 = begin _pipe@5 = gleam_stdlib:map_get( Cast_dict, erlang:element(2, Occurrence) ), gleam@option:from_result(_pipe@5) end, gleam@result:'try'(case Inferred of {some, Column} -> {ok, erlang:element(3, Column)}; none -> case Cast_type@1 of {some, St} -> {ok, St}; none -> {error, {parameter_type_not_inferred, erlang:element(2, Query), erlang:element(2, Occurrence)}} end end, fun(Inferred_type) -> {Field_name, Scalar_type, Nullable, Is_list} = case Macro_info of {some, {macro_arg, _, Name}} -> N = case Inferred of {some, Column@1} -> erlang:element(4, Column@1); none -> false end, {sqlode@naming:to_snake_case( erlang:element(2, Ctx), Name ), Inferred_type, N, false}; {some, {macro_narg, _, Name@1}} -> {sqlode@naming:to_snake_case( erlang:element(2, Ctx), Name@1 ), Inferred_type, true, false}; {some, {macro_slice, _, Name@2}} -> {sqlode@naming:to_snake_case( erlang:element(2, Ctx), Name@2 ), Inferred_type, false, true}; none -> case Inferred of {some, Column@2} -> {sqlode@naming:to_snake_case( erlang:element(2, Ctx), erlang:element(2, Column@2) ), erlang:element(3, Column@2), erlang:element(4, Column@2), false}; none -> {erlang:element(4, Occurrence), Inferred_type, false, false} end end, {ok, {query_param, erlang:element(2, Occurrence), Field_name, Scalar_type, Nullable, Is_list}} end) end ) end ). -file("src/sqlode/query_analyzer.gleam", 30). -spec analyze_query( sqlode@query_analyzer@context:analyzer_context(), sqlode@model:engine(), sqlode@model:catalog(), sqlode@model:parsed_query() ) -> {ok, sqlode@model:analyzed_query()} | {error, sqlode@query_analyzer@context:analysis_error()}. analyze_query(Ctx, Engine, Catalog, Query) -> Tokens = sqlode@lexer:tokenize(erlang:element(5, Query), Engine), gleam@result:'try'( sqlode@query_analyzer@column_inferencer:extract_cte_tables( erlang:element(2, Query), Tokens, Catalog ), fun(Cte_tables) -> With_ctes = merge_virtual_tables(Catalog, Cte_tables), Values_tables = sqlode@query_analyzer@column_inferencer:extract_values_tables( Tokens ), With_values = merge_virtual_tables(With_ctes, Values_tables), gleam@result:'try'( sqlode@query_analyzer@column_inferencer:extract_derived_tables( erlang:element(2, Query), Tokens, With_values ), fun(Derived_tables) -> Augmented = merge_virtual_tables( With_values, Derived_tables ), Occurrences = sqlode@query_analyzer@placeholder:extract( Ctx, Engine, erlang:element(5, Query) ), gleam@result:'try'( build_params(Ctx, Engine, Query, Augmented, Occurrences), fun(Params) -> gleam@result:'try'( sqlode@query_analyzer@column_inferencer:infer_result_columns( Ctx, Engine, Query, Augmented ), fun(Result_columns) -> {ok, {analyzed_query, Query, Params, Result_columns}} end ) end ) end ) end ). -file("src/sqlode/query_analyzer.gleam", 20). -spec analyze_queries( sqlode@model:engine(), sqlode@model:catalog(), sqlode@naming:naming_context(), list(sqlode@model:parsed_query()) ) -> {ok, list(sqlode@model:analyzed_query())} | {error, sqlode@query_analyzer@context:analysis_error()}. analyze_queries(Engine, Catalog, Naming_ctx, Queries) -> Ctx = sqlode@query_analyzer@context:new(Naming_ctx), gleam@list:try_map( Queries, fun(_capture) -> analyze_query(Ctx, Engine, Catalog, _capture) end ).