diff --git a/.scalafmt.conf b/.scalafmt.conf index ef5c2db4..59dd68bb 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.7.15" +version = "3.8.1" align.preset = none align.openParenCallSite = false @@ -15,5 +15,10 @@ docstrings.wrap = no maxColumn = 100 newlines.implicitParamListModifierPrefer = before -runner.dialect = scala213 +runner.dialect = scala3 +fileOverride { + "glob:**/src-2/**" { + runner.dialect = scala213source3 + } +} diff --git a/build.sc b/build.sc index 192987a9..6cb45391 100644 --- a/build.sc +++ b/build.sc @@ -1,12 +1,12 @@ import $file.docs.generateDocs import $ivy.`de.tototec::de.tobiasroeser.mill.vcs.version::0.4.0` import $ivy.`com.github.lolgab::mill-mima::0.1.0` -import $ivy.`com.goyeau::mill-scalafix::0.3.1` +import $ivy.`com.goyeau::mill-scalafix::0.4.0` import de.tobiasroeser.mill.vcs.version.VcsVersion import com.goyeau.mill.scalafix.ScalafixModule import mill._, scalalib._, publish._ -val scalaVersions = Seq("2.13.12"/*, "3.3.1"*/) +val scalaVersions = Seq("2.13.12", "3.4.2") trait Common extends CrossScalaModule with PublishModule with ScalafixModule{ def scalaVersion = crossScalaVersion @@ -27,12 +27,15 @@ trait Common extends CrossScalaModule with PublishModule with ScalafixModule{ ) ) - def scalacOptions = Seq("-Xlint:unused") + def scalacOptions = T { + Seq("-Wunused:privates,locals,explicits,implicits,params") ++ + Option.when(scalaVersion().startsWith("2."))("-Xsource:3") + } } object scalasql extends Cross[ScalaSql](scalaVersions) -trait ScalaSql extends Common{ +trait ScalaSql extends Common{ common => def moduleDeps = Seq(query, operations) def ivyDeps = Agg( ivy"org.apache.logging.log4j:log4j-api:2.20.0", @@ -45,7 +48,7 @@ trait ScalaSql extends Common{ object test extends ScalaTests with ScalafixModule{ - def scalacOptions = Seq("-Xlint:unused") + def scalacOptions = common.scalacOptions def ivyDeps = Agg( ivy"com.github.vertical-blank:sql-formatter:2.0.4", ivy"com.lihaoyi::mainargs:0.4.0", @@ -66,6 +69,9 @@ trait ScalaSql extends Common{ def forkArgs = Seq("-Duser.timezone=Asia/Singapore") } + private def indent(code: Iterable[String]): String = + code.map(_.split("\n").map(" " + _).mkString("\n")).mkString("\n") + object core extends Common with CrossValue { def ivyDeps = Agg( ivy"com.lihaoyi::geny:1.0.0", @@ -100,7 +106,7 @@ trait ScalaSql extends Common{ s"""package scalasql.core.generated |import scalasql.core.Queryable |trait QueryableRow{ - | ${queryableRowDefs.mkString("\n")} + |${indent(queryableRowDefs)} |} |""".stripMargin ) @@ -147,7 +153,6 @@ trait ScalaSql extends Common{ | implicit | ${commaSep(j => s"q$j: Queryable.Row[Q$j, R$j]")} |): Queryable.Row[(${commaSep(j => s"Q$j")}), (${commaSep(j => s"R$j")})] = { - | import scalasql.core.SqlStr.SqlStringSyntax | new Queryable.Row.TupleNQueryable( | Seq(${commaSep(j => s"q$j.walkLabels()")}), | t => Seq(${commaSep(j => s"q$j.walkExprs(t._$j)")}), @@ -166,7 +171,7 @@ trait ScalaSql extends Common{ s""" |implicit def append$i[$commaSepQ, QA, $commaSepR, RA]( | implicit qr0: Queryable.Row[($commaSepQ, QA), ($commaSepR, RA)], - | qr20: Queryable.Row[QA, RA]): $joinAppendType = new $joinAppendType { + | @annotation.nowarn("msg=never used") qr20: Queryable.Row[QA, RA]): $joinAppendType = new $joinAppendType { | override def appendTuple(t: ($commaSepQ), v: QA): ($commaSepQ, QA) = (${commaSep(j => s"t._$j")}, v) | | def qr: Queryable.Row[($commaSepQ, QA), ($commaSepR, RA)] = qr0 @@ -179,23 +184,23 @@ trait ScalaSql extends Common{ |import scalasql.core.{Queryable, Expr} |import scalasql.query.Column |trait Insert[V[_[_]], R]{ - | ${defs(false).mkString("\n")} + |${indent(defs(false))} |} |trait InsertImpl[V[_[_]], R] extends Insert[V, R]{ this: scalasql.query.Insert[V, R] => | def newInsertValues[R]( | insert: scalasql.query.Insert[V, R], - | columns: Seq[Column[_]], - | valuesLists: Seq[Seq[Expr[_]]] + | columns: Seq[Column[?]], + | valuesLists: Seq[Seq[Expr[?]]] | )(implicit qr: Queryable[V[Column], R]): scalasql.query.InsertColumns[V, R] - | ${defs(true).mkString("\n")} + |${indent(defs(true))} |} | |trait QueryableRow{ - | ${queryableRowDefs.mkString("\n")} + |${indent(queryableRowDefs)} |} | |trait JoinAppend extends scalasql.query.JoinAppendLowPriority{ - | ${joinAppendDefs.mkString("\n")} + |${indent(joinAppendDefs)} |} |""".stripMargin ) diff --git a/docs/reference.md b/docs/reference.md index bc6d28b6..06f54422 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -440,7 +440,7 @@ dbClient.transaction { implicit db => db.run(Purchase.delete(_.id <= 3)) ==> 3 db.run(Purchase.select.size) ==> 4 - db.savepoint { sp => + db.savepoint { _ => db.run(Purchase.delete(_ => true)) ==> 4 db.run(Purchase.select.size) ==> 0 } @@ -499,7 +499,7 @@ dbClient.transaction { implicit db => db.run(Purchase.select.size) ==> 4 try { - db.savepoint { sp => + db.savepoint { _ => db.run(Purchase.delete(_ => true)) ==> 4 db.run(Purchase.select.size) ==> 0 throw new FooException @@ -533,11 +533,11 @@ dbClient.transaction { implicit db => db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 } diff --git a/scalasql/core/src/DbApi.scala b/scalasql/core/src/DbApi.scala index c8de1f7c..be9aa105 100644 --- a/scalasql/core/src/DbApi.scala +++ b/scalasql/core/src/DbApi.scala @@ -27,7 +27,7 @@ trait DbApi extends AutoCloseable { * Runs the given [[SqlStr]] of the form `sql"..."` and returns a value of type [[R]] */ def runSql[R](query: SqlStr, fetchSize: Int = -1, queryTimeoutSeconds: Int = -1)( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] @@ -48,7 +48,7 @@ trait DbApi extends AutoCloseable { * arbitrary [[SqlStr]] of the form `sql"..."` and streams the results back to you */ def streamSql[R](sql: SqlStr, fetchSize: Int = -1, queryTimeoutSeconds: Int = -1)( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): Generator[R] @@ -63,7 +63,7 @@ trait DbApi extends AutoCloseable { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] @@ -78,7 +78,7 @@ trait DbApi extends AutoCloseable { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): Generator[R] @@ -104,7 +104,7 @@ trait DbApi extends AutoCloseable { )(implicit fileName: sourcecode.FileName, lineNum: sourcecode.Line): Int def updateGetGeneratedKeysSql[R](sql: SqlStr, fetchSize: Int = -1, queryTimeoutSeconds: Int = -1)( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] @@ -115,7 +115,7 @@ trait DbApi extends AutoCloseable { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] @@ -202,22 +202,20 @@ object DbApi { .asInstanceOf[R] else if (qr.isExecuteUpdate(query)) updateSql(flattened).asInstanceOf[R] else { - try { - val res = stream(query, fetchSize, queryTimeoutSeconds)( - qr.asInstanceOf[Queryable[Q, Seq[_]]], - fileName, - lineNum + val res = stream(query, fetchSize, queryTimeoutSeconds)( + qr.asInstanceOf[Queryable[Q, Seq[?]]], + fileName, + lineNum + ) + if (qr.isSingleRow(query)) { + val results = res.take(2).toVector + assert( + results.size == 1, + s"Single row query must return 1 result, not ${results.size}" ) - if (qr.isSingleRow(query)) { - val results = res.take(2).toVector - assert( - results.size == 1, - s"Single row query must return 1 result, not ${results.size}" - ) - results.head.asInstanceOf[R] - } else { - res.toVector.asInstanceOf[R] - } + results.head.asInstanceOf[R] + } else { + res.toVector.asInstanceOf[R] } } } @@ -248,7 +246,7 @@ object DbApi { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] = streamSql(sql, fetchSize, queryTimeoutSeconds).toVector @@ -258,7 +256,7 @@ object DbApi { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): Generator[R] = { @@ -292,7 +290,7 @@ object DbApi { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] = { @@ -314,7 +312,7 @@ object DbApi { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] = { @@ -327,7 +325,7 @@ object DbApi { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): Generator[R] = { @@ -362,7 +360,7 @@ object DbApi { fetchSize: Int = -1, queryTimeoutSeconds: Int = -1 )( - implicit qr: Queryable.Row[_, R], + implicit qr: Queryable.Row[?, R], fileName: sourcecode.FileName, lineNum: sourcecode.Line ): IndexedSeq[R] = runRawUpdateGetGeneratedKeys0( @@ -466,7 +464,7 @@ object DbApi { queryTimeoutSeconds: Int, fileName: sourcecode.FileName, lineNum: sourcecode.Line, - qr: Queryable.Row[_, R] + qr: Queryable.Row[?, R] ): IndexedSeq[R] = { val statement = connection.prepareStatement(sql, java.sql.Statement.RETURN_GENERATED_KEYS) for ((v, i) <- variables.iterator.zipWithIndex) v(statement, i + 1) diff --git a/scalasql/core/src/Expr.scala b/scalasql/core/src/Expr.scala index a35f5e31..ba9f6898 100644 --- a/scalasql/core/src/Expr.scala +++ b/scalasql/core/src/Expr.scala @@ -7,7 +7,7 @@ import scalasql.core.SqlStr.SqlStringSyntax * a Scala value of a particular type [[T]] */ trait Expr[T] extends SqlStr.Renderable { - protected final def renderSql(ctx: Context): SqlStr = { + private[scalasql] final def renderSql(ctx: Context): SqlStr = { ctx.exprNaming.get(this.exprIdentity).getOrElse(renderToSql0(ctx)) } @@ -37,15 +37,15 @@ object Expr { def identity[T](e: Expr[T]): Identity = e.exprIdentity class Identity() - implicit def ExprQueryable[E[_] <: Expr[_], T]( + implicit def ExprQueryable[E[_] <: Expr[?], T]( implicit mt: TypeMapper[T] ): Queryable.Row[E[T], T] = new ExprQueryable[E, T]() - class ExprQueryable[E[_] <: Expr[_], T]( + class ExprQueryable[E[_] <: Expr[?], T]( implicit tm: TypeMapper[T] ) extends Queryable.Row[E[T], T] { - def walkLabels() = Seq(Nil) - def walkExprs(q: E[T]) = Seq(q) + def walkLabels(): Seq[List[String]] = Seq(Nil) + def walkExprs(q: E[T]): Seq[Expr[?]] = Seq(q) override def construct(args: Queryable.ResultSetIterator): T = args.get(tm) diff --git a/scalasql/core/src/ExprsToSql.scala b/scalasql/core/src/ExprsToSql.scala index 35d8e6eb..ef92ab63 100644 --- a/scalasql/core/src/ExprsToSql.scala +++ b/scalasql/core/src/ExprsToSql.scala @@ -39,7 +39,7 @@ object ExprsToSql { } } - def booleanExprs(prefix: SqlStr, exprs: Seq[Expr[_]])(implicit ctx: Context) = { + def booleanExprs(prefix: SqlStr, exprs: Seq[Expr[?]])(implicit ctx: Context) = { SqlStr.optSeq(exprs.filter(!Expr.isLiteralTrue(_))) { having => prefix + SqlStr.join(having.map(Renderable.renderSql(_)), sql" AND ") } diff --git a/scalasql/core/src/JoinNullable.scala b/scalasql/core/src/JoinNullable.scala index d672a493..89359ccb 100644 --- a/scalasql/core/src/JoinNullable.scala +++ b/scalasql/core/src/JoinNullable.scala @@ -8,8 +8,8 @@ import scalasql.core.SqlStr.SqlStringSyntax */ trait JoinNullable[Q] { def get: Q - def isEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, _]): Expr[Boolean] - def nonEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, _]): Expr[Boolean] + def isEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, ?]): Expr[Boolean] + def nonEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, ?]): Expr[Boolean] def map[V](f: Q => V): JoinNullable[V] } @@ -19,11 +19,11 @@ object JoinNullable { def apply[Q](t: Q): JoinNullable[Q] = new JoinNullable[Q] { def get: Q = t - def isEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, _]): Expr[Boolean] = Expr { + def isEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, ?]): Expr[Boolean] = Expr { implicit ctx => sql"(${f(t)} IS NULL)" } - def nonEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, _]): Expr[Boolean] = Expr { + def nonEmpty[T](f: Q => Expr[T])(implicit qr: Queryable[Q, ?]): Expr[Boolean] = Expr { implicit ctx => sql"(${f(t)} IS NOT NULL)" } diff --git a/scalasql/core/src/Queryable.scala b/scalasql/core/src/Queryable.scala index 37690747..d3d18809 100644 --- a/scalasql/core/src/Queryable.scala +++ b/scalasql/core/src/Queryable.scala @@ -17,7 +17,7 @@ trait Queryable[-Q, R] { * Whether this queryable value is executed using `java.sql.Statement.getGeneratedKeys` * instead of `.executeQuery`. */ - def isGetGeneratedKeys(q: Q): Option[Queryable.Row[_, _]] + def isGetGeneratedKeys(q: Q): Option[Queryable.Row[?, ?]] /** * Whether this queryable value is executed using `java.sql.Statement.executeUpdate` @@ -38,7 +38,7 @@ trait Queryable[-Q, R] { * Returns a sequence of expressions created by this queryable value. Used to generate * the column list `SELECT` clauses, both for nested and top level `SELECT`s */ - def walkExprs(q: Q): Seq[Expr[_]] + def walkExprs(q: Q): Seq[Expr[?]] def walkLabelsAndExprs(q: Q): Queryable.Walked = walkLabels(q).zip(walkExprs(q)) @@ -62,7 +62,7 @@ trait Queryable[-Q, R] { } object Queryable { - type Walked = Seq[(List[String], Expr[_])] + type Walked = Seq[(List[String], Expr[?])] class ResultSetIterator(r: ResultSet) { var index = 0 var nulls = 0 @@ -88,7 +88,7 @@ object Queryable { * available, there is no `Queryable.Row[Select[Q]]`, as `Select[Q]` returns multiple rows */ trait Row[Q, R] extends Queryable[Q, R] { - def isGetGeneratedKeys(q: Q): Option[Queryable.Row[_, _]] = None + def isGetGeneratedKeys(q: Q): Option[Queryable.Row[?, ?]] = None def isExecuteUpdate(q: Q): Boolean = false def isSingleRow(q: Q): Boolean = true def walkLabels(): Seq[List[String]] @@ -112,18 +112,18 @@ object Queryable { object Row extends scalasql.core.generated.QueryableRow { private[scalasql] class TupleNQueryable[Q, R <: scala.Product]( val walkLabels0: Seq[Seq[List[String]]], - val walkExprs0: Q => Seq[Seq[Expr[_]]], + val walkExprs0: Q => Seq[Seq[Expr[?]]], construct0: ResultSetIterator => R, deconstruct0: R => Q ) extends Queryable.Row[Q, R] { - def walkExprs(q: Q) = { + def walkExprs(q: Q): Seq[Expr[?]] = { walkExprs0(q).iterator.zipWithIndex .map { case (v, i) => (i.toString, v) } .flatMap { case (prefix, vs0) => vs0 } .toIndexedSeq } - def walkLabels() = { + def walkLabels(): Seq[List[String]] = { walkLabels0.iterator.zipWithIndex .map { case (v, i) => (i.toString, v) } .flatMap { case (prefix, vs0) => vs0.map { k => prefix +: k } } diff --git a/scalasql/core/src/SqlStr.scala b/scalasql/core/src/SqlStr.scala index 6249e9ec..b877a1a7 100644 --- a/scalasql/core/src/SqlStr.scala +++ b/scalasql/core/src/SqlStr.scala @@ -24,7 +24,7 @@ class SqlStr( def withCompleteQuery(v: Boolean) = new SqlStr(queryParts, interps, v, referencedExprs) override def toString = SqlStr.flatten(this).renderSql(false) - override protected def renderSql(ctx: Context): SqlStr = this + override private[scalasql] def renderSql(ctx: Context): SqlStr = this } object SqlStr { @@ -42,7 +42,7 @@ object SqlStr { isCompleteQuery: Boolean, val referencedExprs: Array[Expr.Identity] ) extends SqlStr(queryParts, interps0, isCompleteQuery, referencedExprs) { - def interpsIterator = interps0.iterator.map(_.asInstanceOf[Interp.TypeInterp[_]]) + def interpsIterator = interps0.iterator.map(_.asInstanceOf[Interp.TypeInterp[?]]) def renderSql(castParams: Boolean) = { val queryStr = queryParts.iterator .zipAll(interpsIterator, "", null) @@ -50,7 +50,7 @@ object SqlStr { case (part, null) => part case (part, param) => val jdbcTypeString = param.mappedType.castTypeString - if (castParams) part + s"CAST(? AS $jdbcTypeString)" else part + "?" + if (castParams) part.toString + s"CAST(? AS $jdbcTypeString)" else part.toString + "?" } .mkString @@ -211,7 +211,7 @@ object SqlStr { new SqlStr(Array(s), emptyInterpArray, false, referencedExprs) trait Renderable { - protected def renderSql(ctx: Context): SqlStr + private[scalasql] def renderSql(ctx: Context): SqlStr } object Renderable { diff --git a/scalasql/core/src/TypeMapper.scala b/scalasql/core/src/TypeMapper.scala index 3a4a8340..e2124674 100644 --- a/scalasql/core/src/TypeMapper.scala +++ b/scalasql/core/src/TypeMapper.scala @@ -1,6 +1,16 @@ package scalasql.core import java.sql.{JDBCType, PreparedStatement, ResultSet} +import java.time.{ + LocalDate, + LocalTime, + LocalDateTime, + ZonedDateTime, + Instant, + OffsetTime, + OffsetDateTime +} +import java.util.UUID // What Quill does // https://github.com/zio/zio-quill/blob/43ee1dab4f717d7e6683aa24c391740f3d17df50/quill-jdbc/src/main/scala/io/getquill/context/jdbc/Encoders.scala#L104 @@ -42,3 +52,71 @@ trait TypeMapper[T] { */ def put(r: PreparedStatement, idx: Int, v: T): Unit } + +object TypeMapper { + + /** + * These definitions are workarounds for a bug in the Scala 3 compiler + * https://github.com/scala/scala3/issues/19436 + * + * The `TableMacros` definition in Scala 3 could ideally just `import dialect.*` to get the + * `TypeMapper` instances in scope, but it triggers a crash similar to the one in the bug report. + * + * Instead, the macro declares a local `given d: DialectTypeMappers = dialect` and relies on these + * implicits to summon the necessary instances. + */ + implicit def stringFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[String] = + d.StringType + implicit def byteFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Byte] = + d.ByteType + implicit def shortFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Short] = + d.ShortType + implicit def intFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Int] = + d.IntType + implicit def longFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Long] = + d.LongType + + implicit def doubleFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Double] = + d.DoubleType + implicit def bigDecimalFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[scala.math.BigDecimal] = d.BigDecimalType + implicit def booleanFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Boolean] = + d.BooleanType + implicit def uuidFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[UUID] = + d.UuidType + implicit def bytesFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[geny.Bytes] = + d.BytesType + implicit def localDateFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[LocalDate] = d.LocalDateType + implicit def localTimeFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[LocalTime] = d.LocalTimeType + + implicit def localDateTimeFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[LocalDateTime] = d.LocalDateTimeType + + implicit def zonedDateTimeFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[ZonedDateTime] = d.ZonedDateTimeType + implicit def instantFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[Instant] = + d.InstantType + + implicit def offsetTimeFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[OffsetTime] = d.OffsetTimeType + + implicit def offsetDateTimeFromDialectTypeMappers( + implicit d: DialectTypeMappers + ): TypeMapper[OffsetDateTime] = d.OffsetDateTimeType + implicit def enumTypeFromDialectTypeMappers[T <: Enumeration#Value]( + implicit d: DialectTypeMappers, + constructor: String => T + ): TypeMapper[T] = d.EnumType[T] + implicit def optionTypeFromDialectTypeMappers[T]( + implicit d: DialectTypeMappers, + inner: TypeMapper[T] + ): TypeMapper[Option[T]] = d.OptionType[T] +} diff --git a/scalasql/operations/src/AggOps.scala b/scalasql/operations/src/AggOps.scala index b303c415..351e32b5 100644 --- a/scalasql/operations/src/AggOps.scala +++ b/scalasql/operations/src/AggOps.scala @@ -5,11 +5,11 @@ import scalasql.core.{Queryable, TypeMapper, Expr} import scalasql.core.Aggregatable import scalasql.core.SqlStr.SqlStringSyntax -class AggOps[T](v: Aggregatable[T])(implicit qr: Queryable.Row[T, _], dialect: DialectTypeMappers) { +class AggOps[T](v: Aggregatable[T])(implicit qr: Queryable.Row[T, ?], dialect: DialectTypeMappers) { import dialect._ /** Counts the rows */ - def size: Expr[Int] = v.aggregateExpr(expr => _ => sql"COUNT(1)") + def size: Expr[Int] = v.aggregateExpr(_ => _ => sql"COUNT(1)") /** Computes the sum of column values */ def sumBy[V: Numeric: TypeMapper](f: T => Expr[V])( diff --git a/scalasql/operations/src/ConcatOps.scala b/scalasql/operations/src/ConcatOps.scala index 5f379ceb..3ac66ca0 100644 --- a/scalasql/operations/src/ConcatOps.scala +++ b/scalasql/operations/src/ConcatOps.scala @@ -7,7 +7,7 @@ trait ConcatOps { /** * Concatenate all arguments. NULL arguments are ignored. */ - def concat(values: Expr[_]*): Expr[String] = Expr { implicit ctx => + def concat(values: Expr[?]*): Expr[String] = Expr { implicit ctx => sql"CONCAT(${SqlStr.join(values.map(v => sql"$v"), SqlStr.commaSep)})" } @@ -15,7 +15,7 @@ trait ConcatOps { * Concatenate all but first arguments with separators. The first parameter is used * as a separator. NULL arguments are ignored. */ - def concatWs(sep: Expr[String], values: Expr[_]*): Expr[String] = Expr { implicit ctx => + def concatWs(sep: Expr[String], values: Expr[?]*): Expr[String] = Expr { implicit ctx => sql"CONCAT_WS($sep, ${SqlStr.join(values.map(v => sql"$v"), SqlStr.commaSep)})" } } diff --git a/scalasql/operations/src/ExprOps.scala b/scalasql/operations/src/ExprOps.scala index cc29ded2..b88fb986 100644 --- a/scalasql/operations/src/ExprOps.scala +++ b/scalasql/operations/src/ExprOps.scala @@ -5,7 +5,7 @@ import scalasql.core.Expr import scalasql.core.SqlStr import scalasql.core.SqlStr.SqlStringSyntax -class ExprOps(v: Expr[_]) { +class ExprOps(v: Expr[?]) { /** * SQL-style Equals to, translates to SQL `=`. Returns `false` if both values are `NULL` diff --git a/scalasql/operations/src/ExprTypedOps.scala b/scalasql/operations/src/ExprTypedOps.scala index b6b9bee2..0aeaf6a5 100644 --- a/scalasql/operations/src/ExprTypedOps.scala +++ b/scalasql/operations/src/ExprTypedOps.scala @@ -7,7 +7,7 @@ import scala.reflect.ClassTag class ExprTypedOps[T: ClassTag](v: Expr[T]) { - protected def isNullable[T: ClassTag] = implicitly[ClassTag[T]].runtimeClass == classOf[Option[_]] + protected def isNullable[T: ClassTag] = implicitly[ClassTag[T]].runtimeClass == classOf[Option[?]] /** * Scala-style Equals to, returns `true` if both values are `NULL`. diff --git a/scalasql/operations/src/PadOps.scala b/scalasql/operations/src/PadOps.scala index e8cd41e5..d5dd0d44 100644 --- a/scalasql/operations/src/PadOps.scala +++ b/scalasql/operations/src/PadOps.scala @@ -3,7 +3,7 @@ import scalasql.core.Expr import scalasql.core.SqlStr.SqlStringSyntax trait PadOps { - protected def v: Expr[_] + protected def v: Expr[?] def rpad(length: Expr[Int], fill: Expr[String]): Expr[String] = Expr { implicit ctx => sql"RPAD($v, $length, $fill)" diff --git a/scalasql/operations/src/TrimOps.scala b/scalasql/operations/src/TrimOps.scala index 1a0e7463..ecc7f97b 100644 --- a/scalasql/operations/src/TrimOps.scala +++ b/scalasql/operations/src/TrimOps.scala @@ -3,7 +3,7 @@ import scalasql.core.Expr import scalasql.core.SqlStr.SqlStringSyntax trait TrimOps { - protected def v: Expr[_] + protected def v: Expr[?] /** * Trim [[x]]s from the left hand side of the string [[v]] diff --git a/scalasql/query/src-3/TableMacro.scala b/scalasql/query/src-3/TableMacro.scala new file mode 100644 index 00000000..fb3feafb --- /dev/null +++ b/scalasql/query/src-3/TableMacro.scala @@ -0,0 +1,163 @@ +package scalasql.query + +import scalasql.core.{DialectTypeMappers, Expr => SqlExpr, Queryable, Sc, TypeMapper} +import scala.compiletime.summonInline +import scala.quoted.* + +object TableMacros { + def applyImpl[V[_[_]] <: Product](using Quotes, Type[V]): Expr[Table.Metadata[V]] = { + import quotes.reflect.* + + val caseClassType = TypeRepr.of[V] + val constructor = caseClassType.typeSymbol.primaryConstructor + val constructorTypeParams = constructor.paramSymss(0) + val constructorValueParams = constructor.paramSymss(1) + + def paramType(param: Symbol): TypeRepr = caseClassType.memberType(param) + + def isTypeParamType(param: Symbol): Boolean = + paramType(param).typeSymbol.toString != constructorTypeParams.head.toString + + def subParam(paramInfo: TypeRepr, tpe: TypeRepr): TypeRepr = + paramInfo.substituteTypes(List(constructorTypeParams.head), List(tpe)) + + def paramTypes(param: Symbol): (TypeRepr, Type[?], Type[?]) = { + val paramTpe = paramType(param) + val scTpe = subParam(paramTpe, TypeRepr.of[Sc]).asType + val exprTpe = subParam(paramTpe, TypeRepr.of[SqlExpr]).asType + (paramTpe, scTpe, exprTpe) + } + + def constructV[F[_]: Type]( + paramTerm: (Symbol, Int) => (TypeRepr, Type[?], Type[?]) => Term + ): Expr[V[F]] = + Apply( + TypeApply( + Select.unique(New(TypeIdent(TypeRepr.of[V].typeSymbol)), ""), + List(TypeTree.of[F]) + ), + constructorValueParams.zipWithIndex.map { case (param, i) => + paramTerm(param, i).tupled(paramTypes(param)) + } + ).asExprOf[V[F]] + + def fromImplicitMetadata[O](paramTpe: TypeRepr)( + f: [T[_[_]]] => Expr[Table.Metadata[T]] => Type[T] ?=> O + ): O = + paramTpe match { + case AppliedType(tpeCtor, _) => + tpeCtor.asType match { + case '[ + type t[_[_]]; t] => + f[t]('{ summonInline[Table.ImplicitMetadata[t]].value }) + } + } + + val queryables = '{ (dialect: DialectTypeMappers, n: Int) => + { + given DialectTypeMappers = dialect + lazy val _ = summon[DialectTypeMappers] + + ${ + Expr.ofList(constructorValueParams.map { param => + val paramTpe = paramType(param) + val tpe = subParam(paramTpe, TypeRepr.of[Sc]) + val tpe2 = subParam(paramTpe, TypeRepr.of[SqlExpr]) + (tpe.asType, tpe2.asType) match { + case ('[t], '[t2]) => '{ summonInline[Queryable.Row[t2, t]] } + } + }) + }.apply(n) + } + } + + val walkLabels0 = '{ () => + ${ + Expr.ofList(constructorValueParams.map { param => + if (isTypeParamType(param)) + fromImplicitMetadata(paramType(param))([T[_[_]]] => t => '{ $t.walkLabels0() }) + else + '{ Seq(${ Expr(param.name) }) } + }) + }.flatten + } + + val queryable = '{ + ( + walkLabels0: () => Seq[String], + dialect: DialectTypeMappers, + queryable: Table.Metadata.QueryableProxy + ) => + new Table.Internal.TableQueryable( + walkLabels0, + (table: V[SqlExpr]) => + ${ + Expr.ofList(constructorValueParams.zipWithIndex.map { case (param, i) => + val paramTpe = paramType(param) + val tpe = subParam(paramTpe, TypeRepr.of[Sc]) + val tpe2 = subParam(paramTpe, TypeRepr.of[SqlExpr]) + (tpe.asType, tpe2.asType) match { + case ('[t], '[t2]) => + '{ + queryable[t2, t](${ Expr(i) }).walkExprs( + ${ Select.unique('table.asTerm, param.name).asExprOf[t2] } + ) + } + } + }) + }.flatten, + construct0 = (args: Queryable.ResultSetIterator) => + ${ + constructV[Sc]((_, i) => { case (_, '[t], '[t2]) => + '{ queryable[t2, t](${ Expr(i) }).construct(args) }.asTerm + }) + }, + deconstruct0 = (r: V[Sc]) => + ${ + constructV[SqlExpr]((param, i) => { case (_, '[t], '[t2]) => + '{ + queryable[t2, t](${ Expr(i) }).deconstruct( + ${ Select.unique('r.asTerm, param.name).asExprOf[t] } + ) + }.asTerm + }) + } + ) + } + + val vExpr0 = '{ + (tableRef: TableRef, dialect: DialectTypeMappers, queryable: Table.Metadata.QueryableProxy) => + { + given DialectTypeMappers = dialect + lazy val _ = summon[DialectTypeMappers] + + ${ + constructV[Column]((param, _) => { case (paramTpe, _, _) => + if (isTypeParamType(param)) + fromImplicitMetadata(paramTpe)( + [T[_[_]]] => t => '{ $t.vExpr(tableRef, dialect) }.asTerm + ) + else + paramTpe.typeArgs.head.asType match { + case '[t] => + '{ + new Column[t]( + tableRef, + Table.columnNameOverride(tableRef.value)(${ Expr(param.name) }) + )(using summonInline[TypeMapper[t]]) + }.asTerm + } + }) + } + } + } + + '{ new Table.Metadata[V]($queryables, $walkLabels0, $queryable, $vExpr0) } + } +} + +trait TableMacros { + inline given initTableMetadata[V[_[_]] <: Product]: Table.Metadata[V] = ${ + TableMacros.applyImpl[V] + } +} diff --git a/scalasql/query/src/Aggregate.scala b/scalasql/query/src/Aggregate.scala index a04a2eb1..f8369be6 100644 --- a/scalasql/query/src/Aggregate.scala +++ b/scalasql/query/src/Aggregate.scala @@ -10,7 +10,7 @@ class Aggregate[Q, R]( ) extends Query.DelegateQueryable[Q, R] { protected override def queryIsSingleRow: Boolean = true - protected def renderSql(ctx: Context) = toSqlStr0(ctx) + private[scalasql] def renderSql(ctx: Context) = toSqlStr0(ctx) override protected def queryConstruct(args: Queryable.ResultSetIterator): R = construct0(args) } diff --git a/scalasql/query/src/CompoundSelect.scala b/scalasql/query/src/CompoundSelect.scala index 04b1fa74..b3ce890c 100644 --- a/scalasql/query/src/CompoundSelect.scala +++ b/scalasql/query/src/CompoundSelect.scala @@ -45,23 +45,23 @@ class CompoundSelect[Q, R]( } } - override def sortBy(f: Q => Expr[_]) = { + override def sortBy(f: Q => Expr[?]) = { val newOrder = Seq(OrderBy(f(expr), None, None)) if (limit.isEmpty && offset.isEmpty) copy(orderBy = newOrder ++ orderBy) else newCompoundSelect(selectToSimpleSelect(), compoundOps, newOrder, None, None) } - override def asc = + override def asc: Select[Q, R] = copy(orderBy = orderBy.take(1).map(_.copy(ascDesc = Some(AscDesc.Asc))) ++ orderBy.drop(1)) - override def desc = + override def desc: Select[Q, R] = copy(orderBy = orderBy.take(1).map(_.copy(ascDesc = Some(AscDesc.Desc))) ++ orderBy.drop(1)) - override def nullsFirst = + override def nullsFirst: Select[Q, R] = copy(orderBy = orderBy.take(1).map(_.copy(nulls = Some(Nulls.First))) ++ orderBy.drop(1)) - override def nullsLast = + override def nullsLast: Select[Q, R] = copy(orderBy = orderBy.take(1).map(_.copy(nulls = Some(Nulls.Last))) ++ orderBy.drop(1)) override def compound0(op: String, other: Select[Q, R]) = { @@ -71,10 +71,11 @@ class CompoundSelect[Q, R]( else newCompoundSelect(selectToSimpleSelect(), Seq(op2), Nil, None, None) } - override def drop(n: Int) = copy(offset = Some(offset.getOrElse(0) + n), limit = limit.map(_ - n)) - override def take(n: Int) = copy(limit = Some(limit.fold(n)(math.min(_, n)))) + override def drop(n: Int): Select[Q, R] = + copy(offset = Some(offset.getOrElse(0) + n), limit = limit.map(_ - n)) + override def take(n: Int): Select[Q, R] = copy(limit = Some(limit.fold(n)(math.min(_, n)))) - override protected def selectRenderer(prevContext: Context) = + override protected def selectRenderer(prevContext: Context): SubqueryRef.Wrapped.Renderer = new CompoundSelect.Renderer(this, prevContext) override protected def selectExprAliases(prevContext: Context) = { diff --git a/scalasql/query/src/Delete.scala b/scalasql/query/src/Delete.scala index 770aa1cd..447bb09f 100644 --- a/scalasql/query/src/Delete.scala +++ b/scalasql/query/src/Delete.scala @@ -16,7 +16,7 @@ object Delete { ) extends Delete[Q] { import dialect._ - protected def renderSql(ctx: Context) = new Renderer(table, filter, ctx).render() + private[scalasql] def renderSql(ctx: Context) = new Renderer(table, filter, ctx).render() protected def queryConstruct(args: Queryable.ResultSetIterator): Int = args.get(IntType) } @@ -24,7 +24,7 @@ object Delete { class Renderer(table: TableRef, expr: Expr[Boolean], prevContext: Context) { lazy val tableNameStr = SqlStr.raw(prevContext.config.tableNameMapper(Table.name(table.value))) - implicit val implicitCtx = Context.compute(prevContext, Nil, Some(table)) + implicit val implicitCtx: Context = Context.compute(prevContext, Nil, Some(table)) def render() = sql"DELETE FROM $tableNameStr WHERE $expr" } diff --git a/scalasql/query/src/From.scala b/scalasql/query/src/From.scala index 5ca8cb86..ef6aeb40 100644 --- a/scalasql/query/src/From.scala +++ b/scalasql/query/src/From.scala @@ -12,7 +12,7 @@ class TableRef(val value: Table.Base) extends From { def fromRefPrefix(prevContext: Context) = prevContext.config.tableNameMapper(Table.name(value)) - def fromExprAliases(prevContext: Context) = Nil + def fromExprAliases(prevContext: Context): Seq[(Expr.Identity, SqlStr)] = Nil def renderSql(name: SqlStr, prevContext: Context, liveExprs: LiveExprs) = { SqlStr.raw(prevContext.config.tableNameMapper(Table.name(value))) + sql" " + name diff --git a/scalasql/query/src/GetGeneratedKeys.scala b/scalasql/query/src/GetGeneratedKeys.scala index 13f9ef4c..9c7e3dab 100644 --- a/scalasql/query/src/GetGeneratedKeys.scala +++ b/scalasql/query/src/GetGeneratedKeys.scala @@ -1,7 +1,7 @@ package scalasql.query import scalasql.core.SqlStr.Renderable -import scalasql.core.{Context, Queryable, SqlStr, WithSqlExpr} +import scalasql.core.{Context, Expr, Queryable, SqlStr, WithSqlExpr} /** * Represents an [[Insert]] query that you want to call `JdbcStatement.getGeneratedKeys` @@ -13,7 +13,7 @@ trait GetGeneratedKeys[Q, R] extends Query[Seq[R]] { object GetGeneratedKeys { - class Impl[Q, R](base: Returning.InsertBase[Q])(implicit qr: Queryable.Row[_, R]) + class Impl[Q, R](base: Returning.InsertBase[Q])(implicit qr: Queryable.Row[?, R]) extends GetGeneratedKeys[Q, R] { def expr = WithSqlExpr.get(base) @@ -21,13 +21,13 @@ object GetGeneratedKeys { Seq(qr.construct(args)) } - protected def queryWalkLabels() = Nil - protected def queryWalkExprs() = Nil + protected def queryWalkLabels(): Seq[List[String]] = Nil + protected def queryWalkExprs(): Seq[Expr[?]] = Nil protected override def queryIsSingleRow = false protected override def queryIsExecuteUpdate = true - override protected def renderSql(ctx: Context): SqlStr = Renderable.renderSql(base)(ctx) + override private[scalasql] def renderSql(ctx: Context): SqlStr = Renderable.renderSql(base)(ctx) - override protected def queryGetGeneratedKeys: Option[Queryable.Row[_, _]] = Some(qr) + override protected def queryGetGeneratedKeys: Option[Queryable.Row[?, ?]] = Some(qr) } } diff --git a/scalasql/query/src/Insert.scala b/scalasql/query/src/Insert.scala index b8f23405..4a62756f 100644 --- a/scalasql/query/src/Insert.scala +++ b/scalasql/query/src/Insert.scala @@ -10,7 +10,7 @@ trait Insert[V[_[_]], R] extends WithSqlExpr[V[Column]] with scalasql.generated. def qr: Queryable[V[Column], R] def select[C, R2](columns: V[Expr] => C, select: Select[C, R2]): InsertSelect[V, C, R, R2] - def columns(f: (V[Column] => Column.Assignment[_])*): InsertColumns[V, R] + def columns(f: (V[Column] => Column.Assignment[?])*): InsertColumns[V, R] def values(f: R*): InsertValues[V, R] def batched[T1](f1: V[Column] => Column[T1])(items: Expr[T1]*): InsertColumns[V, R] @@ -32,9 +32,9 @@ object Insert { def newInsertValues[R]( insert: Insert[V, R], - columns: Seq[Column[_]], - valuesLists: Seq[Seq[Expr[_]]] - )(implicit qr: Queryable[V[Column], R]) = { + columns: Seq[Column[?]], + valuesLists: Seq[Seq[Expr[?]]] + )(implicit qr: Queryable[V[Column], R]): InsertColumns[V, R] = { new InsertColumns.Impl(insert, columns, valuesLists) } @@ -42,7 +42,7 @@ object Insert { newInsertSelect(this, columns(expr.asInstanceOf[V[Expr]]), select) } - def columns(f: (V[Column] => Column.Assignment[_])*): InsertColumns[V, R] = { + def columns(f: (V[Column] => Column.Assignment[?])*): InsertColumns[V, R] = { val kvs = f.map(_(expr)) newInsertValues(this, columns = kvs.map(_.column), valuesLists = Seq(kvs.map(_.value))) } diff --git a/scalasql/query/src/InsertColumns.scala b/scalasql/query/src/InsertColumns.scala index d5969a6c..1b44e1f8 100644 --- a/scalasql/query/src/InsertColumns.scala +++ b/scalasql/query/src/InsertColumns.scala @@ -9,21 +9,21 @@ import scalasql.core.SqlStr.{Renderable, SqlStringSyntax} trait InsertColumns[V[_[_]], R] extends Returning.InsertBase[V[Column]] with Query.ExecuteUpdate[Int] { - def columns: Seq[Column[_]] - def valuesLists: Seq[Seq[Expr[_]]] + def columns: Seq[Column[?]] + def valuesLists: Seq[Seq[Expr[?]]] } object InsertColumns { class Impl[V[_[_]], R]( insert: Insert[V, R], - val columns: Seq[Column[_]], - val valuesLists: Seq[Seq[Expr[_]]] + val columns: Seq[Column[?]], + val valuesLists: Seq[Seq[Expr[?]]] )(implicit val qr: Queryable[V[Column], R], dialect: DialectTypeMappers) extends InsertColumns[V, R] { import dialect.{dialectSelf => _, _} def table = insert.table protected def expr: V[Column] = WithSqlExpr.get(insert) - protected override def renderSql(ctx: Context) = + private[scalasql] override def renderSql(ctx: Context) = new Renderer(columns, ctx, valuesLists, Table.name(table.value)).render() override protected def queryConstruct(args: Queryable.ResultSetIterator): Int = @@ -31,9 +31,9 @@ object InsertColumns { } class Renderer( - columns0: Seq[Column[_]], + columns0: Seq[Column[?]], prevContext: Context, - valuesLists: Seq[Seq[Expr[_]]], + valuesLists: Seq[Seq[Expr[?]]], tableName: String ) { diff --git a/scalasql/query/src/InsertSelect.scala b/scalasql/query/src/InsertSelect.scala index 99794ba2..341a25c9 100644 --- a/scalasql/query/src/InsertSelect.scala +++ b/scalasql/query/src/InsertSelect.scala @@ -19,7 +19,7 @@ object InsertSelect { def table = insert.table - protected override def renderSql(ctx: Context) = + private[scalasql] override def renderSql(ctx: Context) = new Renderer(select, select.qr.walkExprs(columns), ctx, Table.name(table.value)) .render() @@ -28,8 +28,8 @@ object InsertSelect { } class Renderer( - select: Select[_, _], - exprs: Seq[Expr[_]], + select: Select[?, ?], + exprs: Seq[Expr[?]], prevContext: Context, tableName: String ) { @@ -38,7 +38,7 @@ object InsertSelect { lazy val columns = SqlStr.join( exprs - .map(_.asInstanceOf[Column[_]]) + .map(_.asInstanceOf[Column[?]]) .map(c => SqlStr.raw(ctx.config.columnNameMapper(c.name))), SqlStr.commaSep ) diff --git a/scalasql/query/src/InsertValues.scala b/scalasql/query/src/InsertValues.scala index 8b350deb..c949b64e 100644 --- a/scalasql/query/src/InsertValues.scala +++ b/scalasql/query/src/InsertValues.scala @@ -4,7 +4,7 @@ import scalasql.core.{Context, DialectTypeMappers, Expr, Queryable, SqlStr, With import scalasql.core.SqlStr.SqlStringSyntax trait InsertValues[V[_[_]], R] extends Returning.InsertBase[V[Expr]] with Query.ExecuteUpdate[Int] { - def skipColumns(x: (V[Column] => Column[_])*): InsertValues[V, R] + def skipColumns(x: (V[Column] => Column[?])*): InsertValues[V, R] } object InsertValues { class Impl[V[_[_]], R]( @@ -12,7 +12,7 @@ object InsertValues { values: Seq[R], dialect: DialectTypeMappers, qr: Queryable.Row[V[Column], R], - skippedColumns: Seq[Column[_]] + skippedColumns: Seq[Column[?]] ) extends InsertValues[V, R] { def table = insert.table @@ -20,7 +20,7 @@ object InsertValues { override protected def queryConstruct(args: Queryable.ResultSetIterator): Int = args.get(dialect.IntType) - override protected def renderSql(ctx: Context): SqlStr = { + override private[scalasql] def renderSql(ctx: Context): SqlStr = { new Renderer( Table.name(insert.table.value), Table.labels(insert.table.value), @@ -30,7 +30,7 @@ object InsertValues { )(ctx).render() } - override def skipColumns(x: (V[Column] => Column[_])*) = { + override def skipColumns(x: (V[Column] => Column[?])*): InsertValues[V, R] = { new Impl( insert, @@ -46,7 +46,7 @@ object InsertValues { columnsList0: Seq[String], valuesList: Seq[R], qr: Queryable.Row[Q, R], - skippedColumns: Seq[Column[_]] + skippedColumns: Seq[Column[?]] )(implicit ctx: Context) { lazy val skippedColumnsNames = skippedColumns.map(_.name).toSet diff --git a/scalasql/query/src/JoinAppend.scala b/scalasql/query/src/JoinAppend.scala index 3ab2ed87..e85bb7f6 100644 --- a/scalasql/query/src/JoinAppend.scala +++ b/scalasql/query/src/JoinAppend.scala @@ -17,7 +17,7 @@ trait JoinAppendLowPriority { implicit def default[Q, R, Q2, R2]( implicit qr0: Queryable.Row[Q, R], qr20: Queryable.Row[Q2, R2] - ) = new JoinAppend[Q, Q2, (Q, Q2), (R, R2)] { + ): JoinAppend[Q, Q2, (Q, Q2), (R, R2)] = new JoinAppend[Q, Q2, (Q, Q2), (R, R2)] { override def appendTuple(t: Q, v: Q2): (Q, Q2) = (t, v) def qr: Queryable.Row[(Q, Q2), (R, R2)] = Queryable.Row.Tuple2Queryable diff --git a/scalasql/query/src/LateralJoinOps.scala b/scalasql/query/src/LateralJoinOps.scala index 01c870b8..15c6df03 100644 --- a/scalasql/query/src/LateralJoinOps.scala +++ b/scalasql/query/src/LateralJoinOps.scala @@ -7,7 +7,7 @@ import scalasql.core.{JoinNullable, Queryable, Expr, WithSqlExpr} * allow for `JOIN` clauses to access the results of earlier `JOIN` and `FROM` clauses. * Only supported by Postgres and MySql */ -class LateralJoinOps[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] with Joinable[Q, R])( +class LateralJoinOps[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] & Joinable[Q, R])( implicit qr: Queryable.Row[Q, R] ) { diff --git a/scalasql/query/src/Model.scala b/scalasql/query/src/Model.scala index 7f77c924..22f2c4e5 100644 --- a/scalasql/query/src/Model.scala +++ b/scalasql/query/src/Model.scala @@ -5,7 +5,7 @@ import scalasql.core.Expr /** * Models a SQL `ORDER BY` clause */ -case class OrderBy(expr: Expr[_], ascDesc: Option[AscDesc], nulls: Option[Nulls]) +case class OrderBy(expr: Expr[?], ascDesc: Option[AscDesc], nulls: Option[Nulls]) sealed trait AscDesc @@ -40,12 +40,12 @@ object Nulls { /** * Models a SQL `GROUP BY` clause */ -case class GroupBy(key: Expr[_], select: () => Select[_, _], having: Seq[Expr[_]]) +case class GroupBy(key: Expr[?], select: () => Select[?, ?], having: Seq[Expr[?]]) /** * Models a SQL `JOIN` clause */ case class Join(prefix: String, from: Seq[Join.From]) object Join { - case class From(from: scalasql.core.Context.From, on: Option[Expr[_]]) + case class From(from: scalasql.core.Context.From, on: Option[Expr[?]]) } diff --git a/scalasql/query/src/OnConflict.scala b/scalasql/query/src/OnConflict.scala index fdef2fa1..399961c5 100644 --- a/scalasql/query/src/OnConflict.scala +++ b/scalasql/query/src/OnConflict.scala @@ -6,22 +6,22 @@ import scalasql.core.{Context, Queryable, SqlStr, WithSqlExpr} /** * A query with a SQL `ON CONFLICT` clause, typically an `INSERT` or an `UPDATE` */ -class OnConflict[Q, R](query: Query[R] with Returning.InsertBase[Q], expr: Q, table: TableRef) { - def onConflictIgnore(c: (Q => Column[_])*) = +class OnConflict[Q, R](query: Query[R] & Returning.InsertBase[Q], expr: Q, table: TableRef) { + def onConflictIgnore(c: (Q => Column[?])*) = new OnConflict.Ignore(query, c.map(_(expr)), table) - def onConflictUpdate(c: (Q => Column[_])*)(c2: (Q => Column.Assignment[_])*) = + def onConflictUpdate(c: (Q => Column[?])*)(c2: (Q => Column.Assignment[?])*) = new OnConflict.Update(query, c.map(_(expr)), c2.map(_(expr)), table) } object OnConflict { class Ignore[Q, R]( - protected val query: Query[R] with Returning.InsertBase[Q], - columns: Seq[Column[_]], + protected val query: Query[R] & Returning.InsertBase[Q], + columns: Seq[Column[?]], val table: TableRef ) extends Query.DelegateQuery[R] with Returning.InsertBase[Q] { protected def expr = WithSqlExpr.get(query) - protected def renderSql(ctx: Context) = { + private[scalasql] def renderSql(ctx: Context) = { val str = Renderable.renderSql(query)(ctx) str + sql" ON CONFLICT (${SqlStr.join(columns.map(c => SqlStr.raw(c.name)), SqlStr.commaSep)}) DO NOTHING" } @@ -33,14 +33,14 @@ object OnConflict { } class Update[Q, R]( - protected val query: Query[R] with Returning.InsertBase[Q], - columns: Seq[Column[_]], - updates: Seq[Column.Assignment[_]], + protected val query: Query[R] & Returning.InsertBase[Q], + columns: Seq[Column[?]], + updates: Seq[Column.Assignment[?]], val table: TableRef ) extends Query.DelegateQuery[R] with Returning.InsertBase[Q] { protected def expr = WithSqlExpr.get(query) - protected def renderSql(ctx: Context) = { + private[scalasql] def renderSql(ctx: Context) = { implicit val implicitCtx = Context.compute(ctx, Nil, Some(table)) val str = Renderable.renderSql(query) val columnsStr = SqlStr.join(columns.map(c => SqlStr.raw(c.name)), SqlStr.commaSep) diff --git a/scalasql/query/src/Query.scala b/scalasql/query/src/Query.scala index 43d2ea7d..a48f99de 100644 --- a/scalasql/query/src/Query.scala +++ b/scalasql/query/src/Query.scala @@ -9,9 +9,9 @@ import scalasql.core.{Context, Expr, Queryable, SqlStr, WithSqlExpr} */ trait Query[R] extends Renderable { protected def queryWalkLabels(): Seq[List[String]] - protected def queryWalkExprs(): Seq[Expr[_]] + protected def queryWalkExprs(): Seq[Expr[?]] protected def queryIsSingleRow: Boolean - protected def queryGetGeneratedKeys: Option[Queryable.Row[_, _]] = None + protected def queryGetGeneratedKeys: Option[Queryable.Row[?, ?]] = None protected def queryIsExecuteUpdate: Boolean = false protected def queryConstruct(args: Queryable.ResultSetIterator): R @@ -23,8 +23,8 @@ object Query { * Configuration for a typical update [[Query]] */ trait ExecuteUpdate[R] extends scalasql.query.Query[R] { - protected def queryWalkLabels() = Nil - protected def queryWalkExprs() = Nil + protected def queryWalkLabels(): Seq[List[String]] = Nil + protected def queryWalkExprs(): Seq[Expr[?]] = Nil protected override def queryIsSingleRow = true protected override def queryIsExecuteUpdate = true } @@ -34,7 +34,7 @@ object Query { * most of the abstract methods to it */ trait DelegateQuery[R] extends scalasql.query.Query[R] { - protected def query: Query[_] + protected def query: Query[?] protected def queryWalkLabels() = query.queryWalkLabels() protected def queryWalkExprs() = query.queryWalkExprs() protected override def queryIsSingleRow = query.queryIsSingleRow @@ -45,7 +45,7 @@ object Query { * Configuration for a [[Query]] that wraps an expr [[Q]] and [[Queryable]] */ trait DelegateQueryable[Q, R] extends scalasql.query.Query[R] with WithSqlExpr[Q] { - protected def qr: Queryable[Q, _] + protected def qr: Queryable[Q, ?] protected def queryWalkLabels() = qr.walkLabels(expr) protected def queryWalkExprs() = qr.walkExprs(expr) protected override def queryIsSingleRow = qr.isSingleRow(expr) @@ -82,7 +82,7 @@ object Query { class Single[R](protected val query: Query[Seq[R]]) extends Query.DelegateQuery[R] { protected override def queryIsSingleRow: Boolean = true - protected def renderSql(ctx: Context): SqlStr = Renderable.renderSql(query)(ctx) + private[scalasql] def renderSql(ctx: Context): SqlStr = Renderable.renderSql(query)(ctx) protected override def queryConstruct(args: Queryable.ResultSetIterator): R = query.queryConstruct(args).asInstanceOf[R] } diff --git a/scalasql/query/src/Returning.scala b/scalasql/query/src/Returning.scala index 0f0a1d44..daef3213 100644 --- a/scalasql/query/src/Returning.scala +++ b/scalasql/query/src/Returning.scala @@ -27,23 +27,23 @@ object Returning { * returning a `Seq[R]` where `R` is a Scala type compatible with the auto-generated * primary key type (typically something like `Int` or `Long`) */ - def getGeneratedKeys[R](implicit qr: Queryable.Row[_, R]): GetGeneratedKeys[Q, R] = { + def getGeneratedKeys[R](implicit qr: Queryable.Row[?, R]): GetGeneratedKeys[Q, R] = { new GetGeneratedKeys.Impl(this) } } - class InsertImpl[Q, R](returnable: InsertBase[_], returning: Q)( + class InsertImpl[Q, R](returnable: InsertBase[?], returning: Q)( implicit qr: Queryable.Row[Q, R] ) extends Returning.Impl0[Q, R](qr, returnable, returning) with Returning[Q, R] {} - class Impl[Q, R](returnable: Base[_], returning: Q)(implicit qr: Queryable.Row[Q, R]) + class Impl[Q, R](returnable: Base[?], returning: Q)(implicit qr: Queryable.Row[Q, R]) extends Impl0[Q, R](qr, returnable, returning) with Returning[Q, R] class Impl0[Q, R]( protected val qr: Queryable.Row[Q, R], - returnable: Base[_], + returnable: Base[?], protected val expr: Q ) extends Returning[Q, R] { @@ -53,7 +53,7 @@ object Returning { override def queryIsSingleRow = false - protected override def renderSql(ctx0: Context) = { + private[scalasql] override def renderSql(ctx0: Context) = { implicit val implicitCtx = Context.compute(ctx0, Nil, Some(returnable.table)) val prefix = Renderable.renderSql(returnable) diff --git a/scalasql/query/src/Select.scala b/scalasql/query/src/Select.scala index 3cac5702..c3f47b98 100644 --- a/scalasql/query/src/Select.scala +++ b/scalasql/query/src/Select.scala @@ -60,7 +60,7 @@ trait Select[Q, R] preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )(implicit qr: Queryable.Row[Q, R], dialect: DialectTypeMappers): SimpleSelect[Q, R] = new SimpleSelect(expr, exprPrefix, preserveAll, from, joins, where, groupBy0) @@ -70,7 +70,7 @@ trait Select[Q, R] /** * Causes this [[Select]] to ignore duplicate rows, translates into SQL `SELECT DISTINCT` */ - def distinct: Select[Q, R] = selectWithExprPrefix(true, ctx => sql"DISTINCT") + def distinct: Select[Q, R] = selectWithExprPrefix(true, _ => sql"DISTINCT") protected def selectWithExprPrefix(preserveAll: Boolean, s: Context => SqlStr): Select[Q, R] protected def subqueryRef(implicit qr: Queryable.Row[Q, R]) = new SubqueryRef(this) @@ -127,7 +127,7 @@ trait Select[Q, R] * call to [[sortBy]] taking priority. Can be followed by [[asc]], [[desc]], [[nullsFirst]] * or [[nullsLast]] to configure the sort order */ - def sortBy(f: Q => Expr[_]): Select[Q, R] + def sortBy(f: Q => Expr[?]): Select[Q, R] /** * Combined with [[sortBy]] to make the sort order ascending, translates into SQL `ASC` @@ -187,7 +187,7 @@ trait Select[Q, R] */ def take(n: Int): Select[Q, R] - protected def renderSql(ctx: Context): SqlStr = { + private[scalasql] def renderSql(ctx: Context): SqlStr = { val renderer = selectRenderer(ctx) renderer.render(LiveExprs.none).withCompleteQuery(true) @@ -281,7 +281,7 @@ object Select { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )(implicit qr: Queryable.Row[Q, R], dialect: DialectTypeMappers): SimpleSelect[Q, R] = lhs.newSimpleSelect(expr, exprPrefix, preserveAll, from, joins, where, groupBy0) @@ -325,7 +325,7 @@ object Select { )(implicit qrk: Queryable.Row[K, R2], qrv: Queryable.Row[V, R3]): Select[(K, V), (R2, R3)] = selectToSimpleSelect().groupBy(groupKey)(groupAggregate) - override def sortBy(f: Q => Expr[_]): Select[Q, R] = selectToSimpleSelect().sortBy(f) + override def sortBy(f: Q => Expr[?]): Select[Q, R] = selectToSimpleSelect().sortBy(f) override def asc: Select[Q, R] = selectToSimpleSelect().asc override def desc: Select[Q, R] = selectToSimpleSelect().desc override def nullsFirst: Select[Q, R] = selectToSimpleSelect().nullsFirst diff --git a/scalasql/query/src/SimpleSelect.scala b/scalasql/query/src/SimpleSelect.scala index dccee2be..c5359beb 100644 --- a/scalasql/query/src/SimpleSelect.scala +++ b/scalasql/query/src/SimpleSelect.scala @@ -25,7 +25,7 @@ class SimpleSelect[Q, R]( val preserveAll: Boolean, val from: Seq[Context.From], val joins: Seq[Join], - val where: Seq[Expr[_]], + val where: Seq[Expr[?]], val groupBy0: Option[GroupBy] )(implicit val qr: Queryable.Row[Q, R], protected val dialect: DialectTypeMappers) extends Select[Q, R] { @@ -36,7 +36,7 @@ class SimpleSelect[Q, R]( preserveAll: Boolean = this.preserveAll, from: Seq[Context.From] = this.from, joins: Seq[Join] = this.joins, - where: Seq[Expr[_]] = this.where, + where: Seq[Expr[?]] = this.where, groupBy0: Option[GroupBy] = this.groupBy0 )(implicit qr: Queryable.Row[Q, R]) = newSimpleSelect(expr, exprPrefix, preserveAll, from, joins, where, groupBy0) @@ -186,24 +186,24 @@ class SimpleSelect[Q, R]( res } - def sortBy(f: Q => Expr[_]) = { + def sortBy(f: Q => Expr[?]): Select[Q, R] = { newCompoundSelect(this, Nil, Seq(OrderBy(f(expr), None, None)), None, None) } - def asc = throw new Exception(".asc must follow .sortBy") - def desc = throw new Exception(".desc must follow .sortBy") - def nullsFirst = throw new Exception(".nullsFirst must follow .sortBy") - def nullsLast = throw new Exception(".nullsLast must follow .sortBy") + def asc: Select[Q, R] = throw new Exception(".asc must follow .sortBy") + def desc: Select[Q, R] = throw new Exception(".desc must follow .sortBy") + def nullsFirst: Select[Q, R] = throw new Exception(".nullsFirst must follow .sortBy") + def nullsLast: Select[Q, R] = throw new Exception(".nullsLast must follow .sortBy") def compound0(op: String, other: Select[Q, R]) = { val op2 = CompoundSelect.Op(op, Select.toSimpleFrom(other)) newCompoundSelect(this, Seq(op2), Nil, None, None) } - def drop(n: Int) = newCompoundSelect(this, Nil, Nil, None, Some(n)) - def take(n: Int) = newCompoundSelect(this, Nil, Nil, Some(n), None) + def drop(n: Int): Select[Q, R] = newCompoundSelect(this, Nil, Nil, None, Some(n)) + def take(n: Int): Select[Q, R] = newCompoundSelect(this, Nil, Nil, Some(n), None) - protected def selectRenderer(prevContext: Context): SimpleSelect.Renderer[_, _] = + protected def selectRenderer(prevContext: Context): SimpleSelect.Renderer[?, ?] = new SimpleSelect.Renderer(this, prevContext) protected def selectExprAliases(prevContext: Context) = { @@ -237,13 +237,13 @@ object SimpleSelect { )(f: (Q, Q2) => Q3)(implicit jqr: Queryable.Row[Q3, R3]) = { self.joinCopy(other, on, joinPrefix)(f) } - def getRenderer(s: SimpleSelect[_, _], prevContext: Context): SimpleSelect.Renderer[_, _] = + def getRenderer(s: SimpleSelect[?, ?], prevContext: Context): SimpleSelect.Renderer[?, ?] = s.selectRenderer(prevContext) class Renderer[Q, R](query: SimpleSelect[Q, R], prevContext: Context) extends SubqueryRef.Wrapped.Renderer { lazy val flattenedExpr = query.qr.walkLabelsAndExprs(query.expr) lazy val froms = query.from ++ query.joins.flatMap(_.from.map(_.from)) - implicit lazy val context = Context.compute(prevContext, froms, None) + implicit lazy val context: Context = Context.compute(prevContext, froms, None) lazy val joinOns = query.joins.map(_.from.map(_.on.map(t => SqlStr.flatten(Renderable.renderSql(t))))) diff --git a/scalasql/query/src/SqlWindow.scala b/scalasql/query/src/SqlWindow.scala index e7f0d6b0..6a1e26ce 100644 --- a/scalasql/query/src/SqlWindow.scala +++ b/scalasql/query/src/SqlWindow.scala @@ -7,7 +7,7 @@ import scalasql.core.Context case class SqlWindow[T]( e: Expr[T], - partitionBy0: Option[Expr[_]], + partitionBy0: Option[Expr[?]], filter0: Option[Expr[Boolean]], orderBy: Seq[scalasql.query.OrderBy], frameStart0: Option[SqlStr], @@ -37,10 +37,10 @@ case class SqlWindow[T]( } - def partitionBy(e: Expr[_]) = this.copy(partitionBy0 = Some(e)) + def partitionBy(e: Expr[?]) = this.copy(partitionBy0 = Some(e)) def filter(expr: Expr[Boolean]) = copy(filter0 = Some(expr)) - def sortBy(expr: Expr[_]) = { + def sortBy(expr: Expr[?]) = { val newOrder = Seq(OrderBy(expr, None, None)) copy(orderBy = newOrder ++ orderBy) diff --git a/scalasql/query/src/Table.scala b/scalasql/query/src/Table.scala index 650f8f7e..21839860 100644 --- a/scalasql/query/src/Table.scala +++ b/scalasql/query/src/Table.scala @@ -65,7 +65,7 @@ object Table { } class Metadata[V[_[_]]]( - val queryables: (DialectTypeMappers, Int) => Queryable.Row[_, _], + val queryables: (DialectTypeMappers, Int) => Queryable.Row[?, ?], val walkLabels0: () => Seq[String], val queryable: ( () => Seq[String], @@ -79,7 +79,7 @@ object Table { } object Metadata extends scalasql.query.TableMacros { - class QueryableProxy(queryables: Int => Queryable.Row[_, _]) { + class QueryableProxy(queryables: Int => Queryable.Row[?, ?]) { def apply[T, V](n: Int): Queryable.Row[T, V] = queryables(n).asInstanceOf[Queryable.Row[T, V]] } } @@ -87,12 +87,12 @@ object Table { object Internal { class TableQueryable[Q, R <: scala.Product]( walkLabels0: () => Seq[String], - walkExprs0: Q => Seq[Expr[_]], + walkExprs0: Q => Seq[Expr[?]], construct0: Queryable.ResultSetIterator => R, deconstruct0: R => Q = ??? ) extends Queryable.Row[Q, R] { def walkLabels(): Seq[List[String]] = walkLabels0().map(List(_)) - def walkExprs(q: Q): Seq[Expr[_]] = walkExprs0(q) + def walkExprs(q: Q): Seq[Expr[?]] = walkExprs0(q) def construct(args: Queryable.ResultSetIterator) = construct0(args) diff --git a/scalasql/query/src/Update.scala b/scalasql/query/src/Update.scala index f512cbe6..29349256 100644 --- a/scalasql/query/src/Update.scala +++ b/scalasql/query/src/Update.scala @@ -14,7 +14,7 @@ trait Update[Q, R] def filter(f: Q => Expr[Boolean]): Update[Q, R] def withFilter(f: Q => Expr[Boolean]): Update[Q, R] = filter(f) - def set(f: (Q => Column.Assignment[_])*): Update[Q, R] + def set(f: (Q => Column.Assignment[?])*): Update[Q, R] def join0[Q2, R2, QF, RF]( prefix: String, @@ -37,9 +37,9 @@ object Update { class Impl[Q, R]( val expr: Q, val table: TableRef, - val set0: Seq[Column.Assignment[_]], + val set0: Seq[Column.Assignment[?]], val joins: Seq[Join], - val where: Seq[Expr[_]] + val where: Seq[Expr[?]] )(implicit val qr: Queryable.Row[Q, R], dialect: DialectTypeMappers) extends Update[Q, R] { @@ -47,15 +47,15 @@ object Update { protected def copy[Q, R]( expr: Q = this.expr, table: TableRef = this.table, - set0: Seq[Column.Assignment[_]] = this.set0, + set0: Seq[Column.Assignment[?]] = this.set0, joins: Seq[Join] = this.joins, - where: Seq[Expr[_]] = this.where + where: Seq[Expr[?]] = this.where )(implicit qr: Queryable.Row[Q, R], dialect: DialectTypeMappers): Update[Q, R] = new Impl(expr, table, set0, joins, where) def filter(f: Q => Expr[Boolean]) = { this.copy(where = where ++ Seq(f(expr))) } - def set(f: (Q => Column.Assignment[_])*) = { this.copy(set0 = f.map(_(expr))) } + def set(f: (Q => Column.Assignment[?])*) = { this.copy(set0 = f.map(_(expr))) } def join0[Q2, R2, QF, RF]( prefix: String, @@ -74,7 +74,7 @@ object Update { ) } - protected override def renderSql(ctx: Context): SqlStr = + private[scalasql] override def renderSql(ctx: Context): SqlStr = new Renderer(joins, table, set0, where, ctx).render() override protected def queryConstruct(args: Queryable.ResultSetIterator): Int = { @@ -86,12 +86,12 @@ object Update { class Renderer( joins0: Seq[Join], table: TableRef, - set0: Seq[Column.Assignment[_]], - where0: Seq[Expr[_]], + set0: Seq[Column.Assignment[?]], + where0: Seq[Expr[?]], prevContext: Context ) { lazy val froms = joins0.flatMap(_.from).map(_.from) - implicit lazy val implicitCtx = Context.compute(prevContext, froms, Some(table)) + implicit lazy val implicitCtx: Context = Context.compute(prevContext, froms, Some(table)) lazy val tableName = SqlStr.raw(implicitCtx.config.tableNameMapper(Table.name(table.value))) diff --git a/scalasql/query/src/WithCte.scala b/scalasql/query/src/WithCte.scala index 994d4859..16b51c2d 100644 --- a/scalasql/query/src/WithCte.scala +++ b/scalasql/query/src/WithCte.scala @@ -17,7 +17,7 @@ import scalasql.core.SqlStr.SqlStringSyntax */ class WithCte[Q, R]( walked: Queryable.Walked, - val lhs: Select[_, _], + val lhs: Select[?, ?], val cteRef: WithCteRef, val rhs: Select[Q, R], val withPrefix: SqlStr = sql"WITH " @@ -37,12 +37,13 @@ class WithCte[Q, R]( new WithCte(walked, rhs.filter(f), cteRef, rhs) } - override def sortBy(f: Q => Expr[_]) = new WithCte(walked, lhs, cteRef, rhs.sortBy(f)) + override def sortBy(f: Q => Expr[?]): Select[Q, R] = + new WithCte(walked, lhs, cteRef, rhs.sortBy(f)) - override def drop(n: Int) = new WithCte(walked, lhs, cteRef, rhs.drop(n)) - override def take(n: Int) = new WithCte(walked, lhs, cteRef, rhs.take(n)) + override def drop(n: Int): Select[Q, R] = new WithCte(walked, lhs, cteRef, rhs.drop(n)) + override def take(n: Int): Select[Q, R] = new WithCte(walked, lhs, cteRef, rhs.take(n)) - override protected def selectRenderer(prevContext: Context) = + override protected def selectRenderer(prevContext: Context): SubqueryRef.Wrapped.Renderer = new WithCte.Renderer(walked, withPrefix, this, prevContext) override protected def selectExprAliases(prevContext: Context) = { @@ -62,7 +63,7 @@ object WithCte { protected val dialect: DialectTypeMappers ) extends Select.Proxy[Q, R] { - override def joinableToFromExpr = { + override def joinableToFromExpr: (Context.From, Q) = { val otherFrom = lhsSubQueryRef (otherFrom, WithSqlExpr.get(lhs)) } @@ -87,7 +88,7 @@ object WithCte { } } - override protected def renderSql(ctx: Context): SqlStr = { + override private[scalasql] def renderSql(ctx: Context): SqlStr = { SqlStr.raw(ctx.fromNaming(lhsSubQueryRef)) } } diff --git a/scalasql/src/dialects/Dialect.scala b/scalasql/src/dialects/Dialect.scala index 706b4743..c79b0164 100644 --- a/scalasql/src/dialects/Dialect.scala +++ b/scalasql/src/dialects/Dialect.scala @@ -222,7 +222,7 @@ trait Dialect extends DialectTypeMappers { v: Expr[T] ): operations.ExprNumericOps[T] = new operations.ExprNumericOps(v) - implicit def ExprOpsConv(v: Expr[_]): operations.ExprOps = new operations.ExprOps(v) + implicit def ExprOpsConv(v: Expr[?]): operations.ExprOps = new operations.ExprOps(v) implicit def ExprTypedOpsConv[T: ClassTag](v: Expr[T]): operations.ExprTypedOps[T] = new operations.ExprTypedOps(v) @@ -240,7 +240,7 @@ trait Dialect extends DialectTypeMappers { implicit def ExprStringOpsConv( v: Expr[String] - ): operations.ExprStringLikeOps[String] with operations.ExprStringOps[String] + ): operations.ExprStringLikeOps[String] & operations.ExprStringOps[String] implicit def ExprBlobOpsConv(v: Expr[geny.Bytes]): operations.ExprStringLikeOps[geny.Bytes] implicit def AggNumericOpsConv[V: Numeric: TypeMapper](v: Aggregatable[Expr[V]])( @@ -248,7 +248,7 @@ trait Dialect extends DialectTypeMappers { ): operations.AggNumericOps[V] = new operations.AggNumericOps(v) implicit def AggOpsConv[T](v: Aggregatable[T])( - implicit qr: Queryable.Row[T, _] + implicit qr: Queryable.Row[T, ?] ): operations.AggOps[T] = new operations.AggOps(v) implicit def ExprAggOpsConv[T](v: Aggregatable[Expr[T]]): operations.ExprAggOps[T] diff --git a/scalasql/src/dialects/H2Dialect.scala b/scalasql/src/dialects/H2Dialect.scala index 843cdcbc..1543efe4 100644 --- a/scalasql/src/dialects/H2Dialect.scala +++ b/scalasql/src/dialects/H2Dialect.scala @@ -12,7 +12,7 @@ import scalasql.core.{ TypeMapper } import scalasql.{Sc, operations} -import scalasql.query.{CompoundSelect, GroupBy, Join, Joinable, OrderBy, Table} +import scalasql.query.{CompoundSelect, GroupBy, Join, Joinable, OrderBy, Table, Values} import scalasql.core.SqlStr.SqlStringSyntax import scalasql.operations.{ BitwiseFunctionOps, @@ -52,7 +52,7 @@ trait H2Dialect extends Dialect { new H2Dialect.TableOps(t) override implicit def DbApiQueryOpsConv(db: => DbApi): DbApiQueryOps = new DbApiQueryOps(this) { - override def values[Q, R](ts: Seq[R])(implicit qr: Queryable.Row[Q, R]) = + override def values[Q, R](ts: Seq[R])(implicit qr: Queryable.Row[Q, R]): Values[Q, R] = new H2Dialect.Values(ts) } @@ -135,7 +135,7 @@ object H2Dialect extends H2Dialect { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )( implicit qr: Queryable.Row[Q, R], @@ -151,7 +151,7 @@ object H2Dialect extends H2Dialect { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.SimpleSelect( diff --git a/scalasql/src/dialects/MySqlDialect.scala b/scalasql/src/dialects/MySqlDialect.scala index 4b111def..a3ffcf5a 100644 --- a/scalasql/src/dialects/MySqlDialect.scala +++ b/scalasql/src/dialects/MySqlDialect.scala @@ -14,8 +14,10 @@ import scalasql.query.{ Nulls, OrderBy, Query, + SubqueryRef, Table, - TableRef + TableRef, + Values } import scalasql.core.{ Aggregatable, @@ -100,13 +102,13 @@ trait MySqlDialect extends Dialect { new MySqlDialect.OnConflictable[V[Column], Int](query, WithSqlExpr.get(query), query.table) override implicit def DbApiQueryOpsConv(db: => DbApi): DbApiQueryOps = new DbApiQueryOps(this) { - override def values[Q, R](ts: Seq[R])(implicit qr: Queryable.Row[Q, R]) = + override def values[Q, R](ts: Seq[R])(implicit qr: Queryable.Row[Q, R]): Values[Q, R] = new MySqlDialect.Values(ts) } - implicit def LateralJoinOpsConv[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] with Joinable[Q, R])( + implicit def LateralJoinOpsConv[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] & Joinable[Q, R])( implicit qr: Queryable.Row[Q, R] - ) = new LateralJoinOps(wrapped) + ): LateralJoinOps[C, Q, R] = new LateralJoinOps(wrapped) implicit def ExprAggOpsConv[T](v: Aggregatable[Expr[T]]): operations.ExprAggOps[T] = new MySqlDialect.ExprAggOps(v) @@ -216,22 +218,22 @@ object MySqlDialect extends MySqlDialect { class Update[Q, R]( expr: Q, table: TableRef, - set0: Seq[Column.Assignment[_]], + set0: Seq[Column.Assignment[?]], joins: Seq[Join], - where: Seq[Expr[_]] + where: Seq[Expr[?]] )(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.Update.Impl[Q, R](expr, table, set0, joins, where) { protected override def copy[Q, R]( expr: Q = this.expr, table: TableRef = this.table, - set0: Seq[Column.Assignment[_]] = this.set0, + set0: Seq[Column.Assignment[?]] = this.set0, joins: Seq[Join] = this.joins, - where: Seq[Expr[_]] = this.where - )(implicit qr: Queryable.Row[Q, R], dialect: scalasql.core.DialectTypeMappers) = + where: Seq[Expr[?]] = this.where + )(implicit qr: Queryable.Row[Q, R], dialect: scalasql.core.DialectTypeMappers): Update[Q, R] = new Update(expr, table, set0, joins, where) - protected override def renderSql(ctx: Context) = { + private[scalasql] override def renderSql(ctx: Context) = { new UpdateRenderer(this.joins, this.table, this.set0, this.where, ctx).render() } @@ -240,8 +242,8 @@ object MySqlDialect extends MySqlDialect { class UpdateRenderer( joins0: Seq[Join], table: TableRef, - set0: Seq[Column.Assignment[_]], - where0: Seq[Expr[_]], + set0: Seq[Column.Assignment[?]], + where0: Seq[Expr[?]], prevContext: Context ) extends scalasql.query.Update.Renderer(joins0, table, set0, where0, prevContext) { override lazy val updateList = set0.map { case assign => @@ -259,19 +261,19 @@ object MySqlDialect extends MySqlDialect { class OnConflictable[Q, R](val query: Query[R], expr: Q, table: TableRef) { - def onConflictUpdate(c2: Q => Column.Assignment[_]*): OnConflictUpdate[Q, R] = + def onConflictUpdate(c2: Q => Column.Assignment[?]*): OnConflictUpdate[Q, R] = new OnConflictUpdate(this, c2.map(_(expr)), table) } class OnConflictUpdate[Q, R]( insert: OnConflictable[Q, R], - updates: Seq[Column.Assignment[_]], + updates: Seq[Column.Assignment[?]], table: TableRef ) extends Query.DelegateQuery[R] { - protected def query = insert.query + protected def query: Query[?] = insert.query override def queryIsExecuteUpdate = true - protected def renderSql(ctx: Context) = { + private[scalasql] def renderSql(ctx: Context) = { implicit val implicitCtx = Context.compute(ctx, Nil, Some(table)) val str = Renderable.renderSql(insert.query) @@ -307,7 +309,7 @@ object MySqlDialect extends MySqlDialect { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )( implicit qr: Queryable.Row[Q, R], @@ -323,7 +325,7 @@ object MySqlDialect extends MySqlDialect { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.SimpleSelect( @@ -356,7 +358,7 @@ object MySqlDialect extends MySqlDialect { )(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.CompoundSelect(lhs, compoundOps, orderBy, limit, offset) with Select[Q, R] { - protected override def selectRenderer(prevContext: Context) = + protected override def selectRenderer(prevContext: Context): SubqueryRef.Wrapped.Renderer = new CompoundSelectRenderer(this, prevContext) } @@ -395,7 +397,7 @@ object MySqlDialect extends MySqlDialect { class Values[Q, R](ts: Seq[R])(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.Values[Q, R](ts) { - override protected def selectRenderer(prevContext: Context) = + override protected def selectRenderer(prevContext: Context): SubqueryRef.Wrapped.Renderer = new ValuesRenderer[Q, R](this)(implicitly, prevContext) override protected def columnName(n: Int) = s"column_$n" } diff --git a/scalasql/src/dialects/PostgresDialect.scala b/scalasql/src/dialects/PostgresDialect.scala index 6023c56d..038967d1 100644 --- a/scalasql/src/dialects/PostgresDialect.scala +++ b/scalasql/src/dialects/PostgresDialect.scala @@ -33,9 +33,9 @@ trait PostgresDialect extends Dialect with ReturningDialect with OnConflictOps { ): PostgresDialect.ExprStringLikeOps[geny.Bytes] = new PostgresDialect.ExprStringOps(v) - implicit def LateralJoinOpsConv[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] with Joinable[Q, R])( + implicit def LateralJoinOpsConv[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] & Joinable[Q, R])( implicit qr: Queryable.Row[Q, R] - ) = new LateralJoinOps(wrapped) + ): LateralJoinOps[C, Q, R] = new LateralJoinOps(wrapped) implicit def ExprAggOpsConv[T](v: Aggregatable[Expr[T]]): operations.ExprAggOps[T] = new PostgresDialect.ExprAggOps(v) @@ -49,7 +49,7 @@ trait PostgresDialect extends Dialect with ReturningDialect with OnConflictOps { * row” of each set is unpredictable unless ORDER BY is used to ensure that the desired * row appears first. For example: */ - def distinctOn(f: Q => Expr[_]): Select[Q, R] = { + def distinctOn(f: Q => Expr[?]): Select[Q, R] = { Select.withExprPrefix(r, true, implicit ctx => sql"DISTINCT ON (${f(WithSqlExpr.get(r))})") } } @@ -69,7 +69,7 @@ object PostgresDialect extends PostgresDialect { /** * Formats arguments according to a format string. This function is similar to the C function sprintf. */ - def format(template: Expr[String], values: Expr[_]*): Expr[String] = Expr { implicit ctx => + def format(template: Expr[String], values: Expr[?]*): Expr[String] = Expr { implicit ctx => sql"FORMAT($template, ${SqlStr.join(values.map(v => sql"$v"), SqlStr.commaSep)})" } diff --git a/scalasql/src/dialects/SqliteDialect.scala b/scalasql/src/dialects/SqliteDialect.scala index 7ddbb9ec..42fdb8c4 100644 --- a/scalasql/src/dialects/SqliteDialect.scala +++ b/scalasql/src/dialects/SqliteDialect.scala @@ -11,7 +11,7 @@ import scalasql.core.{ TypeMapper } import scalasql.{Sc, operations} -import scalasql.query.{CompoundSelect, GroupBy, Join, OrderBy, Table} +import scalasql.query.{CompoundSelect, GroupBy, Join, OrderBy, SubqueryRef, Table} import scalasql.core.SqlStr.SqlStringSyntax import scalasql.operations.TrimOps @@ -73,7 +73,7 @@ object SqliteDialect extends SqliteDialect { * The typeof(X) function returns a string that indicates the datatype of the * expression X: "null", "integer", "real", "text", or "blob". */ - def typeOf(v: Expr[_]): Expr[String] = Expr { implicit ctx => sql"TYPEOF($v)" } + def typeOf(v: Expr[?]): Expr[String] = Expr { implicit ctx => sql"TYPEOF($v)" } /** * The last_insert_rowid() function returns the ROWID of the last row insert @@ -121,7 +121,7 @@ object SqliteDialect extends SqliteDialect { * 0.0 for numeric formats or an empty string for %s. See the built-in printf() * documentation for additional information. */ - def format(template: Expr[String], values: Expr[_]*): Expr[String] = Expr { implicit ctx => + def format(template: Expr[String], values: Expr[?]*): Expr[String] = Expr { implicit ctx => sql"FORMAT($template, ${SqlStr.join(values.map(v => sql"$v"), SqlStr.commaSep)})" } @@ -135,7 +135,7 @@ object SqliteDialect extends SqliteDialect { * "hex(12345678)" renders as "3132333435363738" not the binary representation of * the integer value "0000000000BC614E". */ - def hex(value: Expr[_]): Expr[String] = Expr { implicit ctx => sql"HEX($value)" } + def hex(value: Expr[?]): Expr[String] = Expr { implicit ctx => sql"HEX($value)" } /** * The unhex(X,Y) function returns a BLOB value which is the decoding of the @@ -221,7 +221,7 @@ object SqliteDialect extends SqliteDialect { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )( implicit qr: Queryable.Row[Q, R], @@ -237,7 +237,7 @@ object SqliteDialect extends SqliteDialect { preserveAll: Boolean, from: Seq[Context.From], joins: Seq[Join], - where: Seq[Expr[_]], + where: Seq[Expr[?]], groupBy0: Option[GroupBy] )(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.SimpleSelect( @@ -260,7 +260,7 @@ object SqliteDialect extends SqliteDialect { )(implicit qr: Queryable.Row[Q, R]) extends scalasql.query.CompoundSelect(lhs, compoundOps, orderBy, limit, offset) with Select[Q, R] { - protected override def selectRenderer(prevContext: Context) = { + protected override def selectRenderer(prevContext: Context): SubqueryRef.Wrapped.Renderer = { new CompoundSelectRenderer(this, prevContext) } } diff --git a/scalasql/src/dialects/TableOps.scala b/scalasql/src/dialects/TableOps.scala index e806de82..2c166899 100644 --- a/scalasql/src/dialects/TableOps.scala +++ b/scalasql/src/dialects/TableOps.scala @@ -1,7 +1,7 @@ package scalasql.dialects import scalasql.dialects.Dialect -import scalasql.core.Expr +import scalasql.core.{Context, Expr} import scalasql.Sc import scalasql.query.{Column, Delete, Insert, Joinable, Select, SimpleSelect, Table, Update} @@ -15,7 +15,7 @@ class TableOps[V[_[_]]](val t: Table[V])(implicit dialect: Dialect) (ref, Table.metadata(t).vExpr(ref, dialect)) } - protected def joinableToFromExpr = { + protected def joinableToFromExpr: (Context.From, V[Expr]) = { val (ref, expr) = toFromExpr0 (ref, expr.asInstanceOf[V[Expr]]) } diff --git a/scalasql/test/src-3/Scala3ExampleTests.scala b/scalasql/test/src-3/Scala3ExampleTests.scala new file mode 100644 index 00000000..10f62b9a --- /dev/null +++ b/scalasql/test/src-3/Scala3ExampleTests.scala @@ -0,0 +1,7 @@ +package scalasql + +import utest._ + +object Scala3ExampleTests extends TestSuite: + def tests = Tests: + test("h2") - example.Scala3H2Example.main(Array()) diff --git a/scalasql/test/src-3/example/Scala3H2Example.scala b/scalasql/test/src-3/example/Scala3H2Example.scala new file mode 100644 index 00000000..eefc9c77 --- /dev/null +++ b/scalasql/test/src-3/example/Scala3H2Example.scala @@ -0,0 +1,61 @@ +package scalasql.example + +import scalasql.Table +import scalasql.H2Dialect._ + +object Scala3H2Example: + + case class ExampleProduct[T[_]]( + id: T[Int], + kebabCaseName: T[String], + name: T[String], + price: T[Double] + ) + + object ExampleProduct extends Table[ExampleProduct] + + // The example H2 database comes from the library `com.h2database:h2:2.2.224` + val dataSource = new org.h2.jdbcx.JdbcDataSource + dataSource.setUrl("jdbc:h2:mem:testScala3;DB_CLOSE_DELAY=-1") + lazy val h2Client = new scalasql.DbClient.DataSource( + dataSource, + config = new scalasql.Config {} + ) + + def main(args: Array[String]): Unit = + h2Client.transaction: db => + db.updateRaw(""" + CREATE TABLE example_product ( + id INTEGER AUTO_INCREMENT PRIMARY KEY, + kebab_case_name VARCHAR(256), + name VARCHAR(256), + price DECIMAL(20, 2) + ); + """) + + val inserted = db.run( + ExampleProduct.insert.batched(_.kebabCaseName, _.name, _.price)( + ("face-mask", "Face Mask", 8.88), + ("guitar", "Guitar", 300), + ("socks", "Socks", 3.14), + ("skate-board", "Skate Board", 123.45), + ("camera", "Camera", 1000.00), + ("cookie", "Cookie", 0.10) + ) + ) + + assert(inserted == 6) + + val result = + db.run(ExampleProduct.select.filter(_.price > 10).sortBy(_.price).desc.map(_.name)) + + assert(result == Seq("Camera", "Guitar", "Skate Board")) + + db.run(ExampleProduct.update(_.name === "Cookie").set(_.price := 11.0)) + + db.run(ExampleProduct.delete(_.name === "Guitar")) + + val result2 = + db.run(ExampleProduct.select.filter(_.price > 10).sortBy(_.price).desc.map(_.name)) + + assert(result2 == Seq("Camera", "Skate Board", "Cookie")) diff --git a/scalasql/test/src/api/TransactionTests.scala b/scalasql/test/src/api/TransactionTests.scala index 09b2e4eb..f95c1c39 100644 --- a/scalasql/test/src/api/TransactionTests.scala +++ b/scalasql/test/src/api/TransactionTests.scala @@ -119,7 +119,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 3)) ==> 3 db.run(Purchase.select.size) ==> 4 - db.savepoint { sp => + db.savepoint { _ => db.run(Purchase.delete(_ => true)) ==> 4 db.run(Purchase.select.size) ==> 0 } @@ -169,7 +169,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.select.size) ==> 4 try { - db.savepoint { sp => + db.savepoint { _ => db.run(Purchase.delete(_ => true)) ==> 4 db.run(Purchase.select.size) ==> 0 throw new FooException @@ -194,7 +194,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.select.size) ==> 4 try { - db.savepoint { sp => + db.savepoint { _ => db.run(Purchase.delete(_ => true)) ==> 4 db.run(Purchase.select.size) ==> 0 throw new FooException @@ -221,7 +221,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 3)) ==> 3 db.run(Purchase.select.size) ==> 4 - db.savepoint { sp => + db.savepoint { _ => db.run(Purchase.delete(_ => true)) ==> 4 db.run(Purchase.select.size) ==> 0 db.rollback() @@ -250,11 +250,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 } @@ -277,12 +277,12 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 try { - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 throw new FooException @@ -306,11 +306,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.select.size) ==> 5 try { - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 } @@ -334,11 +334,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.select.size) ==> 5 try { - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 throw new FooException @@ -360,11 +360,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 } @@ -385,11 +385,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 throw new FooException @@ -412,7 +412,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 @@ -442,7 +442,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 } @@ -469,7 +469,7 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 sp1.rollback() @@ -491,11 +491,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 } @@ -517,11 +517,11 @@ trait TransactionTests extends ScalaSqlSuite { db.run(Purchase.delete(_.id <= 2)) ==> 2 db.run(Purchase.select.size) ==> 5 - db.savepoint { sp1 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 4)) ==> 2 db.run(Purchase.select.size) ==> 3 - db.savepoint { sp2 => + db.savepoint { _ => db.run(Purchase.delete(_.id <= 6)) ==> 2 db.run(Purchase.select.size) ==> 1 db.rollback() diff --git a/scalasql/test/src/operations/DbMathOpsTests.scala b/scalasql/test/src/operations/DbMathOpsTests.scala index 38b3d043..6212a876 100644 --- a/scalasql/test/src/operations/DbMathOpsTests.scala +++ b/scalasql/test/src/operations/DbMathOpsTests.scala @@ -5,7 +5,7 @@ import scalasql.utils.ScalaSqlSuite import utest._ trait ExprMathOpsTests extends ScalaSqlSuite { - override implicit def DbApiOpsConv(db: => DbApi): DbApiOps with MathOps = ??? + override implicit def DbApiOpsConv(db: => DbApi): DbApiOps & MathOps = ??? def description = "Math operations; supported by H2/Postgres/MySql, not supported by Sqlite" def tests = Tests { diff --git a/scalasql/test/src/query/LateralJoinTests.scala b/scalasql/test/src/query/LateralJoinTests.scala index 7e9fc0e6..527fac69 100644 --- a/scalasql/test/src/query/LateralJoinTests.scala +++ b/scalasql/test/src/query/LateralJoinTests.scala @@ -8,7 +8,7 @@ import utils.ScalaSqlSuite import java.time.LocalDate trait LateralJoinTests extends ScalaSqlSuite { - implicit def LateralJoinOpsConv[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] with Joinable[Q, R])( + implicit def LateralJoinOpsConv[C[_, _], Q, R](wrapped: JoinOps[C, Q, R] & Joinable[Q, R])( implicit qr: Queryable.Row[Q, R] ): LateralJoinOps[C, Q, R] def description = """ diff --git a/scalasql/test/src/query/OnConflictTests.scala b/scalasql/test/src/query/OnConflictTests.scala index d0ebd442..aa0e1e2b 100644 --- a/scalasql/test/src/query/OnConflictTests.scala +++ b/scalasql/test/src/query/OnConflictTests.scala @@ -9,7 +9,7 @@ import utils.ScalaSqlSuite import java.time.LocalDate trait OnConflictTests extends ScalaSqlSuite { - this: OnConflictOps with ReturningDialect => + this: OnConflictOps & ReturningDialect => def description = "Queries using `ON CONFLICT DO UPDATE` or `ON CONFLICT DO NOTHING`" override def utestBeforeEach(path: Seq[String]): Unit = checker.reset() def tests = Tests {