-module(cake@internal@write_query). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([to_prepared_statement/3]). -export_type([write_query/1, returning/0, insert/1, insert_into_table/0, insert_columns/0, insert_modifier/0, insert_source/1, insert_row/0, insert_value/0, insert_conflict_strategy/1, insert_confict_target/0, update/1, update_modifier/0, update_table/0, update_sets/0, update_set/0, delete/1, delete_modifier/0, delete_table/0, delete_using/0]). -type write_query(QDA) :: {insert_query, insert(QDA)} | {update_query, update(QDA)} | {delete_query, delete(QDA)}. -type returning() :: no_returning | {returning, list(binary())}. -type insert(QDB) :: {insert, insert_into_table(), insert_columns(), insert_modifier(), insert_source(QDB), insert_conflict_strategy(QDB), returning(), cake@internal@query:epilog(), cake@internal@query:comment()}. -type insert_into_table() :: no_insert_into_table | {insert_into_table, binary()}. -type insert_columns() :: no_insert_columns | {insert_columns, list(binary())}. -type insert_modifier() :: no_insert_modifier | {insert_modifier, binary()}. -type insert_source(QDC) :: no_insert_source | insert_source_default | {insert_source_records, list(QDC), fun((QDC) -> insert_row())} | {insert_source_rows, list(insert_row())} | {insert_source_query, cake@internal@query:'query'()}. -type insert_row() :: {insert_row, list(insert_value())}. -type insert_value() :: {insert_param, binary(), cake@internal@param:param()} | {insert_default, binary()}. -type insert_conflict_strategy(QDD) :: insert_conflict_error | {insert_conflict_ignore, insert_confict_target(), cake@internal@query:where()} | {insert_conflict_update, insert_confict_target(), cake@internal@query:where(), update(QDD)}. -type insert_confict_target() :: {insert_conflict_target, list(binary())} | {insert_conflict_target_constraint, binary()}. -type update(QDE) :: {update, update_table(), update_modifier(), update_sets(), cake@internal@query:from(), cake@internal@query:joins(), cake@internal@query:where(), returning(), cake@internal@query:epilog(), cake@internal@query:comment()} | {gleam_phantom, QDE}. -type update_modifier() :: no_update_modifier | {update_modifier, binary()}. -type update_table() :: no_update_table | {update_table, binary()}. -type update_sets() :: no_update_sets | {update_sets, list(update_set())}. -type update_set() :: {update_param_set, binary(), cake@internal@param:param()} | {update_expression_set, list(binary()), binary()} | {update_sub_query_set, list(binary()), cake@internal@query:'query'()}. -type delete(QDF) :: {delete, delete_modifier(), delete_table(), delete_using(), cake@internal@query:joins(), cake@internal@query:where(), returning(), cake@internal@query:epilog(), cake@internal@query:comment()} | {gleam_phantom, QDF}. -type delete_modifier() :: no_delete_modifier | {delete_modifier, binary()}. -type delete_table() :: no_delete_table | {delete_table, binary()}. -type delete_using() :: no_delete_using | {delete_using, list(cake@internal@query:from())}. -spec returning_apply( cake@internal@prepared_statement:prepared_statement(), returning() ) -> cake@internal@prepared_statement:prepared_statement(). returning_apply(Prp_stm, Rtrn) -> case Rtrn of no_returning -> Prp_stm; {returning, Cols} -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql( _pipe, <<" RETURNING "/utf8>> ), cake@internal@prepared_statement:append_sql( _pipe@1, begin _pipe@2 = Cols, gleam@string:join(_pipe@2, <<", "/utf8>>) end ) end. -spec insert_into_table_apply( cake@internal@prepared_statement:prepared_statement(), insert_into_table() ) -> cake@internal@prepared_statement:prepared_statement(). insert_into_table_apply(Prp_stm, Tbl) -> case Tbl of no_insert_into_table -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<"INSERT INTO"/utf8>> ); {insert_into_table, Tbl_name} -> _pipe@1 = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe@1, <<"INSERT INTO "/utf8, Tbl_name/binary>> ) end. -spec insert_columns_apply( cake@internal@prepared_statement:prepared_statement(), insert_columns() ) -> cake@internal@prepared_statement:prepared_statement(). insert_columns_apply(Prp_stm, Cols) -> case Cols of no_insert_columns -> Prp_stm; {insert_columns, Cols@1} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<<<" ("/utf8, (begin _pipe@1 = Cols@1, gleam@string:join(_pipe@1, <<", "/utf8>>) end)/binary>>/binary, ")"/utf8>> ) end. -spec insert_modifier_apply( cake@internal@prepared_statement:prepared_statement(), insert_modifier() ) -> cake@internal@prepared_statement:prepared_statement(). insert_modifier_apply(Prp_stm, Isrt_mdfr) -> case Isrt_mdfr of no_insert_modifier -> Prp_stm; {insert_modifier, Mdfr} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" "/utf8, Mdfr/binary>> ) end. -spec row_apply( cake@internal@prepared_statement:prepared_statement(), list(insert_value()) ) -> cake@internal@prepared_statement:prepared_statement(). row_apply(New_prp_stm, Row) -> _pipe = Row, gleam@list:fold( _pipe, New_prp_stm, fun(New_prp_stm_inner, Insert_value) -> case Insert_value of {insert_param, _, Param} -> case New_prp_stm_inner =:= New_prp_stm of true -> _pipe@1 = New_prp_stm_inner, cake@internal@prepared_statement:append_param( _pipe@1, Param ); false -> _pipe@2 = New_prp_stm_inner, _pipe@3 = cake@internal@prepared_statement:append_sql( _pipe@2, <<", "/utf8>> ), cake@internal@prepared_statement:append_param( _pipe@3, Param ) end; {insert_default, _} -> case New_prp_stm_inner =:= New_prp_stm of true -> _pipe@4 = New_prp_stm_inner, cake@internal@prepared_statement:append_sql( _pipe@4, <<"DEFAULT"/utf8>> ); false -> _pipe@5 = New_prp_stm_inner, cake@internal@prepared_statement:append_sql( _pipe@5, <<", DEFAULT"/utf8>> ) end end end ). -spec insert_from_params_apply( cake@internal@prepared_statement:prepared_statement(), list(QDP), fun((QDP) -> insert_row()) ) -> cake@internal@prepared_statement:prepared_statement(). insert_from_params_apply(Prp_stm, Src, Cstr) -> Prp_stm@1 = begin _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, <<" ("/utf8>>) end, Prp_stm@2 = begin _pipe@1 = Src, gleam@list:fold( _pipe@1, Prp_stm@1, fun(New_prp_stm, Rcrd) -> {insert_row, Row} = begin _pipe@2 = Rcrd, Cstr(_pipe@2) end, case New_prp_stm =:= Prp_stm@1 of true -> _pipe@3 = New_prp_stm, row_apply(_pipe@3, Row); false -> _pipe@4 = New_prp_stm, _pipe@5 = cake@internal@prepared_statement:append_sql( _pipe@4, <<"), ("/utf8>> ), row_apply(_pipe@5, Row) end end ) end, Prp_stm@3 = begin _pipe@6 = Prp_stm@2, cake@internal@prepared_statement:append_sql(_pipe@6, <<")"/utf8>>) end, Prp_stm@3. -spec insert_from_values_apply( cake@internal@prepared_statement:prepared_statement(), list(insert_row()) ) -> cake@internal@prepared_statement:prepared_statement(). insert_from_values_apply(Prp_stm, Src) -> Prp_stm@1 = begin _pipe = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe, <<" ("/utf8>>) end, Prp_stm@2 = begin _pipe@1 = Src, gleam@list:fold( _pipe@1, Prp_stm@1, fun(New_prp_stm, Row) -> {insert_row, Row@1} = Row, case New_prp_stm =:= Prp_stm@1 of true -> _pipe@2 = New_prp_stm, row_apply(_pipe@2, Row@1); false -> _pipe@3 = New_prp_stm, _pipe@4 = cake@internal@prepared_statement:append_sql( _pipe@3, <<"), ("/utf8>> ), row_apply(_pipe@4, Row@1) end end ) end, Prp_stm@3 = begin _pipe@5 = Prp_stm@2, cake@internal@prepared_statement:append_sql(_pipe@5, <<")"/utf8>>) end, Prp_stm@3. -spec insert_from_query_apply( cake@internal@prepared_statement:prepared_statement(), cake@internal@query:'query'() ) -> cake@internal@prepared_statement:prepared_statement(). insert_from_query_apply(Prp_stm, Qry) -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql(_pipe, <<" ("/utf8>>), _pipe@2 = cake@internal@query:apply(_pipe@1, Qry), cake@internal@prepared_statement:append_sql(_pipe@2, <<")"/utf8>>). -spec insert_source_apply( cake@internal@prepared_statement:prepared_statement(), insert_source(any()) ) -> cake@internal@prepared_statement:prepared_statement(). insert_source_apply(Prp_stm, Src) -> case Src of no_insert_source -> Prp_stm; {insert_source_records, Src@1, Cstr} -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql( _pipe, <<" VALUES"/utf8>> ), insert_from_params_apply(_pipe@1, Src@1, Cstr); {insert_source_rows, Src@2} -> _pipe@2 = Prp_stm, _pipe@3 = cake@internal@prepared_statement:append_sql( _pipe@2, <<" VALUES"/utf8>> ), insert_from_values_apply(_pipe@3, Src@2); {insert_source_query, Qry} -> _pipe@4 = Prp_stm, _pipe@5 = cake@internal@prepared_statement:append_sql( _pipe@4, <<" VALUES"/utf8>> ), insert_from_query_apply(_pipe@5, Qry); insert_source_default -> _pipe@6 = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe@6, <<" DEFAULT VALUES"/utf8>> ) end. -spec insert_on_conflict_target_apply( cake@internal@prepared_statement:prepared_statement(), insert_confict_target() ) -> cake@internal@prepared_statement:prepared_statement(). insert_on_conflict_target_apply(Prp_stm, Cflt_trgt) -> case Cflt_trgt of {insert_conflict_target, Cols} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, begin _pipe@1 = Cols, gleam@string:join(_pipe@1, <<", "/utf8>>) end ); {insert_conflict_target_constraint, Cnstrnt} -> _pipe@2 = Prp_stm, cake@internal@prepared_statement:append_sql(_pipe@2, Cnstrnt) end. -spec update_table_apply( cake@internal@prepared_statement:prepared_statement(), update_table() ) -> cake@internal@prepared_statement:prepared_statement(). update_table_apply(Prp_stm, Tbl) -> case Tbl of no_update_table -> Prp_stm; {update_table, Tbl@1} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" "/utf8, Tbl@1/binary>> ) end. -spec update_modifier_apply( cake@internal@prepared_statement:prepared_statement(), update_modifier() ) -> cake@internal@prepared_statement:prepared_statement(). update_modifier_apply(Prp_stm, Updt_mdfr) -> case Updt_mdfr of no_update_modifier -> Prp_stm; {update_modifier, Mdfr} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" "/utf8, Mdfr/binary>> ) end. -spec update_sets_apply( cake@internal@prepared_statement:prepared_statement(), list(update_set()) ) -> cake@internal@prepared_statement:prepared_statement(). update_sets_apply(Prp_stm, Updt_sts) -> Apply_columns = fun(New_prp_stm, Cols) -> case Cols of [] -> New_prp_stm; [Col] -> _pipe = New_prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<<<" "/utf8, Col/binary>>/binary, " ="/utf8>> ); [_ | _] -> _pipe@1 = New_prp_stm, _pipe@3 = cake@internal@prepared_statement:append_sql( _pipe@1, <<<<" ("/utf8, (begin _pipe@2 = Cols, gleam@string:join(_pipe@2, <<", "/utf8>>) end)/binary>>/binary, ")"/utf8>> ), cake@internal@prepared_statement:append_sql( _pipe@3, <<" ="/utf8>> ) end end, _pipe@4 = Updt_sts, gleam@list:fold( _pipe@4, Prp_stm, fun(New_prp_stm@1, Updt_st) -> New_prp_stm@2 = case New_prp_stm@1 =:= Prp_stm of true -> New_prp_stm@1; false -> _pipe@5 = New_prp_stm@1, cake@internal@prepared_statement:append_sql( _pipe@5, <<","/utf8>> ) end, case Updt_st of {update_param_set, Col@1, Prm} -> _pipe@6 = New_prp_stm@2, _pipe@7 = Apply_columns(_pipe@6, [Col@1]), _pipe@8 = cake@internal@prepared_statement:append_sql( _pipe@7, <<" "/utf8>> ), cake@internal@prepared_statement:append_param(_pipe@8, Prm); {update_expression_set, Cols@1, Expr} -> _pipe@9 = New_prp_stm@2, _pipe@10 = Apply_columns(_pipe@9, Cols@1), cake@internal@prepared_statement:append_sql( _pipe@10, <<" "/utf8, Expr/binary>> ); {update_sub_query_set, Cols@2, Qry} -> _pipe@11 = New_prp_stm@2, _pipe@12 = Apply_columns(_pipe@11, Cols@2), _pipe@13 = cake@internal@prepared_statement:append_sql( _pipe@12, <<" ("/utf8>> ), _pipe@14 = cake@internal@query:apply(_pipe@13, Qry), cake@internal@prepared_statement:append_sql( _pipe@14, <<")"/utf8>> ) end end ). -spec update_set_apply( cake@internal@prepared_statement:prepared_statement(), update_sets() ) -> cake@internal@prepared_statement:prepared_statement(). update_set_apply(Prp_stm, Updt_sts) -> case Updt_sts of no_update_sets -> Prp_stm; {update_sets, Updt_sets} -> _pipe = Prp_stm, update_sets_apply(_pipe, Updt_sets) end. -spec update_apply( cake@internal@prepared_statement:prepared_statement(), update(any()) ) -> cake@internal@prepared_statement:prepared_statement(). update_apply(Prp_stm, Updt) -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql( _pipe, <<"UPDATE"/utf8>> ), _pipe@2 = update_table_apply(_pipe@1, erlang:element(2, Updt)), _pipe@3 = update_modifier_apply(_pipe@2, erlang:element(3, Updt)), _pipe@4 = cake@internal@prepared_statement:append_sql( _pipe@3, <<" SET"/utf8>> ), _pipe@5 = update_set_apply(_pipe@4, erlang:element(4, Updt)), _pipe@6 = cake@internal@query:from_clause_apply( _pipe@5, erlang:element(5, Updt) ), _pipe@7 = cake@internal@query:join_clause_apply( _pipe@6, erlang:element(6, Updt) ), _pipe@8 = cake@internal@query:where_clause_apply( _pipe@7, erlang:element(7, Updt) ), _pipe@9 = returning_apply(_pipe@8, erlang:element(8, Updt)), _pipe@10 = cake@internal@query:comment_apply( _pipe@9, erlang:element(10, Updt) ), cake@internal@query:epilog_apply(_pipe@10, erlang:element(9, Updt)). -spec insert_on_conflict_apply( cake@internal@prepared_statement:prepared_statement(), insert_conflict_strategy(any()) ) -> cake@internal@prepared_statement:prepared_statement(). insert_on_conflict_apply(Prp_stm, On_cnf) -> case On_cnf of insert_conflict_error -> Prp_stm; {insert_conflict_ignore, Cflt_trgt, Whr} -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql( _pipe, <<" ON CONFLICT"/utf8>> ), _pipe@2 = insert_on_conflict_target_apply(_pipe@1, Cflt_trgt), _pipe@3 = cake@internal@query:where_clause_apply(_pipe@2, Whr), cake@internal@prepared_statement:append_sql( _pipe@3, <<" DO NOTHING"/utf8>> ); {insert_conflict_update, Cflt_trgt@1, Whr@1, Upt} -> _pipe@4 = Prp_stm, _pipe@5 = cake@internal@prepared_statement:append_sql( _pipe@4, <<" ON CONFLICT ("/utf8>> ), _pipe@6 = insert_on_conflict_target_apply(_pipe@5, Cflt_trgt@1), _pipe@7 = cake@internal@query:where_clause_apply(_pipe@6, Whr@1), _pipe@8 = cake@internal@prepared_statement:append_sql( _pipe@7, <<" DO "/utf8>> ), update_apply(_pipe@8, Upt) end. -spec insert_apply( cake@internal@prepared_statement:prepared_statement(), insert(any()) ) -> cake@internal@prepared_statement:prepared_statement(). insert_apply(Prp_stm, Isrt) -> _pipe = Prp_stm, _pipe@1 = insert_into_table_apply(_pipe, erlang:element(2, Isrt)), _pipe@2 = insert_columns_apply(_pipe@1, erlang:element(3, Isrt)), _pipe@3 = insert_modifier_apply(_pipe@2, erlang:element(4, Isrt)), _pipe@4 = insert_source_apply(_pipe@3, erlang:element(5, Isrt)), _pipe@5 = insert_on_conflict_apply(_pipe@4, erlang:element(6, Isrt)), _pipe@6 = returning_apply(_pipe@5, erlang:element(7, Isrt)), _pipe@7 = cake@internal@query:comment_apply( _pipe@6, erlang:element(9, Isrt) ), cake@internal@query:epilog_apply(_pipe@7, erlang:element(8, Isrt)). -spec delete_table_apply( cake@internal@prepared_statement:prepared_statement(), delete_table() ) -> cake@internal@prepared_statement:prepared_statement(). delete_table_apply(Prp_stm, Tbl) -> case Tbl of no_delete_table -> Prp_stm; {delete_table, Tbl@1} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" FROM "/utf8, Tbl@1/binary>> ) end. -spec delete_modifier_apply( cake@internal@prepared_statement:prepared_statement(), delete_modifier() ) -> cake@internal@prepared_statement:prepared_statement(). delete_modifier_apply(Prp_stm, Updt_mdfr) -> case Updt_mdfr of no_delete_modifier -> Prp_stm; {delete_modifier, Mdfr} -> _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" "/utf8, Mdfr/binary>> ) end. -spec using_apply( cake@internal@prepared_statement:prepared_statement(), delete_using() ) -> cake@internal@prepared_statement:prepared_statement(). using_apply(Prp_stm, Updt_usng) -> case Updt_usng of no_delete_using -> Prp_stm; {delete_using, Frms} -> Prp_stm@1 = begin _pipe = Prp_stm, cake@internal@prepared_statement:append_sql( _pipe, <<" USING "/utf8>> ) end, _pipe@1 = Frms, gleam@list:fold( _pipe@1, Prp_stm@1, fun(New_prp_stm, Frm) -> New_prp_stm@1 = case {New_prp_stm =:= Prp_stm@1, Frm} of {true, _} -> New_prp_stm; {_, no_from} -> New_prp_stm; {false, _} -> _pipe@2 = New_prp_stm, cake@internal@prepared_statement:append_sql( _pipe@2, <<", "/utf8>> ) end, case Frm of no_from -> New_prp_stm@1; {from_table, Tbl} -> _pipe@3 = New_prp_stm@1, cake@internal@prepared_statement:append_sql( _pipe@3, Tbl ); {from_sub_query, Qry, Als} -> _pipe@4 = Prp_stm@1, _pipe@5 = cake@internal@prepared_statement:append_sql( _pipe@4, <<" ("/utf8>> ), _pipe@6 = cake@internal@query:apply(_pipe@5, Qry), cake@internal@prepared_statement:append_sql( _pipe@6, <<") AS "/utf8, Als/binary>> ) end end ) end. -spec delete_apply( cake@internal@prepared_statement:prepared_statement(), delete(any()) ) -> cake@internal@prepared_statement:prepared_statement(). delete_apply(Prp_stm, Dlt) -> _pipe = Prp_stm, _pipe@1 = cake@internal@prepared_statement:append_sql( _pipe, <<"DELETE"/utf8>> ), _pipe@2 = delete_table_apply(_pipe@1, erlang:element(3, Dlt)), _pipe@3 = delete_modifier_apply(_pipe@2, erlang:element(2, Dlt)), _pipe@4 = using_apply(_pipe@3, erlang:element(4, Dlt)), _pipe@5 = cake@internal@query:join_clause_apply( _pipe@4, erlang:element(5, Dlt) ), _pipe@6 = cake@internal@query:where_clause_apply( _pipe@5, erlang:element(6, Dlt) ), _pipe@7 = returning_apply(_pipe@6, erlang:element(7, Dlt)), _pipe@8 = cake@internal@query:comment_apply(_pipe@7, erlang:element(9, Dlt)), cake@internal@query:epilog_apply(_pipe@8, erlang:element(8, Dlt)). -spec apply( cake@internal@prepared_statement:prepared_statement(), write_query(any()) ) -> cake@internal@prepared_statement:prepared_statement(). apply(Prp_stm, Qry) -> case Qry of {insert_query, Insert} -> _pipe = Prp_stm, insert_apply(_pipe, Insert); {update_query, Update} -> _pipe@1 = Prp_stm, update_apply(_pipe@1, Update); {delete_query, Delete} -> _pipe@2 = Prp_stm, delete_apply(_pipe@2, Delete) end. -spec to_prepared_statement( write_query(any()), 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).