From dc0484894a9372c653cbca1d42f0facfdd73ab61 Mon Sep 17 00:00:00 2001 From: Jacob Wang Date: Sat, 9 Sep 2023 22:39:13 +0100 Subject: [PATCH] Fix fragment helpers to handle fragments without spaces at the end (i.e. fr0, sql interpolator) Fixes #1909 --- .../main/scala/doobie/util/fragments.scala | 10 +- .../scala/doobie/util/FragmentsSuite.scala | 96 +++++++++---------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/modules/core/src/main/scala/doobie/util/fragments.scala b/modules/core/src/main/scala/doobie/util/fragments.scala index ece78b72e..5177cb50a 100644 --- a/modules/core/src/main/scala/doobie/util/fragments.scala +++ b/modules/core/src/main/scala/doobie/util/fragments.scala @@ -23,14 +23,14 @@ object fragments { /** 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")))) + 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-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)" }))) + parentheses(f ++ fr" IN" ++ parentheses(comma(fs.map { case (a,b) => fr0"($a,$b)" }))) /** Returns `(f NOT IN (fs0, fs1, ...))`. */ def notIn[A: util.Put](f: Fragment, fs0: A, fs1: A, fs: A*): Fragment = @@ -38,7 +38,7 @@ object fragments { /** 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")))) + 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] = { @@ -52,7 +52,7 @@ object fragments { /** 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") + val expr = fs.nonEmptyIntercalate(fr" AND") if (withParen) parentheses(expr) else expr } @@ -79,7 +79,7 @@ object fragments { * * @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") + val expr = fs.nonEmptyIntercalate(fr" OR") if (withParen) parentheses(expr) else expr } diff --git a/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala b/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala index 0b59748ee..6ba9e8e71 100644 --- a/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala +++ b/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala @@ -24,12 +24,12 @@ class FragmentsSuite extends munit.FunSuite { 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 nel1 = NonEmptyList.of(1).map(i => sql"$i") + val nel = NonEmptyList.of(1,2,3).map(i => sql"$i") val fs = nel.toList - val someF: Option[Fragment] = Some(fr"${1}") + val someF: Option[Fragment] = Some(sql"${1}") val noneF: Option[Fragment] = None - val ofs = List(Some(fr"${1}"), None, Some(fr"${3}")) + val ofs = List(Some(sql"${1}"), None, Some(sql"${3}")) test("values for one column") { assertEquals(values(nelInt).query[Unit].sql, "VALUES (?) , (?) , (?) ") @@ -40,59 +40,59 @@ class FragmentsSuite extends munit.FunSuite { } test("in (1-column varargs)") { - assertEquals(in(fr"foo", 1,2,3).query[Unit].sql, "(foo IN (? , ? , ? ) ) ") + assertEquals(in(sql"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 (? , ? , ? ) ) ") + assertEquals(in(sql"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) + assertEquals(inOpt(sql"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 (? , ? , ? ) ) ")) + assertEquals(inOpt(sql"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 ((?,?), (?,?)) ) ") + assertEquals(in(sql"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 (? , ? , ? ) ) ") + assertEquals(notIn(sql"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 (? ) ) ") + assertEquals(notIn(sql"foo", NonEmptyList.of(1)).query[Unit].sql, "(foo NOT IN (? ) ) ") } test("notIn (Reducible many)") { - assertEquals(notIn(fr"foo", nelInt).query[Unit].sql, "(foo NOT IN (? , ? , ? ) ) ") + assertEquals(notIn(sql"foo", nelInt).query[Unit].sql, "(foo NOT IN (? , ? , ? ) ) ") } test("notInOpt (Foldable empty)") { - assertEquals(notInOpt(fr"foo", List.empty[Int]).map(_.query[Unit].sql), None) + assertEquals(notInOpt(sql"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 (? ) ) ")) + assertEquals(notInOpt(sql"foo", List(1)).map(_.query[Unit].sql), Some("(foo NOT IN (? ) ) ")) } test("notInOpt (Foldable many)") { - assertEquals(notInOpt(fr"foo", listInt).map(_.query[Unit].sql), Some("(foo NOT IN (? , ? , ? ) ) ")) + assertEquals(notInOpt(sql"foo", listInt).map(_.query[Unit].sql), Some("(foo NOT IN (? , ? , ? ) ) ")) } test("and (vararg 2)") { - assertEquals(and(fs(0), fs(1)).query[Unit].sql, "(? AND ? ) ") + assertEquals(and(fs(0), fs(1)).query[Unit].sql, "(? AND ?) ") } test("and (Reducible 1)") { - assertEquals(and(nel1).query[Unit].sql, "(? ) ") + assertEquals(and(nel1).query[Unit].sql, "(?) ") } test("and (Reducible many)") { - assertEquals(and(nel).query[Unit].sql, "(? AND ? AND ? ) ") + assertEquals(and(nel).query[Unit].sql, "(? AND ? AND ?) ") } test("andOpt (vararg many none)") { @@ -100,11 +100,11 @@ class FragmentsSuite extends munit.FunSuite { } test("andOpt (vararg 1 Some)") { - assertEquals(andOpt(noneF, someF).map(_.query[Unit].sql), Some("(? ) ")) + assertEquals(andOpt(noneF, someF).map(_.query[Unit].sql), Some("(?) ")) } test("andOpt (vararg 2 Some)") { - assertEquals(andOpt(someF, someF).map(_.query[Unit].sql), Some("(? AND ? ) ")) + assertEquals(andOpt(someF, someF).map(_.query[Unit].sql), Some("(? AND ?) ")) } test("andOpt (Foldable empty)") { @@ -112,11 +112,11 @@ class FragmentsSuite extends munit.FunSuite { } test("andOpt (Foldable 1)") { - assertEquals(andOpt(nel.take(1)).map(_.query[Unit].sql), Some("(? ) ")) + assertEquals(andOpt(nel.take(1)).map(_.query[Unit].sql), Some("(?) ")) } test("andOpt (Foldable many)") { - assertEquals(andOpt(nel.toList).map(_.query[Unit].sql), Some("(? AND ? AND ? ) ")) + assertEquals(andOpt(nel.toList).map(_.query[Unit].sql), Some("(? AND ? AND ?) ")) } test("andOpt (list empty)") { @@ -128,19 +128,19 @@ class FragmentsSuite extends munit.FunSuite { } test("andFallbackTrue (many)") { - assertEquals(andFallbackTrue(fs).query[Unit].sql, "(? AND ? AND ? ) ") + assertEquals(andFallbackTrue(fs).query[Unit].sql, "(? AND ? AND ?) ") } test("or (vararg 2)") { - assertEquals(or(fs(0), fs(1)).query[Unit].sql, "(? OR ? ) ") + assertEquals(or(fs(0), fs(1)).query[Unit].sql, "(? OR ?) ") } test("or (Reducible 1)") { - assertEquals(or(nel1).query[Unit].sql, "(? ) ") + assertEquals(or(nel1).query[Unit].sql, "(?) ") } test("or (Reducible many)") { - assertEquals(or(nel).query[Unit].sql, "(? OR ? OR ? ) ") + assertEquals(or(nel).query[Unit].sql, "(? OR ? OR ?) ") } test("orOpt (vararg many none)") { @@ -148,11 +148,11 @@ class FragmentsSuite extends munit.FunSuite { } test("orOpt (vararg 1 Some)") { - assertEquals(orOpt(noneF, someF).map(_.query[Unit].sql), 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 ? ) ")) + assertEquals(orOpt(someF, someF).map(_.query[Unit].sql), Some("(? OR ?) ")) } test("orOpt (Foldable empty)") { @@ -160,11 +160,11 @@ class FragmentsSuite extends munit.FunSuite { } test("orOpt (Foldable 1)") { - assertEquals(orOpt(nel.take(1)).map(_.query[Unit].sql), Some("(? ) ")) + assertEquals(orOpt(nel.take(1)).map(_.query[Unit].sql), Some("(?) ")) } test("orOpt (Foldable many)") { - assertEquals(orOpt(nel.toList).map(_.query[Unit].sql), Some("(? OR ? OR ? ) ")) + assertEquals(orOpt(nel.toList).map(_.query[Unit].sql), Some("(? OR ? OR ?) ")) } test("orOpt (list empty)") { @@ -176,31 +176,31 @@ class FragmentsSuite extends munit.FunSuite { } test("orFallbackFalse (many)") { - assertEquals(orFallbackFalse(fs).query[Unit].sql, "(? OR ? OR ? ) ") + assertEquals(orFallbackFalse(fs).query[Unit].sql, "(? OR ? OR ?) ") } test("whereAnd (varargs single)") { - assertEquals(whereAnd(fs(0)).query[Unit].sql, "WHERE ? ") + assertEquals(whereAnd(fs(0)).query[Unit].sql, "WHERE ?") } test("whereAnd (varargs many)") { - assertEquals(whereAnd(fs(0), fs(0), fs(0)).query[Unit].sql, "WHERE ? AND ? AND ? ") + 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 ? ") + assertEquals(whereAnd(nel1).query[Unit].sql, "WHERE ?") } test("whereAnd (Reducible many)") { - assertEquals(whereAnd(nel).query[Unit].sql, "WHERE ? AND ? AND ? ") + assertEquals(whereAnd(nel).query[Unit].sql, "WHERE ? AND ? AND ?") } test("whereAndOpt (varargs many Some)") { - assertEquals(whereAndOpt(someF, someF).query[Unit].sql, "WHERE ? AND ? ") + assertEquals(whereAndOpt(someF, someF).query[Unit].sql, "WHERE ? AND ?") } test("whereAndOpt (varargs 1 Some)") { - assertEquals(whereAndOpt(ofs(0)).query[Unit].sql, "WHERE ? ") + assertEquals(whereAndOpt(ofs(0)).query[Unit].sql, "WHERE ?") } test("whereAndOpt (varargs all none)") { @@ -212,31 +212,31 @@ class FragmentsSuite extends munit.FunSuite { } test("whereAndOpt (Foldable many)") { - assertEquals(whereAndOpt(fs).query[Unit].sql, "WHERE ? AND ? AND ? ") + assertEquals(whereAndOpt(fs).query[Unit].sql, "WHERE ? AND ? AND ?") } test("whereOr (varargs single)") { - assertEquals(whereOr(fs(0)).query[Unit].sql, "WHERE ? ") + 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 ? ") + assertEquals(whereOr(fs(0), fs(0), fs(0)).query[Unit].sql, "WHERE ? OR ? OR ?") } test("whereOr (Reducible 1)") { - assertEquals(whereOr(nel1).query[Unit].sql, "WHERE ? ") + assertEquals(whereOr(nel1).query[Unit].sql, "WHERE ?") } test("whereOr (Reducible many)") { - assertEquals(whereOr(nel).query[Unit].sql, "WHERE ? OR ? OR ? ") + assertEquals(whereOr(nel).query[Unit].sql, "WHERE ? OR ? OR ?") } test("whereOrOpt (varargs many Some)") { - assertEquals(whereOrOpt(someF, someF).query[Unit].sql, "WHERE ? OR ? ") + assertEquals(whereOrOpt(someF, someF).query[Unit].sql, "WHERE ? OR ?") } test("whereOrOpt (varargs 1 Some)") { - assertEquals(whereOrOpt(ofs(0)).query[Unit].sql, "WHERE ? ") + assertEquals(whereOrOpt(ofs(0)).query[Unit].sql, "WHERE ?") } test("whereOrOpt (varargs all none)") { @@ -248,7 +248,7 @@ class FragmentsSuite extends munit.FunSuite { } test("whereOrOpt (Foldable many)") { - assertEquals(whereOrOpt(fs).query[Unit].sql, "WHERE ? OR ? OR ? ") + assertEquals(whereOrOpt(fs).query[Unit].sql, "WHERE ? OR ? OR ?") } test("orderBy (varargs 1)") { @@ -284,7 +284,7 @@ class FragmentsSuite extends munit.FunSuite { } 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 ) ") + assertEquals(whereAndOpt(Some(sql"hi"), orOpt(List.empty[Fragment]), orOpt(List(sql"a", sql"b"))).query[Unit].sql, "WHERE hi AND (a OR b) ") } case class Person(name: String, age: Int) @@ -292,13 +292,13 @@ class FragmentsSuite extends munit.FunSuite { test("values (1)") { val c = Contact(Person("Bob", 42), Some("addr")) - val f = fr"select" ++ Fragments.values(c) + val f = sql"select" ++ Fragments.values(c) assertEquals(f.query[Contact].unique.transact(xa).unsafeRunSync(), c) } test("values (2)") { val c = Contact(Person("Bob", 42), None) - val f = fr"select" ++ Fragments.values(c) + val f = sql"select" ++ Fragments.values(c) assertEquals(f.query[Contact].unique.transact(xa).unsafeRunSync(), c) }