-module(cake@internal@read_query).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).

-export([combined_query_new/2, group_by_clause_apply/2, combined_order_by/3, select_order_by/3, limit_new/1, offset_new/1, epilog_apply/2, comment_apply/2, fragment_prepared_split_string/1, fragment_count_placeholders/1, from_clause_apply/2, apply/2, to_prepared_statement/3, combined_clause_apply/2, join_apply/2, where_clause_apply/2, join_clause_apply/2]).
-export_type([read_query/0, combined/0, combined_query_kind/0, select_kind/0, select/0, selects/0, select_value/0, from/0, where/0, where_comparison_operator/0, where_value/0, group_by/0, joins/0, join_target/0, join/0, order_by/0, order_by_value/0, order_by_direction/0, limit/0, offset/0, epilog/0, comment/0, fragment/0]).

-type read_query() :: {select_query, select()} | {combined_query, combined()}.

-type combined() :: {combined,
        combined_query_kind(),
        list(select()),
        limit(),
        offset(),
        order_by(),
        epilog(),
        comment()}.

-type combined_query_kind() :: union_distinct |
    union_all |
    except_distinct |
    except_all |
    intersect_distinct |
    intersect_all.

-type select_kind() :: select_all | select_distinct.

-type select() :: {select,
        select_kind(),
        selects(),
        from(),
        joins(),
        where(),
        group_by(),
        where(),
        order_by(),
        limit(),
        offset(),
        epilog(),
        comment()}.

-type selects() :: no_selects | {selects, list(select_value())}.

-type select_value() :: {select_column, binary()} |
    {select_param, cake@param:param()} |
    {select_fragment, fragment()} |
    {select_alias, select_value(), binary()}.

-type from() :: no_from |
    {from_table, binary()} |
    {from_sub_query, read_query(), binary()}.

-type where() :: no_where |
    {not_where, where()} |
    {and_where, list(where())} |
    {or_where, list(where())} |
    {xor_where, list(where())} |
    {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_comparison,
        where_value(),
        where_comparison_operator(),
        where_value()} |
    {where_any_of_sub_query,
        where_value(),
        where_comparison_operator(),
        read_query()} |
    {where_all_of_sub_query,
        where_value(),
        where_comparison_operator(),
        read_query()} |
    {where_in, where_value(), list(where_value())} |
    {where_exists_in_sub_query, read_query()} |
    {where_between, where_value(), where_value(), where_value()} |
    {where_like, where_value(), binary()} |
    {where_i_like, where_value(), binary()} |
    {where_similar_to, where_value(), binary(), binary()} |
    {where_fragment, fragment()}.

-type where_comparison_operator() :: equal |
    greater |
    greater_or_equal |
    lower |
    lower_or_equal |
    unequal.

-type where_value() :: {where_column_value, binary()} |
    {where_param_value, cake@param:param()} |
    {where_fragment_value, fragment()} |
    {where_sub_query_value, read_query()}.

-type group_by() :: no_group_by | {group_by, list(binary())}.

-type joins() :: no_joins | {joins, list(join())}.

-type join_target() :: {join_table, binary()} | {join_sub_query, read_query()}.

-type join() :: {inner_join, join_target(), binary(), where()} |
    {inner_join_lateral_on_true, join_target(), binary()} |
    {left_join, join_target(), binary(), where()} |
    {left_join_lateral_on_true, join_target(), binary()} |
    {right_join, join_target(), binary(), where()} |
    {full_join, join_target(), binary(), where()} |
    {cross_join, join_target(), binary()} |
    {cross_join_lateral, join_target(), binary()}.

-type order_by() :: no_order_by | {order_by, list(order_by_value())}.

-type order_by_value() :: {order_by_column, binary(), order_by_direction()} |
    {order_by_fragment, fragment(), order_by_direction()}.

-type order_by_direction() :: asc |
    asc_nulls_first |
    asc_nulls_last |
    desc |
    desc_nulls_first |
    desc_nulls_last.

-type limit() :: no_limit | {limit, integer()}.

-type offset() :: no_offset | {offset, integer()}.

-type epilog() :: no_epilog | {epilog, binary()}.

-type comment() :: no_comment | {comment, binary()}.

-type fragment() :: {fragment_literal, binary()} |
    {fragment_prepared, binary(), list(cake@param:param())}.

-spec combined_query_new(combined_query_kind(), list(select())) -> combined().
combined_query_new(Knd, Qrys) ->
    _pipe = Qrys,
    {combined,
        Knd,
        _pipe,
        no_limit,
        no_offset,
        no_order_by,
        no_epilog,
        no_comment}.

-spec where_string_apply(
    cake@internal@prepared_statement:prepared_statement(),
    binary()
) -> cake@internal@prepared_statement:prepared_statement().
where_string_apply(Prp_stm, S) ->
    _pipe = Prp_stm,
    cake@internal@prepared_statement:append_sql(_pipe, S).

-spec where_param_apply(
    cake@internal@prepared_statement:prepared_statement(),
    cake@param:param()
) -> cake@internal@prepared_statement:prepared_statement().
where_param_apply(Prp_stm, Prm) ->
    _pipe = Prp_stm,
    cake@internal@prepared_statement:append_param(_pipe, Prm).

-spec group_by_apply(
    cake@internal@prepared_statement:prepared_statement(),
    list(binary())
) -> cake@internal@prepared_statement:prepared_statement().
group_by_apply(Prp_stm, Grpbs) ->
    case Grpbs of
        [] ->
            Prp_stm;

        _ ->
            _pipe = Grpbs,
            gleam@list:fold(
                _pipe,
                Prp_stm,
                fun(New_prp_stm, S) -> case New_prp_stm =:= Prp_stm of
                        true ->
                            _pipe@1 = New_prp_stm,
                            cake@internal@prepared_statement:append_sql(
                                _pipe@1,
                                S
                            );

                        false ->
                            _pipe@2 = New_prp_stm,
                            cake@internal@prepared_statement:append_sql(
                                _pipe@2,
                                <<", "/utf8, S/binary>>
                            )
                    end end
            )
    end.

-spec group_by_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    group_by()
) -> cake@internal@prepared_statement:prepared_statement().
group_by_clause_apply(Prp_stm, Grpb) ->
    case Grpb of
        no_group_by ->
            Prp_stm;

        {group_by, Grpbs} ->
            _pipe = Prp_stm,
            _pipe@1 = cake@internal@prepared_statement:append_sql(
                _pipe,
                <<" GROUP BY "/utf8>>
            ),
            group_by_apply(_pipe@1, Grpbs)
    end.

-spec order_by_append(order_by(), order_by()) -> order_by().
order_by_append(Query_ordb, New_ordb) ->
    case Query_ordb of
        no_order_by ->
            New_ordb;

        {order_by, Qry_ordb_items} ->
            New_ordb_items = case New_ordb of
                no_order_by ->
                    [];

                {order_by, New_ordb@1} ->
                    New_ordb@1
            end,
            New_ordb_item = case Qry_ordb_items of
                [] ->
                    New_ordb_items;

                _ ->
                    _pipe = Qry_ordb_items,
                    lists:append(_pipe, New_ordb_items)
            end,
            case New_ordb_item of
                [] ->
                    no_order_by;

                _ ->
                    {order_by, New_ordb_item}
            end
    end.

-spec combined_order_by(combined(), order_by(), boolean()) -> combined().
combined_order_by(Qry, Ordb, Appnd) ->
    case Appnd of
        true ->
            erlang:setelement(
                6,
                Qry,
                begin
                    _pipe = erlang:element(6, Qry),
                    order_by_append(_pipe, Ordb)
                end
            );

        false ->
            erlang:setelement(6, Qry, Ordb)
    end.

-spec select_order_by(select(), order_by(), boolean()) -> select().
select_order_by(Qry, Ordb, Appnd) ->
    case Appnd of
        true ->
            erlang:setelement(
                9,
                Qry,
                begin
                    _pipe = erlang:element(9, Qry),
                    order_by_append(_pipe, Ordb)
                end
            );

        false ->
            erlang:setelement(9, Qry, Ordb)
    end.

-spec order_by_direction_to_sql(order_by_direction()) -> binary().
order_by_direction_to_sql(Ordbd) ->
    case Ordbd of
        asc ->
            <<"ASC"/utf8>>;

        asc_nulls_first ->
            <<"ASC NULLS FIRST"/utf8>>;

        asc_nulls_last ->
            <<"ASC NULLS LAST"/utf8>>;

        desc ->
            <<"DESC"/utf8>>;

        desc_nulls_first ->
            <<"DESC NULLS FIRST"/utf8>>;

        desc_nulls_last ->
            <<"DESC NULLS LAST"/utf8>>
    end.

-spec limit_new(integer()) -> limit().
limit_new(Lmt) ->
    case Lmt > 0 of
        false ->
            no_limit;

        true ->
            {limit, Lmt}
    end.

-spec limit_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    limit()
) -> cake@internal@prepared_statement:prepared_statement().
limit_clause_apply(Prp_stm, Lmt) ->
    _pipe@1 = case Lmt of
        no_limit ->
            <<""/utf8>>;

        {limit, Lmt@1} ->
            <<" LIMIT "/utf8,
                (begin
                    _pipe = Lmt@1,
                    gleam@int:to_string(_pipe)
                end)/binary>>
    end,
    cake@internal@prepared_statement:append_sql(Prp_stm, _pipe@1).

-spec offset_new(integer()) -> offset().
offset_new(Offst) ->
    case Offst > 0 of
        false ->
            no_offset;

        true ->
            {offset, Offst}
    end.

-spec offset_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    offset()
) -> cake@internal@prepared_statement:prepared_statement().
offset_clause_apply(Prp_stm, Offst) ->
    _pipe@1 = case Offst of
        no_offset ->
            <<""/utf8>>;

        {offset, Offst@1} ->
            <<" OFFSET "/utf8,
                (begin
                    _pipe = Offst@1,
                    gleam@int:to_string(_pipe)
                end)/binary>>
    end,
    cake@internal@prepared_statement:append_sql(Prp_stm, _pipe@1).

-spec epilog_apply(
    cake@internal@prepared_statement:prepared_statement(),
    epilog()
) -> cake@internal@prepared_statement:prepared_statement().
epilog_apply(Prp_stm, Eplg) ->
    case Eplg of
        no_epilog ->
            Prp_stm;

        {epilog, Eplgs} ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(_pipe, Eplgs)
    end.

-spec comment_apply(
    cake@internal@prepared_statement:prepared_statement(),
    comment()
) -> cake@internal@prepared_statement:prepared_statement().
comment_apply(Prp_stm, Cmmnt) ->
    case Cmmnt of
        no_comment ->
            Prp_stm;

        {comment, Cmmnt@1} ->
            case begin
                _pipe = Cmmnt@1,
                gleam_stdlib:contains_string(_pipe, <<"\n"/utf8>>)
            end
            orelse begin
                _pipe@1 = Cmmnt@1,
                gleam_stdlib:contains_string(_pipe@1, <<"\r"/utf8>>)
            end of
                true ->
                    _pipe@2 = Prp_stm,
                    cake@internal@prepared_statement:append_sql(
                        _pipe@2,
                        <<<<" /* "/utf8,
                                (begin
                                    _pipe@3 = Cmmnt@1,
                                    _pipe@4 = gleam@string:trim(_pipe@3),
                                    _pipe@5 = gleam@string:replace(
                                        _pipe@4,
                                        <<"*/"/utf8>>,
                                        <<"* /"/utf8>>
                                    ),
                                    gleam@string:replace(
                                        _pipe@5,
                                        <<"/*"/utf8>>,
                                        <<"/ *"/utf8>>
                                    )
                                end)/binary>>/binary,
                            " */"/utf8>>
                    );

                false ->
                    _pipe@6 = Prp_stm,
                    cake@internal@prepared_statement:append_sql(
                        _pipe@6,
                        <<" -- "/utf8,
                            (begin
                                _pipe@7 = Cmmnt@1,
                                gleam@string:trim(_pipe@7)
                            end)/binary>>
                    )
            end
    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, [X | _]} when X =:= <<"$"/utf8>> ->
                    [Grapheme | Acc];

                {false, [X@1 | Xs]} ->
                    [<<X@1/binary, Grapheme/binary>> | Xs]
            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 fragment_apply(
    cake@internal@prepared_statement:prepared_statement(),
    fragment()
) -> cake@internal@prepared_statement:prepared_statement().
fragment_apply(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, []} ->
            _pipe@1 = Prp_stm,
            cake@internal@prepared_statement:append_sql(_pipe@1, Frgmt@2);

        {fragment_prepared, Frgmt@3, Prms} ->
            Frgmts = begin
                _pipe@2 = Frgmt@3,
                fragment_prepared_split_string(_pipe@2)
            end,
            Frgmt_plchldr_count = begin
                _pipe@3 = Frgmts,
                fragment_count_placeholders(_pipe@3)
            end,
            Prms_count = begin
                _pipe@4 = Prms,
                erlang:length(_pipe@4)
            end,
            Prms@1 = case begin
                _pipe@5 = Frgmt_plchldr_count,
                gleam@int:compare(_pipe@5, Prms_count)
            end of
                eq ->
                    Prms;

                lt ->
                    Missing_placeholders = Prms_count - Frgmt_plchldr_count,
                    _pipe@6 = Prms,
                    gleam@list:take(_pipe@6, Missing_placeholders + 1);

                gt ->
                    Missing_params = Frgmt_plchldr_count - Prms_count,
                    _assert_subject = begin
                        _pipe@7 = Prms,
                        gleam@list:last(_pipe@7)
                    end,
                    {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/read_query"/utf8>>,
                                        function => <<"fragment_apply"/utf8>>,
                                        line => 1487})
                    end,
                    Repeated_last_item = begin
                        _pipe@8 = Last_item,
                        gleam@list:repeat(_pipe@8, Missing_params)
                    end,
                    _pipe@9 = Prms,
                    lists:append(_pipe@9, Repeated_last_item)
            end,
            {New_prp_stm@2, Param_rest} = begin
                _pipe@10 = Frgmts,
                gleam@list:fold(
                    _pipe@10,
                    {Prp_stm, Prms@1},
                    fun(Acc, Frgmnt) ->
                        New_prp_stm = erlang:element(1, Acc),
                        case Frgmnt =:= <<"$"/utf8>> of
                            true ->
                                _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/read_query"/utf8>>,
                                                    function => <<"fragment_apply"/utf8>>,
                                                    line => 1509}
                                            )
                                end,
                                New_prp_stm@1 = begin
                                    _pipe@11 = New_prp_stm,
                                    cake@internal@prepared_statement:append_param(
                                        _pipe@11,
                                        Prm
                                    )
                                end,
                                {New_prp_stm@1, Rest_prms};

                            false ->
                                {begin
                                        _pipe@12 = New_prp_stm,
                                        cake@internal@prepared_statement:append_sql(
                                            _pipe@12,
                                            Frgmnt
                                        )
                                    end,
                                    erlang:element(2, Acc)}
                        end
                    end
                )
            end,
            _ = case Param_rest of
                [] ->
                    true;

                _ ->
                    Crash_msg = <<"The number of placeholders in the fragment does not match the number of parameters. This is likely a user error. Please check the fragment and the parameters."/utf8>>,
                    erlang:error(#{gleam_error => panic,
                            message => Crash_msg,
                            module => <<"cake/internal/read_query"/utf8>>,
                            function => <<"fragment_apply"/utf8>>,
                            line => 1527})
            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, Prm} ->
            _pipe@1 = Prp_stm,
            cake@internal@prepared_statement:append_param(_pipe@1, Prm);

        {select_fragment, Frgmnt} ->
            _pipe@2 = Prp_stm,
            fragment_apply(_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_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    select_kind(),
    selects()
) -> cake@internal@prepared_statement:prepared_statement().
select_clause_apply(Prp_stm, Knd, Slcts) ->
    Select_command = case Knd of
        select_all ->
            <<"SELECT"/utf8>>;

        select_distinct ->
            <<"SELECT DISTINCT"/utf8>>
    end,
    case Slcts of
        no_selects ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(
                _pipe,
                <<Select_command/binary, " *"/utf8>>
            );

        {selects, Slct_vs} ->
            case Slct_vs of
                [] ->
                    Prp_stm;

                Vs ->
                    Prp_stm@1 = begin
                        _pipe@1 = Prp_stm,
                        cake@internal@prepared_statement:append_sql(
                            _pipe@1,
                            <<Select_command/binary, " "/utf8>>
                        )
                    end,
                    _pipe@2 = Vs,
                    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
    end.

-spec order_by_value_apply(
    cake@internal@prepared_statement:prepared_statement(),
    order_by_value()
) -> cake@internal@prepared_statement:prepared_statement().
order_by_value_apply(Prp_stm, V) ->
    case V of
        {order_by_column, Col, Dir} ->
            _pipe = Prp_stm,
            _pipe@1 = cake@internal@prepared_statement:append_sql(_pipe, Col),
            cake@internal@prepared_statement:append_sql(
                _pipe@1,
                <<" "/utf8,
                    (begin
                        _pipe@2 = Dir,
                        order_by_direction_to_sql(_pipe@2)
                    end)/binary>>
            );

        {order_by_fragment, Frgmnt, Dir@1} ->
            _pipe@3 = Prp_stm,
            _pipe@4 = fragment_apply(_pipe@3, Frgmnt),
            cake@internal@prepared_statement:append_sql(
                _pipe@4,
                <<" "/utf8,
                    (begin
                        _pipe@5 = Dir@1,
                        order_by_direction_to_sql(_pipe@5)
                    end)/binary>>
            )
    end.

-spec order_by_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    order_by()
) -> cake@internal@prepared_statement:prepared_statement().
order_by_clause_apply(Prp_stm, Ordb) ->
    case Ordb of
        no_order_by ->
            Prp_stm;

        {order_by, Ordbs} ->
            case Ordbs of
                [] ->
                    Prp_stm;

                Vs ->
                    Prp_stm@1 = begin
                        _pipe = Prp_stm,
                        cake@internal@prepared_statement:append_sql(
                            _pipe,
                            <<" ORDER BY "/utf8>>
                        )
                    end,
                    _pipe@1 = Vs,
                    gleam@list:fold(
                        _pipe@1,
                        Prp_stm@1,
                        fun(New_prp_stm, V) -> case New_prp_stm =:= Prp_stm@1 of
                                true ->
                                    _pipe@2 = New_prp_stm,
                                    order_by_value_apply(_pipe@2, V);

                                false ->
                                    _pipe@3 = New_prp_stm,
                                    _pipe@4 = cake@internal@prepared_statement:append_sql(
                                        _pipe@3,
                                        <<", "/utf8>>
                                    ),
                                    order_by_value_apply(_pipe@4, V)
                            end end
                    )
            end
    end.

-spec from_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    from()
) -> cake@internal@prepared_statement:prepared_statement().
from_clause_apply(Prp_stm, Frm) ->
    case Frm of
        no_from ->
            Prp_stm;

        {from_table, Tbl_nm} ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(
                _pipe,
                <<" FROM "/utf8, Tbl_nm/binary>>
            );

        {from_sub_query, Qry, Als} ->
            _pipe@1 = Prp_stm,
            _pipe@2 = cake@internal@prepared_statement:append_sql(
                _pipe@1,
                <<" FROM ("/utf8>>
            ),
            _pipe@3 = apply(_pipe@2, Qry),
            cake@internal@prepared_statement:append_sql(
                _pipe@3,
                <<") AS "/utf8, Als/binary>>
            )
    end.

-spec apply(cake@internal@prepared_statement:prepared_statement(), read_query()) -> cake@internal@prepared_statement:prepared_statement().
apply(Prp_stm, Qry) ->
    case Qry of
        {select_query, Qry@1} ->
            _pipe = Prp_stm,
            select_builder(_pipe, Qry@1);

        {combined_query, Qry@2} ->
            _pipe@1 = Prp_stm,
            combined_builder(_pipe@1, Qry@2)
    end.

-spec select_builder(
    cake@internal@prepared_statement:prepared_statement(),
    select()
) -> cake@internal@prepared_statement:prepared_statement().
select_builder(Prp_stm, Qry) ->
    _pipe = Prp_stm,
    _pipe@1 = select_clause_apply(
        _pipe,
        erlang:element(2, Qry),
        erlang:element(3, Qry)
    ),
    _pipe@2 = from_clause_apply(_pipe@1, erlang:element(4, Qry)),
    _pipe@3 = join_clause_apply(_pipe@2, erlang:element(5, Qry)),
    _pipe@4 = where_clause_apply(_pipe@3, erlang:element(6, Qry)),
    _pipe@5 = group_by_clause_apply(_pipe@4, erlang:element(7, Qry)),
    _pipe@6 = having_clause_apply(_pipe@5, erlang:element(8, Qry)),
    _pipe@7 = order_by_clause_apply(_pipe@6, erlang:element(9, Qry)),
    _pipe@8 = limit_clause_apply(_pipe@7, erlang:element(10, Qry)),
    _pipe@9 = offset_clause_apply(_pipe@8, erlang:element(11, Qry)),
    _pipe@10 = epilog_apply(_pipe@9, erlang:element(12, Qry)),
    comment_apply(_pipe@10, erlang:element(13, Qry)).

-spec to_prepared_statement(
    read_query(),
    binary(),
    cake@internal@dialect:dialect()
) -> cake@internal@prepared_statement:prepared_statement().
to_prepared_statement(Qry, Plchldr_bs, Dlct) ->
    _pipe = Plchldr_bs,
    _pipe@1 = cake@internal@prepared_statement:new(_pipe, Dlct),
    apply(_pipe@1, Qry).

-spec combined_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    combined()
) -> cake@internal@prepared_statement:prepared_statement().
combined_clause_apply(Prp_stm, Qry) ->
    Sql_command = case erlang:element(2, Qry) of
        union_distinct ->
            <<"UNION"/utf8>>;

        union_all ->
            <<"UNION ALL"/utf8>>;

        except_distinct ->
            <<"EXCEPT"/utf8>>;

        except_all ->
            <<"EXCEPT ALL"/utf8>>;

        intersect_distinct ->
            <<"INTERSECT"/utf8>>;

        intersect_all ->
            <<"INTERSECT ALL"/utf8>>
    end,
    Open_nested_query = fun(Prp_stm@1) ->
        case begin
            _pipe = Prp_stm@1,
            cake@internal@prepared_statement:get_dialect(_pipe)
        end of
            sqlite ->
                _pipe@1 = Prp_stm@1,
                cake@internal@prepared_statement:append_sql(
                    _pipe@1,
                    <<"SELECT * FROM ("/utf8>>
                );

            _ ->
                _pipe@2 = Prp_stm@1,
                cake@internal@prepared_statement:append_sql(
                    _pipe@2,
                    <<"("/utf8>>
                )
        end
    end,
    Close_nested_query = fun(Prp_stm@2, Nested_index) ->
        case begin
            _pipe@3 = Prp_stm@2,
            cake@internal@prepared_statement:get_dialect(_pipe@3)
        end of
            sqlite ->
                _pipe@4 = Prp_stm@2,
                cake@internal@prepared_statement:append_sql(
                    _pipe@4,
                    <<<<") AS "/utf8, "__cake_computed_alias_"/utf8>>/binary,
                        (begin
                            _pipe@5 = Nested_index,
                            gleam@int:to_string(_pipe@5)
                        end)/binary>>
                );

            _ ->
                _pipe@6 = Prp_stm@2,
                cake@internal@prepared_statement:append_sql(
                    _pipe@6,
                    <<")"/utf8>>
                )
        end
    end,
    Prp_stm@3 = begin
        _pipe@7 = Prp_stm,
        Open_nested_query(_pipe@7)
    end,
    {New_prp_stm@2, Nested_index@3} = begin
        _pipe@8 = erlang:element(3, Qry),
        gleam@list:fold(
            _pipe@8,
            {Prp_stm@3, 0},
            fun(Acc, Qry@1) ->
                {New_prp_stm, Nested_index@1} = Acc,
                case New_prp_stm =:= Prp_stm@3 of
                    true ->
                        {begin
                                _pipe@9 = New_prp_stm,
                                select_builder(_pipe@9, Qry@1)
                            end,
                            Nested_index@1};

                    false ->
                        Nested_index@2 = Nested_index@1 + 1,
                        New_prp_stm@1 = begin
                            _pipe@10 = New_prp_stm,
                            _pipe@11 = Close_nested_query(
                                _pipe@10,
                                Nested_index@2
                            ),
                            _pipe@12 = cake@internal@prepared_statement:append_sql(
                                _pipe@11,
                                <<<<" "/utf8, Sql_command/binary>>/binary,
                                    " "/utf8>>
                            ),
                            _pipe@13 = Open_nested_query(_pipe@12),
                            select_builder(_pipe@13, Qry@1)
                        end,
                        {New_prp_stm@1, Nested_index@2}
                end
            end
        )
    end,
    _pipe@14 = New_prp_stm@2,
    Close_nested_query(_pipe@14, Nested_index@3 + 1).

-spec combined_builder(
    cake@internal@prepared_statement:prepared_statement(),
    combined()
) -> cake@internal@prepared_statement:prepared_statement().
combined_builder(Prp_stm, Qry) ->
    _pipe = Prp_stm,
    _pipe@1 = combined_clause_apply(_pipe, Qry),
    _pipe@2 = order_by_clause_apply(_pipe@1, erlang:element(6, Qry)),
    _pipe@3 = limit_clause_apply(_pipe@2, erlang:element(4, Qry)),
    _pipe@4 = offset_clause_apply(_pipe@3, erlang:element(5, Qry)),
    _pipe@5 = epilog_apply(_pipe@4, erlang:element(7, Qry)),
    comment_apply(_pipe@5, erlang:element(8, Qry)).

-spec where_sub_query_apply(
    cake@internal@prepared_statement:prepared_statement(),
    read_query()
) -> cake@internal@prepared_statement:prepared_statement().
where_sub_query_apply(Prp_stm, Qry) ->
    _pipe = Prp_stm,
    _pipe@1 = cake@internal@prepared_statement:append_sql(_pipe, <<"("/utf8>>),
    _pipe@2 = apply(_pipe@1, Qry),
    cake@internal@prepared_statement:append_sql(_pipe@2, <<")"/utf8>>).

-spec where_literal_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where_value(),
    binary()
) -> cake@internal@prepared_statement:prepared_statement().
where_literal_apply(Prp_stm, V, Lt) ->
    case V of
        {where_column_value, Col} ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(
                _pipe,
                <<<<Col/binary, " "/utf8>>/binary, Lt/binary>>
            );

        {where_param_value, Prm} ->
            _pipe@1 = Prp_stm,
            cake@internal@prepared_statement:append_param(_pipe@1, Prm);

        {where_fragment_value, Frgmt} ->
            _pipe@2 = Prp_stm,
            _pipe@3 = fragment_apply(_pipe@2, Frgmt),
            cake@internal@prepared_statement:append_sql(
                _pipe@3,
                <<" "/utf8, Lt/binary>>
            );

        {where_sub_query_value, Qry} ->
            _pipe@4 = Prp_stm,
            _pipe@5 = where_sub_query_apply(_pipe@4, Qry),
            cake@internal@prepared_statement:append_sql(
                _pipe@5,
                <<" "/utf8, Lt/binary>>
            )
    end.

-spec where_comparison_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where_value(),
    binary(),
    where_value()
) -> cake@internal@prepared_statement:prepared_statement().
where_comparison_apply(Prp_stm, Val_a, Oprtr, Val_b) ->
    case {Val_a, Val_b} of
        {{where_column_value, Col_a}, {where_column_value, Col_b}} ->
            _pipe = Prp_stm,
            where_string_apply(
                _pipe,
                <<<<<<<<Col_a/binary, " "/utf8>>/binary, Oprtr/binary>>/binary,
                        " "/utf8>>/binary,
                    Col_b/binary>>
            );

        {{where_column_value, Col}, {where_param_value, Prm}} ->
            _pipe@1 = Prp_stm,
            _pipe@2 = where_string_apply(
                _pipe@1,
                <<<<<<Col/binary, " "/utf8>>/binary, Oprtr/binary>>/binary,
                    " "/utf8>>
            ),
            where_param_apply(_pipe@2, Prm);

        {{where_param_value, Prm@1}, {where_column_value, Col@1}} ->
            _pipe@3 = Prp_stm,
            _pipe@4 = where_param_apply(_pipe@3, Prm@1),
            where_string_apply(
                _pipe@4,
                <<<<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>/binary,
                    Col@1/binary>>
            );

        {{where_param_value, Prm_a}, {where_param_value, Prm_b}} ->
            _pipe@5 = Prp_stm,
            _pipe@6 = where_param_apply(_pipe@5, Prm_a),
            _pipe@7 = where_string_apply(
                _pipe@6,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            where_param_apply(_pipe@7, Prm_b);

        {{where_fragment_value, Frgmt}, {where_column_value, Col@2}} ->
            _pipe@8 = Prp_stm,
            _pipe@9 = fragment_apply(_pipe@8, Frgmt),
            where_string_apply(
                _pipe@9,
                <<<<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>/binary,
                    Col@2/binary>>
            );

        {{where_column_value, Col@3}, {where_fragment_value, Frgmt@1}} ->
            _pipe@10 = Prp_stm,
            _pipe@11 = where_string_apply(
                _pipe@10,
                <<<<<<Col@3/binary, " "/utf8>>/binary, Oprtr/binary>>/binary,
                    " "/utf8>>
            ),
            fragment_apply(_pipe@11, Frgmt@1);

        {{where_fragment_value, Frgmt@2}, {where_param_value, Prm@2}} ->
            _pipe@12 = Prp_stm,
            _pipe@13 = fragment_apply(_pipe@12, Frgmt@2),
            _pipe@14 = where_string_apply(
                _pipe@13,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            where_param_apply(_pipe@14, Prm@2);

        {{where_param_value, Prm@3}, {where_fragment_value, Frgmt@3}} ->
            _pipe@15 = Prp_stm,
            _pipe@16 = where_param_apply(_pipe@15, Prm@3),
            _pipe@17 = where_string_apply(
                _pipe@16,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            fragment_apply(_pipe@17, Frgmt@3);

        {{where_fragment_value, Frgmt_a}, {where_fragment_value, Frgmt_b}} ->
            _pipe@18 = Prp_stm,
            _pipe@19 = fragment_apply(_pipe@18, Frgmt_a),
            _pipe@20 = where_string_apply(
                _pipe@19,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            fragment_apply(_pipe@20, Frgmt_b);

        {{where_sub_query_value, Qry_a}, {where_sub_query_value, Qry_b}} ->
            _pipe@21 = Prp_stm,
            _pipe@22 = where_sub_query_apply(_pipe@21, Qry_a),
            _pipe@23 = where_string_apply(
                _pipe@22,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            where_sub_query_apply(_pipe@23, Qry_b);

        {{where_column_value, Col@4}, {where_sub_query_value, Qry}} ->
            _pipe@24 = Prp_stm,
            _pipe@25 = where_string_apply(
                _pipe@24,
                <<<<<<Col@4/binary, " "/utf8>>/binary, Oprtr/binary>>/binary,
                    " "/utf8>>
            ),
            where_sub_query_apply(_pipe@25, Qry);

        {{where_sub_query_value, Qry@1}, {where_column_value, Col@5}} ->
            _pipe@26 = Prp_stm,
            _pipe@27 = where_sub_query_apply(_pipe@26, Qry@1),
            where_string_apply(
                _pipe@27,
                <<<<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>/binary,
                    Col@5/binary>>
            );

        {{where_param_value, Prm@4}, {where_sub_query_value, Qry@2}} ->
            _pipe@28 = Prp_stm,
            _pipe@29 = where_param_apply(_pipe@28, Prm@4),
            _pipe@30 = where_string_apply(
                _pipe@29,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            where_sub_query_apply(_pipe@30, Qry@2);

        {{where_sub_query_value, Qry@3}, {where_param_value, Prm@5}} ->
            _pipe@31 = Prp_stm,
            _pipe@32 = where_sub_query_apply(_pipe@31, Qry@3),
            _pipe@33 = where_string_apply(
                _pipe@32,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            where_param_apply(_pipe@33, Prm@5);

        {{where_fragment_value, Frgmt@4}, {where_sub_query_value, Qry@4}} ->
            _pipe@34 = Prp_stm,
            _pipe@35 = fragment_apply(_pipe@34, Frgmt@4),
            _pipe@36 = where_string_apply(
                _pipe@35,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            where_sub_query_apply(_pipe@36, Qry@4);

        {{where_sub_query_value, Qry@5}, {where_fragment_value, Frgmt@5}} ->
            _pipe@37 = Prp_stm,
            _pipe@38 = where_sub_query_apply(_pipe@37, Qry@5),
            _pipe@39 = where_string_apply(
                _pipe@38,
                <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
            ),
            fragment_apply(_pipe@39, Frgmt@5)
    end.

-spec where_value_in_values_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where_value(),
    list(where_value())
) -> cake@internal@prepared_statement:prepared_statement().
where_value_in_values_apply(Prp_stm, Val, Prms) ->
    Prp_stm@1 = begin
        _pipe@4 = case Val of
            {where_column_value, Col} ->
                _pipe = Prp_stm,
                cake@internal@prepared_statement:append_sql(_pipe, Col);

            {where_param_value, Prm} ->
                _pipe@1 = Prp_stm,
                cake@internal@prepared_statement:append_param(_pipe@1, Prm);

            {where_fragment_value, Frgmt} ->
                _pipe@2 = Prp_stm,
                fragment_apply(_pipe@2, Frgmt);

            {where_sub_query_value, Qry} ->
                _pipe@3 = Prp_stm,
                where_sub_query_apply(_pipe@3, Qry)
        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_value, Col@1} ->
                    case New_prp_stm =:= Prp_stm@1 of
                        true ->
                            _pipe@6 = New_prp_stm,
                            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_value, Prm@1} ->
                    _pipe@8 = case New_prp_stm =:= Prp_stm@1 of
                        true ->
                            <<""/utf8>>;

                        false ->
                            <<", "/utf8>>
                    end,
                    _pipe@9 = cake@internal@prepared_statement:append_sql(
                        New_prp_stm,
                        _pipe@8
                    ),
                    cake@internal@prepared_statement:append_param(
                        _pipe@9,
                        Prm@1
                    );

                {where_fragment_value, Frgmt@1} ->
                    _pipe@10 = Prp_stm@1,
                    fragment_apply(_pipe@10, Frgmt@1);

                {where_sub_query_value, Qry@1} ->
                    _pipe@11 = Prp_stm@1,
                    where_sub_query_apply(_pipe@11, Qry@1)
            end end
    ),
    cake@internal@prepared_statement:append_sql(_pipe@12, <<")"/utf8>>).

-spec where_between_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where_value(),
    where_value(),
    where_value()
) -> cake@internal@prepared_statement:prepared_statement().
where_between_apply(Prp_stm, Val_a, Val_b, Val_c) ->
    Prp_stm@1 = case Val_a of
        {where_column_value, Col} ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(_pipe, Col);

        {where_param_value, Prm} ->
            _pipe@1 = Prp_stm,
            cake@internal@prepared_statement:append_param(_pipe@1, Prm);

        {where_fragment_value, Frgmt} ->
            _pipe@2 = Prp_stm,
            fragment_apply(_pipe@2, Frgmt);

        {where_sub_query_value, Qry} ->
            _pipe@3 = Prp_stm,
            where_sub_query_apply(_pipe@3, Qry)
    end,
    Prp_stm@2 = begin
        _pipe@4 = Prp_stm@1,
        cake@internal@prepared_statement:append_sql(
            _pipe@4,
            <<" BETWEEN "/utf8>>
        )
    end,
    Prp_stm@3 = case Val_b of
        {where_column_value, Col@1} ->
            _pipe@5 = Prp_stm@2,
            cake@internal@prepared_statement:append_sql(_pipe@5, Col@1);

        {where_param_value, Prm@1} ->
            _pipe@6 = Prp_stm@2,
            cake@internal@prepared_statement:append_param(_pipe@6, Prm@1);

        {where_fragment_value, Frgmt@1} ->
            _pipe@7 = Prp_stm@2,
            fragment_apply(_pipe@7, Frgmt@1);

        {where_sub_query_value, Qry@1} ->
            _pipe@8 = Prp_stm@2,
            where_sub_query_apply(_pipe@8, Qry@1)
    end,
    Prp_stm@4 = begin
        _pipe@9 = Prp_stm@3,
        cake@internal@prepared_statement:append_sql(_pipe@9, <<" AND "/utf8>>)
    end,
    Prp_stm@5 = case Val_c of
        {where_column_value, Col@2} ->
            _pipe@10 = Prp_stm@4,
            cake@internal@prepared_statement:append_sql(_pipe@10, Col@2);

        {where_param_value, Prm@2} ->
            _pipe@11 = Prp_stm@4,
            cake@internal@prepared_statement:append_param(_pipe@11, Prm@2);

        {where_fragment_value, Frgmt@2} ->
            _pipe@12 = Prp_stm@4,
            fragment_apply(_pipe@12, Frgmt@2);

        {where_sub_query_value, Qry@2} ->
            _pipe@13 = Prp_stm@4,
            where_sub_query_apply(_pipe@13, Qry@2)
    end,
    Prp_stm@5.

-spec join_apply(cake@internal@prepared_statement:prepared_statement(), join()) -> cake@internal@prepared_statement:prepared_statement().
join_apply(Prp_stm, Jn) ->
    case erlang:element(2, Jn) of
        {join_table, Tbl} ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(
                _pipe,
                <<<<Tbl/binary, " AS "/utf8>>/binary,
                    (erlang:element(3, Jn))/binary>>
            );

        {join_sub_query, Qry} ->
            _pipe@1 = Prp_stm,
            _pipe@2 = cake@internal@prepared_statement:append_sql(
                _pipe@1,
                <<"("/utf8>>
            ),
            _pipe@3 = apply(_pipe@2, Qry),
            cake@internal@prepared_statement:append_sql(
                _pipe@3,
                <<") AS "/utf8, (erlang:element(3, Jn))/binary>>
            )
    end.

-spec where_logical_operator_apply(
    cake@internal@prepared_statement:prepared_statement(),
    binary(),
    list(where()),
    boolean()
) -> cake@internal@prepared_statement:prepared_statement().
where_logical_operator_apply(Prp_stm, Oprtr, Whs, Wrp_prns) ->
    Prp_stm@1 = case Wrp_prns of
        true ->
            _pipe = Prp_stm,
            cake@internal@prepared_statement:append_sql(_pipe, <<"("/utf8>>);

        false ->
            Prp_stm
    end,
    Prp_stm@2 = begin
        _pipe@1 = Whs,
        gleam@list:fold(
            _pipe@1,
            Prp_stm@1,
            fun(New_prp_stm, Wh) -> case New_prp_stm =:= Prp_stm@1 of
                    true ->
                        _pipe@2 = New_prp_stm,
                        where_apply(_pipe@2, Wh);

                    false ->
                        _pipe@3 = New_prp_stm,
                        _pipe@4 = cake@internal@prepared_statement:append_sql(
                            _pipe@3,
                            <<<<" "/utf8, Oprtr/binary>>/binary, " "/utf8>>
                        ),
                        where_apply(_pipe@4, Wh)
                end end
        )
    end,
    Prp_stm@3 = case Wrp_prns of
        true ->
            _pipe@5 = Prp_stm@2,
            cake@internal@prepared_statement:append_sql(_pipe@5, <<")"/utf8>>);

        false ->
            Prp_stm@2
    end,
    Prp_stm@3.

-spec where_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where()
) -> cake@internal@prepared_statement:prepared_statement().
where_apply(Prp_stm, Wh) ->
    case Wh of
        no_where ->
            Prp_stm;

        {and_where, Whs} ->
            _pipe = Prp_stm,
            where_logical_operator_apply(_pipe, <<"AND"/utf8>>, Whs, false);

        {or_where, Whs@1} ->
            _pipe@1 = Prp_stm,
            where_logical_operator_apply(_pipe@1, <<"OR"/utf8>>, Whs@1, true);

        {xor_where, Whs@2} ->
            _pipe@2 = Prp_stm,
            where_xor_apply(_pipe@2, Whs@2);

        {not_where, Wh@1} ->
            _pipe@3 = Prp_stm,
            _pipe@4 = cake@internal@prepared_statement:append_sql(
                _pipe@3,
                <<"NOT("/utf8>>
            ),
            _pipe@5 = where_apply(_pipe@4, Wh@1),
            cake@internal@prepared_statement:append_sql(_pipe@5, <<")"/utf8>>);

        {where_is_bool, Val, true} ->
            _pipe@6 = Prp_stm,
            where_literal_apply(_pipe@6, Val, <<"IS TRUE"/utf8>>);

        {where_is_bool, Val@1, false} ->
            _pipe@7 = Prp_stm,
            where_literal_apply(_pipe@7, Val@1, <<"IS FALSE"/utf8>>);

        {where_is_not_bool, Val@2, true} ->
            _pipe@8 = Prp_stm,
            where_literal_apply(_pipe@8, Val@2, <<"IS NOT TRUE"/utf8>>);

        {where_is_not_bool, Val@3, false} ->
            _pipe@9 = Prp_stm,
            where_literal_apply(_pipe@9, Val@3, <<"IS NOT FALSE"/utf8>>);

        {where_is_null, Val@4} ->
            _pipe@10 = Prp_stm,
            where_literal_apply(_pipe@10, Val@4, <<"IS NULL"/utf8>>);

        {where_is_not_null, Val@5} ->
            _pipe@11 = Prp_stm,
            where_literal_apply(_pipe@11, Val@5, <<"IS NOT NULL"/utf8>>);

        {where_comparison, Val_a, equal, Val_b} ->
            _pipe@12 = Prp_stm,
            where_comparison_apply(_pipe@12, Val_a, <<"="/utf8>>, Val_b);

        {where_comparison, Val_a@1, greater, Val_b@1} ->
            _pipe@13 = Prp_stm,
            where_comparison_apply(_pipe@13, Val_a@1, <<">"/utf8>>, Val_b@1);

        {where_comparison, Val_a@2, greater_or_equal, Val_b@2} ->
            _pipe@14 = Prp_stm,
            where_comparison_apply(_pipe@14, Val_a@2, <<">="/utf8>>, Val_b@2);

        {where_comparison, Val_a@3, lower, Val_b@3} ->
            _pipe@15 = Prp_stm,
            where_comparison_apply(_pipe@15, Val_a@3, <<"<"/utf8>>, Val_b@3);

        {where_comparison, Val_a@4, lower_or_equal, Val_b@4} ->
            _pipe@16 = Prp_stm,
            where_comparison_apply(_pipe@16, Val_a@4, <<"<="/utf8>>, Val_b@4);

        {where_comparison, Val_a@5, unequal, Val_b@5} ->
            _pipe@17 = Prp_stm,
            where_comparison_apply(_pipe@17, Val_a@5, <<"<>"/utf8>>, Val_b@5);

        {where_any_of_sub_query, Val@6, equal, Qry} ->
            _pipe@18 = Prp_stm,
            _pipe@19 = where_literal_apply(_pipe@18, Val@6, <<"= ANY"/utf8>>),
            where_sub_query_apply(_pipe@19, Qry);

        {where_any_of_sub_query, Val@7, greater, Qry@1} ->
            _pipe@20 = Prp_stm,
            _pipe@21 = where_literal_apply(_pipe@20, Val@7, <<"> ANY"/utf8>>),
            where_sub_query_apply(_pipe@21, Qry@1);

        {where_any_of_sub_query, Val@8, greater_or_equal, Qry@2} ->
            _pipe@22 = Prp_stm,
            _pipe@23 = where_literal_apply(_pipe@22, Val@8, <<">= ANY"/utf8>>),
            where_sub_query_apply(_pipe@23, Qry@2);

        {where_any_of_sub_query, Val@9, lower, Qry@3} ->
            _pipe@24 = Prp_stm,
            _pipe@25 = where_literal_apply(_pipe@24, Val@9, <<"< ANY"/utf8>>),
            where_sub_query_apply(_pipe@25, Qry@3);

        {where_any_of_sub_query, Val@10, lower_or_equal, Qry@4} ->
            _pipe@26 = Prp_stm,
            _pipe@27 = where_literal_apply(_pipe@26, Val@10, <<"<= ANY"/utf8>>),
            where_sub_query_apply(_pipe@27, Qry@4);

        {where_any_of_sub_query, Val@11, unequal, Qry@5} ->
            _pipe@28 = Prp_stm,
            _pipe@29 = where_literal_apply(_pipe@28, Val@11, <<"<> ANY"/utf8>>),
            where_sub_query_apply(_pipe@29, Qry@5);

        {where_all_of_sub_query, Val@12, equal, Qry@6} ->
            _pipe@30 = Prp_stm,
            _pipe@31 = where_literal_apply(_pipe@30, Val@12, <<"= ALL"/utf8>>),
            where_sub_query_apply(_pipe@31, Qry@6);

        {where_all_of_sub_query, Val@13, greater, Qry@7} ->
            _pipe@32 = Prp_stm,
            _pipe@33 = where_literal_apply(_pipe@32, Val@13, <<"> ALL"/utf8>>),
            where_sub_query_apply(_pipe@33, Qry@7);

        {where_all_of_sub_query, Val@14, greater_or_equal, Qry@8} ->
            _pipe@34 = Prp_stm,
            _pipe@35 = where_literal_apply(_pipe@34, Val@14, <<">= ALL"/utf8>>),
            where_sub_query_apply(_pipe@35, Qry@8);

        {where_all_of_sub_query, Val@15, lower, Qry@9} ->
            _pipe@36 = Prp_stm,
            _pipe@37 = where_literal_apply(_pipe@36, Val@15, <<"< ALL"/utf8>>),
            where_sub_query_apply(_pipe@37, Qry@9);

        {where_all_of_sub_query, Val@16, lower_or_equal, Qry@10} ->
            _pipe@38 = Prp_stm,
            _pipe@39 = where_literal_apply(_pipe@38, Val@16, <<"<= ALL"/utf8>>),
            where_sub_query_apply(_pipe@39, Qry@10);

        {where_all_of_sub_query, Val@17, unequal, Qry@11} ->
            _pipe@40 = Prp_stm,
            _pipe@41 = where_literal_apply(_pipe@40, Val@17, <<"<> ALL"/utf8>>),
            where_sub_query_apply(_pipe@41, Qry@11);

        {where_between, Val_a@6, Val_b@6, Val_c} ->
            _pipe@42 = Prp_stm,
            where_between_apply(_pipe@42, Val_a@6, Val_b@6, Val_c);

        {where_in, Val@18, Vals} ->
            _pipe@43 = Prp_stm,
            where_value_in_values_apply(_pipe@43, Val@18, Vals);

        {where_exists_in_sub_query, Qry@12} ->
            _pipe@44 = Prp_stm,
            _pipe@45 = cake@internal@prepared_statement:append_sql(
                _pipe@44,
                <<" EXISTS "/utf8>>
            ),
            where_sub_query_apply(_pipe@45, Qry@12);

        {where_like, Val@19, Prm} ->
            _pipe@46 = Prp_stm,
            where_comparison_apply(
                _pipe@46,
                Val@19,
                <<"LIKE"/utf8>>,
                begin
                    _pipe@47 = Prm,
                    _pipe@48 = {string_param, _pipe@47},
                    {where_param_value, _pipe@48}
                end
            );

        {where_i_like, Val@20, Prm@1} ->
            _pipe@49 = Prp_stm,
            where_comparison_apply(
                _pipe@49,
                Val@20,
                <<"ILIKE"/utf8>>,
                begin
                    _pipe@50 = Prm@1,
                    _pipe@51 = {string_param, _pipe@50},
                    {where_param_value, _pipe@51}
                end
            );

        {where_similar_to, Val@21, Prm@2, Ecp_chr} ->
            _pipe@52 = Prp_stm,
            _pipe@55 = where_comparison_apply(
                _pipe@52,
                Val@21,
                <<"SIMILAR TO"/utf8>>,
                begin
                    _pipe@53 = Prm@2,
                    _pipe@54 = {string_param, _pipe@53},
                    {where_param_value, _pipe@54}
                end
            ),
            cake@internal@prepared_statement:append_sql(
                _pipe@55,
                <<<<" ESCAPE '"/utf8, Ecp_chr/binary>>/binary, "'"/utf8>>
            );

        {where_fragment, Fragment} ->
            _pipe@56 = Prp_stm,
            fragment_apply(_pipe@56, Fragment)
    end.

-spec where_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where()
) -> cake@internal@prepared_statement:prepared_statement().
where_clause_apply(Prp_stm, Wh) ->
    case Wh of
        no_where ->
            Prp_stm;

        _ ->
            _pipe = Prp_stm,
            _pipe@1 = cake@internal@prepared_statement:append_sql(
                _pipe,
                <<" WHERE "/utf8>>
            ),
            where_apply(_pipe@1, Wh)
    end.

-spec having_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    where()
) -> cake@internal@prepared_statement:prepared_statement().
having_clause_apply(Prp_stm, Wh) ->
    case Wh of
        no_where ->
            Prp_stm;

        _ ->
            _pipe = Prp_stm,
            _pipe@1 = cake@internal@prepared_statement:append_sql(
                _pipe,
                <<" HAVING "/utf8>>
            ),
            where_apply(_pipe@1, Wh)
    end.

-spec custom_where_xor_apply(
    cake@internal@prepared_statement:prepared_statement(),
    list(where())
) -> cake@internal@prepared_statement:prepared_statement().
custom_where_xor_apply(Prp_stm, Whs) ->
    Xor_idxs = begin
        _pipe = Whs,
        _pipe@1 = erlang:length(_pipe),
        _pipe@2 = gleam@int:subtract(_pipe@1, 1),
        gleam@list:range(0, _pipe@2)
    end,
    Prp_stm@1 = begin
        _pipe@3 = Prp_stm,
        cake@internal@prepared_statement:append_sql(_pipe@3, <<"("/utf8>>)
    end,
    Prp_stm@2 = begin
        _pipe@4 = Xor_idxs,
        gleam@list:fold(
            _pipe@4,
            Prp_stm@1,
            fun(New_prp_stm, Xor_idx) ->
                New_prp_stm@1 = case New_prp_stm =:= Prp_stm@1 of
                    true ->
                        New_prp_stm;

                    false ->
                        _pipe@5 = New_prp_stm,
                        cake@internal@prepared_statement:append_sql(
                            _pipe@5,
                            <<") OR ("/utf8>>
                        )
                end,
                {New_prp_stm@2, _} = begin
                    _pipe@6 = Whs,
                    gleam@list:fold(
                        _pipe@6,
                        {New_prp_stm@1, 0},
                        fun(Acc, Wh) ->
                            {New_prp_stm_per_xor, Wh_idx} = Acc,
                            New_prp_stm_per_xor@1 = case {Wh_idx =:= Xor_idx,
                                Wh_idx} of
                                {true, 0} ->
                                    _pipe@7 = New_prp_stm_per_xor,
                                    where_apply(_pipe@7, Wh);

                                {true, _} ->
                                    _pipe@8 = New_prp_stm_per_xor,
                                    _pipe@9 = cake@internal@prepared_statement:append_sql(
                                        _pipe@8,
                                        <<" AND ("/utf8>>
                                    ),
                                    _pipe@10 = where_apply(_pipe@9, Wh),
                                    cake@internal@prepared_statement:append_sql(
                                        _pipe@10,
                                        <<")"/utf8>>
                                    );

                                {false, 0} ->
                                    _pipe@11 = New_prp_stm_per_xor,
                                    _pipe@12 = cake@internal@prepared_statement:append_sql(
                                        _pipe@11,
                                        <<"NOT("/utf8>>
                                    ),
                                    _pipe@13 = where_apply(_pipe@12, Wh),
                                    cake@internal@prepared_statement:append_sql(
                                        _pipe@13,
                                        <<")"/utf8>>
                                    );

                                {false, _} ->
                                    _pipe@14 = New_prp_stm_per_xor,
                                    _pipe@15 = cake@internal@prepared_statement:append_sql(
                                        _pipe@14,
                                        <<" AND NOT("/utf8>>
                                    ),
                                    _pipe@16 = where_apply(_pipe@15, Wh),
                                    cake@internal@prepared_statement:append_sql(
                                        _pipe@16,
                                        <<")"/utf8>>
                                    )
                            end,
                            {New_prp_stm_per_xor@1, Wh_idx + 1}
                        end
                    )
                end,
                New_prp_stm@2
            end
        )
    end,
    Prp_stm@3 = begin
        _pipe@17 = Prp_stm@2,
        cake@internal@prepared_statement:append_sql(_pipe@17, <<")"/utf8>>)
    end,
    Prp_stm@3.

-spec vanilla_where_xor_apply(
    cake@internal@prepared_statement:prepared_statement(),
    list(where())
) -> cake@internal@prepared_statement:prepared_statement().
vanilla_where_xor_apply(Prp_stm, Whs) ->
    Prp_stm@1 = begin
        _pipe = Prp_stm,
        cake@internal@prepared_statement:append_sql(_pipe, <<"("/utf8>>)
    end,
    _pipe@1 = Whs,
    _pipe@5 = gleam@list:fold(
        _pipe@1,
        Prp_stm@1,
        fun(New_prp_stm, Wh) -> case New_prp_stm =:= Prp_stm@1 of
                true ->
                    _pipe@2 = New_prp_stm,
                    where_apply(_pipe@2, Wh);

                false ->
                    _pipe@3 = New_prp_stm,
                    _pipe@4 = cake@internal@prepared_statement:append_sql(
                        _pipe@3,
                        <<" XOR "/utf8>>
                    ),
                    where_apply(_pipe@4, Wh)
            end end
    ),
    cake@internal@prepared_statement:append_sql(_pipe@5, <<")"/utf8>>).

-spec where_xor_apply(
    cake@internal@prepared_statement:prepared_statement(),
    list(where())
) -> cake@internal@prepared_statement:prepared_statement().
where_xor_apply(Prp_stm, Whs) ->
    case begin
        _pipe = Prp_stm,
        cake@internal@prepared_statement:get_dialect(_pipe)
    end of
        postgres ->
            custom_where_xor_apply(Prp_stm, Whs);

        sqlite ->
            custom_where_xor_apply(Prp_stm, Whs);

        maria ->
            vanilla_where_xor_apply(Prp_stm, Whs);

        mysql ->
            vanilla_where_xor_apply(Prp_stm, Whs)
    end.

-spec join_clause_apply(
    cake@internal@prepared_statement:prepared_statement(),
    joins()
) -> cake@internal@prepared_statement:prepared_statement().
join_clause_apply(Prp_stm, Jns) ->
    case Jns of
        {joins, Jns@1} ->
            _pipe = Jns@1,
            gleam@list:fold(
                _pipe,
                Prp_stm,
                fun(New_prp_stm, Jn) ->
                    Join_command_apply = 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_apply(_pipe@2, Jn)
                    end,
                    On_apply = 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_apply(_pipe@4, On)
                    end,
                    case Jn of
                        {inner_join, _, _, On@1} ->
                            _pipe@5 = New_prp_stm,
                            _pipe@6 = Join_command_apply(
                                _pipe@5,
                                <<"INNER JOIN"/utf8>>
                            ),
                            On_apply(_pipe@6, On@1);

                        {inner_join_lateral_on_true, _, _} ->
                            _pipe@7 = New_prp_stm,
                            _pipe@8 = Join_command_apply(
                                _pipe@7,
                                <<"INNER JOIN LATERAL"/utf8>>
                            ),
                            cake@internal@prepared_statement:append_sql(
                                _pipe@8,
                                <<" ON TRUE"/utf8>>
                            );

                        {left_join, _, _, On@2} ->
                            _pipe@9 = New_prp_stm,
                            _pipe@10 = Join_command_apply(
                                _pipe@9,
                                <<"LEFT OUTER JOIN"/utf8>>
                            ),
                            On_apply(_pipe@10, On@2);

                        {left_join_lateral_on_true, _, _} ->
                            _pipe@11 = New_prp_stm,
                            _pipe@12 = Join_command_apply(
                                _pipe@11,
                                <<"LEFT JOIN LATERAL"/utf8>>
                            ),
                            cake@internal@prepared_statement:append_sql(
                                _pipe@12,
                                <<" ON TRUE"/utf8>>
                            );

                        {right_join, _, _, On@3} ->
                            _pipe@13 = New_prp_stm,
                            _pipe@14 = Join_command_apply(
                                _pipe@13,
                                <<"RIGHT OUTER JOIN"/utf8>>
                            ),
                            On_apply(_pipe@14, On@3);

                        {full_join, _, _, On@4} ->
                            _pipe@15 = New_prp_stm,
                            _pipe@16 = Join_command_apply(
                                _pipe@15,
                                <<"FULL OUTER JOIN"/utf8>>
                            ),
                            On_apply(_pipe@16, On@4);

                        {cross_join, _, _} ->
                            _pipe@17 = New_prp_stm,
                            Join_command_apply(_pipe@17, <<"CROSS JOIN"/utf8>>);

                        {cross_join_lateral, _, _} ->
                            _pipe@18 = New_prp_stm,
                            Join_command_apply(
                                _pipe@18,
                                <<"CROSS JOIN LATERAL"/utf8>>
                            )
                    end
                end
            );

        no_joins ->
            Prp_stm
    end.
