-module(sqlode@internal@codegen@queries). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/sqlode/internal/codegen/queries.gleam"). -export([render/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/codegen/queries.gleam", 173). ?DOC(false). -spec engine_placeholder_style_expr(sqlode@internal@model:engine()) -> binary(). engine_placeholder_style_expr(Engine) -> case Engine of postgre_s_q_l -> <<"runtime.DollarNumbered"/utf8>>; my_s_q_l -> <<"runtime.QuestionPositional"/utf8>>; s_q_lite -> <<"runtime.QuestionNumbered"/utf8>> end. -file("src/sqlode/internal/codegen/queries.gleam", 181). ?DOC(false). -spec render_query_function( sqlode@internal@naming:naming_context(), sqlode@internal@model:analyzed_query(), boolean(), binary() ) -> binary(). render_query_function(Naming_ctx, Query, Emit_sql_as_comment, Style_expr) -> Has_params = not gleam@list:is_empty(erlang:element(3, Query)), Comment = case Emit_sql_as_comment of true -> [<<"// SQL: "/utf8, (erlang:element(5, erlang:element(2, Query)))/binary>>]; false -> [] end, Return_type = case Has_params of true -> Params_type = <<(sqlode@internal@naming:to_pascal_case( Naming_ctx, erlang:element(2, erlang:element(2, Query)) ))/binary, "Params"/utf8>>, <<<<"runtime.RawQuery(params."/utf8, Params_type/binary>>/binary, ")"/utf8>>; false -> <<"runtime.RawQuery(Nil)"/utf8>> end, Encode_line = case Has_params of true -> Values_fn = <<(erlang:element(3, erlang:element(2, Query)))/binary, "_values"/utf8>>, <<<<" encode: params."/utf8, Values_fn/binary>>/binary, ","/utf8>>; false -> <<" encode: fn(_) { [] },"/utf8>> end, Slice_params = gleam@list:filter( erlang:element(3, Query), fun(P) -> erlang:element(6, P) end ), Slice_info_line = case Slice_params of [] -> <<" slice_info: fn(_) { [] },"/utf8>>; _ -> Entries = begin _pipe = Slice_params, _pipe@1 = gleam@list:map( _pipe, fun(P@1) -> <<<<<<<<"#("/utf8, (erlang:integer_to_binary( erlang:element(2, P@1) ))/binary>>/binary, ", list.length(p."/utf8>>/binary, (erlang:element(3, P@1))/binary>>/binary, "))"/utf8>> end ), gleam@string:join(_pipe@1, <<", "/utf8>>) end, <<<<" slice_info: fn(p) { ["/utf8, Entries/binary>>/binary, "] },"/utf8>> end, gleam@string:join( lists:append( [Comment, [<<<<<<<<"pub fn "/utf8, (erlang:element(3, erlang:element(2, Query)))/binary>>/binary, "() -> "/utf8>>/binary, Return_type/binary>>/binary, " {"/utf8>>, <<" runtime.RawQuery("/utf8>>, <<<<" name: \""/utf8, (sqlode@internal@codegen@common:escape_string( erlang:element(2, erlang:element(2, Query)) ))/binary>>/binary, "\","/utf8>>, <<<<" sql: \""/utf8, (sqlode@internal@codegen@common:escape_string( erlang:element(5, erlang:element(2, Query)) ))/binary>>/binary, "\","/utf8>>, <<<<" command: runtime."/utf8, (sqlode@internal@model:query_command_to_string( erlang:element(4, erlang:element(2, Query)) ))/binary>>/binary, ","/utf8>>, <<<<" param_count: "/utf8, (erlang:integer_to_binary( erlang:element(7, erlang:element(2, Query)) ))/binary>>/binary, ","/utf8>>, <<<<" placeholder_style: "/utf8, Style_expr/binary>>/binary, ","/utf8>>, Encode_line, Slice_info_line, <<" )"/utf8>>, <<"}"/utf8>>]] ), <<"\n"/utf8>> ). -file("src/sqlode/internal/codegen/queries.gleam", 318). ?DOC(false). -spec param_arg_type( sqlode@internal@model:query_param(), sqlode@internal@model:type_mapping() ) -> binary(). param_arg_type(Param, Type_mapping) -> Base = sqlode@internal@codegen@common:qualified_field_type( erlang:element(4, Param), Type_mapping ), case erlang:element(6, Param) of true -> <<<<"List("/utf8, Base/binary>>/binary, ")"/utf8>>; false -> case erlang:element(5, Param) of true -> <<<<"Option("/utf8, Base/binary>>/binary, ")"/utf8>>; false -> Base end end. -file("src/sqlode/internal/codegen/queries.gleam", 258). ?DOC(false). -spec render_prepare_function( sqlode@internal@naming:naming_context(), sqlode@internal@model:analyzed_query(), sqlode@internal@model:type_mapping() ) -> binary(). render_prepare_function(Naming_ctx, Query, Type_mapping) -> Type_name = <<(sqlode@internal@naming:to_pascal_case( Naming_ctx, erlang:element(2, erlang:element(2, Query)) ))/binary, "Params"/utf8>>, Descriptor_call = <<(erlang:element(3, erlang:element(2, Query)))/binary, "()"/utf8>>, case erlang:element(3, Query) of [] -> gleam@string:join( [<<<<"pub fn prepare_"/utf8, (erlang:element(3, erlang:element(2, Query)))/binary>>/binary, "() -> #(String, List(runtime.Value)) {"/utf8>>, <<<<" runtime.prepare("/utf8, Descriptor_call/binary>>/binary, ", Nil)"/utf8>>, <<"}"/utf8>>], <<"\n"/utf8>> ); Params -> Arg_list = begin _pipe = Params, _pipe@1 = gleam@list:map( _pipe, fun(P) -> <<<<<<<<(erlang:element(3, P))/binary, " "/utf8>>/binary, (erlang:element(3, P))/binary>>/binary, ": "/utf8>>/binary, (param_arg_type(P, Type_mapping))/binary>> end ), gleam@string:join(_pipe@1, <<", "/utf8>>) end, Constructor_args = begin _pipe@2 = Params, _pipe@3 = gleam@list:map( _pipe@2, fun(P@1) -> <<<<(erlang:element(3, P@1))/binary, ": "/utf8>>/binary, (erlang:element(3, P@1))/binary>> end ), gleam@string:join(_pipe@3, <<", "/utf8>>) end, gleam@string:join( [<<<<<<<<"pub fn prepare_"/utf8, (erlang:element(3, erlang:element(2, Query)))/binary>>/binary, "("/utf8>>/binary, Arg_list/binary>>/binary, ") -> #(String, List(runtime.Value)) {"/utf8>>, <<" runtime.prepare("/utf8>>, <<<<" "/utf8, Descriptor_call/binary>>/binary, ","/utf8>>, <<<<<<<<" params."/utf8, Type_name/binary>>/binary, "("/utf8>>/binary, Constructor_args/binary>>/binary, "),"/utf8>>, <<" )"/utf8>>, <<"}"/utf8>>], <<"\n"/utf8>> ) end. -file("src/sqlode/internal/codegen/queries.gleam", 333). ?DOC(false). -spec has_result_columns(sqlode@internal@model:analyzed_query()) -> boolean(). has_result_columns(Query) -> case erlang:element(4, erlang:element(2, Query)) of one -> not gleam@list:is_empty(erlang:element(4, Query)); many -> not gleam@list:is_empty(erlang:element(4, Query)); _ -> false end. -file("src/sqlode/internal/codegen/queries.gleam", 540). ?DOC(false). -spec module_alias_for(binary()) -> binary(). module_alias_for(Module_path) -> case gleam@string:split(Module_path, <<"/"/utf8>>) of [] -> Module_path; Segments -> case gleam@list:last(Segments) of {ok, Last} -> Last; {error, _} -> Module_path end end. -file("src/sqlode/internal/codegen/queries.gleam", 530). ?DOC(false). -spec qualified_decoder_hook_call(gleam@option:option(binary()), binary()) -> binary(). qualified_decoder_hook_call(Module, Fn_name) -> case Module of {some, Module_path} -> <<<<(module_alias_for(Module_path))/binary, "."/utf8>>/binary, Fn_name/binary>>; none -> Fn_name end. -file("src/sqlode/internal/codegen/queries.gleam", 483). ?DOC(false). -spec render_raw_base_decoder( sqlode@internal@model:engine(), sqlode@internal@model:scalar_type(), sqlode@internal@model:type_mapping() ) -> binary(). render_raw_base_decoder(Engine, Scalar_type, Type_mapping_mode) -> case Scalar_type of {enum_type, _} -> sqlode@internal@codegen@common:render_enum_or_set_decoder( Scalar_type, fun(_capture) -> sqlode@internal@type_mapping:scalar_type_to_decoder( Engine, _capture ) end ); {set_type, _} -> sqlode@internal@codegen@common:render_enum_or_set_decoder( Scalar_type, fun(_capture) -> sqlode@internal@type_mapping:scalar_type_to_decoder( Engine, _capture ) end ); {custom_type, _, Module, _, {some, Hooks}} -> <<<<<<<<"decode.map("/utf8, (sqlode@internal@type_mapping:scalar_type_to_decoder( Engine, Scalar_type ))/binary>>/binary, ", "/utf8>>/binary, (qualified_decoder_hook_call( Module, erlang:element(3, Hooks) ))/binary>>/binary, ")"/utf8>>; _ -> case (Type_mapping_mode =:= strong_mapping) andalso sqlode@internal@type_mapping:is_rich_type( Scalar_type ) of true -> Constructor = sqlode@internal@type_mapping:scalar_type_to_gleam_type( Scalar_type, strong_mapping ), <<<<<<<<"decode.map("/utf8, (sqlode@internal@type_mapping:scalar_type_to_decoder( Engine, Scalar_type ))/binary>>/binary, ", models."/utf8>>/binary, Constructor/binary>>/binary, ")"/utf8>>; false -> sqlode@internal@type_mapping:scalar_type_to_decoder( Engine, Scalar_type ) end end. -file("src/sqlode/internal/codegen/queries.gleam", 340). ?DOC(false). -spec render_decoder_function( sqlode@internal@naming:naming_context(), sqlode@internal@model:analyzed_query(), sqlode@internal@model:engine(), binary(), gleam@dict:dict(binary(), binary()), boolean(), sqlode@internal@model:type_mapping() ) -> binary(). render_decoder_function( Naming_ctx, Query, Engine, _, Table_matches, Emit_exact_table_names, Type_mapping_mode ) -> Type_name = <<(sqlode@internal@naming:to_pascal_case( Naming_ctx, erlang:element(2, erlang:element(2, Query)) ))/binary, "Row"/utf8>>, Constructor_name = case gleam_stdlib:map_get( Table_matches, erlang:element(3, erlang:element(2, Query)) ) of {ok, Table_type} -> Table_type; {error, _} -> Type_name end, {_, Field_lines} = gleam@list:fold( erlang:element(4, Query), {0, []}, fun(Acc, Col) -> {Idx, Lines} = Acc, case Col of {scalar_result, {result_column, Name, Scalar_type, Nullable, _}} -> Field_name = sqlode@internal@naming:to_snake_case( Naming_ctx, Name ), Base = render_raw_base_decoder( Engine, Scalar_type, Type_mapping_mode ), Decoder = case Nullable of true -> <<<<"decode.optional("/utf8, Base/binary>>/binary, ")"/utf8>>; false -> Base end, Line = <<<<<<<<<<<<" use "/utf8, Field_name/binary>>/binary, " <- decode.field("/utf8>>/binary, (erlang:integer_to_binary(Idx))/binary>>/binary, ", "/utf8>>/binary, Decoder/binary>>/binary, ")"/utf8>>, {Idx + 1, lists:append(Lines, [Line])}; {embedded_result, {embedded_column, Embed_name, Embed_table_name, Embed_cols}} -> Embed_field_name = sqlode@internal@naming:to_snake_case( Naming_ctx, Embed_name ), Embed_type_name = sqlode@internal@naming:table_type_name( Naming_ctx, Embed_table_name, Emit_exact_table_names ), {New_idx, Decode_lines} = gleam@list:fold( Embed_cols, {Idx, []}, fun(Inner_acc, C) -> {I, Ls} = Inner_acc, Field_name@1 = sqlode@internal@naming:to_snake_case( Naming_ctx, erlang:element(2, C) ), Base@1 = render_raw_base_decoder( Engine, erlang:element(3, C), Type_mapping_mode ), Decoder@1 = case erlang:element(4, C) of true -> <<<<"decode.optional("/utf8, Base@1/binary>>/binary, ")"/utf8>>; false -> Base@1 end, Line@1 = <<<<<<<<<<<<" use "/utf8, Field_name@1/binary>>/binary, " <- decode.field("/utf8>>/binary, (erlang:integer_to_binary(I))/binary>>/binary, ", "/utf8>>/binary, Decoder@1/binary>>/binary, ")"/utf8>>, {I + 1, lists:append(Ls, [Line@1])} end ), Embed_constructor_fields = begin _pipe = gleam@list:map( Embed_cols, fun(C@1) -> <<(sqlode@internal@naming:to_snake_case( Naming_ctx, erlang:element(2, C@1) ))/binary, ":"/utf8>> end ), gleam@string:join(_pipe, <<", "/utf8>>) end, Constructor_line = <<<<<<<<<<<<" let "/utf8, Embed_field_name/binary>>/binary, " = models."/utf8>>/binary, Embed_type_name/binary>>/binary, "("/utf8>>/binary, Embed_constructor_fields/binary>>/binary, ")"/utf8>>, All_lines = lists:append(Decode_lines, [Constructor_line]), {New_idx, lists:append(Lines, All_lines)} end end ), Constructor_fields = begin _pipe@1 = erlang:element(4, Query), _pipe@2 = gleam@list:flat_map(_pipe@1, fun(Col@1) -> case Col@1 of {scalar_result, {result_column, Name@1, _, _, _}} -> [<<(sqlode@internal@naming:to_snake_case( Naming_ctx, Name@1 ))/binary, ":"/utf8>>]; {embedded_result, {embedded_column, Name@2, _, _}} -> [<<(sqlode@internal@naming:to_snake_case( Naming_ctx, Name@2 ))/binary, ":"/utf8>>] end end), gleam@string:join(_pipe@2, <<", "/utf8>>) end, gleam@string:join( lists:append( [[<<<<<<<<"pub fn "/utf8, (erlang:element(3, erlang:element(2, Query)))/binary>>/binary, "_decoder() -> decode.Decoder(models."/utf8>>/binary, Type_name/binary>>/binary, ") {"/utf8>>], Field_lines, [<<<<<<<<" decode.success(models."/utf8, Constructor_name/binary>>/binary, "("/utf8>>/binary, Constructor_fields/binary>>/binary, "))"/utf8>>, <<"}"/utf8>>]] ), <<"\n"/utf8>> ). -file("src/sqlode/internal/codegen/queries.gleam", 571). ?DOC(false). -spec resolve_static_placeholders( binary(), integer(), sqlode@internal@model:engine() ) -> binary(). resolve_static_placeholders(Sql, Param_count, Engine) -> gleam@int:range( 1, Param_count + 1, Sql, fun(Current_sql, Idx) -> Param = sqlode@runtime:param_marker(Idx), Slice = sqlode@runtime:slice_marker(Idx), Placeholder = case Engine of postgre_s_q_l -> <<"$"/utf8, (erlang:integer_to_binary(Idx))/binary>>; s_q_lite -> <<"?"/utf8, (erlang:integer_to_binary(Idx))/binary>>; my_s_q_l -> <<"?"/utf8>> end, _pipe = Current_sql, _pipe@1 = gleam@string:replace(_pipe, Param, Placeholder), gleam@string:replace(_pipe@1, Slice, Placeholder) end ). -file("src/sqlode/internal/codegen/queries.gleam", 551). ?DOC(false). -spec render_query_info_literal( sqlode@internal@model:parsed_query(), sqlode@internal@model:engine() ) -> binary(). render_query_info_literal(Query, Engine) -> Sql = resolve_static_placeholders( erlang:element(5, Query), erlang:element(7, Query), Engine ), <<<<<<<<<<<<<<<<"runtime.QueryInfo(name: \""/utf8, (sqlode@internal@codegen@common:escape_string( erlang:element(2, Query) ))/binary>>/binary, "\", sql: \""/utf8>>/binary, (sqlode@internal@codegen@common:escape_string(Sql))/binary>>/binary, "\", command: runtime."/utf8>>/binary, (sqlode@internal@model:query_command_to_string( erlang:element(4, Query) ))/binary>>/binary, ", param_count: "/utf8>>/binary, (erlang:integer_to_binary(erlang:element(7, Query)))/binary>>/binary, ")"/utf8>>. -file("src/sqlode/internal/codegen/queries.gleam", 12). ?DOC(false). -spec render( sqlode@internal@naming:naming_context(), sqlode@internal@model:sql_block(), list(sqlode@internal@model:analyzed_query()), gleam@dict:dict(binary(), binary()), boolean() ) -> binary(). render(Naming_ctx, Block, Queries, Table_matches, Emit_exact_table_names) -> {sql_block, _, Engine, _, _, Gleam, _} = Block, {gleam_output, Out, Runtime, _, _, _, _, _, _, _} = Gleam, Module_path = sqlode@internal@codegen@common:out_to_module_path(Out), Emit_sql_as_comment = erlang:element(5, Gleam), Has_slices = sqlode@internal@codegen@common:queries_have_slices(Queries), Style_expr = engine_placeholder_style_expr(Engine), Query_functions = begin _pipe = Queries, _pipe@1 = gleam@list:map( _pipe, fun(_capture) -> render_query_function( Naming_ctx, _capture, Emit_sql_as_comment, Style_expr ) end ), gleam@string:join(_pipe@1, <<"\n\n"/utf8>>) end, Prepare_functions = begin _pipe@2 = Queries, _pipe@3 = gleam@list:map( _pipe@2, fun(_capture@1) -> render_prepare_function( Naming_ctx, _capture@1, erlang:element(4, Gleam) ) end ), _pipe@4 = gleam@list:filter(_pipe@3, fun(S) -> S /= <<""/utf8>> end), gleam@string:join(_pipe@4, <<"\n\n"/utf8>>) end, All_items = case Queries of [] -> <<"[]"/utf8>>; _ -> _pipe@5 = Queries, _pipe@6 = gleam@list:map( _pipe@5, fun(Query) -> render_query_info_literal(erlang:element(2, Query), Engine) end ), _pipe@7 = gleam@string:join(_pipe@6, <<", "/utf8>>), (fun(Items) -> <<<<"["/utf8, Items/binary>>/binary, "]"/utf8>> end)( _pipe@7 ) end, Has_any_params = gleam@list:any( Queries, fun(Q) -> not gleam@list:is_empty(erlang:element(3, Q)) end ), Decoder_queries = begin _pipe@8 = Queries, gleam@list:filter(_pipe@8, fun(Q@1) -> has_result_columns(Q@1) end) end, Decoder_functions = case Decoder_queries of [] -> <<""/utf8>>; _ -> _pipe@9 = Decoder_queries, _pipe@10 = gleam@list:map( _pipe@9, fun(_capture@2) -> render_decoder_function( Naming_ctx, _capture@2, Engine, Module_path, Table_matches, Emit_exact_table_names, erlang:element(4, Gleam) ) end ), gleam@string:join(_pipe@10, <<"\n\n"/utf8>>) end, Has_decoders = not gleam@list:is_empty(Decoder_queries), Has_nullable = (Has_decoders andalso gleam@list:any( Decoder_queries, fun(Q@2) -> gleam@list:any(erlang:element(4, Q@2), fun(Col) -> case Col of {scalar_result, {result_column, _, _, true, _}} -> true; _ -> false end end) end )) orelse gleam@list:any( Queries, fun(Q@3) -> gleam@list:any( erlang:element(3, Q@3), fun(P) -> erlang:element(5, P) end ) end ), Needs_models_for_rich_params = ((erlang:element(4, Gleam) =:= strong_mapping) orelse (erlang:element(4, Gleam) =:= rich_mapping)) andalso gleam@list:any( Queries, fun(Q@4) -> gleam@list:any( erlang:element(3, Q@4), fun(P@1) -> sqlode@internal@type_mapping:is_rich_type( erlang:element(4, P@1) ) end ) end ), Custom_imports = begin _pipe@11 = sqlode@internal@codegen@common:param_scalar_types(Queries), sqlode@internal@codegen@common:custom_type_imports(_pipe@11) end, Imports = lists:append([case Has_slices of true -> [<<"import gleam/list"/utf8>>]; false -> [] end, case Has_decoders of true -> [<<"import gleam/dynamic/decode"/utf8>>]; false -> [] end, case Has_nullable of true -> [<<"import gleam/option.{type Option}"/utf8>>]; false -> [] end, [<<"import "/utf8, (sqlode@internal@codegen@common:runtime_import_path(Gleam))/binary>>], case Has_any_params of true -> [<<<<"import "/utf8, Module_path/binary>>/binary, "/params"/utf8>>]; false -> [] end, case Has_decoders orelse Needs_models_for_rich_params of true -> [<<<<"import "/utf8, Module_path/binary>>/binary, "/models"/utf8>>]; false -> [] end, Custom_imports]), gleam@string:join( lists:append( [[<<"// Code generated by sqlode. DO NOT EDIT."/utf8>>, <<"// engine: "/utf8, (sqlode@internal@model:engine_to_string(Engine))/binary>>, <<"// runtime: "/utf8, (sqlode@internal@model:runtime_to_string(Runtime))/binary>>, <<""/utf8>>], Imports, [<<""/utf8>>, <<"pub fn all() -> List(runtime.QueryInfo) {"/utf8>>, <<" "/utf8, All_items/binary>>, <<"}"/utf8>>, <<""/utf8>>, Query_functions], case Prepare_functions of <<""/utf8>> -> []; _ -> [<<""/utf8>>, Prepare_functions] end, case Decoder_functions of <<""/utf8>> -> []; _ -> [<<""/utf8>>, Decoder_functions] end] ), <<"\n"/utf8>> ).