Skip to content

Commit

Permalink
Merge branch 'zio:master' into mysql-onconflict-update-with-renames
Browse files Browse the repository at this point in the history
  • Loading branch information
joelsonoda committed Jun 27, 2023
2 parents 234d718 + 872c797 commit 856b1bd
Show file tree
Hide file tree
Showing 27 changed files with 449 additions and 26 deletions.
7 changes: 4 additions & 3 deletions build.sbt
Expand Up @@ -276,7 +276,7 @@ lazy val `quill-engine` =
.settings(
libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.4.2",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.4",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5",
("com.github.takayahilton" %%% "sql-formatter" % "1.2.1").cross(CrossVersion.for3Use2_13),
"io.suzaku" %% "boopickle" % "1.4.0"
),
Expand Down Expand Up @@ -306,7 +306,7 @@ lazy val `quill-core` =
"dev.zio" %% "zio-logging" % "2.1.13",
"dev.zio" %% "zio" % Version.zio,
"dev.zio" %% "zio-streams" % Version.zio,
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.4"
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5"
)
)
.jvmSettings(
Expand Down Expand Up @@ -798,7 +798,8 @@ lazy val basicSettings = excludeFilterSettings ++ Seq(
"-unchecked",
"-Ywarn-dead-code",
"-Ywarn-numeric-widen",
"-Ywarn-value-discard"
"-Ywarn-value-discard",
"-Ypatmat-exhaust-depth", "40"
),
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
Expand Down
4 changes: 4 additions & 0 deletions docs/logging.md
Expand Up @@ -77,6 +77,10 @@ To enable that use `quill.binds.log` option:
```
java -Dquill.binds.log=true -jar myapp.jar
```
The option `quill.query.tooLong` restricts the maximum length of logged SQL statements:
```
java -Dquill.binds.log=true -Dquill.query.tooLong=10000 -jar myapp.jar
```

## Pretty Printing

Expand Down
4 changes: 2 additions & 2 deletions docs/writing-queries.md
Expand Up @@ -256,7 +256,7 @@ For example when we want to return information from records that are being updat
val desc = "Update Product"
val sku = 2002L
val q = quote {
query[Product].filter(p => p.id == 42).update(_.description = lift(desc), _.sku = lift(sku)).returning(r => (r.id, r.description))
query[Product].filter(p => p.id == 42).update(_.description -> lift(desc), _.sku -> lift(sku)).returning(r => (r.id, r.description))
}
val updated = ctx.run(q) //: (Int, String)
// Postgres
Expand Down Expand Up @@ -309,7 +309,7 @@ Return *all* the records that were updated.
val desc = "Update Product"
val sku = 2002L
val q = quote {
query[Product].filter(p => p.id == 42).update(_.description = lift(desc), _.sku = lift(sku)).returning(r => (r.id, r.description))
query[Product].filter(p => p.id == 42).update(_.description -> lift(desc), _.sku -> lift(sku)).returning(r => (r.id, r.description))
}
val updated = ctx.run(q) //: List[(Int, String)]
// Postgres
Expand Down
Expand Up @@ -52,6 +52,7 @@ trait Liftables extends QuatLiftable {
case OptionTableForall(a, b, c) => q"$pack.OptionTableForall($a,$b,$c)"
case OptionFlatten(a) => q"$pack.OptionFlatten($a)"
case OptionGetOrElse(a, b) => q"$pack.OptionGetOrElse($a,$b)"
case OptionOrElse(a, b) => q"$pack.OptionOrElse($a,$b)"
case OptionFlatMap(a, b, c) => q"$pack.OptionFlatMap($a,$b,$c)"
case OptionMap(a, b, c) => q"$pack.OptionMap($a,$b,$c)"
case OptionForall(a, b, c) => q"$pack.OptionForall($a,$b,$c)"
Expand Down
Expand Up @@ -14,7 +14,7 @@ import scala.collection.immutable.StringOps
import scala.reflect.macros.TypecheckException
import io.getquill.ast.Implicits._
import io.getquill.ast.Renameable.Fixed
import io.getquill.ast.Visibility.{Hidden, Visible}
import io.getquill.ast.Visibility.Visible
import io.getquill.quat._
import io.getquill.util.Messages.TraceType
import io.getquill.util.{Interleave, Interpolator, Messages}
Expand Down Expand Up @@ -588,6 +588,8 @@ trait Parsing extends ValueComputation with QuatMaking with MacroUtilBase {
OptionFlatten(astParser(o))
case q"$o.getOrElse[$t]($body)" if is[Option[Any]](o) =>
OptionGetOrElse(astParser(o), astParser(body))
case q"$o.orElse[$t]($body)" if is[Option[Any]](o) =>
OptionOrElse(astParser(o), astParser(body))
case q"$o.contains[$t]($body)" if is[Option[Any]](o) =>
OptionContains(astParser(o), astParser(body))
case q"$o.isEmpty" if is[Option[Any]](o) =>
Expand Down
Expand Up @@ -44,6 +44,7 @@ trait Unliftables extends QuatUnliftable {
case q"$pack.OptionTableForall.apply(${a: Ast}, ${b: Ident}, ${c: Ast})" => OptionTableForall(a, b, c)
case q"$pack.OptionFlatten.apply(${a: Ast})" => OptionFlatten(a)
case q"$pack.OptionGetOrElse.apply(${a: Ast}, ${b: Ast})" => OptionGetOrElse(a, b)
case q"$pack.OptionOrElse.apply(${a: Ast}, ${b: Ast})" => OptionOrElse(a, b)
case q"$pack.OptionFlatMap.apply(${a: Ast}, ${b: Ident}, ${c: Ast})" => OptionFlatMap(a, b, c)
case q"$pack.OptionMap.apply(${a: Ast}, ${b: Ident}, ${c: Ast})" => OptionMap(a, b, c)
case q"$pack.OptionForall.apply(${a: Ast}, ${b: Ident}, ${c: Ast})" => OptionForall(a, b, c)
Expand Down
Expand Up @@ -433,6 +433,14 @@ class StatefulTransformerSpec extends Spec {
att.state mustEqual List(Ident("a"), Ident("b"))
}
}
"orElse" in {
val ast: Ast = OptionOrElse(Ident("a"), Ident("b"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"))(ast) match {
case (at, att) =>
at mustEqual OptionOrElse(Ident("a'"), Ident("b'"))
att.state mustEqual List(Ident("a"), Ident("b"))
}
}
"flatMap - Unchecked" in {
val ast: Ast = OptionTableFlatMap(Ident("a"), Ident("b"), Ident("c"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) match {
Expand Down
Expand Up @@ -284,6 +284,11 @@ class StatelessTransformerSpec extends Spec {
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"))(ast) mustEqual
OptionGetOrElse(Ident("a'"), Ident("b'"))
}
"orElse" in {
val ast: Ast = OptionOrElse(Ident("a"), Ident("b"))
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"))(ast) mustEqual
OptionOrElse(Ident("a'"), Ident("b'"))
}
"flatMap - Unchecked" in {
val ast: Ast = OptionTableFlatMap(Ident("a"), Ident("b"), Ident("c"))
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) mustEqual
Expand Down
Expand Up @@ -522,6 +522,13 @@ class MirrorIdiomSpec extends Spec {
stmt"${(q.ast: Ast).token}" mustEqual
stmt"(o) => o.getOrElse(1)"
}
"orElse" in {
val q = quote { (o: Option[Int]) =>
o.orElse(Option(1))
}
stmt"${(q.ast: Ast).token}" mustEqual
stmt"(o) => o.orElse(Option(1))"
}
"flatten" in {
val q = quote { (o: Option[Option[Int]]) =>
o.flatten
Expand Down
Expand Up @@ -12,6 +12,7 @@ class FlattenOptionOperationSpec extends Spec { // hello

def o = Ident("o")
def c1 = Constant.auto(1)
def c2 = Constant.auto(2)
def cFoo = Constant.auto("foo")
def cBar = Constant.auto("bar")
def cValue = Constant.auto("value")
Expand All @@ -24,7 +25,31 @@ class FlattenOptionOperationSpec extends Spec { // hello
o.getOrElse(1)
}
new FlattenOptionOperation(AnsiConcat, TraceConfig.Empty)(q.ast.body: Ast) mustEqual
If(BinaryOperation(Ident("o"), EqualityOperator.`_!=`, NullValue), Ident("o"), Constant.auto(1))
IfExist(o, o, c1)
}
"orElse" - {
"regular operation" in {
val q = quote { (o: Option[Int]) =>
o.orElse(Option(1))
}
new FlattenOptionOperation(AnsiConcat, TraceConfig.Empty)(q.ast.body: Ast) mustEqual
IfExist(o, o, c1)
}
"with forall" in {
val q = quote { (o: Option[Int]) =>
o.orElse(Option(1)).forall(_ == 2)
}
new FlattenOptionOperation(AnsiConcat, TraceConfig.Empty)(q.ast.body: Ast) mustEqual
((o +==+ c2) +||+ (IsNullCheck(o) +&&+ (c1 +==+ c2))
+||+ (IsNullCheck(o) +&&+ IsNullCheck(c1)))
}
"with exists" in {
val q = quote { (o: Option[Int]) =>
o.orElse(Option(1)).exists(_ == 2)
}
new FlattenOptionOperation(AnsiConcat, TraceConfig.Empty)(q.ast.body: Ast) mustEqual
((o +==+ c2 +&&+ IsNotNullCheck(o)) +||+ (c1 +==+ c2 +&&+ IsNotNullCheck(c1)))
}
}
"flatten" - {
"regular operation" in {
Expand Down
Expand Up @@ -1541,6 +1541,12 @@ class QuotationSpec extends Spec {
Constant.auto(true)
)
}
"orElse" in {
val q = quote { (o: Option[Int]) =>
o.orElse(Option(11))
}
quote(unquote(q)).ast.body mustEqual OptionOrElse(Ident("o"), OptionApply(Constant.auto(11)))
}
"flatten" in {
val q = quote { (o: Option[Option[Int]]) =>
o.flatten
Expand Down
1 change: 1 addition & 0 deletions quill-engine/src/main/scala/io/getquill/MirrorIdiom.scala
Expand Up @@ -163,6 +163,7 @@ trait MirrorIdiomBase extends Idiom {
case OptionTableForall(ast, alias, body) => stmt"${ast.token}.forall((${alias.token}) => ${body.token})"
case OptionFlatten(ast) => stmt"${ast.token}.flatten"
case OptionGetOrElse(ast, body) => stmt"${ast.token}.getOrElse(${body.token})"
case OptionOrElse(ast, body) => stmt"${ast.token}.orElse(${body.token})"
case OptionFlatMap(ast, alias, body) => stmt"${ast.token}.flatMap((${alias.token}) => ${body.token})"
case OptionMap(ast, alias, body) => stmt"${ast.token}.map((${alias.token}) => ${body.token})"
case OptionForall(ast, alias, body) => stmt"${ast.token}.forall((${alias.token}) => ${body.token})"
Expand Down
3 changes: 3 additions & 0 deletions quill-engine/src/main/scala/io/getquill/ast/Ast.scala
Expand Up @@ -502,6 +502,9 @@ case class OptionFlatten(ast: Ast) extends OptionOperation { def quat = ast.quat
case class OptionGetOrElse(ast: Ast, body: Ast) extends OptionOperation {
def quat = body.quat; def bestQuat = body.bestQuat
}
case class OptionOrElse(ast: Ast, body: Ast) extends OptionOperation {
def quat = body.quat; def bestQuat = body.bestQuat
}
case class OptionFlatMap(ast: Ast, alias: Ident, body: Ast) extends OptionOperation {
def quat = body.quat; def bestQuat = body.bestQuat
}
Expand Down
Expand Up @@ -78,6 +78,10 @@ trait StatefulTransformer[T] {
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionGetOrElse(at, ct), ctt)
case OptionOrElse(a, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionOrElse(at, ct), ctt)
case OptionFlatMap(a, b, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
Expand Down
Expand Up @@ -94,6 +94,10 @@ trait StatefulTransformerWithStack[T] {
val (at, att) = apply(a)(History(o))
val (ct, ctt) = att.apply(c)(History(o))
(OptionGetOrElse(at, ct), ctt)
case OptionOrElse(a, c) =>
val (at, att) = apply(a)(History(o))
val (ct, ctt) = att.apply(c)(History(o))
(OptionOrElse(at, ct), ctt)
case OptionFlatMap(a, b, c) =>
val (at, att) = apply(a)(History(o))
val (ct, ctt) = att.apply(c)(History(o))
Expand Down
Expand Up @@ -48,6 +48,7 @@ trait StatelessTransformer {
case OptionTableForall(a, b, c) => OptionTableForall(apply(a), applyIdent(b), apply(c))
case OptionFlatten(a) => OptionFlatten(apply(a))
case OptionGetOrElse(a, b) => OptionGetOrElse(apply(a), apply(b))
case OptionOrElse(a, b) => OptionOrElse(apply(a), apply(b))
case OptionFlatMap(a, b, c) => OptionFlatMap(apply(a), applyIdent(b), apply(c))
case OptionMap(a, b, c) => OptionMap(apply(a), applyIdent(b), apply(c))
case OptionForall(a, b, c) => OptionForall(apply(a), applyIdent(b), apply(c))
Expand Down
Expand Up @@ -87,15 +87,31 @@ class FlattenOptionOperation(concatBehavior: ConcatBehavior, traceConfig: TraceC
case OptionGetOrElse(ast, body) =>
apply(If(IsNotNullCheck(ast), ast, body))

case OptionOrElse(ast, body) =>
apply(If(IsNotNullCheck(ast), ast, body))

case OptionFlatMap(ast, alias, body) =>
uncheckedReduction(ast, alias, body, containsNonFallthroughElement)

case OptionMap(ast, alias, body) =>
uncheckedReduction(ast, alias, body, containsNonFallthroughElement)

case OptionForall(OptionOrElse(a, b), alias, body) =>
val reducedA = BetaReduction(body, alias -> a)
val reducedB = BetaReduction(body, alias -> b)
val isNullA = IsNullCheck(a)
val isNullB = IsNullCheck(b)

apply(reducedA) +||+ apply((isNullA +&&+ reducedB): Ast) +||+ apply((isNullA +&&+ isNullB): Ast)

case OptionForall(ast, alias, body) =>
uncheckedForall(ast, alias, body, containsNonFallthroughElement)

case OptionExists(OptionOrElse(a, b), alias, body) =>
val reducedA = BetaReduction(body, alias -> a)
val reducedB = BetaReduction(body, alias -> b)
apply((reducedA +&&+ IsNotNullCheck(a)): Ast) +||+ apply((reducedB +&&+ IsNotNullCheck(b)): Ast)

case OptionExists(ast, alias, body) =>
validateContainsOrElse(
containsNonFallthroughElement(body),
Expand Down
Expand Up @@ -3,9 +3,10 @@ package io.getquill.context.jasync.mysql
import com.github.jasync.sql.db.{QueryResult, ResultSetKt}
import io.getquill.ReturnAction.ReturnColumns
import io.getquill.base.Spec
import io.getquill.{Literal, MysqlJAsyncContext, ReturnAction}

import scala.concurrent.ExecutionContext.Implicits.global
import io.getquill.{Literal, MysqlJAsyncContext, ReturnAction}
import scala.concurrent.Future

class MysqlJAsyncContextSpec extends Spec {

Expand Down Expand Up @@ -56,6 +57,55 @@ class MysqlJAsyncContextSpec extends Spec {
testContext.prepareParams("", (ps, session) => (Nil, ps ++ List("Sarah", 127))) mustEqual List("'Sarah'", "127")
}

"provides transaction support" - {
"success" in {
await(for {
_ <- testContext.run(qr4.delete)
_ <- testContext.transaction { implicit ec =>
testContext.run(qr4.insert(_.i -> 33))
}
r <- testContext.run(qr4)
} yield r).map(_.i) mustEqual List(33)
}
"failure" in {
await(for {
_ <- testContext.run(qr4.delete)
e <- testContext.transaction { implicit ec =>
Future.sequence(
Seq(
testContext.run(qr4.insert(_.i -> 18)),
Future(throw new IllegalStateException)
)
)
}.recoverWith { case e: Exception =>
Future(e.getClass.getSimpleName)
}
r <- testContext.run(qr4)
} yield (e, r.isEmpty)) mustEqual (("CompletionException", true))
}
"nested" in {
await(for {
_ <- testContext.run(qr4.delete)
_ <- testContext.transaction { implicit ec =>
testContext.transaction { implicit ec =>
testContext.run(qr4.insert(_.i -> 33))
}
}
r <- testContext.run(qr4)
} yield r).map(_.i) mustEqual List(33)
}
"nested transactions use the same connection" in {
await(for {
e <- testContext.transaction { implicit ec =>
val externalConn = ec.conn
testContext.transaction { implicit ec =>
Future(externalConn == ec.conn)
}
}
} yield e) mustEqual true
}
}

override protected def beforeAll(): Unit = {
await(testContext.run(qr1.delete))
()
Expand Down

0 comments on commit 856b1bd

Please sign in to comment.