Current section
Files
Jump to
Current section
Files
src/sqlode@query_analyzer@context.erl
-module(sqlode@query_analyzer@context).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/sqlode/query_analyzer/context.gleam").
-export([analysis_error_to_string/1, new/1, find_column/3, find_column_in_tables/3]).
-export_type([analysis_error/0, analyzer_context/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type analysis_error() :: {table_not_found, binary(), binary()} |
{column_not_found, binary(), binary(), binary()} |
{parameter_type_not_inferred, binary(), integer()} |
{parameter_type_conflict,
binary(),
integer(),
sqlode@model:scalar_type(),
sqlode@model:scalar_type()} |
{unrecognized_cast_type, binary(), integer(), binary()} |
{compound_column_count_mismatch, binary(), integer(), integer()} |
{unsupported_expression, binary(), binary()} |
{ambiguous_column_name, binary(), binary(), list(binary())}.
-type analyzer_context() :: {analyzer_context, sqlode@naming:naming_context()}.
-file("src/sqlode/query_analyzer/context.gleam", 97).
-spec scalar_type_label(sqlode@model:scalar_type()) -> binary().
scalar_type_label(T) ->
case T of
int_type ->
<<"Int"/utf8>>;
float_type ->
<<"Float"/utf8>>;
bool_type ->
<<"Bool"/utf8>>;
string_type ->
<<"String"/utf8>>;
bytes_type ->
<<"BitArray"/utf8>>;
date_time_type ->
<<"DateTime"/utf8>>;
date_type ->
<<"Date"/utf8>>;
time_type ->
<<"Time"/utf8>>;
uuid_type ->
<<"Uuid"/utf8>>;
json_type ->
<<"Json"/utf8>>;
{enum_type, Name} ->
<<<<"Enum("/utf8, Name/binary>>/binary, ")"/utf8>>;
{custom_type, Name@1, _, _} ->
Name@1;
{array_type, Element} ->
<<<<"List("/utf8, (scalar_type_label(Element))/binary>>/binary,
")"/utf8>>
end.
-file("src/sqlode/query_analyzer/context.gleam", 32).
-spec analysis_error_to_string(analysis_error()) -> binary().
analysis_error_to_string(Error) ->
case Error of
{table_not_found, Query_name, Table_name} ->
<<<<<<<<"Query \""/utf8, Query_name/binary>>/binary,
"\": table \""/utf8>>/binary,
Table_name/binary>>/binary,
"\" not found in schema"/utf8>>;
{column_not_found, Query_name@1, Table_name@1, Column_name} ->
<<<<<<<<<<<<"Query \""/utf8, Query_name@1/binary>>/binary,
"\": column \""/utf8>>/binary,
Column_name/binary>>/binary,
"\" not found in table \""/utf8>>/binary,
Table_name@1/binary>>/binary,
"\""/utf8>>;
{parameter_type_not_inferred, Query_name@2, Param_index} ->
<<<<<<<<<<<<"Query \""/utf8, Query_name@2/binary>>/binary,
"\": could not infer type for parameter $"/utf8>>/binary,
(erlang:integer_to_binary(Param_index))/binary>>/binary,
". Use a type cast (e.g. $"/utf8>>/binary,
(erlang:integer_to_binary(Param_index))/binary>>/binary,
"::int) to specify the type"/utf8>>;
{unrecognized_cast_type, Query_name@3, Param_index@1, Cast_type} ->
<<<<<<<<<<"Query \""/utf8, Query_name@3/binary>>/binary,
"\": unrecognized cast type \""/utf8>>/binary,
Cast_type/binary>>/binary,
"\" for parameter $"/utf8>>/binary,
(erlang:integer_to_binary(Param_index@1))/binary>>;
{compound_column_count_mismatch,
Query_name@4,
First_count,
Branch_count} ->
<<<<<<<<<<"Query \""/utf8, Query_name@4/binary>>/binary,
"\": compound query branch has "/utf8>>/binary,
(erlang:integer_to_binary(Branch_count))/binary>>/binary,
" columns, but the first branch has "/utf8>>/binary,
(erlang:integer_to_binary(First_count))/binary>>;
{parameter_type_conflict, Query_name@5, Param_index@2, Type_a, Type_b} ->
<<<<<<<<<<<<<<<<"Query \""/utf8, Query_name@5/binary>>/binary,
"\": parameter $"/utf8>>/binary,
(erlang:integer_to_binary(Param_index@2))/binary>>/binary,
" has conflicting inferred types \""/utf8>>/binary,
(scalar_type_label(Type_a))/binary>>/binary,
"\" and \""/utf8>>/binary,
(scalar_type_label(Type_b))/binary>>/binary,
"\". Use a type cast to resolve the ambiguity"/utf8>>;
{unsupported_expression, Query_name@6, Expression} ->
<<<<<<<<"Query \""/utf8, Query_name@6/binary>>/binary,
"\": unsupported expression \""/utf8>>/binary,
Expression/binary>>/binary,
"\", cannot infer result type. Use CAST to specify the type explicitly"/utf8>>;
{ambiguous_column_name, Query_name@7, Column_name@1, Matching_tables} ->
<<<<<<<<<<<<"Query \""/utf8, Query_name@7/binary>>/binary,
"\": column \""/utf8>>/binary,
Column_name@1/binary>>/binary,
"\" is ambiguous — found in tables: "/utf8>>/binary,
(gleam@string:join(Matching_tables, <<", "/utf8>>))/binary>>/binary,
". Use a table qualifier (e.g. table.column) to resolve the ambiguity"/utf8>>
end.
-file("src/sqlode/query_analyzer/context.gleam", 119).
-spec new(sqlode@naming:naming_context()) -> analyzer_context().
new(Naming_ctx) ->
{analyzer_context, Naming_ctx}.
-file("src/sqlode/query_analyzer/context.gleam", 123).
-spec find_column(sqlode@model:catalog(), binary(), binary()) -> gleam@option:option(sqlode@model:column()).
find_column(Catalog, Table_name, Column_name) ->
case begin
_pipe = erlang:element(2, Catalog),
gleam@list:find(
_pipe,
fun(Table) ->
erlang:element(2, Table) =:= sqlode@naming:normalize_identifier(
Table_name
)
end
)
end of
{ok, Table@1} ->
_pipe@1 = erlang:element(3, Table@1),
_pipe@2 = gleam@list:find(
_pipe@1,
fun(Column) ->
erlang:element(2, Column) =:= sqlode@naming:normalize_identifier(
Column_name
)
end
),
gleam@option:from_result(_pipe@2);
{error, _} ->
none
end.
-file("src/sqlode/query_analyzer/context.gleam", 149).
?DOC(
" Search for a column across multiple tables, returning the column and the\n"
" table name where it was found.\n"
"\n"
" Returns `Error(matching_table_names)` when the column exists in more than\n"
" one of the given tables (ambiguous reference).\n"
).
-spec find_column_in_tables(sqlode@model:catalog(), list(binary()), binary()) -> {ok,
gleam@option:option({binary(), sqlode@model:column()})} |
{error, list(binary())}.
find_column_in_tables(Catalog, Table_names, Column_name) ->
Matches = gleam@list:filter_map(
Table_names,
fun(Name) -> case find_column(Catalog, Name, Column_name) of
{some, Col} ->
{ok, {Name, Col}};
none ->
{error, nil}
end end
),
case Matches of
[] ->
{ok, none};
[Single] ->
{ok, {some, Single}};
_ ->
{error, gleam@list:map(Matches, fun(M) -> erlang:element(1, M) end)}
end.