-module(sqlode@internal@query_validation). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/sqlode/internal/query_validation.gleam"). -export([validate_no_duplicate_names/1, validate_unsupported_annotations/1, validate_array_engine_support/2, validate_native_annotations/1, error_to_string/1]). -export_type([validation_error/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. ?MODULEDOC(false). -type validation_error() :: {duplicate_name, binary(), list(binary())} | {normalized_name_collision, binary(), list(binary()), list(binary())} | {unsupported_annotation, binary(), binary(), binary()} | {unsupported_array_for_engine, binary(), binary()}. -file("src/sqlode/internal/query_validation.gleam", 64). ?DOC(false). -spec find_duplicate_group( list(sqlode@internal@query_ir:tokenized_query()), fun((sqlode@internal@query_ir:tokenized_query()) -> binary()) ) -> {ok, {binary(), list(sqlode@internal@query_ir:tokenized_query())}} | {error, nil}. find_duplicate_group(Queries, Key) -> _pipe = gleam@list:group(Queries, Key), _pipe@1 = maps:to_list(_pipe), gleam@list:find( _pipe@1, fun(Entry) -> erlang:length(erlang:element(2, Entry)) > 1 end ). -file("src/sqlode/internal/query_validation.gleam", 39). ?DOC(false). -spec validate_no_duplicate_names( list(sqlode@internal@query_ir:tokenized_query()) ) -> {ok, nil} | {error, validation_error()}. validate_no_duplicate_names(Queries) -> case find_duplicate_group( Queries, fun(Q) -> erlang:element(2, erlang:element(2, Q)) end ) of {ok, {Name, Dupes}} -> Paths = begin _pipe = Dupes, _pipe@1 = gleam@list:map( _pipe, fun(Q@1) -> erlang:element(6, erlang:element(2, Q@1)) end ), gleam@list:unique(_pipe@1) end, {error, {duplicate_name, Name, Paths}}; {error, nil} -> case find_duplicate_group( Queries, fun(Q@2) -> erlang:element(3, erlang:element(2, Q@2)) end ) of {ok, {Function_name, Colliding}} -> Names = begin _pipe@2 = Colliding, _pipe@3 = gleam@list:map( _pipe@2, fun(Q@3) -> erlang:element(2, erlang:element(2, Q@3)) end ), gleam@list:unique(_pipe@3) end, Paths@1 = begin _pipe@4 = Colliding, _pipe@5 = gleam@list:map( _pipe@4, fun(Q@4) -> erlang:element(6, erlang:element(2, Q@4)) end ), gleam@list:unique(_pipe@5) end, {error, {normalized_name_collision, Function_name, Names, Paths@1}}; {error, nil} -> {ok, nil} end end. -file("src/sqlode/internal/query_validation.gleam", 77). ?DOC(false). -spec validate_unsupported_annotations( list(sqlode@internal@model:analyzed_query()) ) -> {ok, nil} | {error, validation_error()}. validate_unsupported_annotations(Queries) -> Unsupported = fun(Command) -> case Command of query_batch_one -> true; query_batch_many -> true; query_batch_exec -> true; query_copy_from -> true; _ -> false end end, case gleam@list:find( Queries, fun(Q) -> Unsupported(erlang:element(4, erlang:element(2, Q))) end ) of {ok, Q@1} -> {Command@1, Alternative} = case erlang:element( 4, erlang:element(2, Q@1) ) of query_batch_one -> {<<":batchone"/utf8>>, <<":one"/utf8>>}; query_batch_many -> {<<":batchmany"/utf8>>, <<":many"/utf8>>}; query_batch_exec -> {<<":batchexec"/utf8>>, <<":exec"/utf8>>}; query_copy_from -> {<<":copyfrom"/utf8>>, <<":exec"/utf8>>}; _ -> {<<""/utf8>>, <<":exec"/utf8>>} end, {error, {unsupported_annotation, erlang:element(2, erlang:element(2, Q@1)), Command@1, <<<<<>/binary, Alternative/binary>>/binary, " instead, or add '-- sqlode:skip' before the annotation to bypass this query"/utf8>>}}; {error, _} -> {ok, nil} end. -file("src/sqlode/internal/query_validation.gleam", 114). ?DOC(false). -spec validate_array_engine_support( sqlode@internal@model:engine(), list(sqlode@internal@model:analyzed_query()) ) -> {ok, nil} | {error, validation_error()}. validate_array_engine_support(Engine, Queries) -> case Engine of postgre_s_q_l -> {ok, nil}; _ -> Has_array = fun(Q) -> gleam@list:any( erlang:element(3, Q), fun(P) -> case erlang:element(4, P) of {array_type, _} -> true; _ -> false end end ) end, case gleam@list:find(Queries, Has_array) of {ok, Q@1} -> {error, {unsupported_array_for_engine, erlang:element(2, erlang:element(2, Q@1)), sqlode@internal@model:engine_to_string(Engine)}}; {error, _} -> {ok, nil} end end. -file("src/sqlode/internal/query_validation.gleam", 145). ?DOC(false). -spec validate_native_annotations(list(sqlode@internal@model:analyzed_query())) -> {ok, nil} | {error, validation_error()}. validate_native_annotations(Queries) -> case gleam@list:find( Queries, fun(Q) -> erlang:element(4, erlang:element(2, Q)) =:= query_exec_result end ) of {ok, Q@1} -> {error, {unsupported_annotation, erlang:element(2, erlang:element(2, Q@1)), <<":execresult"/utf8>>, <<":execresult is not supported with native runtime. Use :exec, :execrows, or :execlastid instead"/utf8>>}}; {error, _} -> {ok, nil} end. -file("src/sqlode/internal/query_validation.gleam", 185). ?DOC(false). -spec quote_join(list(binary())) -> binary(). quote_join(Names) -> _pipe = Names, _pipe@1 = gleam@list:map( _pipe, fun(N) -> <<<<"\""/utf8, N/binary>>/binary, "\""/utf8>> end ), gleam@string:join(_pipe@1, <<", "/utf8>>). -file("src/sqlode/internal/query_validation.gleam", 159). ?DOC(false). -spec error_to_string(validation_error()) -> binary(). error_to_string(Error) -> case Error of {duplicate_name, Name, Paths} -> <<<<<<"duplicate query name \""/utf8, Name/binary>>/binary, "\" found in: "/utf8>>/binary, (gleam@string:join(Paths, <<", "/utf8>>))/binary>>; {normalized_name_collision, Function_name, Names, Paths@1} -> <<<<<<<<<<<<"query names "/utf8, (quote_join(Names))/binary>>/binary, " all normalize to the generated identifier \""/utf8>>/binary, Function_name/binary>>/binary, "\" (found in: "/utf8>>/binary, (gleam@string:join(Paths@1, <<", "/utf8>>))/binary>>/binary, "). Rename one of them so the derived function, params, row, and decoder identifiers are unique."/utf8>>; {unsupported_annotation, Query_name, Command, Detail} -> <<<<<<<<<<"Query "/utf8, Query_name/binary>>/binary, " uses "/utf8>>/binary, Command/binary>>/binary, ": "/utf8>>/binary, Detail/binary>>; {unsupported_array_for_engine, Query_name@1, Engine} -> <<<<<<<<"Query \""/utf8, Query_name@1/binary>>/binary, "\": array parameters are not supported for engine \""/utf8>>/binary, Engine/binary>>/binary, "\". Arrays are only supported with PostgreSQL"/utf8>> end.