Current section

Files

Jump to
sqlode src sqlode@internal@query_analyzer@param_inferencer.erl
Raw

src/sqlode@internal@query_analyzer@param_inferencer.erl

-module(sqlode@internal@query_analyzer@param_inferencer).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/sqlode/internal/query_analyzer/param_inferencer.gleam").
-export([infer_insert_params/4, infer_insert_params_from_ir/3, extract_type_casts/3, extract_int_context_params/2, infer_in_params/5, infer_equality_params/5]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 66).
?DOC(false).
-spec map_insert_columns(
sqlode@internal@model:engine(),
sqlode@internal@model:catalog(),
binary(),
list(binary()),
list(list(sqlode@internal@lexer:token())),
integer(),
gleam@dict:dict(binary(), integer()),
list({integer(), sqlode@internal@model:column()})
) -> list({integer(), sqlode@internal@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};
[{keyword, <<"cast"/utf8>>},
l_paren,
{placeholder, P@1},
{keyword, <<"as"/utf8>>},
_,
r_paren] ->
{some, P@1};
_ ->
none
end,
{Maybe_index, Next_occurrence, Updated_seen} = case Value_placeholder of
{some, P@2} ->
sqlode@internal@query_analyzer@placeholder:resolve_index(
Engine,
P@2,
Occurrence,
Seen
);
none ->
{none, Occurrence, Seen}
end,
Acc@1 = case Maybe_index of
{some, Index} ->
case sqlode@internal@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/internal/query_analyzer/param_inferencer.gleam", 18).
?DOC(false).
-spec infer_insert_params(
sqlode@internal@query_analyzer@context:analyzer_context(),
sqlode@internal@model:engine(),
list(sqlode@internal@lexer:token()),
sqlode@internal@model:catalog()
) -> list({integer(), sqlode@internal@model:column()}).
infer_insert_params(_, Engine, Tokens, Catalog) ->
case sqlode@internal@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/internal/query_analyzer/param_inferencer.gleam", 44).
?DOC(false).
-spec infer_insert_params_from_ir(
sqlode@internal@model:engine(),
sqlode@internal@query_ir:sql_statement(),
sqlode@internal@model:catalog()
) -> list({integer(), sqlode@internal@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/internal/query_analyzer/param_inferencer.gleam", 417).
?DOC(false).
-spec is_comparison_op(binary()) -> boolean().
is_comparison_op(Op) ->
((((((Op =:= <<"="/utf8>>) orelse (Op =:= <<"!="/utf8>>)) orelse (Op =:= <<"<>"/utf8>>))
orelse (Op =:= <<"<"/utf8>>))
orelse (Op =:= <<">"/utf8>>))
orelse (Op =:= <<"<="/utf8>>))
orelse (Op =:= <<">="/utf8>>).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 457).
?DOC(false).
-spec column_of(sqlode@internal@query_ir:expr()) -> gleam@option:option({gleam@option:option(binary()),
binary()}).
column_of(Expr) ->
case Expr of
{column_ref, Table, Name} ->
{some, {Table, Name}};
_ ->
none
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 464).
?DOC(false).
-spec param_of(sqlode@internal@query_ir:expr()) -> gleam@option:option(binary()).
param_of(Expr) ->
case Expr of
{param, _, Raw} ->
{some, Raw};
{cast, Inner, _} ->
param_of(Inner);
_ ->
none
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 236).
?DOC(false).
-spec assignment_match(sqlode@internal@query_ir:assignment()) -> {ok,
sqlode@internal@query_analyzer@token_utils:equality_match()} |
{error, nil}.
assignment_match(Assignment) ->
case param_of(erlang:element(3, Assignment)) of
{some, Raw} ->
{ok,
{equality_match,
sqlode@internal@naming:normalize_identifier(
erlang:element(2, Assignment)
),
none,
Raw}};
none ->
{error, nil}
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 484).
?DOC(false).
-spec normalize_table_qualifier(gleam@option:option(binary())) -> gleam@option:option(binary()).
normalize_table_qualifier(Table) ->
case Table of
{some, T} ->
{some, string:lowercase(T)};
none ->
none
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 472).
?DOC(false).
-spec build_match(gleam@option:option(binary()), binary(), binary()) -> sqlode@internal@query_analyzer@token_utils:equality_match().
build_match(Table, Name, Placeholder) ->
{equality_match,
sqlode@internal@naming:normalize_identifier(Name),
normalize_table_qualifier(Table),
Placeholder}.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 433).
?DOC(false).
-spec comparison_match(
sqlode@internal@query_ir:expr(),
sqlode@internal@query_ir:expr()
) -> gleam@option:option(sqlode@internal@query_analyzer@token_utils:equality_match()).
comparison_match(Left, Right) ->
case {column_of(Left), param_of(Right)} of
{{some, {Table, Name}}, {some, Raw}} ->
{some, build_match(Table, Name, Raw)};
{_, _} ->
case {column_of(Right), param_of(Left)} of
{{some, {Table@1, Name@1}}, {some, Raw@1}} ->
{some, build_match(Table@1, Name@1, Raw@1)};
{_, _} ->
none
end
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 447).
?DOC(false).
-spec like_match(
sqlode@internal@query_ir:expr(),
sqlode@internal@query_ir:expr()
) -> gleam@option:option(sqlode@internal@query_analyzer@token_utils:equality_match()).
like_match(Subject, Pattern) ->
case {column_of(Subject), param_of(Pattern)} of
{{some, {Table, Name}}, {some, Raw}} ->
{some, build_match(Table, Name, Raw)};
{_, _} ->
none
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 705).
?DOC(false).
-spec in_list_match(
sqlode@internal@query_ir:expr(),
list(sqlode@internal@query_ir:expr())
) -> gleam@option:option(sqlode@internal@query_analyzer@token_utils:equality_match()).
in_list_match(Subject, Values) ->
case Values of
[Only] ->
case {column_of(Subject), param_of(Only)} of
{{some, {Table, Name}}, {some, Raw}} ->
{some, build_match(Table, Name, Raw)};
{_, _} ->
none
end;
_ ->
none
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 737).
?DOC(false).
-spec quantified_param_of(sqlode@internal@query_ir:expr()) -> gleam@option:option(binary()).
quantified_param_of(Expr) ->
case Expr of
{tuple, [Only]} ->
param_of(Only);
_ ->
param_of(Expr)
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 726).
?DOC(false).
-spec quantified_match(
sqlode@internal@query_ir:expr(),
sqlode@internal@query_ir:quantifier(),
sqlode@internal@query_ir:expr()
) -> gleam@option:option(sqlode@internal@query_analyzer@token_utils:equality_match()).
quantified_match(Left, _, Right) ->
case {column_of(Left), quantified_param_of(Right)} of
{{some, {Table, Name}}, {some, Raw}} ->
{some, build_match(Table, Name, Raw)};
{_, _} ->
none
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 755).
?DOC(false).
-spec scan_token_matches(
sqlode@internal@model:engine(),
sqlode@internal@model:catalog(),
binary(),
list(binary()),
list(sqlode@internal@query_analyzer@token_utils:equality_match()),
integer(),
gleam@dict:dict(binary(), integer()),
list({integer(), sqlode@internal@model:column()})
) -> {ok, list({integer(), sqlode@internal@model:column()})} |
{error, sqlode@internal@query_analyzer@context:analysis_error()}.
scan_token_matches(
Engine,
Catalog,
Query_name,
All_tables,
Matches,
Occurrence,
Seen,
Acc
) ->
case Matches of
[] ->
{ok, Acc};
[Match | Rest] ->
{Maybe_index, Next_occurrence, Updated_seen} = sqlode@internal@query_analyzer@placeholder:resolve_index(
Engine,
erlang:element(4, Match),
Occurrence,
Seen
),
case Maybe_index of
none ->
scan_token_matches(
Engine,
Catalog,
Query_name,
All_tables,
Rest,
Next_occurrence,
Updated_seen,
Acc
);
{some, Index} ->
Lookup = case erlang:element(3, Match) of
{some, Table} ->
{ok,
begin
_pipe = sqlode@internal@query_analyzer@context:find_column(
Catalog,
Table,
erlang:element(2, Match)
),
gleam@option:map(
_pipe,
fun(Col) -> {Table, Col} end
)
end};
none ->
sqlode@internal@query_analyzer@context:find_column_in_tables(
Catalog,
All_tables,
erlang:element(2, Match)
)
end,
case Lookup of
{error, Matching_tables} ->
{error,
{ambiguous_column_name,
Query_name,
erlang:element(2, Match),
Matching_tables}};
{ok, {some, {_, Column}}} ->
scan_token_matches(
Engine,
Catalog,
Query_name,
All_tables,
Rest,
Next_occurrence,
Updated_seen,
[{Index,
{column,
erlang:element(2, Column),
erlang:element(3, Column),
false}} |
Acc]
);
{ok, none} ->
scan_token_matches(
Engine,
Catalog,
Query_name,
All_tables,
Rest,
Next_occurrence,
Updated_seen,
Acc
)
end
end
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 989).
?DOC(false).
-spec resolve_placeholder_index(
sqlode@internal@model:engine(),
binary(),
integer()
) -> integer().
resolve_placeholder_index(Engine, Raw, Occurrence) ->
case Engine of
postgre_s_q_l ->
case begin
_pipe = Raw,
_pipe@1 = gleam@string:replace(_pipe, <<"$"/utf8>>, <<""/utf8>>),
gleam_stdlib:parse_int(_pipe@1)
end of
{ok, N} ->
N;
{error, _} ->
Occurrence
end;
_ ->
Occurrence
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 945).
?DOC(false).
-spec scan_cast_hints(
list(sqlode@internal@lexer:token()),
sqlode@internal@model:engine(),
integer(),
list({integer(), binary()})
) -> list({integer(), binary()}).
scan_cast_hints(Tokens, Engine, Occurrence, Acc) ->
case Tokens of
[] ->
lists:reverse(Acc);
[{keyword, <<"cast"/utf8>>},
l_paren,
{placeholder, Raw},
{keyword, <<"as"/utf8>>},
{ident, T},
r_paren |
Rest] ->
Index = resolve_placeholder_index(Engine, Raw, Occurrence),
scan_cast_hints(
Rest,
Engine,
Occurrence + 1,
[{Index, string:lowercase(T)} | Acc]
);
[{keyword, <<"cast"/utf8>>},
l_paren,
{placeholder, Raw@1},
{keyword, <<"as"/utf8>>},
{keyword, T@1},
r_paren |
Rest@1] ->
Index@1 = resolve_placeholder_index(Engine, Raw@1, Occurrence),
scan_cast_hints(
Rest@1,
Engine,
Occurrence + 1,
[{Index@1, T@1} | Acc]
);
[{placeholder, _} | Rest@2] ->
scan_cast_hints(Rest@2, Engine, Occurrence + 1, Acc);
[_ | Rest@3] ->
scan_cast_hints(Rest@3, Engine, Occurrence, Acc)
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 1008).
?DOC(false).
-spec cast_type_to_scalar(binary()) -> {ok, sqlode@internal@model:scalar_type()} |
{error, nil}.
cast_type_to_scalar(Type_name) ->
sqlode@internal@model:parse_sql_type(gleam@string:trim(Type_name)).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 902).
?DOC(false).
-spec extract_type_casts(
sqlode@internal@query_analyzer@context:analyzer_context(),
sqlode@internal@model:engine(),
list(sqlode@internal@lexer:token())
) -> {ok, gleam@dict:dict(integer(), sqlode@internal@model:scalar_type())} |
{error, {integer(), binary()}}.
extract_type_casts(_, Engine, Tokens) ->
Pg_casts = sqlode@internal@query_analyzer@token_utils:find_type_casts(
Tokens
),
gleam@result:'try'(
gleam@list:try_fold(
Pg_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
),
fun(Pg_dict) ->
Cast_hints = scan_cast_hints(Tokens, Engine, 1, []),
gleam@result:'try'(
gleam@list:try_fold(
Cast_hints,
Pg_dict,
fun(D@1, Pair) ->
{Index@1, Type_name} = Pair,
case cast_type_to_scalar(Type_name) of
{ok, Scalar_type@1} ->
{ok,
gleam@dict:insert(
D@1,
Index@1,
Scalar_type@1
)};
{error, nil} ->
{error, {Index@1, gleam@string:trim(Type_name)}}
end
end
),
fun(Cast_dict) -> {ok, Cast_dict} end
)
end
).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 1047).
?DOC(false).
-spec scan_int_context_indices(
list(sqlode@internal@lexer:token()),
sqlode@internal@model:engine(),
integer(),
boolean(),
list(integer())
) -> list(integer()).
scan_int_context_indices(Tokens, Engine, Occurrence, In_int_context, Acc) ->
case Tokens of
[] ->
lists:reverse(Acc);
[{keyword, K} | Rest] ->
Lower = string:lowercase(K),
Next_state = case Lower of
<<"limit"/utf8>> ->
true;
<<"offset"/utf8>> ->
true;
<<"union"/utf8>> ->
false;
<<"except"/utf8>> ->
false;
<<"intersect"/utf8>> ->
false;
<<"returning"/utf8>> ->
false;
<<"for"/utf8>> ->
false;
_ ->
In_int_context
end,
scan_int_context_indices(Rest, Engine, Occurrence, Next_state, Acc);
[{placeholder, Raw} | Rest@1] ->
Assigned = case Engine of
postgre_s_q_l ->
case begin
_pipe = Raw,
_pipe@1 = gleam@string:replace(
_pipe,
<<"$"/utf8>>,
<<""/utf8>>
),
gleam_stdlib:parse_int(_pipe@1)
end of
{ok, N} ->
N;
{error, _} ->
Occurrence
end;
_ ->
Occurrence
end,
Acc@1 = case In_int_context of
true ->
[Assigned | Acc];
false ->
Acc
end,
scan_int_context_indices(
Rest@1,
Engine,
Occurrence + 1,
In_int_context,
Acc@1
);
[_ | Rest@2] ->
scan_int_context_indices(
Rest@2,
Engine,
Occurrence,
In_int_context,
Acc
)
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 1032).
?DOC(false).
-spec extract_int_context_params(
list(sqlode@internal@lexer:token()),
sqlode@internal@model:engine()
) -> gleam@dict:dict(integer(), sqlode@internal@model:scalar_type()).
extract_int_context_params(Tokens, Engine) ->
Int_indices = scan_int_context_indices(Tokens, Engine, 1, false, []),
gleam@list:fold(
Int_indices,
maps:new(),
fun(D, Idx) -> gleam@dict:insert(D, Idx, int_type) end
).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 560).
?DOC(false).
-spec walk_set_op_iq(gleam@option:option(sqlode@internal@query_ir:set_op())) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_set_op_iq(Set_op) ->
case Set_op of
{some, {set_op, _, _, Right}} ->
walk_select_core_iq(Right);
none ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 534).
?DOC(false).
-spec walk_select_core_iq(sqlode@internal@query_ir:select_core()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_select_core_iq(Core) ->
lists:append(
[gleam@list:flat_map(erlang:element(3, Core), fun walk_select_item_iq/1),
gleam@list:flat_map(
erlang:element(4, Core),
fun walk_from_item_joins_iq/1
),
walk_optional_expr_iq(erlang:element(5, Core)),
gleam@list:flat_map(erlang:element(6, Core), fun walk_expr_iq/1),
walk_optional_expr_iq(erlang:element(7, Core)),
gleam@list:flat_map(
erlang:element(8, Core),
fun walk_order_key_iq/1
),
walk_optional_expr_iq(erlang:element(9, Core)),
walk_optional_expr_iq(erlang:element(10, Core)),
walk_set_op_iq(erlang:element(11, Core))]
).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 556).
?DOC(false).
-spec walk_order_key_iq(sqlode@internal@query_ir:order_key()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_order_key_iq(Key) ->
walk_expr_iq(erlang:element(2, Key)).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 623).
?DOC(false).
-spec walk_expr_iq(sqlode@internal@query_ir:expr()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_expr_iq(Expr) ->
case Expr of
{in_expr, Subject, {in_list, Values}, _} ->
case in_list_match(Subject, Values) of
{some, M} ->
[M];
none ->
lists:append(
walk_expr_iq(Subject),
gleam@list:flat_map(Values, fun walk_expr_iq/1)
)
end;
{in_expr, Subject@1, Source, _} ->
lists:append(walk_expr_iq(Subject@1), walk_in_source_iq(Source));
{quantified, _, Left, Quantifier, Right} ->
case quantified_match(Left, Quantifier, Right) of
{some, M@1} ->
[M@1];
none ->
lists:append(walk_expr_iq(Left), walk_expr_iq(Right))
end;
{binary, _, Left@1, Right@1} ->
lists:append(walk_expr_iq(Left@1), walk_expr_iq(Right@1));
{like_expr, Subject@2, _, Pattern, _, _} ->
lists:append(walk_expr_iq(Subject@2), walk_expr_iq(Pattern));
{unary, _, Arg} ->
walk_expr_iq(Arg);
{between, Subject@3, Low, High, _} ->
lists:append(
[walk_expr_iq(Subject@3), walk_expr_iq(Low), walk_expr_iq(High)]
);
{is_check, Subject@4, _, _} ->
walk_expr_iq(Subject@4);
{'case', Scrutinee, Branches, Else_} ->
lists:append(
[walk_optional_expr_iq(Scrutinee),
gleam@list:flat_map(
Branches,
fun(B) ->
lists:append(
walk_expr_iq(erlang:element(2, B)),
walk_expr_iq(erlang:element(3, B))
)
end
),
walk_optional_expr_iq(Else_)]
);
{cast, Subject@5, _} ->
walk_expr_iq(Subject@5);
{func, _, Args, _, Filter, Over} ->
lists:append(
[gleam@list:flat_map(
Args,
fun(A) -> walk_expr_iq(erlang:element(2, A)) end
),
walk_optional_expr_iq(Filter),
case Over of
{some, Spec} ->
walk_window_spec_iq(Spec);
none ->
[]
end]
);
{tuple, Elements} ->
gleam@list:flat_map(Elements, fun walk_expr_iq/1);
{array_lit, Elements@1} ->
gleam@list:flat_map(Elements@1, fun walk_expr_iq/1);
{exists, Core, _} ->
walk_select_core_iq(Core);
{scalar_subquery, Core@1} ->
walk_select_core_iq(Core@1);
_ ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 569).
?DOC(false).
-spec walk_window_spec_iq(sqlode@internal@query_ir:window_spec()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_window_spec_iq(Spec) ->
lists:append(
[gleam@list:flat_map(erlang:element(2, Spec), fun walk_expr_iq/1),
gleam@list:flat_map(
erlang:element(3, Spec),
fun walk_order_key_iq/1
)]
).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 578).
?DOC(false).
-spec walk_select_item_iq(sqlode@internal@query_ir:select_item_ex()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_select_item_iq(Item) ->
case Item of
{expr_item, Expr, _} ->
walk_expr_iq(Expr);
{star_ex, _} ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 601).
?DOC(false).
-spec walk_join_on_iq(sqlode@internal@query_ir:join_on()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_join_on_iq(On) ->
case On of
{join_on_expr, Expr} ->
walk_expr_iq(Expr);
_ ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 587).
?DOC(false).
-spec walk_from_item_joins_iq(sqlode@internal@query_ir:from_item_ex()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_from_item_joins_iq(From) ->
case From of
{from_join, Left, Right, _, On, _} ->
lists:append(
[walk_from_item_joins_iq(Left),
walk_from_item_joins_iq(Right),
walk_join_on_iq(On)]
);
_ ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 608).
?DOC(false).
-spec walk_optional_expr_iq(
gleam@option:option(sqlode@internal@query_ir:expr())
) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_optional_expr_iq(Expr) ->
case Expr of
{some, E} ->
walk_expr_iq(E);
none ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 513).
?DOC(false).
-spec find_in_quantified_matches_in_stmt(sqlode@internal@query_ir:stmt()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
find_in_quantified_matches_in_stmt(Stmt) ->
case Stmt of
{select_stmt, _, Core} ->
walk_select_core_iq(Core);
{update_stmt, _, _, _, Assignments, _, Where_, _} ->
lists:append(
[gleam@list:flat_map(
Assignments,
fun(A) -> walk_expr_iq(erlang:element(3, A)) end
),
walk_optional_expr_iq(Where_)]
);
{delete_stmt, _, _, _, _, Where_@1, _} ->
walk_optional_expr_iq(Where_@1);
{insert_stmt, _, _, _, _, _, _} ->
[];
{unstructured_stmt, _, _} ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 688).
?DOC(false).
-spec walk_in_source_iq(sqlode@internal@query_ir:in_source()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_in_source_iq(Source) ->
case Source of
{in_subquery, Core} ->
walk_select_core_iq(Core);
{in_list, Values} ->
gleam@list:flat_map(Values, fun walk_expr_iq/1);
{in_slice_macro, _} ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 853).
?DOC(false).
-spec infer_in_params(
sqlode@internal@query_analyzer@context:analyzer_context(),
sqlode@internal@model:engine(),
binary(),
list(sqlode@internal@lexer:token()),
sqlode@internal@model:catalog()
) -> {ok, list({integer(), sqlode@internal@model:column()})} |
{error, sqlode@internal@query_analyzer@context:analysis_error()}.
infer_in_params(_, Engine, Query_name, Tokens, Catalog) ->
Main_tokens = sqlode@internal@query_analyzer@token_utils:strip_leading_with(
Tokens
),
All_tables = sqlode@internal@query_analyzer@token_utils:extract_table_names(
Main_tokens
),
case All_tables of
[] ->
{ok, []};
_ ->
Matches = case sqlode@internal@query_analyzer@expr_parser:parse_stmt(
Tokens,
Engine
) of
{unstructured_stmt, _, _} ->
lists:append(
sqlode@internal@query_analyzer@token_utils:find_in_patterns(
Main_tokens
),
sqlode@internal@query_analyzer@token_utils:find_quantified_patterns(
Main_tokens
)
);
{insert_stmt, _, _, _, _, _, _} ->
lists:append(
sqlode@internal@query_analyzer@token_utils:find_in_patterns(
Main_tokens
),
sqlode@internal@query_analyzer@token_utils:find_quantified_patterns(
Main_tokens
)
);
Stmt ->
find_in_quantified_matches_in_stmt(Stmt)
end,
_pipe = scan_token_matches(
Engine,
Catalog,
Query_name,
All_tables,
Matches,
1,
maps:new(),
[]
),
gleam@result:map(_pipe, fun lists:reverse/1)
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 279).
?DOC(false).
-spec walk_set_op(gleam@option:option(sqlode@internal@query_ir:set_op())) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_set_op(Set_op) ->
case Set_op of
{some, {set_op, _, _, Right}} ->
walk_select_core(Right);
none ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 250).
?DOC(false).
-spec walk_select_core(sqlode@internal@query_ir:select_core()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_select_core(Core) ->
lists:append(
[gleam@list:flat_map(erlang:element(3, Core), fun walk_select_item/1),
gleam@list:flat_map(
erlang:element(4, Core),
fun walk_from_item_joins/1
),
walk_optional_expr(erlang:element(5, Core)),
gleam@list:flat_map(erlang:element(6, Core), fun walk_expr/1),
walk_optional_expr(erlang:element(7, Core)),
gleam@list:flat_map(erlang:element(8, Core), fun walk_order_key/1),
walk_optional_expr(erlang:element(9, Core)),
walk_optional_expr(erlang:element(10, Core)),
walk_set_op(erlang:element(11, Core))]
).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 275).
?DOC(false).
-spec walk_order_key(sqlode@internal@query_ir:order_key()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_order_key(Key) ->
walk_expr(erlang:element(2, Key)).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 347).
?DOC(false).
-spec walk_expr(sqlode@internal@query_ir:expr()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_expr(Expr) ->
case Expr of
{binary, Op, Left, Right} ->
case is_comparison_op(Op) of
true ->
case comparison_match(Left, Right) of
{some, M} ->
[M];
none ->
lists:append(walk_expr(Left), walk_expr(Right))
end;
false ->
lists:append(walk_expr(Left), walk_expr(Right))
end;
{like_expr, Subject, _, Pattern, _, _} ->
case like_match(Subject, Pattern) of
{some, M@1} ->
[M@1];
none ->
lists:append(walk_expr(Subject), walk_expr(Pattern))
end;
{unary, _, Arg} ->
walk_expr(Arg);
{between, Subject@1, Low, High, _} ->
lists:append(
[walk_expr(Subject@1), walk_expr(Low), walk_expr(High)]
);
{is_check, Subject@2, _, _} ->
walk_expr(Subject@2);
{'case', Scrutinee, Branches, Else_} ->
lists:append(
[walk_optional_expr(Scrutinee),
gleam@list:flat_map(
Branches,
fun(B) ->
lists:append(
walk_expr(erlang:element(2, B)),
walk_expr(erlang:element(3, B))
)
end
),
walk_optional_expr(Else_)]
);
{cast, Subject@3, _} ->
walk_expr(Subject@3);
{func, _, Args, _, Filter, Over} ->
lists:append(
[gleam@list:flat_map(
Args,
fun(A) -> walk_expr(erlang:element(2, A)) end
),
walk_optional_expr(Filter),
case Over of
{some, Spec} ->
walk_window_spec(Spec);
none ->
[]
end]
);
{tuple, Elements} ->
gleam@list:flat_map(Elements, fun walk_expr/1);
{array_lit, Elements@1} ->
gleam@list:flat_map(Elements@1, fun walk_expr/1);
{exists, Core, _} ->
walk_select_core(Core);
{scalar_subquery, Core@1} ->
walk_select_core(Core@1);
{in_expr, Subject@4, Source, _} ->
lists:append(walk_expr(Subject@4), walk_in_source(Source));
{quantified, _, Left@1, _, Right@1} ->
lists:append(walk_expr(Left@1), walk_expr(Right@1));
_ ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 288).
?DOC(false).
-spec walk_window_spec(sqlode@internal@query_ir:window_spec()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_window_spec(Spec) ->
lists:append(
[gleam@list:flat_map(erlang:element(2, Spec), fun walk_expr/1),
gleam@list:flat_map(erlang:element(3, Spec), fun walk_order_key/1)]
).
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 297).
?DOC(false).
-spec walk_select_item(sqlode@internal@query_ir:select_item_ex()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_select_item(Item) ->
case Item of
{expr_item, Expr, _} ->
walk_expr(Expr);
{star_ex, _} ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 323).
?DOC(false).
-spec walk_join_on(sqlode@internal@query_ir:join_on()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_join_on(On) ->
case On of
{join_on_expr, Expr} ->
walk_expr(Expr);
_ ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 306).
?DOC(false).
-spec walk_from_item_joins(sqlode@internal@query_ir:from_item_ex()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_from_item_joins(From) ->
case From of
{from_join, Left, Right, _, On, _} ->
lists:append(
[walk_from_item_joins(Left),
walk_from_item_joins(Right),
walk_join_on(On)]
);
_ ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 330).
?DOC(false).
-spec walk_optional_expr(gleam@option:option(sqlode@internal@query_ir:expr())) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_optional_expr(Expr) ->
case Expr of
{some, E} ->
walk_expr(E);
none ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 206).
?DOC(false).
-spec find_equality_matches_in_stmt(sqlode@internal@query_ir:stmt()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
find_equality_matches_in_stmt(Stmt) ->
case Stmt of
{select_stmt, _, Core} ->
walk_select_core(Core);
{update_stmt, _, _, _, Assignments, _, Where_, _} ->
lists:append(
[gleam@list:filter_map(Assignments, fun assignment_match/1),
gleam@list:flat_map(
Assignments,
fun(A) -> walk_expr(erlang:element(3, A)) end
),
walk_optional_expr(Where_)]
);
{delete_stmt, _, _, _, _, Where_@1, _} ->
walk_optional_expr(Where_@1);
{insert_stmt, _, _, _, _, _, _} ->
[];
{unstructured_stmt, _, _} ->
[]
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 132).
?DOC(false).
-spec infer_equality_params(
sqlode@internal@query_analyzer@context:analyzer_context(),
sqlode@internal@model:engine(),
binary(),
list(sqlode@internal@lexer:token()),
sqlode@internal@model:catalog()
) -> {ok, list({integer(), sqlode@internal@model:column()})} |
{error, sqlode@internal@query_analyzer@context:analysis_error()}.
infer_equality_params(_, Engine, Query_name, Tokens, Catalog) ->
Main_tokens = sqlode@internal@query_analyzer@token_utils:strip_leading_with(
Tokens
),
All_tables = sqlode@internal@query_analyzer@token_utils:extract_table_names(
Main_tokens
),
case All_tables of
[] ->
{ok, []};
_ ->
Matches = case sqlode@internal@query_analyzer@expr_parser:parse_stmt(
Tokens,
Engine
) of
{unstructured_stmt, _, _} ->
sqlode@internal@query_analyzer@token_utils:find_equality_patterns(
Main_tokens
);
{insert_stmt, _, _, _, _, _, _} ->
sqlode@internal@query_analyzer@token_utils:find_equality_patterns(
Main_tokens
);
Stmt ->
find_equality_matches_in_stmt(Stmt)
end,
_pipe = scan_token_matches(
Engine,
Catalog,
Query_name,
All_tables,
Matches,
1,
maps:new(),
[]
),
gleam@result:map(_pipe, fun lists:reverse/1)
end.
-file("src/sqlode/internal/query_analyzer/param_inferencer.gleam", 409).
?DOC(false).
-spec walk_in_source(sqlode@internal@query_ir:in_source()) -> list(sqlode@internal@query_analyzer@token_utils:equality_match()).
walk_in_source(Source) ->
case Source of
{in_subquery, Core} ->
walk_select_core(Core);
{in_list, Values} ->
gleam@list:flat_map(Values, fun walk_expr/1);
{in_slice_macro, _} ->
[]
end.