-module(sqlode@query_analyzer@param_inferencer). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/sqlode/query_analyzer/param_inferencer.gleam"). -export([infer_insert_params/4, infer_insert_params_from_ir/3, infer_equality_params/4, infer_in_params/4, extract_type_casts/3]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 61). -spec map_insert_columns( sqlode@model:engine(), sqlode@model:catalog(), binary(), list(binary()), list(list(sqlode@lexer:token())), integer(), gleam@dict:dict(binary(), integer()), list({integer(), sqlode@model:column()}) ) -> list({integer(), sqlode@model:column()}). map_insert_columns( Engine, Catalog, Table_name, Columns, Values, Occurrence, Seen, Acc ) -> case {Columns, Values} of {[], _} -> Acc; {_, []} -> Acc; {[Column_name | Rest_columns], [Value_tokens | Rest_values]} -> Value_placeholder = case Value_tokens of [{placeholder, P}] -> {some, P}; _ -> none end, {Maybe_index, Next_occurrence, Updated_seen} = case Value_placeholder of {some, P@1} -> sqlode@query_analyzer@placeholder:resolve_index( Engine, P@1, Occurrence, Seen ); none -> {none, Occurrence, Seen} end, Acc@1 = case Maybe_index of {some, Index} -> case sqlode@query_analyzer@context:find_column( Catalog, Table_name, Column_name ) of {some, Column} -> [{Index, Column} | Acc]; none -> Acc end; none -> Acc end, map_insert_columns( Engine, Catalog, Table_name, Rest_columns, Rest_values, Next_occurrence, Updated_seen, Acc@1 ) end. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 13). -spec infer_insert_params( sqlode@query_analyzer@context:analyzer_context(), sqlode@model:engine(), list(sqlode@lexer:token()), sqlode@model:catalog() ) -> list({integer(), sqlode@model:column()}). infer_insert_params(_, Engine, Tokens, Catalog) -> case sqlode@query_analyzer@token_utils:find_insert_parts(Tokens) of {some, Parts} -> _pipe = map_insert_columns( Engine, Catalog, erlang:element(2, Parts), erlang:element(3, Parts), erlang:element(4, Parts), 1, maps:new(), [] ), lists:reverse(_pipe); none -> [] end. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 39). ?DOC( " Structured IR variant of `infer_insert_params`. Consumes the\n" " pre-parsed `InsertStatement` directly instead of re-scanning\n" " the token list.\n" ). -spec infer_insert_params_from_ir( sqlode@model:engine(), sqlode@query_ir:sql_statement(), sqlode@model:catalog() ) -> list({integer(), sqlode@model:column()}). infer_insert_params_from_ir(Engine, Statement, Catalog) -> case Statement of {insert_statement, Table_name, Columns, Value_groups, _} -> _pipe = map_insert_columns( Engine, Catalog, Table_name, Columns, Value_groups, 1, maps:new(), [] ), lists:reverse(_pipe); _ -> [] end. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 137). -spec scan_token_matches( sqlode@model:engine(), sqlode@model:catalog(), binary(), list(binary()), list(sqlode@query_analyzer@token_utils:equality_match()), integer(), gleam@dict:dict(binary(), integer()), list({integer(), sqlode@model:column()}) ) -> list({integer(), sqlode@model:column()}). scan_token_matches( Engine, Catalog, Primary_table, All_tables, Matches, Occurrence, Seen, Acc ) -> case Matches of [] -> Acc; [Match | Rest] -> {Maybe_index, Next_occurrence, Updated_seen} = sqlode@query_analyzer@placeholder:resolve_index( Engine, erlang:element(4, Match), Occurrence, Seen ), Acc@1 = case Maybe_index of {some, Index} -> Found = case erlang:element(3, Match) of {some, Table} -> sqlode@query_analyzer@context:find_column( Catalog, Table, erlang:element(2, Match) ); none -> case sqlode@query_analyzer@context:find_column_in_tables( Catalog, All_tables, erlang:element(2, Match) ) of {ok, {some, Pair}} -> {some, erlang:element(2, Pair)}; _ -> none end end, case Found of {some, Column} -> [{Index, Column} | Acc]; none -> case sqlode@query_analyzer@context:find_column( Catalog, Primary_table, erlang:element(2, Match) ) of {some, Column@1} -> [{Index, Column@1} | Acc]; none -> Acc end end; none -> Acc end, scan_token_matches( Engine, Catalog, Primary_table, All_tables, Rest, Next_occurrence, Updated_seen, Acc@1 ) end. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 110). -spec infer_equality_params( sqlode@query_analyzer@context:analyzer_context(), sqlode@model:engine(), list(sqlode@lexer:token()), sqlode@model:catalog() ) -> list({integer(), sqlode@model:column()}). infer_equality_params(_, Engine, Tokens, Catalog) -> All_tables = sqlode@query_analyzer@token_utils:extract_table_names(Tokens), case All_tables of [] -> []; [Primary | _] -> Matches = sqlode@query_analyzer@token_utils:find_equality_patterns( Tokens ), _pipe = scan_token_matches( Engine, Catalog, Primary, All_tables, Matches, 1, maps:new(), [] ), lists:reverse(_pipe) end. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 199). -spec infer_in_params( sqlode@query_analyzer@context:analyzer_context(), sqlode@model:engine(), list(sqlode@lexer:token()), sqlode@model:catalog() ) -> list({integer(), sqlode@model:column()}). infer_in_params(_, Engine, Tokens, Catalog) -> All_tables = sqlode@query_analyzer@token_utils:extract_table_names(Tokens), case All_tables of [] -> []; [Primary | _] -> Matches = sqlode@query_analyzer@token_utils:find_in_patterns(Tokens), _pipe = scan_token_matches( Engine, Catalog, Primary, All_tables, Matches, 1, maps:new(), [] ), lists:reverse(_pipe) end. -file("src/sqlode/query_analyzer/param_inferencer.gleam", 253). -spec cast_type_to_scalar(binary()) -> {ok, sqlode@model:scalar_type()} | {error, nil}. cast_type_to_scalar(Type_name) -> sqlode@model:parse_sql_type(gleam@string:trim(Type_name)). -file("src/sqlode/query_analyzer/param_inferencer.gleam", 226). -spec extract_type_casts( sqlode@query_analyzer@context:analyzer_context(), sqlode@model:engine(), list(sqlode@lexer:token()) ) -> {ok, gleam@dict:dict(integer(), sqlode@model:scalar_type())} | {error, {integer(), binary()}}. extract_type_casts(_, Engine, Tokens) -> case Engine of postgre_s_q_l -> Casts = sqlode@query_analyzer@token_utils:find_type_casts(Tokens), gleam@list:try_fold( Casts, maps:new(), fun(D, Cast) -> case begin _pipe = erlang:element(2, Cast), _pipe@1 = gleam@string:replace( _pipe, <<"$"/utf8>>, <<""/utf8>> ), gleam_stdlib:parse_int(_pipe@1) end of {ok, Index} -> case cast_type_to_scalar(erlang:element(3, Cast)) of {ok, Scalar_type} -> {ok, gleam@dict:insert(D, Index, Scalar_type)}; {error, nil} -> {error, {Index, gleam@string:trim( erlang:element(3, Cast) )}} end; {error, _} -> {ok, D} end end ); _ -> {ok, maps:new()} end.