diff --git a/modules/core/src/main/scala/doobie/util/fragments.scala b/modules/core/src/main/scala/doobie/util/fragments.scala index ece78b72e..8101a644b 100644 --- a/modules/core/src/main/scala/doobie/util/fragments.scala +++ b/modules/core/src/main/scala/doobie/util/fragments.scala @@ -7,7 +7,7 @@ package util import cats.data.NonEmptyList import cats.syntax.all._ -import cats.{Foldable, Functor, Reducible} +import cats.{Foldable, Reducible} import doobie.implicits._ /** Module of `Fragment` constructors. */ @@ -19,126 +19,89 @@ object fragments { /** Returns `(f IN (fs0, fs1, ...))`. */ def in[A: util.Put](f: Fragment, fs0: A, fs1: A, fs: A*): Fragment = - in(f, NonEmptyList(fs0, fs1 :: fs.toList)) + in(f, fs0 :: fs1 :: fs.toList) - /** Returns `(f IN (fs0, fs1, ...))`, or `false` for empty `fs`. */ - def in[F[_]: Reducible: Functor, A: util.Put](f: Fragment, fs: F[A]): Fragment = - parentheses(f ++ fr"IN" ++ parentheses(comma(fs.map(a => fr"$a")))) - - def inOpt[F[_]: Foldable, A: util.Put](f: Fragment, fs: F[A]): Option[Fragment] = - NonEmptyList.fromFoldable(fs).map(nel => in(f, nel)) + /** Returns `(f IN (fs0, fs1, ...))`, or `false` for empty `fs` by default. */ + def in[F[_]: Foldable, A: util.Put](f: Fragment, fs: F[A], onEmpty: Boolean = false): Fragment = fs.toList.toNel match { + case Some(fs) => parentheses(f ++ fr"IN" ++ parentheses(comma(fs.map(a => fr"$a")))) + case None => fr"$onEmpty" + } - /** Returns `(f IN ((fs0-A, fs0-B), (fs1-A, fs1-B), ...))`, or `false` for empty `fs`. */ - def in[F[_]: Reducible: Functor, A: util.Put, B: util.Put](f: Fragment, fs: F[(A,B)]): Fragment = - parentheses(f ++ fr"IN" ++ parentheses(comma(fs.map { case (a,b) => fr0"($a,$b)" }))) + /** Returns `(f IN ((fs0-A, fs0-B), (fs1-A, fs1-B), ...))`, or `false` for empty `fs` by default. */ + def inPairs[F[_]: Foldable, A: util.Put, B: util.Put](f: Fragment, fs: F[(A,B)], onEmpty: Boolean = false): Fragment = fs.toList.toNel match { + case Some(fs) => parentheses(f ++ fr"IN" ++ parentheses(comma(fs.map { case (a,b) => fr0"($a,$b)" }))) + case None => fr"$onEmpty" + } /** Returns `(f NOT IN (fs0, fs1, ...))`. */ def notIn[A: util.Put](f: Fragment, fs0: A, fs1: A, fs: A*): Fragment = - notIn(f, NonEmptyList(fs0, fs1 :: fs.toList)) + notIn(f, fs0 :: fs1 :: fs.toList) - /** Returns `(f NOT IN (fs0, fs1, ...))`, or `true` for empty `fs`. */ - def notIn[F[_]: Reducible: Functor, A: util.Put](f: Fragment, fs: F[A]): Fragment = { - parentheses(f ++ fr"NOT IN" ++ parentheses(comma(fs.map(a => fr"$a")))) - } - - def notInOpt[F[_]: Foldable, A: util.Put](f: Fragment, fs: F[A]): Option[Fragment] = { - NonEmptyList.fromFoldable(fs).map(nel => notIn(f, nel)) + /** Returns `(f NOT IN (fs0, fs1, ...))`, or `true` for empty `fs` by default. */ + def notIn[F[_]: Foldable, A: util.Put](f: Fragment, fs: F[A], onEmpty: Boolean = true): Fragment = fs.toList.toNel match { + case Some(fs) => parentheses(f ++ fr"NOT IN" ++ parentheses(comma(fs.map(a => fr"$a")))) + case None => fr"$onEmpty" } - + /** Returns `(f1 AND f2 AND ... fn)`. */ def and(f1: Fragment, f2: Fragment, fs: Fragment*): Fragment = - and(NonEmptyList(f1, f2 :: fs.toList)) - - /** Returns `(f1 AND f2 AND ... fn)` for a non-empty collection. - * @param withParen If this is false, does not wrap the resulting expression with parenthesis */ - def and[F[_]: Reducible](fs: F[Fragment], withParen: Boolean = true): Fragment = { - val expr = fs.nonEmptyIntercalate(fr"AND") - if (withParen) parentheses(expr) else expr - } + and(f1 :: f2 :: fs.toList) - /** Returns `(f1 AND f2 AND ... fn)` for all defined fragments, returning None if there are no defined fragments */ - def andOpt(opt1: Option[Fragment], opt2: Option[Fragment], opts: Option[Fragment]*): Option[Fragment] = { - andOpt((opt1 :: opt2 :: opts.toList).flatten) + /** Returns `(f1 AND f2 AND ... fn)`, or `true` for empty `fs` by default. */ + def and[F[_]: Foldable](fs: F[Fragment], onEmpty: Boolean = true): Fragment = fs.toList.toNel match { + case Some(fs) => parentheses(fs.intercalate(fr"AND")) + case None => fr"$onEmpty" } - /** Returns `(f1 AND f2 AND ... fn)`, or None if the collection is empty. */ - def andOpt[F[_]: Foldable](fs: F[Fragment], withParen: Boolean = true): Option[Fragment] = { - NonEmptyList.fromFoldable(fs).map(nel => and(nel, withParen)) - } + /** Returns `(f1 AND f2 AND ... fn)` for all defined fragments. */ + def andOpt(f1: Option[Fragment], fs: Option[Fragment]*): Fragment = + and((f1 :: fs.toList).unite) - /** Similar to andOpt, but defaults to FALSE if passed an empty collection */ - def andFallbackTrue[F[_] : Foldable](fs: F[Fragment]): Fragment = { - andOpt(fs).getOrElse(fr"TRUE") - } + /** Returns `(f1 AND f2 AND ... fn)` for all defined fragments. */ + def andOpt[F[_]: Foldable](fs: F[Option[Fragment]], onEmpty: Boolean = true): Fragment = + and(fs.toList.unite, onEmpty) /** Returns `(f1 OR f2 OR ... fn)`. */ def or(f1: Fragment, f2: Fragment, fs: Fragment*): Fragment = - or(NonEmptyList(f1, f2 :: fs.toList)) - - /** Returns `(f1 OR f2 OR ... fn)` for a non-empty collection. - * - * @param withParen If this is false, does not wrap the resulting expression with parenthesis */ - def or[F[_] : Reducible](fs: F[Fragment], withParen: Boolean = true): Fragment = { - val expr = fs.nonEmptyIntercalate(fr"OR") - if (withParen) parentheses(expr) else expr - } + or(f1 :: f2 :: fs.toList) - /** Returns `(f1 OR f2 OR ... fn)` for all defined fragments, returning None if there are no defined fragments */ - def orOpt(opt1: Option[Fragment], opt2: Option[Fragment], opts: Option[Fragment]*): Option[Fragment] = { - orOpt((opt1 :: opt2 :: opts.toList).flatten) + /** Returns `(f1 OR f2 OR ... fn)`, or `false` for empty `fs` by default. */ + def or[F[_]: Foldable](fs: F[Fragment], onEmpty: Boolean = false): Fragment = fs.toList.toNel match { + case Some(fs) => parentheses(fs.intercalate(fr"OR")) + case None => fr"$onEmpty" } - /** Returns `(f1 OR f2 OR ... fn)`, or None if the collection is empty. */ - def orOpt[F[_]: Foldable](fs: F[Fragment], withParen: Boolean = true): Option[Fragment] = { - NonEmptyList.fromFoldable(fs).map(nel => or(nel, withParen)) - } - - /** Similar to orOpt, but defaults to FALSE if passed an empty collection */ - def orFallbackFalse[F[_]: Foldable](fs: F[Fragment]): Fragment = { - orOpt(fs).getOrElse(fr"FALSE") - } + /** Returns `(f1 OR f2 OR ... fn)` for all defined fragments. */ + def orOpt(f1: Option[Fragment], fs: Option[Fragment]*): Fragment = + or((f1 :: fs.toList).unite) + + /** Returns `(f1 OR f2 OR ... fn)` for all defined fragments. */ + def orOpt[F[_]: Foldable](fs: F[Option[Fragment]], onEmpty: Boolean = false): Fragment = + or(fs.toList.unite, onEmpty) /** Returns `WHERE f1 AND f2 AND ... fn`. */ def whereAnd(f1: Fragment, fs: Fragment*): Fragment = - whereAnd(NonEmptyList(f1,fs.toList)) + whereAnd(f1 :: fs.toList) /** Returns `WHERE f1 AND f2 AND ... fn` or the empty fragment if `fs` is empty. */ - def whereAnd[F[_]: Reducible](fs: F[Fragment]): Fragment = - fr"WHERE" ++ and(fs, withParen = false) + def whereAnd[F[_]: Foldable](fs: F[Fragment]): Fragment = + if (fs.isEmpty) Fragment.empty else fr"WHERE" ++ and(fs) /** Returns `WHERE f1 AND f2 AND ... fn` for defined `f`, if any, otherwise the empty fragment. */ - def whereAndOpt(f1: Option[Fragment], f2: Option[Fragment], fs: Option[Fragment]*): Fragment = { - whereAndOpt((f1 :: f2 :: fs.toList).flatten) - } - - /** Returns `WHERE f1 AND f2 AND ... fn` if collection is not empty. If collection is empty returns an empty fragment. */ - def whereAndOpt[F[_]: Foldable](fs: F[Fragment]): Fragment = { - NonEmptyList.fromFoldable(fs) match { - case Some(nel) => whereAnd(nel) - case None => Fragment.empty - } - } + def whereAndOpt(fs: Option[Fragment]*): Fragment = + whereAnd(fs.toList.unite) /** Returns `WHERE f1 OR f2 OR ... fn`. */ def whereOr(f1: Fragment, fs: Fragment*): Fragment = whereOr(NonEmptyList(f1, fs.toList)) /** Returns `WHERE f1 OR f2 OR ... fn` or the empty fragment if `fs` is empty. */ - def whereOr[F[_] : Reducible](fs: F[Fragment]): Fragment = - fr"WHERE" ++ or(fs, withParen = false) + def whereOr[F[_]: Foldable](fs: F[Fragment]): Fragment = + if (fs.isEmpty) Fragment.empty else fr"WHERE" ++ or(fs) /** Returns `WHERE f1 OR f2 OR ... fn` for defined `f`, if any, otherwise the empty fragment. */ - def whereOrOpt(f1: Option[Fragment], f2: Option[Fragment], fs: Option[Fragment]*): Fragment = { - whereOrOpt((f1 :: f2 :: fs.toList).flatten) - } - - /** Returns `WHERE f1 OR f2 OR ... fn` if collection is not empty. If collection is empty returns an empty fragment. */ - def whereOrOpt[F[_] : Foldable](fs: F[Fragment]): Fragment = { - NonEmptyList.fromFoldable(fs) match { - case Some(nel) => whereOr(nel) - case None => Fragment.empty - } - } + def whereOrOpt(fs: Option[Fragment]*): Fragment = + whereOr(fs.toList.unite) /** Returns `SET f1, f2, ... fn`. */ def set(f1: Fragment, fs: Fragment*): Fragment = @@ -160,24 +123,20 @@ object fragments { comma(NonEmptyList(f1, f2 :: fs.toList)) /** Returns `f1, f2, ... fn`. */ - def comma[F[_]: Reducible](fs: F[Fragment]): Fragment = - fs.nonEmptyIntercalate(fr",") + def comma[F[_]: Foldable](fs: F[Fragment]): Fragment = + fs.intercalate(fr",") /** Returns `ORDER BY f1, f2, ... fn`. */ def orderBy(f1: Fragment, fs: Fragment*): Fragment = - orderBy(NonEmptyList(f1, fs.toList)) - - def orderBy[F[_]: Reducible](fs: F[Fragment]): Fragment = - fr"ORDER BY" ++ comma(fs) + comma(NonEmptyList(f1, fs.toList)) /** Returns `ORDER BY f1, f2, ... fn` or the empty fragment if `fs` is empty. */ - def orderByOpt[F[_]: Foldable](fs: F[Fragment]): Fragment = - NonEmptyList.fromFoldable(fs) match { - case Some(nel) => orderBy(nel) - case None => Fragment.empty - } + def orderBy[F[_]: Foldable](fs: F[Fragment]): Fragment = fs.toList.toNel match { + case Some(fs) => fr"ORDER BY" ++ comma(fs) + case None => Fragment.empty + } /** Returns `ORDER BY f1, f2, ... fn` for defined `f`, if any, otherwise the empty fragment. */ - def orderByOpt(f1: Option[Fragment], f2: Option[Fragment], fs: Option[Fragment]*): Fragment = - orderByOpt((f1 :: f2 :: fs.toList).flatten) + def orderByOpt(fs: Option[Fragment]*): Fragment = + orderBy(fs.toList.unite) } diff --git a/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala b/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala index 0b59748ee..958ed93c6 100644 --- a/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala +++ b/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala @@ -17,276 +17,131 @@ class FragmentsSuite extends munit.FunSuite { val xa = Transactor.fromDriverManager[IO]( driver = "org.h2.Driver", url = "jdbc:h2:mem:queryspec;DB_CLOSE_DELAY=-1", - user = "sa", - password = "", + user = "sa", + password = "", logHandler = None ) - val nelInt = NonEmptyList.of(1,2,3) - val listInt = nelInt.toList - val nel1 = NonEmptyList.of(1).map(i => fr"$i") - val nel = NonEmptyList.of(1,2,3).map(i => fr"$i") - val fs = nel.toList - val someF: Option[Fragment] = Some(fr"${1}") - val noneF: Option[Fragment] = None - val ofs = List(Some(fr"${1}"), None, Some(fr"${3}")) + val nel = List(1,2,3).toNel.getOrElse(sys.error("unpossible")) + val fs = List(1,2,3).map(n => fr"$n") + val ofs = List(1,2,3).map(n => Some(fr"$n").filter(_ => n % 2 =!= 0)) test("values for one column") { - assertEquals(values(nelInt).query[Unit].sql, "VALUES (?) , (?) , (?) ") + assertEquals(values(nel).query[Unit].sql, "VALUES (?) , (?) , (?) ") } test("values for two columns") { assertEquals(values(NonEmptyList.of((1, true), (2, false))).query[Unit].sql, "VALUES (?,?) , (?,?) ") } - - test("in (1-column varargs)") { - assertEquals(in(fr"foo", 1,2,3).query[Unit].sql, "(foo IN (? , ? , ? ) ) ") - } - - test("in (1-column Reducible many)") { - assertEquals(in(fr"foo", nelInt).query[Unit].sql, "(foo IN (? , ? , ? ) ) ") - } - - test("inOpt (1-column Reducible empty)") { - assertEquals(inOpt(fr"foo", List.empty[Int]).map(_.query[Unit].sql), None) - } - - test("inOpt (1-column Reducible many)") { - assertEquals(inOpt(fr"foo", listInt).map(_.query[Unit].sql), Some("(foo IN (? , ? , ? ) ) ")) - } - - test("in (2-column varargs)") { - assertEquals(in(fr"foo", NonEmptyList.of((1, true), (2, false))).query[Unit].sql, "(foo IN ((?,?), (?,?)) ) ") - } - - test("notIn (varargs many)") { - assertEquals(notIn(fr"foo", 1, 2, 3).query[Unit].sql, "(foo NOT IN (? , ? , ? ) ) ") - } - test("notIn (Reducible 1)") { - assertEquals(notIn(fr"foo", NonEmptyList.of(1)).query[Unit].sql, "(foo NOT IN (? ) ) ") + test("in for one column") { + assertEquals(in(fr"foo", nel).query[Unit].sql, "(foo IN (? , ? , ? ) ) ") } - test("notIn (Reducible many)") { - assertEquals(notIn(fr"foo", nelInt).query[Unit].sql, "(foo NOT IN (? , ? , ? ) ) ") + test("in for two columns") { + assertEquals(inPairs(fr"foo", NonEmptyList.of((1, true), (2, false))).query[Unit].sql, "(foo IN ((?,?), (?,?)) ) ") } - test("notInOpt (Foldable empty)") { - assertEquals(notInOpt(fr"foo", List.empty[Int]).map(_.query[Unit].sql), None) - } - - test("notInOpt (Foldable 1)") { - assertEquals(notInOpt(fr"foo", List(1)).map(_.query[Unit].sql), Some("(foo NOT IN (? ) ) ")) + test("notIn") { + assertEquals(notIn(fr"foo", nel).query[Unit].sql, "(foo NOT IN (? , ? , ? ) ) ") } - test("notInOpt (Foldable many)") { - assertEquals(notInOpt(fr"foo", listInt).map(_.query[Unit].sql), Some("(foo NOT IN (? , ? , ? ) ) ")) + test("and (many)") { + assertEquals(and(fs).query[Unit].sql, "(? AND ? AND ? ) ") } - test("and (vararg 2)") { + test("and (two)") { assertEquals(and(fs(0), fs(1)).query[Unit].sql, "(? AND ? ) ") } - test("and (Reducible 1)") { - assertEquals(and(nel1).query[Unit].sql, "(? ) ") - } - - test("and (Reducible many)") { - assertEquals(and(nel).query[Unit].sql, "(? AND ? AND ? ) ") - } - - test("andOpt (vararg many none)") { - assertEquals(andOpt(None, None).map(_.query[Unit].sql), None) + test("and (empty)") { + assertEquals(and(List[Fragment]()).query[Unit].sql, "? ") } - test("andOpt (vararg 1 Some)") { - assertEquals(andOpt(noneF, someF).map(_.query[Unit].sql), Some("(? ) ")) + test("andOpt (many)") { + assertEquals(andOpt(ofs).query[Unit].sql, "(? AND ? ) ") } - test("andOpt (vararg 2 Some)") { - assertEquals(andOpt(someF, someF).map(_.query[Unit].sql), Some("(? AND ? ) ")) + test("andOpt (one)") { + assertEquals(andOpt(ofs(0)).query[Unit].sql, "(? ) ") } - test("andOpt (Foldable empty)") { - assertEquals(andOpt(List.empty[Fragment]).map(_.query[Unit].sql), None) + test("andOpt (none)") { + assertEquals(andOpt(None, None).query[Unit].sql, "? ") } - test("andOpt (Foldable 1)") { - assertEquals(andOpt(nel.take(1)).map(_.query[Unit].sql), Some("(? ) ")) + test("or (many)") { + assertEquals(or(fs).query[Unit].sql, "(? OR ? OR ? ) ") } - test("andOpt (Foldable many)") { - assertEquals(andOpt(nel.toList).map(_.query[Unit].sql), Some("(? AND ? AND ? ) ")) - } - - test("andOpt (list empty)") { - assertEquals(andOpt(List.empty[Fragment]).map(_.query[Unit].sql), None) - } - - test("andFallbackTrue (empty)") { - assertEquals(andFallbackTrue(List.empty[Fragment]).query[Unit].sql, "TRUE ") - } - - test("andFallbackTrue (many)") { - assertEquals(andFallbackTrue(fs).query[Unit].sql, "(? AND ? AND ? ) ") - } - - test("or (vararg 2)") { + test("or (two)") { assertEquals(or(fs(0), fs(1)).query[Unit].sql, "(? OR ? ) ") } - test("or (Reducible 1)") { - assertEquals(or(nel1).query[Unit].sql, "(? ) ") - } - - test("or (Reducible many)") { - assertEquals(or(nel).query[Unit].sql, "(? OR ? OR ? ) ") - } - - test("orOpt (vararg many none)") { - assertEquals(orOpt(None, None).map(_.query[Unit].sql), None) - } - - test("orOpt (vararg 1 Some)") { - assertEquals(orOpt(noneF, someF).map(_.query[Unit].sql), Some("(? ) ")) - } - - test("orOpt (vararg 2 Some)") { - assertEquals(orOpt(someF, someF).map(_.query[Unit].sql), Some("(? OR ? ) ")) + test("or (empty)") { + assertEquals(or(List[Fragment]()).query[Unit].sql, "? ") } - test("orOpt (Foldable empty)") { - assertEquals(orOpt(List.empty[Fragment]).map(_.query[Unit].sql), None) + test("orOpt (many)") { + assertEquals(orOpt(ofs).query[Unit].sql, "(? OR ? ) ") } - test("orOpt (Foldable 1)") { - assertEquals(orOpt(nel.take(1)).map(_.query[Unit].sql), Some("(? ) ")) + test("orOpt (one)") { + assertEquals(orOpt(ofs(0)).query[Unit].sql, "(? ) ") } - test("orOpt (Foldable many)") { - assertEquals(orOpt(nel.toList).map(_.query[Unit].sql), Some("(? OR ? OR ? ) ")) + test("orOpt (none)") { + assertEquals(orOpt(None, None).query[Unit].sql, "? ") } - test("orOpt (list empty)") { - assertEquals(orOpt(List.empty[Fragment]).map(_.query[Unit].sql), None) + test("whereAnd (many)") { + assertEquals(whereAnd(fs).query[Unit].sql, "WHERE (? AND ? AND ? ) ") } - test("orFallbackFalse (empty)") { - assertEquals(orFallbackFalse(List.empty[Fragment]).query[Unit].sql, "FALSE ") + test("whereAnd (single)") { + assertEquals(whereAnd(fs(0)).query[Unit].sql, "WHERE (? ) ") } - test("orFallbackFalse (many)") { - assertEquals(orFallbackFalse(fs).query[Unit].sql, "(? OR ? OR ? ) ") + test("whereAnd (empty)") { + assertEquals(whereAnd(List[Fragment]()).query[Unit].sql, "") } - test("whereAnd (varargs single)") { - assertEquals(whereAnd(fs(0)).query[Unit].sql, "WHERE ? ") + test("whereAndOpt (many)") { + assertEquals(whereAndOpt(ofs: _*).query[Unit].sql, "WHERE (? AND ? ) ") } - test("whereAnd (varargs many)") { - assertEquals(whereAnd(fs(0), fs(0), fs(0)).query[Unit].sql, "WHERE ? AND ? AND ? ") - } - - test("whereAnd (Reducible 1)") { - assertEquals(whereAnd(nel1).query[Unit].sql, "WHERE ? ") - } - - test("whereAnd (Reducible many)") { - assertEquals(whereAnd(nel).query[Unit].sql, "WHERE ? AND ? AND ? ") - } - - test("whereAndOpt (varargs many Some)") { - assertEquals(whereAndOpt(someF, someF).query[Unit].sql, "WHERE ? AND ? ") + test("whereAndOpt (one)") { + assertEquals(whereAndOpt(ofs(0)).query[Unit].sql, "WHERE (? ) ") } - test("whereAndOpt (varargs 1 Some)") { - assertEquals(whereAndOpt(ofs(0)).query[Unit].sql, "WHERE ? ") - } - - test("whereAndOpt (varargs all none)") { + test("whereAndOpt (none)") { assertEquals(whereAndOpt(None, None).query[Unit].sql, "") } - - test("whereAndOpt (Foldable empty)") { - assertEquals(whereAndOpt(List.empty[Fragment]).query[Unit].sql, "") - } - - test("whereAndOpt (Foldable many)") { - assertEquals(whereAndOpt(fs).query[Unit].sql, "WHERE ? AND ? AND ? ") - } - - test("whereOr (varargs single)") { - assertEquals(whereOr(fs(0)).query[Unit].sql, "WHERE ? ") - } - test("whereOr (varargs many)") { - assertEquals(whereOr(fs(0), fs(0), fs(0)).query[Unit].sql, "WHERE ? OR ? OR ? ") + test("whereOr (many)") { + assertEquals(whereOr(fs).query[Unit].sql, "WHERE (? OR ? OR ? ) ") } - test("whereOr (Reducible 1)") { - assertEquals(whereOr(nel1).query[Unit].sql, "WHERE ? ") + test("whereOr (single)") { + assertEquals(whereOr(fs(0)).query[Unit].sql, "WHERE (? ) ") } - test("whereOr (Reducible many)") { - assertEquals(whereOr(nel).query[Unit].sql, "WHERE ? OR ? OR ? ") + test("whereOr (empty)") { + assertEquals(whereOr(List[Fragment]()).query[Unit].sql, "") } - test("whereOrOpt (varargs many Some)") { - assertEquals(whereOrOpt(someF, someF).query[Unit].sql, "WHERE ? OR ? ") + test("whereOrOpt (many)") { + assertEquals(whereOrOpt(ofs: _*).query[Unit].sql, "WHERE (? OR ? ) ") } - test("whereOrOpt (varargs 1 Some)") { - assertEquals(whereOrOpt(ofs(0)).query[Unit].sql, "WHERE ? ") + test("whereOrOpt (one)") { + assertEquals(whereOrOpt(ofs(0)).query[Unit].sql, "WHERE (? ) ") } - test("whereOrOpt (varargs all none)") { + test("whereOrOpt (none)") { assertEquals(whereOrOpt(None, None).query[Unit].sql, "") } - test("whereOrOpt (Foldable empty)") { - assertEquals(whereOrOpt(List.empty[Fragment]).query[Unit].sql, "") - } - - test("whereOrOpt (Foldable many)") { - assertEquals(whereOrOpt(fs).query[Unit].sql, "WHERE ? OR ? OR ? ") - } - - test("orderBy (varargs 1)") { - assertEquals(orderBy(fr0"a").query[Unit].sql, "ORDER BY a") - } - - test("orderBy (varargs many)") { - assertEquals(orderBy(fr0"a", fr0"b").query[Unit].sql, "ORDER BY a, b") - } - - test("orderBy (Reducible 1)") { - assertEquals(orderBy(NonEmptyList.of(fr0"a")).query[Unit].sql, "ORDER BY a") - } - - test("orderBy (Reducible many)") { - assertEquals(orderBy(NonEmptyList.of(fr0"a", fr0"b")).query[Unit].sql, "ORDER BY a, b") - } - - test("orderByOpt (varargs Some many) ") { - assertEquals(orderByOpt(Some(fr0"a"), Some(fr0"b")).query[Unit].sql, "ORDER BY a, b") - } - - test("orderByOpt (varargs all None) ") { - assertEquals(orderByOpt(None, None).query[Unit].sql, "") - } - - test("orderByOpt (Foldable empty) ") { - assertEquals(orderByOpt(List.empty[Fragment]).query[Unit].sql, "") - } - - test("orderByOpt (Foldable many) ") { - assertEquals(orderByOpt(List(fr0"a", fr0"b")).query[Unit].sql, "ORDER BY a, b") - } - - test("Usage test: whereAndOpt") { - assertEquals(whereAndOpt(Some(fr"hi"), orOpt(List.empty[Fragment]), orOpt(List(fr"a", fr"b"))).query[Unit].sql, "WHERE hi AND (a OR b ) ") - } - case class Person(name: String, age: Int) case class Contact(person: Person, address: Option[String])