Current section
Files
Jump to
Current section
Files
src/sqlode@query_analyzer.erl
-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
).