-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>>; decimal_type -> <<"Decimal"/utf8>>; {enum_type, Name} -> <<<<"Enum("/utf8, Name/binary>>/binary, ")"/utf8>>; {set_type, Name@1} -> <<<<"Set("/utf8, Name@1/binary>>/binary, ")"/utf8>>; {custom_type, Name@2, _, _} -> Name@2; {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", 121). -spec new(sqlode@naming:naming_context()) -> analyzer_context(). new(Naming_ctx) -> {analyzer_context, Naming_ctx}. -file("src/sqlode/query_analyzer/context.gleam", 125). -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", 151). ?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.