-module(cake@internal@query). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([order_by_part_to_sql/1, limit_offset_new/2, limit_new/1, offset_new/1, limit_offset_apply/2, limit_offset_get/1, combined_query_new/2, combined_get_select_queries/1, combined_order_by/3, select_order_by/3, epilog_apply/2, qualified_identifier/1, fragment_prepared_split_string/1, fragment_count_placeholders/1, from_part_apply/2, builder_apply/2, select_builder/2, builder_new/2, combined_builder_apply_command_sql/2, combined_builder/2, where_part_apply_clause/2, join_parts_apply_clause/2]). -export_type(['query'/0, order_by_part/0, order_by_direction_part/0, limit_offset_part/0, combined_kind/0, combined_query/0, select_query/0, select_value/0, from_part/0, where_part/0, where_value/0, join/0, join_part/0, epilog_part/0, fragment/0]). -type 'query'() :: {select, select_query()} | {combined, combined_query()}. -type order_by_part() :: {order_by_column_part, binary(), order_by_direction_part()}. -type order_by_direction_part() :: asc | desc | asc_nulls_first | desc_nulls_first. -type limit_offset_part() :: {limit_offset, integer(), integer()} | {limit_no_offset, integer()} | {no_limit_offset, integer()} | no_limit_no_offset. -type combined_kind() :: union | union_all | except | except_all | intersect | intersect_all. -type combined_query() :: {combined_query, combined_kind(), list(select_query()), limit_offset_part(), list(order_by_part()), epilog_part()}. -type select_query() :: {select_query, from_part(), list(select_value()), list(join_part()), where_part(), limit_offset_part(), list(order_by_part()), epilog_part()}. -type select_value() :: {select_column, binary()} | {select_param, cake@param:param()} | {select_fragment, fragment()} | {select_alias, select_value(), binary()}. -type from_part() :: {from_table, binary()} | {from_sub_query, 'query'(), binary()} | no_from_part. -type where_part() :: {where_equal, where_value(), where_value()} | {where_lower, where_value(), where_value()} | {where_lower_or_equal, where_value(), where_value()} | {where_greater, where_value(), where_value()} | {where_greater_or_equal, where_value(), where_value()} | {where_unequal, where_value(), where_value()} | {where_is_bool, where_value(), boolean()} | {where_is_not_bool, where_value(), boolean()} | {where_is_null, where_value()} | {where_is_not_null, where_value()} | {where_like, where_value(), binary()} | {where_i_like, where_value(), binary()} | {where_similar, where_value(), binary()} | {where_in, where_value(), list(where_value())} | {where_between, where_value(), where_value(), where_value()} | {and_where, list(where_part())} | {or_where, list(where_part())} | {not_where, where_part()} | no_where_part. -type where_value() :: {where_column, binary()} | {where_param, cake@param:param()} | {where_fragment, fragment()}. -type join() :: {join_table, binary()} | {join_sub_query, 'query'()}. -type join_part() :: {cross_join, join(), binary()} | {inner_join, join(), binary(), where_part()} | {left_outer_join, join(), binary(), where_part()} | {right_outer_join, join(), binary(), where_part()} | {full_outer_join, join(), binary(), where_part()}. -type epilog_part() :: {epilog, binary()} | no_epilog_part. -type fragment() :: {fragment_literal, binary()} | {fragment_prepared, binary(), list(cake@param:param())}. -spec combined_builder_apply_to_sql( cake@internal@prepared_statement:prepared_statement(), combined_query(), fun((combined_query()) -> binary()) ) -> cake@internal@prepared_statement:prepared_statement(). combined_builder_apply_to_sql(Prp_stm, Qry, Mb_fun) -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Mb_fun(Qry)). -spec select_builder_apply_to_sql( cake@internal@prepared_statement:prepared_statement(), select_query(), fun((select_query()) -> binary()) ) -> cake@internal@prepared_statement:prepared_statement(). select_builder_apply_to_sql(Prp_stm, Qry, Mb_fun) -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Mb_fun(Qry)). -spec order_by_part_to_sql(order_by_part()) -> binary(). order_by_part_to_sql(Ordbpt) -> case erlang:element(3, Ordbpt) of asc -> <<"ASC NULLS LAST"/utf8>>; desc -> <<"DESC NULLS LAST"/utf8>>; asc_nulls_first -> <<"ASC NULLS FIRST"/utf8>>; desc_nulls_first -> <<"DESC NULLS FIRST"/utf8>> end. -spec combined_builder_maybe_add_order_sql(combined_query()) -> binary(). combined_builder_maybe_add_order_sql(Qry) -> case erlang:element(5, Qry) of [] -> <<""/utf8>>; _ -> Order_bys = begin _pipe = erlang:element(5, Qry), gleam@list:map( _pipe, fun(Ordrb) -> <<<<(erlang:element(2, Ordrb))/binary, " "/utf8>>/binary, (order_by_part_to_sql(Ordrb))/binary>> end ) end, <<" ORDER BY "/utf8, (gleam@string:join(Order_bys, <<", "/utf8>>))/binary>> end. -spec select_builder_maybe_add_order_sql(select_query()) -> binary(). select_builder_maybe_add_order_sql(Qry) -> case erlang:element(7, Qry) of [] -> <<""/utf8>>; _ -> Order_bys = begin _pipe = erlang:element(7, Qry), gleam@list:map( _pipe, fun(Ordrb) -> <<<<(erlang:element(2, Ordrb))/binary, " "/utf8>>/binary, (order_by_part_to_sql(Ordrb))/binary>> end ) end, <<" ORDER BY "/utf8, (gleam@string:join(Order_bys, <<", "/utf8>>))/binary>> end. -spec limit_offset_new(integer(), integer()) -> limit_offset_part(). limit_offset_new(Lmt, Offst) -> case {Lmt >= 0, Offst >= 0} of {true, true} -> {limit_offset, Lmt, Offst}; {true, false} -> {limit_no_offset, Lmt}; {false, _} -> no_limit_no_offset end. -spec limit_new(integer()) -> limit_offset_part(). limit_new(Lmt) -> case Lmt >= 0 of true -> {limit_no_offset, Lmt}; false -> no_limit_no_offset end. -spec offset_new(integer()) -> limit_offset_part(). offset_new(Offst) -> case Offst >= 0 of true -> {no_limit_offset, Offst}; false -> no_limit_no_offset end. -spec limit_offset_apply( cake@internal@prepared_statement:prepared_statement(), limit_offset_part() ) -> cake@internal@prepared_statement:prepared_statement(). limit_offset_apply(Prp_stm, Lmt_prt) -> _pipe = case Lmt_prt of {limit_offset, Lmt, Offst} -> <<<<<<" LIMIT "/utf8, (gleam@int:to_string(Lmt))/binary>>/binary, " OFFSET "/utf8>>/binary, (gleam@int:to_string(Offst))/binary>>; {limit_no_offset, Lmt@1} -> <<" LIMIT "/utf8, (gleam@int:to_string(Lmt@1))/binary>>; {no_limit_offset, Offst@1} -> <<" OFFSET "/utf8, (gleam@int:to_string(Offst@1))/binary>>; no_limit_no_offset -> <<""/utf8>> end, cake@internal@prepared_statement:append_sql(Prp_stm, _pipe). -spec limit_offset_get(select_query()) -> limit_offset_part(). limit_offset_get(Qry) -> erlang:element(6, Qry). -spec select_builder_maybe_apply_limit_offset( cake@internal@prepared_statement:prepared_statement(), select_query() ) -> cake@internal@prepared_statement:prepared_statement(). select_builder_maybe_apply_limit_offset(Prp_stm, Qry) -> _pipe = Qry, _pipe@1 = limit_offset_get(_pipe), limit_offset_apply(Prp_stm, _pipe@1). -spec combined_query_remove_order_by_from_selects(list(select_query())) -> list(select_query()). combined_query_remove_order_by_from_selects(Qrys) -> _pipe = Qrys, gleam@list:map(_pipe, fun(Qry) -> erlang:setelement(7, Qry, []) end). -spec combined_query_new(combined_kind(), list(select_query())) -> combined_query(). combined_query_new(Knd, Qrys) -> _pipe = Qrys, _pipe@1 = combined_query_remove_order_by_from_selects(_pipe), {combined_query, Knd, _pipe@1, no_limit_no_offset, [], no_epilog_part}. -spec combined_get_select_queries(combined_query()) -> list(select_query()). combined_get_select_queries(Cmbnd_qry) -> erlang:element(3, Cmbnd_qry). -spec combined_order_by(combined_query(), order_by_part(), boolean()) -> combined_query(). combined_order_by(Qry, Ordb, Appnd) -> case Appnd of true -> erlang:setelement( 5, Qry, begin _pipe = erlang:element(5, Qry), cake@stdlib@listx:append_item(_pipe, Ordb) end ); false -> erlang:setelement(5, Qry, cake@stdlib@listx:wrap(Ordb)) end. -spec select_order_by(select_query(), order_by_part(), boolean()) -> select_query(). select_order_by(Qry, Ordb, Appnd) -> case Appnd of true -> erlang:setelement( 7, Qry, begin _pipe = erlang:element(7, Qry), cake@stdlib@listx:append_item(_pipe, Ordb) end ); false -> erlang:setelement(7, Qry, cake@stdlib@listx:wrap(Ordb)) end. -spec where_part_apply_string( cake@internal@prepared_statement:prepared_statement(), binary() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_string(Prp_stm, S) -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, S). -spec where_part_apply_param( cake@internal@prepared_statement:prepared_statement(), cake@param:param() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_param(Prp_stm, Prm) -> Nxt_plchldr = begin _pipe = Prp_stm, cake@internal@prepared_statement:next_placeholder(_pipe) end, _pipe@1 = Prp_stm, cake@internal@prepared_statement:append_sql_and_param( _pipe@1, Nxt_plchldr, Prm ). -spec epilog_apply( cake@internal@prepared_statement:prepared_statement(), epilog_part() ) -> cake@internal@prepared_statement:prepared_statement(). epilog_apply(Prp_stm, Prt) -> case Prt of no_epilog_part -> Prp_stm; {epilog, Eplg} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Eplg) end. -spec qualified_identifier(binary()) -> fun((binary()) -> binary()). qualified_identifier(Scp) -> fun(Identifier) -> <<<>/binary, Identifier/binary>> end. -spec fragment_prepared_split_string(binary()) -> list(binary()). fragment_prepared_split_string(Str_frgmt) -> _pipe = Str_frgmt, _pipe@1 = gleam@string:to_graphemes(_pipe), _pipe@2 = gleam@list:fold( _pipe@1, [], fun(Acc, Grapheme) -> case {Grapheme =:= <<"$"/utf8>>, Acc} of {true, _} -> [<<"$"/utf8>> | Acc]; {false, []} -> [Grapheme]; {false, [First | _]} when First =:= <<"$"/utf8>> -> [Grapheme | Acc]; {false, [First@1 | Rest]} -> [<> | Rest] end end ), lists:reverse(_pipe@2). -spec fragment_count_placeholders(list(binary())) -> integer(). fragment_count_placeholders(S_frgmts) -> _pipe = S_frgmts, gleam@list:fold( _pipe, 0, fun(Count, S_frgmt) -> case S_frgmt =:= <<"$"/utf8>> of true -> Count + 1; false -> Count end end ). -spec apply_fragment( cake@internal@prepared_statement:prepared_statement(), fragment() ) -> cake@internal@prepared_statement:prepared_statement(). apply_fragment(Prp_stm, Frgmt) -> case Frgmt of {fragment_literal, Frgmt@1} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Frgmt@1); {fragment_prepared, Frgmt@2, Prms} -> Frgmt_parts = begin _pipe@1 = Frgmt@2, fragment_prepared_split_string(_pipe@1) end, Frgmt_plchldr_count = begin _pipe@2 = Frgmt_parts, fragment_count_placeholders(_pipe@2) end, Prms_count = begin _pipe@3 = Prms, erlang:length(_pipe@3) end, Prms@1 = case begin _pipe@4 = Frgmt_plchldr_count, gleam@int:compare(_pipe@4, Prms_count) end of eq -> Prms; lt -> Missing_placeholders = Prms_count - Frgmt_plchldr_count, _pipe@5 = Prms, gleam@list:take(_pipe@5, Missing_placeholders + 1); gt -> Missing_params = Frgmt_plchldr_count - Prms_count, _assert_subject = gleam@list:last(Prms), {ok, Last_item} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"cake/internal/query"/utf8>>, function => <<"apply_fragment"/utf8>>, line => 960}) end, Repeated_last_item = begin _pipe@6 = Last_item, gleam@list:repeat(_pipe@6, Missing_params) end, _pipe@7 = Prms, lists:append(_pipe@7, Repeated_last_item) end, {New_prp_stm@2, Empty_param_rest} = begin _pipe@8 = Frgmt_parts, gleam@list:fold( _pipe@8, {Prp_stm, Prms@1}, fun(Acc, Frgmnt_prt) -> New_prp_stm = erlang:element(1, Acc), case Frgmnt_prt =:= <<"$"/utf8>> of true -> Nxt_plchldr = begin _pipe@9 = New_prp_stm, cake@internal@prepared_statement:next_placeholder( _pipe@9 ) end, _assert_subject@1 = erlang:element(2, Acc), [Prm | Rest_prms] = case _assert_subject@1 of [_ | _] -> _assert_subject@1; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@1, module => <<"cake/internal/query"/utf8>>, function => <<"apply_fragment"/utf8>>, line => 982} ) end, New_prp_stm@1 = begin _pipe@10 = New_prp_stm, cake@internal@prepared_statement:append_sql_and_param( _pipe@10, Nxt_plchldr, Prm ) end, {New_prp_stm@1, Rest_prms}; false -> {begin _pipe@11 = New_prp_stm, cake@internal@prepared_statement:append_sql( _pipe@11, Frgmnt_prt ) end, erlang:element(2, Acc)} end end ) end, [] = case Empty_param_rest of [] -> Empty_param_rest; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@2, module => <<"cake/internal/query"/utf8>>, function => <<"apply_fragment"/utf8>>, line => 1000}) end, New_prp_stm@2 end. -spec select_value_apply( cake@internal@prepared_statement:prepared_statement(), select_value() ) -> cake@internal@prepared_statement:prepared_statement(). select_value_apply(Prp_stm, V) -> case V of {select_column, Col} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Col); {select_param, Param} -> _pipe@1 = Prp_stm, cake@internal@prepared_statement:append_param(_pipe@1, Param); {select_fragment, Frgmnt} -> _pipe@2 = Prp_stm, apply_fragment(_pipe@2, Frgmnt); {select_alias, V@1, Als} -> _pipe@3 = Prp_stm, _pipe@4 = select_value_apply(_pipe@3, V@1), cake@internal@prepared_statement:append_sql( _pipe@4, <<" AS "/utf8, Als/binary>> ) end. -spec select_part_apply_clause( cake@internal@prepared_statement:prepared_statement(), list(select_value()) ) -> cake@internal@prepared_statement:prepared_statement(). select_part_apply_clause(Prp_stm, Vs) -> Prp_stm@1 = begin _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, <<"SELECT "/utf8>>) end, case Vs of [] -> _pipe@1 = Prp_stm@1, cake@internal@prepared_statement:append_sql(_pipe@1, <<"*"/utf8>>); Vs@1 -> _pipe@2 = Vs@1, gleam@list:fold( _pipe@2, Prp_stm@1, fun(New_prp_stm, V) -> case New_prp_stm =:= Prp_stm@1 of true -> _pipe@3 = New_prp_stm, select_value_apply(_pipe@3, V); false -> _pipe@4 = New_prp_stm, _pipe@5 = cake@internal@prepared_statement:append_sql( _pipe@4, <<", "/utf8>> ), select_value_apply(_pipe@5, V) end end ) end. -spec select_builder_maybe_apply_select( cake@internal@prepared_statement:prepared_statement(), select_query() ) -> cake@internal@prepared_statement:prepared_statement(). select_builder_maybe_apply_select(Prp_stm, Qry) -> _pipe = Prp_stm, select_part_apply_clause(_pipe, erlang:element(3, Qry)). -spec where_part_apply_literal( cake@internal@prepared_statement:prepared_statement(), where_value(), binary() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_literal(Prp_stm, V, Lt) -> case V of {where_column, Col} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<<>/binary, Lt/binary>> ); {where_param, Prm} -> Nxt_plchldr = begin _pipe@1 = Prp_stm, cake@internal@prepared_statement:next_placeholder(_pipe@1) end, _pipe@2 = Prp_stm, cake@internal@prepared_statement:append_sql_and_param( _pipe@2, <<<>/binary, Lt/binary>>, Prm ); {where_fragment, Frgmt} -> _pipe@3 = Prp_stm, apply_fragment(_pipe@3, Frgmt) end. -spec where_part_apply_comparison( cake@internal@prepared_statement:prepared_statement(), where_value(), binary(), where_value() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_comparison(Prp_stm, Val_a, Oprtr, Val_b) -> case {Val_a, Val_b} of {{where_column, Col_a}, {where_column, Col_b}} -> _pipe = Prp_stm, where_part_apply_string( _pipe, <<<<<<<>/binary, Oprtr/binary>>/binary, " "/utf8>>/binary, Col_b/binary>> ); {{where_column, Col}, {where_param, Prm}} -> _pipe@1 = Prp_stm, _pipe@2 = where_part_apply_string( _pipe@1, <<<<<>/binary, Oprtr/binary>>/binary, " "/utf8>> ), where_part_apply_param(_pipe@2, Prm); {{where_param, Prm@1}, {where_column, Col@1}} -> _pipe@3 = Prp_stm, _pipe@4 = where_part_apply_param(_pipe@3, Prm@1), where_part_apply_string( _pipe@4, <<<<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>/binary, Col@1/binary>> ); {{where_param, Prm_a}, {where_param, Prm_b}} -> _pipe@5 = Prp_stm, _pipe@6 = where_part_apply_param(_pipe@5, Prm_a), _pipe@7 = where_part_apply_string( _pipe@6, <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>> ), where_part_apply_param(_pipe@7, Prm_b); {{where_fragment, Frgmt}, {where_column, Col@2}} -> _pipe@8 = Prp_stm, _pipe@9 = apply_fragment(_pipe@8, Frgmt), where_part_apply_string( _pipe@9, <<<<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>/binary, Col@2/binary>> ); {{where_column, Col@3}, {where_fragment, Frgmt@1}} -> _pipe@10 = Prp_stm, _pipe@11 = where_part_apply_string( _pipe@10, <<<<<>/binary, Oprtr/binary>>/binary, " "/utf8>> ), apply_fragment(_pipe@11, Frgmt@1); {{where_fragment, Frgmt@2}, {where_param, Prm@2}} -> _pipe@12 = Prp_stm, _pipe@13 = apply_fragment(_pipe@12, Frgmt@2), _pipe@14 = where_part_apply_string( _pipe@13, <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>> ), where_part_apply_param(_pipe@14, Prm@2); {{where_param, Prm@3}, {where_fragment, Frgmt@3}} -> _pipe@15 = Prp_stm, _pipe@16 = where_part_apply_param(_pipe@15, Prm@3), _pipe@17 = where_part_apply_string( _pipe@16, <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>> ), apply_fragment(_pipe@17, Frgmt@3); {{where_fragment, Frgmt_a}, {where_fragment, Frgmt_b}} -> _pipe@18 = Prp_stm, _pipe@19 = apply_fragment(_pipe@18, Frgmt_a), _pipe@20 = where_part_apply_string( _pipe@19, <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>> ), apply_fragment(_pipe@20, Frgmt_b) end. -spec where_part_apply_value_in_values( cake@internal@prepared_statement:prepared_statement(), where_value(), list(where_value()) ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_value_in_values(Prp_stm, Val, Prms) -> Prp_stm@1 = begin _pipe@4 = case Val of {where_column, Col} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Col); {where_param, Prm} -> Nxt_plchldr_a = begin _pipe@1 = Prp_stm, cake@internal@prepared_statement:next_placeholder(_pipe@1) end, _pipe@2 = Prp_stm, cake@internal@prepared_statement:append_sql_and_param( _pipe@2, Nxt_plchldr_a, Prm ); {where_fragment, Frgmt} -> _pipe@3 = Prp_stm, apply_fragment(_pipe@3, Frgmt) end, cake@internal@prepared_statement:append_sql(_pipe@4, <<" IN ("/utf8>>) end, _pipe@5 = Prms, _pipe@12 = gleam@list:fold( _pipe@5, Prp_stm@1, fun(New_prp_stm, V) -> case V of {where_column, Col@1} -> case New_prp_stm =:= Prp_stm@1 of true -> _pipe@6 = Prp_stm@1, cake@internal@prepared_statement:append_sql( _pipe@6, Col@1 ); false -> _pipe@7 = New_prp_stm, cake@internal@prepared_statement:append_sql( _pipe@7, <<", "/utf8, Col@1/binary>> ) end; {where_param, Prm@1} -> _pipe@10 = case New_prp_stm =:= Prp_stm@1 of true -> _pipe@8 = New_prp_stm, cake@internal@prepared_statement:next_placeholder( _pipe@8 ); false -> <<", "/utf8, (begin _pipe@9 = New_prp_stm, cake@internal@prepared_statement:next_placeholder( _pipe@9 ) end)/binary>> end, cake@internal@prepared_statement:append_sql_and_param( New_prp_stm, _pipe@10, Prm@1 ); {where_fragment, Frgmt@1} -> _pipe@11 = Prp_stm@1, apply_fragment(_pipe@11, Frgmt@1) end end ), cake@internal@prepared_statement:append_sql(_pipe@12, <<")"/utf8>>). -spec where_part_apply_between( cake@internal@prepared_statement:prepared_statement(), where_value(), where_value(), where_value() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_between(Prp_stm, Val_a, Val_b, Val_c) -> Prp_stm@1 = begin _pipe@4 = case Val_a of {where_column, Col} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, Col); {where_param, Prm} -> Nxt_plchldr = begin _pipe@1 = Prp_stm, cake@internal@prepared_statement:next_placeholder(_pipe@1) end, _pipe@2 = Prp_stm, cake@internal@prepared_statement:append_sql_and_param( _pipe@2, Nxt_plchldr, Prm ); {where_fragment, Frgmt} -> _pipe@3 = Prp_stm, apply_fragment(_pipe@3, Frgmt) end, cake@internal@prepared_statement:append_sql( _pipe@4, <<" BETWEEN "/utf8>> ) end, Prp_stm@2 = begin _pipe@9 = case Val_b of {where_column, Col@1} -> _pipe@5 = Prp_stm@1, cake@internal@prepared_statement:append_sql(_pipe@5, Col@1); {where_param, Prm@1} -> Nxt_plchldr@1 = begin _pipe@6 = Prp_stm@1, cake@internal@prepared_statement:next_placeholder(_pipe@6) end, _pipe@7 = Prp_stm@1, cake@internal@prepared_statement:append_sql_and_param( _pipe@7, Nxt_plchldr@1, Prm@1 ); {where_fragment, Frgmt@1} -> _pipe@8 = Prp_stm@1, apply_fragment(_pipe@8, Frgmt@1) end, cake@internal@prepared_statement:append_sql(_pipe@9, <<" AND "/utf8>>) end, Prp_stm@3 = case Val_c of {where_column, Col@2} -> _pipe@10 = Prp_stm@2, cake@internal@prepared_statement:append_sql(_pipe@10, Col@2); {where_param, Prm@2} -> Nxt_plchldr_a = begin _pipe@11 = Prp_stm@2, cake@internal@prepared_statement:next_placeholder(_pipe@11) end, _pipe@12 = Prp_stm@2, cake@internal@prepared_statement:append_sql_and_param( _pipe@12, Nxt_plchldr_a, Prm@2 ); {where_fragment, Frgmt@2} -> _pipe@13 = Prp_stm@2, apply_fragment(_pipe@13, Frgmt@2) end, Prp_stm@3. -spec from_part_apply( cake@internal@prepared_statement:prepared_statement(), from_part() ) -> cake@internal@prepared_statement:prepared_statement(). from_part_apply(Prp_stm, Prt) -> case Prt of {from_table, Tbl} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" FROM "/utf8, Tbl/binary>> ); {from_sub_query, Qry, Als} -> _pipe@1 = Prp_stm, _pipe@2 = cake@internal@prepared_statement:append_sql( _pipe@1, <<" FROM ("/utf8>> ), _pipe@3 = builder_apply(_pipe@2, Qry), cake@internal@prepared_statement:append_sql( _pipe@3, <<") AS "/utf8, Als/binary>> ); no_from_part -> Prp_stm end. -spec builder_apply( cake@internal@prepared_statement:prepared_statement(), 'query'() ) -> cake@internal@prepared_statement:prepared_statement(). builder_apply(Prp_stm, Qry) -> case Qry of {select, Qry@1} -> _pipe = Prp_stm, select_builder(_pipe, Qry@1); {combined, Qry@2} -> _pipe@1 = Prp_stm, combined_builder(_pipe@1, Qry@2) end. -spec select_builder( cake@internal@prepared_statement:prepared_statement(), select_query() ) -> cake@internal@prepared_statement:prepared_statement(). select_builder(Prp_stm, Qry) -> _pipe = Prp_stm, _pipe@1 = select_builder_maybe_apply_select(_pipe, Qry), _pipe@2 = select_builder_maybe_apply_from(_pipe@1, Qry), _pipe@3 = select_builder_maybe_apply_join(_pipe@2, Qry), _pipe@4 = select_builder_maybe_apply_where(_pipe@3, Qry), _pipe@5 = select_builder_apply_to_sql( _pipe@4, Qry, fun select_builder_maybe_add_order_sql/1 ), select_builder_maybe_apply_limit_offset(_pipe@5, Qry). -spec select_builder_maybe_apply_from( cake@internal@prepared_statement:prepared_statement(), select_query() ) -> cake@internal@prepared_statement:prepared_statement(). select_builder_maybe_apply_from(Prp_stm, Qry) -> _pipe = Prp_stm, from_part_apply(_pipe, erlang:element(2, Qry)). -spec builder_new('query'(), binary()) -> cake@internal@prepared_statement:prepared_statement(). builder_new(Qry, Prp_stm_prfx) -> _pipe = Prp_stm_prfx, _pipe@1 = cake@internal@prepared_statement:new(_pipe), builder_apply(_pipe@1, Qry). -spec combined_builder_apply_command_sql( cake@internal@prepared_statement:prepared_statement(), combined_query() ) -> cake@internal@prepared_statement:prepared_statement(). combined_builder_apply_command_sql(Prp_stm, Cmbnd_qry) -> Sql_command = case erlang:element(2, Cmbnd_qry) of union -> <<"UNION"/utf8>>; union_all -> <<"UNION ALL"/utf8>>; except -> <<"EXCEPT"/utf8>>; except_all -> <<"EXCEPT ALL"/utf8>>; intersect -> <<"INTERSECT"/utf8>>; intersect_all -> <<"INTERSECT ALL"/utf8>> end, _pipe = erlang:element(3, Cmbnd_qry), gleam@list:fold( _pipe, Prp_stm, fun(New_prp_stm, Qry) -> case New_prp_stm =:= Prp_stm of true -> _pipe@1 = New_prp_stm, select_builder(_pipe@1, Qry); false -> _pipe@2 = New_prp_stm, _pipe@3 = cake@internal@prepared_statement:append_sql( _pipe@2, <<<<" "/utf8, Sql_command/binary>>/binary, " "/utf8>> ), select_builder(_pipe@3, Qry) end end ). -spec combined_builder( cake@internal@prepared_statement:prepared_statement(), combined_query() ) -> cake@internal@prepared_statement:prepared_statement(). combined_builder(Prp_stm, Cmbnd_qry) -> _pipe = Prp_stm, _pipe@1 = combined_builder_apply_command_sql(_pipe, Cmbnd_qry), _pipe@2 = combined_builder_apply_to_sql( _pipe@1, Cmbnd_qry, fun combined_builder_maybe_add_order_sql/1 ), _pipe@3 = limit_offset_apply(_pipe@2, erlang:element(4, Cmbnd_qry)), epilog_apply(_pipe@3, erlang:element(6, Cmbnd_qry)). -spec join_part_apply( cake@internal@prepared_statement:prepared_statement(), join_part() ) -> cake@internal@prepared_statement:prepared_statement(). join_part_apply(Prp_stm, Prt) -> case erlang:element(2, Prt) of {join_table, Tbl} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<<>/binary, (erlang:element(3, Prt))/binary>> ); {join_sub_query, Qry} -> _pipe@1 = Prp_stm, _pipe@2 = cake@internal@prepared_statement:append_sql( _pipe@1, <<"("/utf8>> ), _pipe@3 = builder_apply(_pipe@2, Qry), cake@internal@prepared_statement:append_sql( _pipe@3, <<") AS "/utf8, (erlang:element(3, Prt))/binary>> ) end. -spec where_part_apply_logical_operator( cake@internal@prepared_statement:prepared_statement(), binary(), list(where_part()) ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_logical_operator(Prp_stm, Oprtr, Prts) -> Prp_stm@1 = begin _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, <<"("/utf8>>) end, _pipe@1 = Prts, _pipe@5 = gleam@list:fold( _pipe@1, Prp_stm@1, fun(New_prp_stm, Prt) -> case New_prp_stm =:= Prp_stm@1 of true -> _pipe@2 = New_prp_stm, where_part_apply(_pipe@2, Prt); false -> _pipe@3 = New_prp_stm, _pipe@4 = cake@internal@prepared_statement:append_sql( _pipe@3, <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>> ), where_part_apply(_pipe@4, Prt) end end ), cake@internal@prepared_statement:append_sql(_pipe@5, <<")"/utf8>>). -spec where_part_apply( cake@internal@prepared_statement:prepared_statement(), where_part() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply(Prp_stm, Prt) -> case Prt of {where_equal, Val_a, Val_b} -> _pipe = Prp_stm, where_part_apply_comparison(_pipe, Val_a, <<"="/utf8>>, Val_b); {where_lower, Val_a@1, Val_b@1} -> _pipe@1 = Prp_stm, where_part_apply_comparison(_pipe@1, Val_a@1, <<"<"/utf8>>, Val_b@1); {where_lower_or_equal, Val_a@2, Val_b@2} -> _pipe@2 = Prp_stm, where_part_apply_comparison( _pipe@2, Val_a@2, <<"<="/utf8>>, Val_b@2 ); {where_greater, Val_a@3, Val_b@3} -> _pipe@3 = Prp_stm, where_part_apply_comparison(_pipe@3, Val_a@3, <<">"/utf8>>, Val_b@3); {where_greater_or_equal, Val_a@4, Val_b@4} -> _pipe@4 = Prp_stm, where_part_apply_comparison( _pipe@4, Val_a@4, <<">="/utf8>>, Val_b@4 ); {where_unequal, Val_a@5, Val_b@5} -> _pipe@5 = Prp_stm, where_part_apply_comparison( _pipe@5, Val_a@5, <<"<>"/utf8>>, Val_b@5 ); {where_is_bool, Val, true} -> _pipe@6 = Prp_stm, where_part_apply_literal(_pipe@6, Val, <<"IS TRUE"/utf8>>); {where_is_bool, Val@1, false} -> _pipe@7 = Prp_stm, where_part_apply_literal(_pipe@7, Val@1, <<"IS FALSE"/utf8>>); {where_is_not_bool, Val@2, true} -> _pipe@8 = Prp_stm, where_part_apply_literal(_pipe@8, Val@2, <<"IS NOT TRUE"/utf8>>); {where_is_not_bool, Val@3, false} -> _pipe@9 = Prp_stm, where_part_apply_literal(_pipe@9, Val@3, <<"IS NOT FALSE"/utf8>>); {where_is_null, Val@4} -> _pipe@10 = Prp_stm, where_part_apply_literal(_pipe@10, Val@4, <<"IS NULL"/utf8>>); {where_is_not_null, Val@5} -> _pipe@11 = Prp_stm, where_part_apply_literal(_pipe@11, Val@5, <<"IS NOT NULL"/utf8>>); {where_like, Val@6, Prm} -> _pipe@12 = Prp_stm, where_part_apply_comparison( _pipe@12, Val@6, <<"LIKE"/utf8>>, {where_param, {string_param, Prm}} ); {where_i_like, Col, Prm@1} -> _pipe@13 = Prp_stm, where_part_apply_comparison( _pipe@13, Col, <<"ILIKE"/utf8>>, {where_param, {string_param, Prm@1}} ); {where_similar, Col@1, Prm@2} -> _pipe@14 = Prp_stm, _pipe@15 = where_part_apply_comparison( _pipe@14, Col@1, <<"SIMILAR TO"/utf8>>, {where_param, {string_param, Prm@2}} ), cake@internal@prepared_statement:append_sql( _pipe@15, <<" ESCAPE '/'"/utf8>> ); {and_where, Prts} -> _pipe@16 = Prp_stm, where_part_apply_logical_operator(_pipe@16, <<"AND"/utf8>>, Prts); {or_where, Prts@1} -> _pipe@17 = Prp_stm, where_part_apply_logical_operator(_pipe@17, <<"OR"/utf8>>, Prts@1); {not_where, Prt@1} -> _pipe@18 = Prp_stm, _pipe@19 = cake@internal@prepared_statement:append_sql( _pipe@18, <<"NOT ("/utf8>> ), _pipe@20 = where_part_apply(_pipe@19, Prt@1), cake@internal@prepared_statement:append_sql(_pipe@20, <<")"/utf8>>); {where_in, Val@7, Vals} -> _pipe@21 = Prp_stm, where_part_apply_value_in_values(_pipe@21, Val@7, Vals); {where_between, Val_a@6, Val_b@6, Val_c} -> _pipe@22 = Prp_stm, where_part_apply_between(_pipe@22, Val_a@6, Val_b@6, Val_c); no_where_part -> Prp_stm end. -spec where_part_apply_clause( cake@internal@prepared_statement:prepared_statement(), where_part() ) -> cake@internal@prepared_statement:prepared_statement(). where_part_apply_clause(Prp_stm, Prt) -> case Prt of no_where_part -> Prp_stm; Prt@1 -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql( _pipe, <<" WHERE "/utf8>> ), where_part_apply(_pipe@1, Prt@1) end. -spec select_builder_maybe_apply_where( cake@internal@prepared_statement:prepared_statement(), select_query() ) -> cake@internal@prepared_statement:prepared_statement(). select_builder_maybe_apply_where(Prp_stm, Qry) -> _pipe = Prp_stm, where_part_apply_clause(_pipe, erlang:element(5, Qry)). -spec join_parts_apply_clause( cake@internal@prepared_statement:prepared_statement(), list(join_part()) ) -> cake@internal@prepared_statement:prepared_statement(). join_parts_apply_clause(Prp_stm, Prts) -> _pipe = Prts, gleam@list:fold( _pipe, Prp_stm, fun(New_prp_stm, Prt) -> Apply_join = fun(New_prp_stm@1, Sql_command) -> _pipe@1 = New_prp_stm@1, _pipe@2 = cake@internal@prepared_statement:append_sql( _pipe@1, <<<<" "/utf8, Sql_command/binary>>/binary, " "/utf8>> ), join_part_apply(_pipe@2, Prt) end, Apply_on = fun(New_prp_stm@2, On) -> _pipe@3 = New_prp_stm@2, _pipe@4 = cake@internal@prepared_statement:append_sql( _pipe@3, <<" ON "/utf8>> ), where_part_apply(_pipe@4, On) end, case Prt of {cross_join, _, _} -> _pipe@5 = New_prp_stm, Apply_join(_pipe@5, <<"CROSS JOIN"/utf8>>); {inner_join, _, _, On@1} -> _pipe@6 = New_prp_stm, _pipe@7 = Apply_join(_pipe@6, <<"INNER JOIN"/utf8>>), Apply_on(_pipe@7, On@1); {left_outer_join, _, _, On@2} -> _pipe@8 = New_prp_stm, _pipe@9 = Apply_join(_pipe@8, <<"LEFT OUTER JOIN"/utf8>>), Apply_on(_pipe@9, On@2); {right_outer_join, _, _, On@3} -> _pipe@10 = New_prp_stm, _pipe@11 = Apply_join(_pipe@10, <<"RIGHT OUTER JOIN"/utf8>>), Apply_on(_pipe@11, On@3); {full_outer_join, _, _, On@4} -> _pipe@12 = New_prp_stm, _pipe@13 = Apply_join(_pipe@12, <<"FULL OUTER JOIN"/utf8>>), Apply_on(_pipe@13, On@4) end end ). -spec select_builder_maybe_apply_join( cake@internal@prepared_statement:prepared_statement(), select_query() ) -> cake@internal@prepared_statement:prepared_statement(). select_builder_maybe_apply_join(Prp_stm, Qry) -> _pipe = Prp_stm, join_parts_apply_clause(_pipe, erlang:element(4, Qry)).