diff --git a/src/cake.gleam b/src/cake.gleam index a1cbde0..1c288ef 100644 --- a/src/cake.gleam +++ b/src/cake.gleam @@ -90,7 +90,7 @@ pub fn run_dummy_union_all() { // |> query.select_query_order_asc("name") let union_query = - query.union_all_query_new([select_query_a, select_query_b]) + query.union_except_query_new([select_query_a, select_query_b]) // |> query.union_set_limit(1) |> query.query_union_wrap |> iox.dbg diff --git a/src/cake/internal/query.gleam b/src/cake/internal/query.gleam index 887f7f8..f233211 100644 --- a/src/cake/internal/query.gleam +++ b/src/cake/internal/query.gleam @@ -1,8 +1,5 @@ import cake/stdlib/iox -type EpilogPart = - String - // —————————————————————————————————————————————————————————————————————————— // // ———— Query ——————————————————————————————————————————————————————————————— // // —————————————————————————————————————————————————————————————————————————— // @@ -25,85 +22,90 @@ pub fn query_union_wrap(qry: UnionQuery) -> Query { // —————————————————————————————————————————————————————————————————————————— // pub type UnionKind { - All - Distinct - Except - Intersect + UnionAll + UnionDistinct + UnionExcept + UnionIntersect } // List of SQL parts that will be used to build a union query. pub type UnionQuery { - // unify and have a kind key that is All or Distinct - UnionDistinctQuery( - select_queries: List(SelectQuery), - limit_offset: LimitOffsetPart, - // Epilog allows you to append raw SQL to the end of queries. - // You should never put raw user data into epilog. - epilog: EpilogPart, - ) - UnionAllQuery( + UnionQuery( + union_kind: UnionKind, select_queries: List(SelectQuery), limit_offset: LimitOffsetPart, + // order_by: List(OrderByPart), // Epilog allows you to append raw SQL to the end of queries. // You should never put raw user data into epilog. epilog: EpilogPart, ) - // TODO: also takes order_by, limit, offset // TODO: order_by of contained selects must be stripped } pub fn union_distinct_query_new( select_queries slct_qrys: List(SelectQuery), ) -> UnionQuery { - UnionDistinctQuery( + UnionQuery( + union_kind: UnionDistinct, select_queries: slct_qrys, limit_offset: NoLimitOffset, - epilog: "", + epilog: NoEpilogPart, ) } pub fn union_all_query_new( select_queries slct_qrys: List(SelectQuery), ) -> UnionQuery { - UnionAllQuery( + UnionQuery( + union_kind: UnionAll, select_queries: slct_qrys, limit_offset: NoLimitOffset, - epilog: "", + epilog: NoEpilogPart, + ) +} + +pub fn union_except_query_new( + select_queries slct_qrys: List(SelectQuery), +) -> UnionQuery { + UnionQuery( + union_kind: UnionExcept, + select_queries: slct_qrys, + limit_offset: NoLimitOffset, + epilog: NoEpilogPart, + ) +} + +pub fn union_intersect_query_new( + select_queries slct_qrys: List(SelectQuery), +) -> UnionQuery { + UnionQuery( + union_kind: UnionIntersect, + select_queries: slct_qrys, + limit_offset: NoLimitOffset, + epilog: NoEpilogPart, ) } pub fn union_get_select_queries(union_query uq: UnionQuery) -> List(SelectQuery) { - case uq { - // TODO: UNION vs UNION ALL vs EXCEPT vs INTERSECT - UnionDistinctQuery( - select_queries: slct_qrys, - limit_offset: _lmt_offst, - epilog: _epl, - ) -> slct_qrys - UnionAllQuery( - select_queries: slct_qrys, - limit_offset: _lmt_offst, - epilog: _epl, - ) -> slct_qrys - } + uq.select_queries } -// pub fn union_query_set_limit( -// query qry: UnionQuery, -// limit lmt: Int, -// ) -> UnionQuery { -// let limit_offset = limit_new(lmt) -// UnionQuery(..qry, limit_offset: limit_offset) -// } +pub fn union_query_set_limit( + query qry: UnionQuery, + limit lmt: Int, +) -> UnionQuery { + let limit_offset = limit_new(lmt) + UnionQuery(..qry, limit_offset: limit_offset) +} -// pub fn union_query_set_limit_and_offset( -// query qry: UnionQuery, -// limit lmt: Int, -// offset offst: Int, -// ) -> UnionQuery { -// let limit_offset = limit_offset_new(limit: lmt, offset: offst) -// UnionQuery(..qry, limit_offset: limit_offset) -// } +pub fn union_query_set_limit_and_offset( + query qry: UnionQuery, + limit lmt: Int, + offset offst: Int, +) -> UnionQuery { + let limit_offset = limit_offset_new(limit: lmt, offset: offst) + UnionQuery(..qry, limit_offset: limit_offset) +} // —————————————————————————————————————————————————————————————————————————— // // ———— SelectQuery ————————————————————————————————————————————————————————— // @@ -128,6 +130,7 @@ pub type SelectQuery { // use order_by, limit and offset, possibly make them real types, too // at least alias them order_by: List(#(String, OrderByDirectionPart)), + epilog: EpilogPart, ) } @@ -143,6 +146,7 @@ pub fn select_query_new( where: NoWherePart, order_by: [], limit_offset: NoLimitOffset, + epilog: NoEpilogPart, ) } @@ -153,6 +157,7 @@ pub fn select_query_new_from(from from: FromPart) -> SelectQuery { where: NoWherePart, order_by: [], limit_offset: NoLimitOffset, + epilog: NoEpilogPart, ) } @@ -163,6 +168,7 @@ pub fn select_query_new_select(select select: List(SelectPart)) -> SelectQuery { where: NoWherePart, order_by: [], limit_offset: NoLimitOffset, + epilog: NoEpilogPart, ) } @@ -618,3 +624,29 @@ pub fn limit_offset_apply( pub fn limit_offset_get(select_query slct_qry: SelectQuery) -> LimitOffsetPart { slct_qry.limit_offset } + +// —————————————————————————————————————————————————————————————————————————— // +// ———— Epilog Part ————————————————————————————————————————————————————————— // +// —————————————————————————————————————————————————————————————————————————— // + +pub opaque type EpilogPart { + Epilog(string: String) + NoEpilogPart +} + +pub fn epilog_new(epilog: String) -> EpilogPart { + case epilog { + "" -> NoEpilogPart + _ -> Epilog(string: epilog) + } +} + +pub fn epilog_apply( + prepared_statement prp_stm: PreparedStatement, + epilog_part epl_prt: EpilogPart, +) -> PreparedStatement { + case epl_prt { + NoEpilogPart -> prp_stm + Epilog(string: epl) -> epl |> prepared_statement.with_sql(prp_stm, _) + } +} diff --git a/src/cake/prepared_statement_builder/select_builder.gleam b/src/cake/prepared_statement_builder/select_builder.gleam index 0f39be4..f885cca 100644 --- a/src/cake/prepared_statement_builder/select_builder.gleam +++ b/src/cake/prepared_statement_builder/select_builder.gleam @@ -71,9 +71,8 @@ fn maybe_add_limit_offset( prepared_statement prp_stm: PreparedStatement, select_query slct_qry: SelectQuery, ) -> PreparedStatement { - let lmt_offst = - query.limit_offset_get(slct_qry) - |> iox.dbg_label("lmt_offst") + let lmt_offst = query.limit_offset_get(slct_qry) + // |> iox.dbg_label("lmt_offst") prp_stm |> query.limit_offset_apply(lmt_offst) diff --git a/src/cake/prepared_statement_builder/union_builder.gleam b/src/cake/prepared_statement_builder/union_builder.gleam index f1f6d69..bc82d5b 100644 --- a/src/cake/prepared_statement_builder/union_builder.gleam +++ b/src/cake/prepared_statement_builder/union_builder.gleam @@ -1,5 +1,6 @@ import cake/internal/query.{ - type SelectQuery, type UnionQuery, UnionAllQuery, UnionDistinctQuery, + type SelectQuery, type UnionQuery, UnionAll, UnionDistinct, UnionExcept, + UnionIntersect, } import cake/prepared_statement.{type PreparedStatement} import cake/prepared_statement_builder/select_builder @@ -22,20 +23,14 @@ pub fn apply_sql( prepared_statement prp_stm: PreparedStatement, select uq: UnionQuery, ) -> PreparedStatement { - let #(union_keyword, slct_qrys, lmt_offst, epl) = case uq { - UnionDistinctQuery( - select_queries: slct_qrys, - limit_offset: lmt_offst, - epilog: epl, - ) -> #("UNION", slct_qrys, lmt_offst, epl) - UnionAllQuery( - select_queries: slct_qrys, - limit_offset: lmt_offst, - epilog: epl, - ) -> #("UNION ALL", slct_qrys, lmt_offst, epl) + let union_keyword = case uq.union_kind { + UnionAll -> "UNION ALL" + UnionDistinct -> "UNION" + UnionExcept -> "EXCEPT" + UnionIntersect -> "INTERSECT" } - slct_qrys + uq.select_queries |> list.fold( prp_stm, fn(acc: PreparedStatement, sq: SelectQuery) -> PreparedStatement { @@ -49,6 +44,6 @@ pub fn apply_sql( } }, ) - |> query.limit_offset_apply(lmt_offst) - |> prepared_statement.with_sql(" " <> epl) + |> query.limit_offset_apply(uq.limit_offset) + |> query.epilog_apply(uq.epilog) }