-module(sqlode@codegen@queries). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/sqlode/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. -file("src/sqlode/codegen/queries.gleam", 149). -spec engine_placeholder_style_expr(sqlode@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/codegen/queries.gleam", 157). -spec render_query_function( sqlode@naming:naming_context(), sqlode@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@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@codegen@common:escape_string( erlang:element(2, erlang:element(2, Query)) ))/binary>>/binary, "\","/utf8>>, <<<<" sql: \""/utf8, (sqlode@codegen@common:escape_string( erlang:element(5, erlang:element(2, Query)) ))/binary>>/binary, "\","/utf8>>, <<<<" command: runtime."/utf8, (sqlode@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/codegen/queries.gleam", 287). ?DOC( " Render the Gleam type of a single parameter for a `prepare_*`\n" " argument position. Mirrors the type used in the `Params` record\n" " field: base type, optionally wrapped in `Option(…)` when the\n" " parameter is nullable or `List(…)` when it is a slice.\n" ). -spec param_arg_type(sqlode@model:query_param(), sqlode@model:type_mapping()) -> binary(). param_arg_type(Param, Type_mapping) -> Base = sqlode@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/codegen/queries.gleam", 234). ?DOC( " Emit a `prepare_` convenience wrapper that\n" " constructs the generated params record inline (for parameterised\n" " queries) or passes `Nil` (for parameterless queries) and then\n" " returns `runtime.prepare(…)` directly. Callers consume the\n" " `#(sql, values)` tuple without composing the descriptor, params\n" " record and `runtime.prepare` call by hand.\n" ). -spec render_prepare_function( sqlode@naming:naming_context(), sqlode@model:analyzed_query(), sqlode@model:type_mapping() ) -> binary(). render_prepare_function(Naming_ctx, Query, Type_mapping) -> Type_name = <<(sqlode@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, (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/codegen/queries.gleam", 302). -spec has_result_columns(sqlode@model:analyzed_query()) -> boolean(). has_result_columns(Query) -> case erlang:element(4, erlang:element(2, Query)) of query_one -> not gleam@list:is_empty(erlang:element(4, Query)); query_many -> not gleam@list:is_empty(erlang:element(4, Query)); _ -> false end. -file("src/sqlode/codegen/queries.gleam", 309). -spec render_decoder_function( sqlode@naming:naming_context(), sqlode@model:analyzed_query(), sqlode@model:engine(), binary(), gleam@dict:dict(binary(), binary()), boolean() ) -> binary(). render_decoder_function( Naming_ctx, Query, Engine, _, Table_matches, Emit_exact_table_names ) -> Type_name = <<(sqlode@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@naming:to_snake_case(Naming_ctx, Name), Base = sqlode@codegen@common:render_enum_or_set_decoder( Scalar_type, fun(_capture) -> sqlode@type_mapping:scalar_type_to_decoder( Engine, _capture ) end ), 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@naming:to_snake_case( Naming_ctx, Embed_name ), Embed_type_name = sqlode@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@naming:to_snake_case( Naming_ctx, erlang:element(2, C) ), Base@1 = sqlode@codegen@common:render_enum_or_set_decoder( erlang:element(3, C), fun(_capture@1) -> sqlode@type_mapping:scalar_type_to_decoder( Engine, _capture@1 ) end ), 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@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@naming:to_snake_case(Naming_ctx, Name@1))/binary, ":"/utf8>>]; {embedded_result, {embedded_column, Name@2, _, _}} -> [<<(sqlode@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/codegen/queries.gleam", 446). -spec render_query_info_literal(sqlode@model:parsed_query()) -> binary(). render_query_info_literal(Query) -> <<<<<<<<<<<<<<<<"runtime.QueryInfo(name: \""/utf8, (sqlode@codegen@common:escape_string( erlang:element(2, Query) ))/binary>>/binary, "\", sql: \""/utf8>>/binary, (sqlode@codegen@common:escape_string( erlang:element(5, Query) ))/binary>>/binary, "\", command: runtime."/utf8>>/binary, (sqlode@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/codegen/queries.gleam", 11). -spec render( sqlode@naming:naming_context(), sqlode@model:sql_block(), list(sqlode@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@codegen@common:out_to_module_path(Out), Emit_sql_as_comment = erlang:element(5, Gleam), Has_slices = sqlode@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)) 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 ) 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 ), 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@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 of true -> [<<<<"import "/utf8, Module_path/binary>>/binary, "/models"/utf8>>]; false -> [] end]), gleam@string:join( lists:append( [[<<"// Code generated by sqlode. DO NOT EDIT."/utf8>>, <<"// engine: "/utf8, (sqlode@model:engine_to_string(Engine))/binary>>, <<"// runtime: "/utf8, (sqlode@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>> ).