From e231613750db3a7c036b70718a837f09e9ef8db5 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Sun, 29 Dec 2024 19:48:53 +0900 Subject: [PATCH 01/28] Added twiddles-core dependencies in dsl project --- build.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sbt b/build.sbt index 496789dc0..28c6b92ae 100644 --- a/build.sbt +++ b/build.sbt @@ -72,6 +72,7 @@ lazy val dsl = crossProject(JVMPlatform, JSPlatform, NativePlatform) .module("dsl", "Projects that provide a way to connect to the database") .settings( libraryDependencies ++= Seq( + "org.typelevel" %%% "twiddles-core" % "0.8.0", "org.typelevel" %%% "cats-effect" % "3.5.7", "org.typelevel" %%% "munit-cats-effect" % "2.0.0" % Test ) From 18fac6d554fb858b65fb5bb5b33f22e444231a3c Mon Sep 17 00:00:00 2001 From: takapi327 Date: Sun, 29 Dec 2024 19:49:17 +0900 Subject: [PATCH 02/28] Added ContravariantSemigroupal Encoder given --- .../src/main/scala/ldbc/dsl/codec/Encoder.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala index e2992b47d..b622cfbdc 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala @@ -10,7 +10,11 @@ import java.time.* import scala.compiletime.* +import cats.ContravariantSemigroupal import cats.data.NonEmptyList +import cats.syntax.all.* + +import org.typelevel.twiddles.TwiddleSyntax /** * Trait for converting Scala types to types that can be handled by PreparedStatement. @@ -42,13 +46,17 @@ trait Encoder[A]: /** `Encoder` is semigroupal: a pair of encoders make a encoder for a pair. */ def product[B](that: Encoder[B]): Encoder[(A, B)] = (value: (A, B)) => encode(value._1) product that.encode(value._2) -object Encoder: +object Encoder extends TwiddleSyntax[Encoder]: /** Types that can be handled by PreparedStatement. */ type Supported = Boolean | Byte | Short | Int | Long | Float | Double | BigDecimal | String | Array[Byte] | LocalTime | LocalDate | LocalDateTime | None.type def apply[A](using encoder: Encoder[A]): Encoder[A] = encoder + + given ContravariantSemigroupal[Encoder] with + override def contramap[A, B](fa: Encoder[A])(f: B => A): Encoder[B] = fa.contramap(f) + override def product[A, B](fa: Encoder[A], fb: Encoder[B]): Encoder[(A, B)] = fa.product(fb) given Encoder[Boolean] with override def encode(value: Boolean): Encoded = From 040c03280eefe5368010dd9ad89c03ab1df73d3b Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:42:24 +0900 Subject: [PATCH 03/28] Fixed Decoder to support twiddles --- .../main/scala/ldbc/dsl/codec/Decoder.scala | 242 ++++++------------ 1 file changed, 74 insertions(+), 168 deletions(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala index 625f2ff26..0d6c87aef 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala @@ -8,11 +8,11 @@ package ldbc.dsl.codec import java.time.* -import scala.compiletime.* import scala.deriving.Mirror -import cats.Functor -import cats.syntax.all.* +import cats.Applicative + +import org.typelevel.twiddles.TwiddleSyntax import ldbc.sql.ResultSet @@ -22,179 +22,85 @@ import ldbc.sql.ResultSet * @tparam A * Scala types that match SQL DataType */ -class Decoder[A](f: (resultSet: ResultSet, prefix: Option[String]) => A): +trait Decoder[A]: + self => /** - * Method to retrieve data from a ResultSet + * Offset value for the next data to be retrieved from the ResultSet. + */ + def offset: Int = 1 + + /** + * Method to retrieve data from a ResultSet using an Index number. * * @param resultSet - * A table of data representing a database result set, which is usually generated by executing a statement that - * queries the database. - * @param prefix - * Prefix to be added to the column name when retrieving data from the ResultSet. + * A table of data representing a database result set, which is usually generated by executing a statement that + * queries the database. + * @param index + * Index number of the data to be retrieved from the ResultSet. */ - def decode(resultSet: ResultSet, prefix: Option[String]): A = f(resultSet, prefix) + def decode(resultSet: ResultSet, index: Int): A + + /** Map decoded results to a new type `B`, yielding a `Decoder[B]`. */ + def map[B](f: A => B): Decoder[B] = new Decoder[B]: + override def offset: Int = self.offset + override def decode(resultSet: ResultSet, index: Int): B = f(self.decode(resultSet, index)) /** `Decoder` is semigroupal: a pair of decoders make a decoder for a pair. */ - def product[B](fb: Decoder[B]): Decoder[(A, B)] = - new Decoder((resultSet, prefix) => (this.decode(resultSet, None), fb.decode(resultSet, None))) + def product[B](fb: Decoder[B]): Decoder[(A, B)] = new Decoder[(A, B)]: + override def offset: Int = self.offset + fb.offset + override def decode(resultSet: ResultSet, index: Int): (A, B) = + (self.decode(resultSet, index), fb.decode(resultSet, index + self.offset)) /** Lift this `Decoder` into `Option`. */ - def opt: Decoder[Option[A]] = - new Decoder((resultSet, prefix) => - val value = this.decode(resultSet, prefix) + def opt: Decoder[Option[A]] = new Decoder[Option[A]]: + override def offset: Int = self.offset + override def decode(resultSet: ResultSet, index: Int): Option[A] = + val value = self.decode(resultSet, index) if resultSet.wasNull() then None else Some(value) - ) -object Decoder: - - given Functor[[A] =>> Decoder[A]] with - override def map[A, B](fa: Decoder[A])(f: A => B): Decoder[B] = - new Decoder((resultSet, prefix) => f(fa.decode(resultSet, prefix))) - - /** - * Trait to get the DataType that matches the Scala type information from the ResultSet. - * - * @tparam A - * Scala types that match SQL DataType - */ - trait Elem[A]: - - /** - * Method to retrieve data from a ResultSet using column names. - * - * @param resultSet - * A table of data representing a database result set, which is usually generated by executing a statement that - * queries the database. - * @param columnLabel - * Column name of the data to be retrieved from the ResultSet. - */ - def decode(resultSet: ResultSet, columnLabel: String): A - - /** - * Method to retrieve data from a ResultSet using an Index number. - * - * @param resultSet - * A table of data representing a database result set, which is usually generated by executing a statement that - * queries the database. - * @param index - * Index number of the data to be retrieved from the ResultSet. - */ - def decode(resultSet: ResultSet, index: Int): A - - object Elem: - - def apply[T]( - decodeLabel: ResultSet => String => T, - decodeIndex: ResultSet => Int => T - ): Elem[T] = - new Elem[T]: - override def decode(resultSet: ResultSet, columnLabel: String): T = - decodeLabel(resultSet)(columnLabel) - - override def decode(resultSet: ResultSet, index: Int): T = - decodeIndex(resultSet)(index) - - given Functor[[T] =>> Elem[T]] with - override def map[A, B](fa: Elem[A])(f: A => B): Elem[B] = - Elem( - resultSet => columnLabel => f(fa.decode(resultSet, columnLabel)), - resultSet => index => f(fa.decode(resultSet, index)) - ) - - /** - * A method to convert the specified Scala type to an arbitrary type so that it can be handled by Decoder. - * - * @param f - * Function to convert from type A to B. - * @param decoder - * Decoder to retrieve the DataType matching the type A information from the ResultSet. - * @tparam A - * The Scala type to be converted from. - * @tparam B - * The Scala type to be converted to. - */ - def mapping[A, B](f: A => B)(using decoder: Decoder.Elem[A]): Decoder.Elem[B] = - decoder.map(f(_)) - - given Elem[String] = Elem(_.getString, _.getString) - given Elem[Boolean] = Elem(_.getBoolean, _.getBoolean) - given Elem[Byte] = Elem(_.getByte, _.getByte) - given Elem[Array[Byte]] = Elem(_.getBytes, _.getBytes) - given Elem[Short] = Elem(_.getShort, _.getShort) - given Elem[Int] = Elem(_.getInt, _.getInt) - given Elem[Long] = Elem(_.getLong, _.getLong) - given Elem[Float] = Elem(_.getFloat, _.getFloat) - given Elem[Double] = Elem(_.getDouble, _.getDouble) - given Elem[LocalDate] = Elem(_.getDate, _.getDate) - given Elem[LocalTime] = Elem(_.getTime, _.getTime) - given Elem[LocalDateTime] = Elem(_.getTimestamp, _.getTimestamp) - given Elem[BigDecimal] = Elem(_.getBigDecimal, _.getBigDecimal) - - given (using decoder: Elem[String]): Elem[BigInt] = - decoder.map(str => if str == null then null else BigInt(str)) - - given (using decoder: Elem[Int]): Elem[Year] = - decoder.map(int => Year.of(int)) - - given (using decoder: Elem[String]): Elem[YearMonth] = - decoder.map(str => YearMonth.parse(str)) - - given [A](using decoder: Elem[A]): Elem[Option[A]] with - override def decode(resultSet: ResultSet, columnLabel: String): Option[A] = - val value = decoder.decode(resultSet, columnLabel) - if resultSet.wasNull() then None else Some(value) - - override def decode(resultSet: ResultSet, index: Int): Option[A] = - val value = decoder.decode(resultSet, index) - if resultSet.wasNull() then None else Some(value) - - def one[A](using decoder: Decoder.Elem[A]): Decoder[A] = - new Decoder((resultSet, prefix) => decoder.decode(resultSet, 1)) - - inline given derived[A](using mirror: Mirror.Of[A]): Decoder[A] = - inline mirror match - case s: Mirror.SumOf[A] => error("Sum type is not supported") - case p: Mirror.ProductOf[A] => derivedProduct(p) - - private[ldbc] inline def derivedProduct[A](mirror: Mirror.ProductOf[A]): Decoder[A] = - val labels = constValueTuple[mirror.MirroredElemLabels].toArray.map(_.toString) - val decodes = getDecoders[mirror.MirroredElemTypes].toArray - - new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => - val results = labels.zip(decodes).map { (label, decoder) => - val columns = (prefix.map(_ + ".").getOrElse("") + label).split('.') - // When selecting columns with a Select statement, no more than two `. ` is never used more than once when selecting a column in a Select statement. - // Therefore, if the length of the columns is greater than 2, it is assumed that the column name is specified in the format `table`.`column`. - // To support mapping to both nested classes and class Tuple`. ` to support mapping to both nested classes and class tuples. - val column = - if columns.length > 2 then columns.tail.mkString(".") else constValue[mirror.MirroredLabel] ++ "." ++ label - decoder match - case dm: Decoder.Elem[t] => dm.decode(resultSet, column) - case d: Decoder[t] => d.decode(resultSet, Some(column)) - } - - mirror.fromTuple(Tuple.fromArray(results).asInstanceOf[mirror.MirroredElemTypes]) - ) - - private[ldbc] inline def derivedTuple[A](mirror: Mirror.ProductOf[A]): Decoder[A] = - val decodes = getDecoders[mirror.MirroredElemTypes].toArray - - new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => - val results = decodes.zipWithIndex.map { (decoder, index) => - decoder match - case dm: Decoder.Elem[t] => dm.decode(resultSet, index + 1) - case d: Decoder[t] => d.decode(resultSet, prefix) - } - - mirror.fromTuple(Tuple.fromArray(results).asInstanceOf[mirror.MirroredElemTypes]) - ) - - private[ldbc] inline def getDecoders[T <: Tuple]: Tuple = - inline erasedValue[T] match - case _: EmptyTuple => EmptyTuple - case _: (t *: ts) => - summonFrom { - case dm: Decoder.Elem[`t`] => dm - case d: Decoder[`t`] => d - } *: getDecoders[ts] +object Decoder extends TwiddleSyntax[Decoder]: + + def apply[A](using decoder: Decoder[A]): Decoder[A] = decoder + + given Applicative[Decoder] with + override def map[A, B](fa: Decoder[A])(f: A => B): Decoder[B] = fa map f + override def ap[A, B](fab: Decoder[A => B])(fa: Decoder[A]): Decoder[B] = + map(fab.product(fa)) { case (fabb, a) => fabb(a) } + override def pure[A](x: A): Decoder[A] = new Decoder[A]: + override def offset: Int = 0 + override def decode(resultSet: ResultSet, index: Int): A = x + + given Decoder[String] = (resultSet: ResultSet, index: Int) => resultSet.getString(index) + given Decoder[Boolean] = (resultSet: ResultSet, index: Int) => resultSet.getBoolean(index) + given Decoder[Byte] = (resultSet: ResultSet, index: Int) => resultSet.getByte(index) + given Decoder[Array[Byte]] = (resultSet: ResultSet, index: Int) => resultSet.getBytes(index) + given Decoder[Short] = (resultSet: ResultSet, index: Int) => resultSet.getShort(index) + given Decoder[Int] = (resultSet: ResultSet, index: Int) => resultSet.getInt(index) + given Decoder[Long] = (resultSet: ResultSet, index: Int) => resultSet.getLong(index) + given Decoder[Float] = (resultSet: ResultSet, index: Int) => resultSet.getFloat(index) + given Decoder[Double] = (resultSet: ResultSet, index: Int) => resultSet.getDouble(index) + given Decoder[LocalDate] = (resultSet: ResultSet, index: Int) => resultSet.getDate(index) + given Decoder[LocalTime] = (resultSet: ResultSet, index: Int) => resultSet.getTime(index) + given Decoder[LocalDateTime] = (resultSet: ResultSet, index: Int) => resultSet.getTimestamp(index) + given Decoder[BigDecimal] = (resultSet: ResultSet, index: Int) => resultSet.getBigDecimal(index) + + given (using decoder: Decoder[String]): Decoder[BigInt] = + decoder.map(str => if str == null then null else BigInt(str)) + + given (using decoder: Decoder[Int]): Decoder[Year] = + decoder.map(int => Year.of(int)) + + given (using decoder: Decoder[String]): Decoder[YearMonth] = + decoder.map(str => YearMonth.parse(str)) + + given [A](using decoder: Decoder[A]): Decoder[Option[A]] = decoder.opt + + given [A, B](using da: Decoder[A], db: Decoder[B]): Decoder[(A, B)] = + da.product(db) + + given [H, T <: Tuple](using dh: Decoder[H], dt: Decoder[T]): Decoder[H *: T] = + dh.product(dt).map { case (h, t) => h *: t } + + given [P <: Product](using mirror: Mirror.ProductOf[P], decoder: Decoder[mirror.MirroredElemTypes]): Decoder[P] = + decoder.to[P] From 5607034ed703fcd786caf05070d9177c98ba7db2 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:42:44 +0900 Subject: [PATCH 04/28] Fixed Encoder to support twiddles --- .../src/main/scala/ldbc/dsl/codec/Encoder.scala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala index b622cfbdc..75d58d48d 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala @@ -9,6 +9,7 @@ package ldbc.dsl.codec import java.time.* import scala.compiletime.* +import scala.deriving.Mirror import cats.ContravariantSemigroupal import cats.data.NonEmptyList @@ -53,7 +54,7 @@ object Encoder extends TwiddleSyntax[Encoder]: LocalTime | LocalDate | LocalDateTime | None.type def apply[A](using encoder: Encoder[A]): Encoder[A] = encoder - + given ContravariantSemigroupal[Encoder] with override def contramap[A, B](fa: Encoder[A])(f: B => A): Encoder[B] = fa.contramap(f) override def product[A, B](fa: Encoder[A], fb: Encoder[B]): Encoder[(A, B)] = fa.product(fb) @@ -126,6 +127,15 @@ object Encoder extends TwiddleSyntax[Encoder]: case Some(value) => encoder.encode(value) case None => Encoded.success(List(None)) + given [A, B](using ea: Encoder[A], eb: Encoder[B]): Encoder[(A, B)] = + ea.product(eb) + + given [H, T <: Tuple](using eh: Encoder[H], et: Encoder[T]): Encoder[H *: T] = + eh.product(et).contramap { case h *: t => (h, t) } + + given [P <: Product](using mirror: Mirror.ProductOf[P], encoder: Encoder[mirror.MirroredElemTypes]): Encoder[P] = + encoder.to[P] + type MapToTuple[T] <: Tuple = T match case EmptyTuple => EmptyTuple case h *: EmptyTuple => Encoder[h] *: EmptyTuple From 6d5c7ece56961cee0cb336b474b61c7a122bb104 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:45:38 +0900 Subject: [PATCH 05/28] Update new Decoder syntax --- .../src/main/scala/ldbc/dsl/Mysql.scala | 25 +++---------------- .../scala/ldbc/dsl/ResultSetConsumer.scala | 4 +-- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/Mysql.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/Mysql.scala index 91fa1f2cd..e043ce4dd 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/Mysql.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/Mysql.scala @@ -7,8 +7,6 @@ package ldbc.dsl import scala.annotation.targetName -import scala.deriving.Mirror -import scala.compiletime.erasedValue import cats.syntax.all.* @@ -44,23 +42,8 @@ case class Mysql[F[_]: Temporal](statement: String, params: List[Parameter.Dynam * @return * A [[ldbc.dsl.Query]] instance */ - inline def query[T](using decoder: Decoder.Elem[T]): Query[F, T] = - Query.Impl[F, T](statement, params, Decoder.one[T]) - - /** - * A method to convert a query to a [[ldbc.dsl.Query]]. - * - * {{{ - * sql"SELECT `name`, `age` FROM user".query[User] - * }}} - * - * @return - * A [[ldbc.dsl.Query]] instance - */ - inline def query[P <: Product](using mirror: Mirror.ProductOf[P]): Query[F, P] = - inline erasedValue[P] match - case _: Tuple => Query.Impl[F, P](statement, params, Decoder.derivedTuple(mirror)) - case _ => Query.Impl[F, P](statement, params, Decoder.derivedProduct(mirror)) + def query[T](using decoder: Decoder[T]): Query[F, T] = + Query.Impl[F, T](statement, params, decoder) /** * A method to execute an update operation against the MySQL server. @@ -95,9 +78,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: List[Parameter.Dynam * @return * The primary key value */ - def returning[T <: String | Int | Long](using decoder: Decoder.Elem[T]): DBIO[F, T] = - given Decoder[T] = Decoder.one[T] - + def returning[T <: String | Int | Long](using Decoder[T]): DBIO[F, T] = DBIO.Impl[F, T]( statement, params, diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/ResultSetConsumer.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/ResultSetConsumer.scala index dd405b1aa..83806453e 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/ResultSetConsumer.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/ResultSetConsumer.scala @@ -50,7 +50,7 @@ object ResultSetConsumer: given [F[_]: Monad, T](using decoder: Decoder[T]): ResultSetConsumer[F, Option[T]] with override def consume(resultSet: ResultSet): F[Option[T]] = - if resultSet.next() then Monad[F].pure(decoder.decode(resultSet, None).some) else Monad[F].pure(None) + if resultSet.next() then Monad[F].pure(decoder.decode(resultSet, 1).some) else Monad[F].pure(None) given [F[_]: Monad, T, G[_]](using decoder: Decoder[T], @@ -58,5 +58,5 @@ object ResultSetConsumer: ): ResultSetConsumer[F, G[T]] with override def consume(resultSet: ResultSet): F[G[T]] = val builder = factoryCompat.newBuilder - while resultSet.next() do builder += decoder.decode(resultSet, None) + while resultSet.next() do builder += decoder.decode(resultSet, 1) Monad[F].pure(builder.result()) From 748f5e60ed79b7d9037ee8d3f4ac53f2bc116cdc Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:47:29 +0900 Subject: [PATCH 06/28] Update new Decoder syntax in statement project --- .../main/scala/ldbc/statement/Column.scala | 77 ++++++++----------- .../ldbc/statement/syntax/CommandSyntax.scala | 2 +- .../ldbc/statement/syntax/QuerySyntax.scala | 6 +- 3 files changed, 36 insertions(+), 49 deletions(-) diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala index 8f0b84a2a..f440021ad 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala @@ -59,7 +59,7 @@ trait Column[A]: def opt: Column[Option[A]] = Column.Opt[A](name, alias, decoder, encoder) - def count(using decoder: Decoder.Elem[Int]): Column.Count = Column.Count(name, alias) + def count(using Decoder[Int]): Column.Count = Column.Count(name, alias) def asc: OrderBy.Order[A] = OrderBy.Order.asc(this) def desc: OrderBy.Order[A] = OrderBy.Order.desc(this) @@ -73,10 +73,8 @@ trait Column[A]: override def name: String = self.name override def alias: Option[String] = self.alias override def as(name: String): Column[B] = this - override def decoder: Decoder[B] = - new Decoder[B]((resultSet: ResultSet, prefix: Option[String]) => f(self.decoder.decode(resultSet, prefix))) - override def encoder: Encoder[B] = - (value: B) => self.encoder.encode(g(value)) + override def decoder: Decoder[B] = self.decoder.map(f) + override def encoder: Encoder[B] = (value: B) => self.encoder.encode(g(value)) override def updateStatement: String = self.updateStatement override def duplicateKeyUpdateStatement: String = self.duplicateKeyUpdateStatement override def values: Int = self.values @@ -98,12 +96,14 @@ trait Column[A]: s"${ self.duplicateKeyUpdateStatement }, ${ fb.duplicateKeyUpdateStatement }" override def values: Int = self.values + fb.values override def opt: Column[Option[(A, B)]] = - val decoder = new Decoder[Option[(A, B)]]((resultSet: ResultSet, prefix: Option[String]) => - for - v1 <- self.opt.decoder.decode(resultSet, prefix) - v2 <- fb.opt.decoder.decode(resultSet, prefix) - yield (v1, v2) - ) + val decoder = new Decoder[Option[(A, B)]]: + override def offset: Int = self.decoder.offset + fb.decoder.offset + override def decode(resultSet: ResultSet, index: Int): Option[(A, B)] = + for + v1 <- self.opt.decoder.decode(resultSet, index) + v2 <- fb.opt.decoder.decode(resultSet, index + self.decoder.offset) + yield (v1, v2) + val encoder: Encoder[Option[(A, B)]] = { case Some((v1, v2)) => self.opt.encoder.encode(Some(v1)).product(fb.opt.encoder.encode(Some(v2))) case None => self.opt.encoder.encode(None).product(fb.opt.encoder.encode(None)) @@ -503,7 +503,7 @@ trait Column[A]: @targetName("_bitFlip") def ~(value: Extract[A])(using Encoder[Extract[A]]): BitFlip[A] = bitFlip(value) - def combine(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = + def combine(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = Column.MultiColumn[A]("+", this, other) /** @@ -520,9 +520,9 @@ trait Column[A]: * A query to combine columns in a SELECT statement */ @targetName("_combine") - def ++(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = combine(other) + def ++(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = combine(other) - def deduct(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = + def deduct(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = Column.MultiColumn[A]("-", this, other) /** @@ -539,9 +539,9 @@ trait Column[A]: * A query to subtract columns in a SELECT statement */ @targetName("_deduct") - def --(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = deduct(other) + def --(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = deduct(other) - def multiply(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = + def multiply(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = Column.MultiColumn[A]("*", this, other) /** @@ -558,9 +558,9 @@ trait Column[A]: * A query to multiply columns in a SELECT statement */ @targetName("_multiply") - def *(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = multiply(other) + def *(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = multiply(other) - def smash(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = + def smash(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = Column.MultiColumn[A]("/", this, other) /** @@ -577,7 +577,7 @@ trait Column[A]: * A query to divide columns in a SELECT statement */ @targetName("_smash") - def /(other: Column[A])(using Decoder.Elem[A], Encoder[A]): Column.MultiColumn[A] = smash(other) + def /(other: Column[A])(using Decoder[A], Encoder[A]): Column.MultiColumn[A] = smash(other) /** List of sub query methods */ def _equals(value: SQL): SubQuery[A] = @@ -684,8 +684,9 @@ object Column extends TwiddleSyntax[Column]: override def name: String = "" override def alias: Option[String] = None override def as(name: String): Column[A] = this - override def decoder: Decoder[A] = - new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => value) + override def decoder: Decoder[A] = new Decoder[A]: + override def offset: Int = 0 + override def decode(resultSet: ResultSet, index: Int): A = value override def encoder: Encoder[A] = (value: A) => Encoder.Encoded.success(List.empty) override def insertStatement: String = "" override def updateStatement: String = "" @@ -693,10 +694,10 @@ object Column extends TwiddleSyntax[Column]: override def values: Int = 0 override private[ldbc] def list: List[Column[?]] = List.empty - def apply[A](name: String)(using elem: Decoder.Elem[A], encoder: Encoder[A]): Column[A] = + def apply[A](name: String)(using Decoder[A], Encoder[A]): Column[A] = Impl[A](name) - def apply[A](name: String, alias: String)(using elem: Decoder.Elem[A], encoder: Encoder[A]): Column[A] = + def apply[A](name: String, alias: String)(using Decoder[A], Encoder[A]): Column[A] = Impl[A](name, s"$alias.$name") private[ldbc] case class Impl[A]( @@ -708,27 +709,16 @@ object Column extends TwiddleSyntax[Column]: update: Option[String] = None ) extends Column[A]: override def as(name: String): Column[A] = - this.copy( - alias = Some(name), - decoder = - new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => decoder.decode(resultSet, Some(name))) - ) + this.copy(alias = Some(name)) override def values: Int = length.getOrElse(1) override def updateStatement: String = update.getOrElse(s"$name = ?") override def duplicateKeyUpdateStatement: String = s"$name = VALUES(${ alias.getOrElse(name) })" object Impl: - def apply[A](name: String)(using elem: Decoder.Elem[A], encoder: Encoder[A]): Column[A] = - val decoder = new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => - val column = prefix.map(_ + ".").getOrElse("") + name - elem.decode(resultSet, column) - ) + def apply[A](name: String)(using decoder: Decoder[A], encoder: Encoder[A]): Column[A] = Impl[A](name, None, decoder, encoder) - def apply[A](name: String, alias: String)(using elem: Decoder.Elem[A], encoder: Encoder[A]): Column[A] = - val decoder = new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => - elem.decode(resultSet, prefix.getOrElse(alias)) - ) + def apply[A](name: String, alias: String)(using decoder: Decoder[A], encoder: Encoder[A]): Column[A] = Impl[A](name, Some(alias), decoder, encoder) private[ldbc] case class Opt[A]( @@ -750,32 +740,27 @@ object Column extends TwiddleSyntax[Column]: flag: String, left: Column[A], right: Column[A] - )(using elem: Decoder.Elem[A], _encoder: Encoder[A]) + )(using _decoder: Decoder[A], _encoder: Encoder[A]) extends Column[A]: override def name: String = s"${ left.noBagQuotLabel } $flag ${ right.noBagQuotLabel }" override def alias: Option[String] = Some( s"${ left.alias.getOrElse(left.name) } $flag ${ right.alias.getOrElse(right.name) }" ) override def as(name: String): Column[A] = this - override def decoder: Decoder[A] = - new Decoder[A]((resultSet: ResultSet, prefix: Option[String]) => - elem.decode(resultSet, prefix.map(_ + ".").getOrElse("") + name) - ) + override def decoder: Decoder[A] = _decoder override def encoder: Encoder[A] = _encoder override def insertStatement: String = "" override def updateStatement: String = "" override def duplicateKeyUpdateStatement: String = "" private[ldbc] case class Count(_name: String, _alias: Option[String])(using - elem: Decoder.Elem[Int], + _decoder: Decoder[Int], _encoder: Encoder[Int] ) extends Column[Int]: override def name: String = s"COUNT($_name)" override def alias: Option[String] = _alias.map(a => s"COUNT($a)") override def as(name: String): Column[Int] = this.copy(s"$name.${ _name }") - override def decoder: Decoder[Int] = new Decoder[Int]((resultSet: ResultSet, prefix: Option[String]) => - elem.decode(resultSet, alias.getOrElse(name)) - ) + override def decoder: Decoder[Int] = _decoder override def encoder: Encoder[Int] = _encoder override def toString: String = name override def insertStatement: String = "" diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/CommandSyntax.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/CommandSyntax.scala index ec2387a37..15fb2f9b4 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/CommandSyntax.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/CommandSyntax.scala @@ -44,4 +44,4 @@ trait CommandSyntax[F[_]]: * @return * The primary key value */ - def returning[T <: String | Int | Long](using decoder: Decoder.Elem[T]): DBIO[F, T] + def returning[T <: String | Int | Long](using Decoder[T]): DBIO[F, T] diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala index 01c2ec00e..7661acebe 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala @@ -9,6 +9,7 @@ package ldbc.statement.syntax import scala.deriving.Mirror import ldbc.dsl.{ Query as DslQuery, * } +import ldbc.dsl.codec.Decoder import ldbc.statement.Query trait QuerySyntax[F[_]]: @@ -37,8 +38,9 @@ trait QuerySyntax[F[_]]: * @return * A [[ldbc.dsl.Query]] instance */ - inline def queryTo[P <: Product](using + def queryTo[P <: Product](using m1: Mirror.ProductOf[P], m2: Mirror.ProductOf[B], - check: m1.MirroredElemTypes =:= m2.MirroredElemTypes + check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, + decoder: Decoder[P] ): DslQuery[F, P] From ccc1f58a6546524a38ef5c059db3188580715d1d Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:48:37 +0900 Subject: [PATCH 07/28] Update new Decoder syntax in query builder project --- .../main/scala/ldbc/query/builder/Table.scala | 55 +++++++------------ .../scala/ldbc/query/builder/TableQuery.scala | 17 +----- .../ldbc/query/builder/syntax/package.scala | 14 ++--- 3 files changed, 27 insertions(+), 59 deletions(-) diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala index 4d11de303..3f29d2a23 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala @@ -53,40 +53,17 @@ object Table: private[ldbc] case class Impl[P <: Product]( $name: String, columns: List[Column[?]] - )(using mirror: Mirror.ProductOf[P]) + )(using decoder: Decoder[P], encoder: Encoder[P]) extends Table[P]: override def statement: String = $name override def * : Column[P] = - val decoder: Decoder[P] = new Decoder[P]((resultSet, prefix) => - mirror.fromTuple( - Tuple - .fromArray(columns.map(_.decoder.decode(resultSet, prefix)).toArray) - .asInstanceOf[mirror.MirroredElemTypes] - ) - ) - - val encoder: Encoder[P] = (value: P) => - val list: List[(Any, Column[?])] = Tuple.fromProduct(value).toList.zip(columns) - list - .map { case (value, column) => column.encoder.encode(value.asInstanceOf) } - .foldLeft(Encoder.Encoded.success(List.empty[Encoder.Supported])) { - case (Encoder.Encoded.Success(fs1), Encoder.Encoded.Success(fs2)) => - Encoder.Encoded.success(fs1 ::: fs2) - case (Encoder.Encoded.Failure(e1), Encoder.Encoded.Failure(e2)) => - Encoder.Encoded.failure(e1.head, (e1.tail ++ e2.toList)*) - case (Encoder.Encoded.Failure(e), _) => - Encoder.Encoded.failure(e.head, e.tail*) - case (_, Encoder.Encoded.Failure(e)) => - Encoder.Encoded.failure(e.head, e.tail*) - } - val alias = columns.flatMap(_.alias).mkString(", ") Column.Impl[P]( columns.map(_.name).mkString(", "), if alias.isEmpty then None else Some(alias), - decoder, + decoder.to[P], encoder, Some(columns.length), Some(columns.map(column => s"${ column.name } = ?").mkString(", ")) @@ -110,8 +87,12 @@ object Table: case Some(naming) => naming case None => '{ Naming.SNAKE } - val mirror = Expr.summon[Mirror.ProductOf[P]].getOrElse { - report.errorAndAbort(s"Mirror for type $tpe not found") + val decoder = Expr.summon[Decoder[P]].getOrElse { + report.errorAndAbort(s"Decoder for type $tpe not found") + } + + val encoder = Expr.summon[Encoder[P]].getOrElse { + report.errorAndAbort(s"Encoder for type $tpe not found") } val labels = symbol.primaryConstructor.paramSymss.flatten @@ -131,7 +112,7 @@ object Table: case ValDef(name, tpt, _) => tpt.tpe.asType match case '[tpe] => - val decoder = Expr.summon[Decoder.Elem[tpe]].getOrElse { + val decoder = Expr.summon[Decoder[tpe]].getOrElse { report.errorAndAbort(s"Decoder for type $tpe not found") } val encoder = Expr.summon[Encoder[tpe]].getOrElse { @@ -149,7 +130,7 @@ object Table: ${ Expr.ofSeq(labels) } .zip($codecs) .map { - case (label: String, codec: (Decoder.Elem[t], Encoder[?])) => + case (label: String, codec: (Decoder[t], Encoder[?])) => Column[t](label, $naming.format($name))(using codec._1, codec._2.asInstanceOf[Encoder[t]]) } .toList @@ -159,7 +140,7 @@ object Table: Impl[P]( $naming.format($name), $columns - )(using $mirror) + )(using $decoder.to[P], $encoder) } private def derivedWithNameImpl[P <: Product](name: Expr[String])(using @@ -177,8 +158,12 @@ object Table: case Some(naming) => naming case None => '{ Naming.SNAKE } - val mirror = Expr.summon[Mirror.ProductOf[P]].getOrElse { - report.errorAndAbort(s"Mirror for type $tpe not found") + val decoder = Expr.summon[Decoder[P]].getOrElse { + report.errorAndAbort(s"Decoder for type $tpe not found") + } + + val encoder = Expr.summon[Encoder[P]].getOrElse { + report.errorAndAbort(s"Encoder for type $tpe not found") } val labels = symbol.primaryConstructor.paramSymss.flatten @@ -198,7 +183,7 @@ object Table: case ValDef(name, tpt, _) => tpt.tpe.asType match case '[tpe] => - val decoder = Expr.summon[Decoder.Elem[tpe]].getOrElse { + val decoder = Expr.summon[Decoder[tpe]].getOrElse { report.errorAndAbort(s"Decoder for type $tpe not found") } val encoder = Expr.summon[Encoder[tpe]].getOrElse { @@ -214,7 +199,7 @@ object Table: ${ Expr.ofSeq(labels) } .zip($codecs) .map { - case (label: String, codec: (Decoder.Elem[t], Encoder[?])) => + case (label: String, codec: (Decoder[t], Encoder[?])) => Column[t](label, $name)(using codec._1, codec._2.asInstanceOf[Encoder[t]]) } .toList @@ -224,7 +209,7 @@ object Table: Impl[P]( $name, $columns - )(using $mirror) + )(using $decoder, $encoder) } trait Opt[P] extends SharedTable, AbstractTable.Opt[P]: diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/TableQuery.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/TableQuery.scala index 73dcb6ee8..a5f54cc44 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/TableQuery.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/TableQuery.scala @@ -17,28 +17,15 @@ private[ldbc] case class TableQueryImpl[A <: SharedTable & AbstractTable[?], B < column: Column[AbstractTableQuery.Extract[A]], name: String, params: List[Parameter.Dynamic] -)(using mirror: Mirror.ProductOf[B]) - extends AbstractTableQuery[A, Table.Opt[AbstractTableQuery.Extract[A]]]: +) extends AbstractTableQuery[A, Table.Opt[AbstractTableQuery.Extract[A]]]: override private[ldbc] def toOption: AbstractTableQuery[A, Table.Opt[AbstractTableQuery.Extract[A]]] = val columnOpt = - val decoder: Decoder[Option[B]] = new Decoder[Option[B]]((resultSet, prefix) => - val decoded = table.columns.map(_.opt.decoder.decode(resultSet, prefix)) - if decoded.flatten.length == table.columns.length then - Option( - mirror.fromTuple( - Tuple - .fromArray(decoded.flatten.toArray) - .asInstanceOf[mirror.MirroredElemTypes] - ) - ) - else None - ) val alias = table.columns.flatMap(_.alias).mkString(", ") Column.Impl[Option[B]]( table.columns.map(_.name).mkString(", "), if alias.isEmpty then None else Some(alias), - decoder, + column.opt.decoder.asInstanceOf[Decoder[Option[B]]], column.opt.encoder.asInstanceOf[Encoder[Option[B]]], Some(table.columns.length), Some(table.columns.map(column => s"${ column.name } = ?").mkString(", ")) diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala index eb2a4cc16..db9e45ca8 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala @@ -7,7 +7,6 @@ package ldbc.query.builder import scala.deriving.Mirror -import scala.compiletime.erasedValue import cats.syntax.all.* @@ -32,14 +31,13 @@ package object syntax: def query: DslQuery[F, B] = DslQuery.Impl[F, B](query.statement, query.params, query.columns.decoder) - inline def queryTo[P <: Product](using + def queryTo[P <: Product](using m1: Mirror.ProductOf[P], m2: Mirror.ProductOf[B], - check: m1.MirroredElemTypes =:= m2.MirroredElemTypes + check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, + decoder: Decoder[P] ): DslQuery[F, P] = - inline erasedValue[P] match - case _: Tuple => DslQuery.Impl[F, P](query.statement, query.params, Decoder.derivedTuple(m1)) - case _ => DslQuery.Impl[F, P](query.statement, query.params, Decoder.derivedProduct(m1)) + DslQuery.Impl[F, P](query.statement, query.params, decoder) extension (command: Command) def update: DBIO[Int] = @@ -55,9 +53,7 @@ package object syntax: yield result ) - def returning[T <: String | Int | Long](using decoder: Decoder.Elem[T]): DBIO[T] = - given Decoder[T] = Decoder.one[T] - + def returning[T <: String | Int | Long](using Decoder[T]): DBIO[T] = DBIO.Impl[F, T]( command.statement, command.params, From 6409405fd29b38771365883f11d4cb938361c6c5 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:49:43 +0900 Subject: [PATCH 08/28] Update new Decoder syntax in schema project --- .../src/main/scala/ldbc/schema/ColumnImpl.scala | 5 +---- .../src/main/scala/ldbc/schema/Table.scala | 9 +++------ .../main/scala/ldbc/schema/syntax/package.scala | 14 +++++--------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala b/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala index 55b23777e..56d8882e7 100644 --- a/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala +++ b/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala @@ -20,10 +20,7 @@ private[ldbc] case class ColumnImpl[T]( ) extends Column[T]: override def as(name: String): Column[T] = - this.copy( - alias = Some(name), - decoder = new Decoder[T]((resultSet, prefix) => decoder.decode(resultSet, Some(name))) - ) + this.copy(alias = Some(name)) override def statement: String = dataType.fold(s"`$name`")(dataType => s"`$name` ${ dataType.queryString }") + attributes diff --git a/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala b/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala index 6a2a8dd13..feb324eec 100644 --- a/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala +++ b/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala @@ -18,22 +18,19 @@ trait Table[T](val $name: String) extends AbstractTable[T]: type Column[A] = ldbc.statement.Column[A] - protected final def column[A](name: String)(using elem: Decoder.Elem[A], encoder: Encoder[A]): Column[A] = - val decoder = new Decoder[A]((resultSet, prefix) => elem.decode(resultSet, prefix.getOrElse(s"${ $name }.$name"))) + protected final def column[A](name: String)(using decoder: Decoder[A], encoder: Encoder[A]): Column[A] = ColumnImpl[A](name, Some(s"${ $name }.$name"), decoder, encoder, None, List.empty) protected final def column[A](name: String, dataType: DataType[A])(using - elem: Decoder.Elem[A], + decoder: Decoder[A], encoder: Encoder[A] ): Column[A] = - val decoder = new Decoder[A]((resultSet, prefix) => elem.decode(resultSet, prefix.getOrElse(s"${ $name }.$name"))) ColumnImpl[A](name, Some(s"${ $name }.$name"), decoder, encoder, Some(dataType), List.empty) protected final def column[A](name: String, dataType: DataType[A], attributes: Attribute[A]*)(using - elem: Decoder.Elem[A], + decoder: Decoder[A], encoder: Encoder[A] ): Column[A] = - val decoder = new Decoder[A]((resultSet, prefix) => elem.decode(resultSet, prefix.getOrElse(s"${ $name }.$name"))) ColumnImpl[A](name, Some(s"${ $name }.$name"), decoder, encoder, Some(dataType), attributes.toList) /** diff --git a/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala b/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala index b0863fc28..5b63e72a3 100644 --- a/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala +++ b/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala @@ -7,7 +7,6 @@ package ldbc.schema import scala.deriving.Mirror -import scala.compiletime.erasedValue import cats.effect.* @@ -29,14 +28,13 @@ package object syntax: def query: DslQuery[F, B] = DslQuery.Impl[F, B](query.statement, query.params, query.columns.decoder) - inline def queryTo[P <: Product](using + def queryTo[P <: Product](using m1: Mirror.ProductOf[P], m2: Mirror.ProductOf[B], - check: m1.MirroredElemTypes =:= m2.MirroredElemTypes + check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, + decoder: Decoder[P] ): DslQuery[F, P] = - inline erasedValue[P] match - case _: Tuple => DslQuery.Impl[F, P](query.statement, query.params, Decoder.derivedTuple(m1)) - case _ => DslQuery.Impl[F, P](query.statement, query.params, Decoder.derivedProduct(m1)) + DslQuery.Impl[F, P](query.statement, query.params, decoder) extension (command: Command) def update: DBIO[Int] = @@ -52,9 +50,7 @@ package object syntax: yield result ) - def returning[T <: String | Int | Long](using decoder: Decoder.Elem[T]): DBIO[T] = - given Decoder[T] = Decoder.one[T] - + def returning[T <: String | Int | Long](using Decoder[T]): DBIO[T] = DBIO.Impl[F, T]( command.statement, command.params, From 13f0749ebfd3167450d64565b868ae3f592f7a86 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:50:18 +0900 Subject: [PATCH 09/28] Update new Decoder syntax for tests model --- tests/src/main/scala/ldbc/tests/model/Country.scala | 3 +-- tests/src/main/scala/ldbc/tests/model/CountryLanguage.scala | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/src/main/scala/ldbc/tests/model/Country.scala b/tests/src/main/scala/ldbc/tests/model/Country.scala index 5b8150e48..f438e1ed0 100644 --- a/tests/src/main/scala/ldbc/tests/model/Country.scala +++ b/tests/src/main/scala/ldbc/tests/model/Country.scala @@ -44,8 +44,7 @@ object Country: given Encoder[Continent] = Encoder[String].contramap(_.value) - given Decoder.Elem[Continent] = - Decoder.Elem.mapping[String, Continent](str => Continent.valueOf(str.replace(" ", "_"))) + given Decoder[Continent] = Decoder[String].map(str => Continent.valueOf(str.replace(" ", "_"))) given Table[Country] = Table.derived[Country]("country") diff --git a/tests/src/main/scala/ldbc/tests/model/CountryLanguage.scala b/tests/src/main/scala/ldbc/tests/model/CountryLanguage.scala index 25809d74d..d1f56a6f9 100644 --- a/tests/src/main/scala/ldbc/tests/model/CountryLanguage.scala +++ b/tests/src/main/scala/ldbc/tests/model/CountryLanguage.scala @@ -27,8 +27,7 @@ object CountryLanguage: given Encoder[IsOfficial] = Encoder[String].contramap(_.toString) - given Decoder.Elem[IsOfficial] = - Decoder.Elem.mapping[String, IsOfficial](str => IsOfficial.valueOf(str)) + given Decoder[IsOfficial] = Decoder[String].map(IsOfficial.valueOf) given Table[CountryLanguage] = Table.derived[CountryLanguage]("countrylanguage") From 9ebda5e10da8bce83e139cb9ccdcdf4b9d11d9c8 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:52:21 +0900 Subject: [PATCH 10/28] Update tests --- .../src/test/scala/ldbc/tests/CodecTest.scala | 2 +- .../tests/SQLStringContextQueryTest.scala | 75 ++++--------------- 2 files changed, 16 insertions(+), 61 deletions(-) diff --git a/tests/src/test/scala/ldbc/tests/CodecTest.scala b/tests/src/test/scala/ldbc/tests/CodecTest.scala index d3aa46d33..58a2e636b 100644 --- a/tests/src/test/scala/ldbc/tests/CodecTest.scala +++ b/tests/src/test/scala/ldbc/tests/CodecTest.scala @@ -294,7 +294,7 @@ trait CodecTest extends CatsEffectSuite: (for _ <- sql"CREATE TABLE none_test (none INT)".update _ <- sql"INSERT INTO none_test (none) VALUES (NULL)".update - result <- sql"SELECT * FROM none_test WHERE none IS NULL".query[None.type].to[Option] + result <- sql"SELECT * FROM none_test WHERE none IS NULL".query[Option[String]].to[Option] yield result).transaction(conn) }, Some(None) diff --git a/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala b/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala index ae460b9af..3ab054dfe 100644 --- a/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala +++ b/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala @@ -33,36 +33,6 @@ class LdbcSQLStringContextQueryTest extends SQLStringContextQueryTest: ssl = SSL.Trusted ) - test( - "If the acquired column name and the field name of the class to be mapped are different, an exception is raised." - ) { - case class City(id: Int, title: String) - - interceptIO[ldbc.connector.exception.SQLException]( - connection.use { conn => - sql"SELECT Id, Name FROM city LIMIT 1" - .query[City] - .to[Option] - .readOnly(conn) - } - ) - } - - test( - "If the number of columns retrieved is different from the number of fields in the class to be mapped, an exception is raised." - ) { - case class City(id: Int, name: String, age: Int) - - interceptIO[ldbc.connector.exception.SQLException]( - connection.use { conn => - sql"SELECT Id, Name FROM city LIMIT 1" - .query[City] - .to[Option] - .readOnly(conn) - } - ) - } - class JdbcSQLStringContextQueryTest extends SQLStringContextQueryTest: val ds = new MysqlDataSource() @@ -75,36 +45,6 @@ class JdbcSQLStringContextQueryTest extends SQLStringContextQueryTest: override def connection: Resource[IO, Connection[IO]] = Resource.make(jdbc.connector.MysqlDataSource[IO](ds).getConnection)(_.close()) - test( - "If the acquired column name and the field name of the class to be mapped are different, an exception is raised." - ) { - case class City(id: Int, title: String) - - interceptIO[java.sql.SQLException]( - connection.use { conn => - sql"SELECT Id, Name FROM city LIMIT 1" - .query[City] - .to[Option] - .readOnly(conn) - } - ) - } - - test( - "If the number of columns retrieved is different from the number of fields in the class to be mapped, an exception is raised." - ) { - case class City(id: Int, name: String, age: Int) - - interceptIO[java.sql.SQLException]( - connection.use { conn => - sql"SELECT Id, Name FROM city LIMIT 1" - .query[City] - .to[Option] - .readOnly(conn) - } - ) - } - trait SQLStringContextQueryTest extends CatsEffectSuite: given Tracer[IO] = Tracer.noop[IO] @@ -788,3 +728,18 @@ trait SQLStringContextQueryTest extends CatsEffectSuite: Some((City(1, "Kabul"), Country("AFG", "Afghanistan"))) ) } + + test( + "If the number of columns retrieved is different from the number of fields in the class to be mapped, an exception is raised." + ) { + case class City(id: Int, name: String, age: Int) + + interceptIO[ArrayIndexOutOfBoundsException]( + connection.use { conn => + sql"SELECT Id, Name FROM city LIMIT 1" + .query[City] + .to[Option] + .readOnly(conn) + } + ) + } From 019cdd3ca640aa0ae3fb63f2e12cb4833daf4d4c Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:53:04 +0900 Subject: [PATCH 11/28] Action sbt scalafmtAll --- .../main/scala/ldbc/dsl/codec/Decoder.scala | 10 ++--- .../main/scala/ldbc/dsl/codec/Encoder.scala | 4 +- .../ldbc/query/builder/syntax/package.scala | 8 ++-- .../main/scala/ldbc/schema/ColumnImpl.scala | 2 +- .../src/main/scala/ldbc/schema/Table.scala | 4 +- .../scala/ldbc/schema/syntax/package.scala | 8 ++-- .../main/scala/ldbc/statement/Column.scala | 38 +++++++++---------- .../ldbc/statement/syntax/QuerySyntax.scala | 8 ++-- 8 files changed, 41 insertions(+), 41 deletions(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala index 0d6c87aef..ee2559877 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Decoder.scala @@ -43,8 +43,8 @@ trait Decoder[A]: /** Map decoded results to a new type `B`, yielding a `Decoder[B]`. */ def map[B](f: A => B): Decoder[B] = new Decoder[B]: - override def offset: Int = self.offset - override def decode(resultSet: ResultSet, index: Int): B = f(self.decode(resultSet, index)) + override def offset: Int = self.offset + override def decode(resultSet: ResultSet, index: Int): B = f(self.decode(resultSet, index)) /** `Decoder` is semigroupal: a pair of decoders make a decoder for a pair. */ def product[B](fb: Decoder[B]): Decoder[(A, B)] = new Decoder[(A, B)]: @@ -68,8 +68,8 @@ object Decoder extends TwiddleSyntax[Decoder]: override def ap[A, B](fab: Decoder[A => B])(fa: Decoder[A]): Decoder[B] = map(fab.product(fa)) { case (fabb, a) => fabb(a) } override def pure[A](x: A): Decoder[A] = new Decoder[A]: - override def offset: Int = 0 - override def decode(resultSet: ResultSet, index: Int): A = x + override def offset: Int = 0 + override def decode(resultSet: ResultSet, index: Int): A = x given Decoder[String] = (resultSet: ResultSet, index: Int) => resultSet.getString(index) given Decoder[Boolean] = (resultSet: ResultSet, index: Int) => resultSet.getBoolean(index) @@ -101,6 +101,6 @@ object Decoder extends TwiddleSyntax[Decoder]: given [H, T <: Tuple](using dh: Decoder[H], dt: Decoder[T]): Decoder[H *: T] = dh.product(dt).map { case (h, t) => h *: t } - + given [P <: Product](using mirror: Mirror.ProductOf[P], decoder: Decoder[mirror.MirroredElemTypes]): Decoder[P] = decoder.to[P] diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala index 75d58d48d..00dce470a 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala @@ -56,8 +56,8 @@ object Encoder extends TwiddleSyntax[Encoder]: def apply[A](using encoder: Encoder[A]): Encoder[A] = encoder given ContravariantSemigroupal[Encoder] with - override def contramap[A, B](fa: Encoder[A])(f: B => A): Encoder[B] = fa.contramap(f) - override def product[A, B](fa: Encoder[A], fb: Encoder[B]): Encoder[(A, B)] = fa.product(fb) + override def contramap[A, B](fa: Encoder[A])(f: B => A): Encoder[B] = fa.contramap(f) + override def product[A, B](fa: Encoder[A], fb: Encoder[B]): Encoder[(A, B)] = fa.product(fb) given Encoder[Boolean] with override def encode(value: Boolean): Encoded = diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala index db9e45ca8..220be2ffe 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/syntax/package.scala @@ -32,10 +32,10 @@ package object syntax: def query: DslQuery[F, B] = DslQuery.Impl[F, B](query.statement, query.params, query.columns.decoder) def queryTo[P <: Product](using - m1: Mirror.ProductOf[P], - m2: Mirror.ProductOf[B], - check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, - decoder: Decoder[P] + m1: Mirror.ProductOf[P], + m2: Mirror.ProductOf[B], + check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, + decoder: Decoder[P] ): DslQuery[F, P] = DslQuery.Impl[F, P](query.statement, query.params, decoder) diff --git a/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala b/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala index 56d8882e7..3ba790b4d 100644 --- a/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala +++ b/module/ldbc-schema/src/main/scala/ldbc/schema/ColumnImpl.scala @@ -20,7 +20,7 @@ private[ldbc] case class ColumnImpl[T]( ) extends Column[T]: override def as(name: String): Column[T] = - this.copy(alias = Some(name)) + this.copy(alias = Some(name)) override def statement: String = dataType.fold(s"`$name`")(dataType => s"`$name` ${ dataType.queryString }") + attributes diff --git a/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala b/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala index feb324eec..d64855ae1 100644 --- a/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala +++ b/module/ldbc-schema/src/main/scala/ldbc/schema/Table.scala @@ -22,13 +22,13 @@ trait Table[T](val $name: String) extends AbstractTable[T]: ColumnImpl[A](name, Some(s"${ $name }.$name"), decoder, encoder, None, List.empty) protected final def column[A](name: String, dataType: DataType[A])(using - decoder: Decoder[A], + decoder: Decoder[A], encoder: Encoder[A] ): Column[A] = ColumnImpl[A](name, Some(s"${ $name }.$name"), decoder, encoder, Some(dataType), List.empty) protected final def column[A](name: String, dataType: DataType[A], attributes: Attribute[A]*)(using - decoder: Decoder[A], + decoder: Decoder[A], encoder: Encoder[A] ): Column[A] = ColumnImpl[A](name, Some(s"${ $name }.$name"), decoder, encoder, Some(dataType), attributes.toList) diff --git a/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala b/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala index 5b63e72a3..87b0415ad 100644 --- a/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala +++ b/module/ldbc-schema/src/main/scala/ldbc/schema/syntax/package.scala @@ -29,10 +29,10 @@ package object syntax: def query: DslQuery[F, B] = DslQuery.Impl[F, B](query.statement, query.params, query.columns.decoder) def queryTo[P <: Product](using - m1: Mirror.ProductOf[P], - m2: Mirror.ProductOf[B], - check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, - decoder: Decoder[P] + m1: Mirror.ProductOf[P], + m2: Mirror.ProductOf[B], + check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, + decoder: Decoder[P] ): DslQuery[F, P] = DslQuery.Impl[F, P](query.statement, query.params, decoder) diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala index f440021ad..fae44db95 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/Column.scala @@ -70,11 +70,11 @@ trait Column[A]: def imap[B](f: A => B)(g: B => A): Column[B] = new Column[B]: - override def name: String = self.name - override def alias: Option[String] = self.alias - override def as(name: String): Column[B] = this - override def decoder: Decoder[B] = self.decoder.map(f) - override def encoder: Encoder[B] = (value: B) => self.encoder.encode(g(value)) + override def name: String = self.name + override def alias: Option[String] = self.alias + override def as(name: String): Column[B] = this + override def decoder: Decoder[B] = self.decoder.map(f) + override def encoder: Encoder[B] = (value: B) => self.encoder.encode(g(value)) override def updateStatement: String = self.updateStatement override def duplicateKeyUpdateStatement: String = self.duplicateKeyUpdateStatement override def values: Int = self.values @@ -685,8 +685,8 @@ object Column extends TwiddleSyntax[Column]: override def alias: Option[String] = None override def as(name: String): Column[A] = this override def decoder: Decoder[A] = new Decoder[A]: - override def offset: Int = 0 - override def decode(resultSet: ResultSet, index: Int): A = value + override def offset: Int = 0 + override def decode(resultSet: ResultSet, index: Int): A = value override def encoder: Encoder[A] = (value: A) => Encoder.Encoded.success(List.empty) override def insertStatement: String = "" override def updateStatement: String = "" @@ -746,23 +746,23 @@ object Column extends TwiddleSyntax[Column]: override def alias: Option[String] = Some( s"${ left.alias.getOrElse(left.name) } $flag ${ right.alias.getOrElse(right.name) }" ) - override def as(name: String): Column[A] = this - override def decoder: Decoder[A] = _decoder + override def as(name: String): Column[A] = this + override def decoder: Decoder[A] = _decoder override def encoder: Encoder[A] = _encoder override def insertStatement: String = "" override def updateStatement: String = "" override def duplicateKeyUpdateStatement: String = "" private[ldbc] case class Count(_name: String, _alias: Option[String])(using - _decoder: Decoder[Int], + _decoder: Decoder[Int], _encoder: Encoder[Int] ) extends Column[Int]: - override def name: String = s"COUNT($_name)" - override def alias: Option[String] = _alias.map(a => s"COUNT($a)") - override def as(name: String): Column[Int] = this.copy(s"$name.${ _name }") - override def decoder: Decoder[Int] = _decoder - override def encoder: Encoder[Int] = _encoder - override def toString: String = name - override def insertStatement: String = "" - override def updateStatement: String = "" - override def duplicateKeyUpdateStatement: String = "" + override def name: String = s"COUNT($_name)" + override def alias: Option[String] = _alias.map(a => s"COUNT($a)") + override def as(name: String): Column[Int] = this.copy(s"$name.${ _name }") + override def decoder: Decoder[Int] = _decoder + override def encoder: Encoder[Int] = _encoder + override def toString: String = name + override def insertStatement: String = "" + override def updateStatement: String = "" + override def duplicateKeyUpdateStatement: String = "" diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala index 7661acebe..55723e62e 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/syntax/QuerySyntax.scala @@ -39,8 +39,8 @@ trait QuerySyntax[F[_]]: * A [[ldbc.dsl.Query]] instance */ def queryTo[P <: Product](using - m1: Mirror.ProductOf[P], - m2: Mirror.ProductOf[B], - check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, - decoder: Decoder[P] + m1: Mirror.ProductOf[P], + m2: Mirror.ProductOf[B], + check: m1.MirroredElemTypes =:= m2.MirroredElemTypes, + decoder: Decoder[P] ): DslQuery[F, P] From e9af719a14286cbfd6890d149de926dc63dd98b0 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:55:22 +0900 Subject: [PATCH 12/28] Action sbt scalafmtSbt --- build.sbt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 28c6b92ae..b19c819e1 100644 --- a/build.sbt +++ b/build.sbt @@ -72,7 +72,7 @@ lazy val dsl = crossProject(JVMPlatform, JSPlatform, NativePlatform) .module("dsl", "Projects that provide a way to connect to the database") .settings( libraryDependencies ++= Seq( - "org.typelevel" %%% "twiddles-core" % "0.8.0", + "org.typelevel" %%% "twiddles-core" % "0.8.0", "org.typelevel" %%% "cats-effect" % "3.5.7", "org.typelevel" %%% "munit-cats-effect" % "2.0.0" % Test ) @@ -84,8 +84,7 @@ lazy val statement = crossProject(JVMPlatform, JSPlatform, NativePlatform) .module("statement", "Project for building type-safe statements") .settings( libraryDependencies ++= Seq( - "org.typelevel" %%% "twiddles-core" % "0.8.0", - "org.scalatest" %%% "scalatest" % "3.2.18" % Test + "org.scalatest" %%% "scalatest" % "3.2.18" % Test ) ) .dependsOn(dsl) From 786f6cb531e429510f01ce5d0a0c8327307e7115 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:57:00 +0900 Subject: [PATCH 13/28] Delete unused --- .../src/main/scala/ldbc/query/builder/Table.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala index 3f29d2a23..8914c2214 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala @@ -63,7 +63,7 @@ object Table: Column.Impl[P]( columns.map(_.name).mkString(", "), if alias.isEmpty then None else Some(alias), - decoder.to[P], + decoder, encoder, Some(columns.length), Some(columns.map(column => s"${ column.name } = ?").mkString(", ")) From a02b5c1283dc5348a78d4b701edc5fbe00a8ddf3 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 18:57:29 +0900 Subject: [PATCH 14/28] Delete unused --- .../src/main/scala/ldbc/query/builder/Table.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala index 8914c2214..33761c890 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/Table.scala @@ -140,7 +140,7 @@ object Table: Impl[P]( $naming.format($name), $columns - )(using $decoder.to[P], $encoder) + )(using $decoder, $encoder) } private def derivedWithNameImpl[P <: Product](name: Expr[String])(using From 98358a3eea911af2db098968e13caad8290a38be Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:03:44 +0900 Subject: [PATCH 15/28] Change Old Decoder.Elem to new Decoder --- docs/src/main/scala/05-Program.scala | 2 +- .../src/main/scala/ldbc/codegen/TableModelGenerator.scala | 4 +--- .../src/test/scala/ldbc/schema/ColumnImplTest.scala | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/src/main/scala/05-Program.scala b/docs/src/main/scala/05-Program.scala index 42bcc0df6..16061963a 100644 --- a/docs/src/main/scala/05-Program.scala +++ b/docs/src/main/scala/05-Program.scala @@ -31,7 +31,7 @@ import ldbc.dsl.codec.* val program1: DBIO[Int] = sql"INSERT INTO user (name, email, status) VALUES (${ "user 1" }, ${ "user@example.com" }, ${ Status.Active })".update - given Decoder.Elem[Status] = Decoder.Elem.mapping[Boolean, Status] { + given Decoder[Status] = Decoder[Boolean].map { case true => Status.Active case false => Status.InActive } diff --git a/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala b/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala index a3a79c8d3..085d3de72 100644 --- a/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala +++ b/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala @@ -148,9 +148,7 @@ private[ldbc] object TableModelGenerator: Some(s"""enum $enumName extends model.Enum: | case ${ types.mkString(", ") } | object $enumName extends model.EnumDataType[$enumName]: - | given ldbc.dsl.codec.Decoder.Elem[$enumName] = new ldbc.dsl.codec.Decoder.Elem[$enumName]: - | override def decode(resultSet: ldbc.sql.ResultSet, columnLabel: String): $enumName = $enumName.fromOrdinal(resultSet.getInt(columnLabel)) - | override def decode(resultSet: ldbc.sql.ResultSet, index: Int): $enumName = $enumName.fromOrdinal(resultSet.getInt(index)) + | given ldbc.dsl.codec.Decoder[$enumName] = new ldbc.dsl.codec.Decoder[$enumName].map($enumName.fromOrdinal) | given ldbc.dsl.codec.Encoder[$enumName] = ldbc.dsl.codec.Encoder[Int].contramap(_.ordinal) |""".stripMargin) case _ => None diff --git a/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala b/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala index a45914ac1..2a1601aab 100644 --- a/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala +++ b/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala @@ -15,10 +15,9 @@ import ldbc.schema.attribute.* class ColumnImplTest extends AnyFlatSpec: private def column[A](name: String, dataType: DataType[A], attributes: Attribute[A]*)(using - elem: Decoder.Elem[A], + decoder: Decoder[A], encoder: Encoder[A] ): Column[A] = - val decoder = new Decoder[A]((resultSet, prefix) => elem.decode(resultSet, prefix.getOrElse(name))) ColumnImpl[A](name, None, decoder, encoder, Some(dataType), attributes.toList) it should "The query string of the Column model generated with only label and DataType matches the specified string." in { From 7228b3c9837d9661d6ca413d1fb4b55cf371c3e6 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:04:21 +0900 Subject: [PATCH 16/28] Action sbt scalafmtAll --- .../src/main/scala/ldbc/codegen/TableModelGenerator.scala | 2 +- .../ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala b/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala index 085d3de72..d47c5f018 100644 --- a/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala +++ b/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala @@ -148,7 +148,7 @@ private[ldbc] object TableModelGenerator: Some(s"""enum $enumName extends model.Enum: | case ${ types.mkString(", ") } | object $enumName extends model.EnumDataType[$enumName]: - | given ldbc.dsl.codec.Decoder[$enumName] = new ldbc.dsl.codec.Decoder[$enumName].map($enumName.fromOrdinal) + | given ldbc.dsl.codec.Decoder[$enumName] = new ldbc.dsl.codec.Decoder[Int].map($enumName.fromOrdinal) | given ldbc.dsl.codec.Encoder[$enumName] = ldbc.dsl.codec.Encoder[Int].contramap(_.ordinal) |""".stripMargin) case _ => None diff --git a/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala b/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala index 2a1601aab..dc9ac2806 100644 --- a/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala +++ b/module/ldbc-schema/src/test/scala/ldbc/schema/ColumnImplTest.scala @@ -15,7 +15,7 @@ import ldbc.schema.attribute.* class ColumnImplTest extends AnyFlatSpec: private def column[A](name: String, dataType: DataType[A], attributes: Attribute[A]*)(using - decoder: Decoder[A], + decoder: Decoder[A], encoder: Encoder[A] ): Column[A] = ColumnImpl[A](name, None, decoder, encoder, Some(dataType), attributes.toList) From b238c9dfb8a4cfd0529397610e8d2fd2c4bdb13b Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:17:13 +0900 Subject: [PATCH 17/28] Fixed compile error --- .../src/main/scala/benchmark/Model.scala | 11 +++++ .../tests/SQLStringContextQueryTest.scala | 45 ++++++++++++------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/benchmark/src/main/scala/benchmark/Model.scala b/benchmark/src/main/scala/benchmark/Model.scala index 719b20d10..abd215d86 100644 --- a/benchmark/src/main/scala/benchmark/Model.scala +++ b/benchmark/src/main/scala/benchmark/Model.scala @@ -6,6 +6,7 @@ package benchmark +import ldbc.dsl.codec.* import ldbc.query.builder.Table import ldbc.query.builder.formatter.Naming @@ -15,6 +16,10 @@ case class Model1( c1: Int ) derives Table +object Model1: + given Encoder[Model1] = Encoder[Int].to[Model1] + given Decoder[Model1] = Decoder[Int].to[Model1] + case class Model5( c1: Int, c2: Int, @@ -59,6 +64,9 @@ case class Model20( c20: Int ) derives Table +object Model20: + given Decoder[Model20] = (Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int]).to[Model20] + case class Model25( c1: Int, c2: Int, @@ -87,6 +95,9 @@ case class Model25( c25: Int ) derives Table +object Model25: + given Decoder[Model25] = (Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int]).to[Model25] + case class City( id: Int, name: String, diff --git a/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala b/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala index 3ab054dfe..f9fe0bec1 100644 --- a/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala +++ b/tests/src/test/scala/ldbc/tests/SQLStringContextQueryTest.scala @@ -33,6 +33,21 @@ class LdbcSQLStringContextQueryTest extends SQLStringContextQueryTest: ssl = SSL.Trusted ) + test( + "If the number of columns retrieved is different from the number of fields in the class to be mapped, an exception is raised." + ) { + case class City(id: Int, name: String, age: Int) + + interceptIO[ArrayIndexOutOfBoundsException]( + connection.use { conn => + sql"SELECT Id, Name FROM city LIMIT 1" + .query[City] + .to[Option] + .readOnly(conn) + } + ) + } + class JdbcSQLStringContextQueryTest extends SQLStringContextQueryTest: val ds = new MysqlDataSource() @@ -45,6 +60,21 @@ class JdbcSQLStringContextQueryTest extends SQLStringContextQueryTest: override def connection: Resource[IO, Connection[IO]] = Resource.make(jdbc.connector.MysqlDataSource[IO](ds).getConnection)(_.close()) + test( + "If the number of columns retrieved is different from the number of fields in the class to be mapped, an exception is raised." + ) { + case class City(id: Int, name: String, age: Int) + + interceptIO[java.sql.SQLException]( + connection.use { conn => + sql"SELECT Id, Name FROM city LIMIT 1" + .query[City] + .to[Option] + .readOnly(conn) + } + ) + } + trait SQLStringContextQueryTest extends CatsEffectSuite: given Tracer[IO] = Tracer.noop[IO] @@ -728,18 +758,3 @@ trait SQLStringContextQueryTest extends CatsEffectSuite: Some((City(1, "Kabul"), Country("AFG", "Afghanistan"))) ) } - - test( - "If the number of columns retrieved is different from the number of fields in the class to be mapped, an exception is raised." - ) { - case class City(id: Int, name: String, age: Int) - - interceptIO[ArrayIndexOutOfBoundsException]( - connection.use { conn => - sql"SELECT Id, Name FROM city LIMIT 1" - .query[City] - .to[Option] - .readOnly(conn) - } - ) - } From 36b3ba6d51ed533f592f2f56d6f5f7d352ecd187 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:18:57 +0900 Subject: [PATCH 18/28] Action sbt scalafmtAll --- benchmark/src/main/scala/benchmark/Model.scala | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/benchmark/src/main/scala/benchmark/Model.scala b/benchmark/src/main/scala/benchmark/Model.scala index abd215d86..03156f879 100644 --- a/benchmark/src/main/scala/benchmark/Model.scala +++ b/benchmark/src/main/scala/benchmark/Model.scala @@ -65,7 +65,12 @@ case class Model20( ) derives Table object Model20: - given Decoder[Model20] = (Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int]).to[Model20] + given Decoder[Model20] = ( + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] + ).to[Model20] case class Model25( c1: Int, @@ -96,7 +101,13 @@ case class Model25( ) derives Table object Model25: - given Decoder[Model25] = (Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int]).to[Model25] + given Decoder[Model25] = ( + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: + Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] + ).to[Model25] case class City( id: Int, From ccdd952d64115e4bf4f82437a49a1c852905b483 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:24:13 +0900 Subject: [PATCH 19/28] Added Encoder given --- benchmark/src/main/scala/benchmark/Model.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/benchmark/src/main/scala/benchmark/Model.scala b/benchmark/src/main/scala/benchmark/Model.scala index 03156f879..33b5d9f5d 100644 --- a/benchmark/src/main/scala/benchmark/Model.scala +++ b/benchmark/src/main/scala/benchmark/Model.scala @@ -101,6 +101,13 @@ case class Model25( ) derives Table object Model25: + given Encoder[Model25] = ( + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] + ).to[Model25] given Decoder[Model25] = ( Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: From 41c67537d4218e7d706f5eb45f751bd307f1df02 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:29:00 +0900 Subject: [PATCH 20/28] Added Encoder given --- benchmark/src/main/scala/benchmark/Model.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/benchmark/src/main/scala/benchmark/Model.scala b/benchmark/src/main/scala/benchmark/Model.scala index 33b5d9f5d..5f5d73440 100644 --- a/benchmark/src/main/scala/benchmark/Model.scala +++ b/benchmark/src/main/scala/benchmark/Model.scala @@ -65,6 +65,12 @@ case class Model20( ) derives Table object Model20: + given Encoder[Model20] = ( + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: + Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] + ).to[Model20] given Decoder[Model20] = ( Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: From d760dd7d597cc79c6f4dbe377133d58d2d6585e5 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:29:25 +0900 Subject: [PATCH 21/28] Action sbt scalafmtAll --- benchmark/src/main/scala/benchmark/Model.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/src/main/scala/benchmark/Model.scala b/benchmark/src/main/scala/benchmark/Model.scala index 5f5d73440..d41dd7971 100644 --- a/benchmark/src/main/scala/benchmark/Model.scala +++ b/benchmark/src/main/scala/benchmark/Model.scala @@ -70,7 +70,7 @@ object Model20: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] *: Encoder[Int] - ).to[Model20] + ).to[Model20] given Decoder[Model20] = ( Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: Decoder[Int] *: From b67963dd69737840ea15b6be239fc1fdea36d272 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:35:55 +0900 Subject: [PATCH 22/28] Added implicit-search-limit scalacOptions for tests project --- build.sbt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index b19c819e1..6dadfc8b6 100644 --- a/build.sbt +++ b/build.sbt @@ -201,7 +201,8 @@ lazy val tests = crossProject(JVMPlatform) .settings( name := "tests", description := "Projects for testing", - Test / fork := true + Test / fork := true, + scalacOptions += "-Ximplicit-search-limit:100000" ) .defaultSettings .settings( From 3dee0d2aa75194ba8ff3f61bf137e73f7849410f Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 19:37:21 +0900 Subject: [PATCH 23/28] Delete unused new prefix --- .../src/main/scala/ldbc/codegen/TableModelGenerator.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala b/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala index d47c5f018..9774000e1 100644 --- a/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala +++ b/module/ldbc-codegen/shared/src/main/scala/ldbc/codegen/TableModelGenerator.scala @@ -148,7 +148,7 @@ private[ldbc] object TableModelGenerator: Some(s"""enum $enumName extends model.Enum: | case ${ types.mkString(", ") } | object $enumName extends model.EnumDataType[$enumName]: - | given ldbc.dsl.codec.Decoder[$enumName] = new ldbc.dsl.codec.Decoder[Int].map($enumName.fromOrdinal) + | given ldbc.dsl.codec.Decoder[$enumName] = ldbc.dsl.codec.Decoder[Int].map($enumName.fromOrdinal) | given ldbc.dsl.codec.Encoder[$enumName] = ldbc.dsl.codec.Encoder[Int].contramap(_.ordinal) |""".stripMargin) case _ => None From b09745a1addfbf1b2e9a0afe0c1dae8c0ec0c13d Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 21:13:15 +0900 Subject: [PATCH 24/28] Added Country Decoder --- tests/src/main/scala/ldbc/tests/model/Country.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/src/main/scala/ldbc/tests/model/Country.scala b/tests/src/main/scala/ldbc/tests/model/Country.scala index f438e1ed0..cd4371817 100644 --- a/tests/src/main/scala/ldbc/tests/model/Country.scala +++ b/tests/src/main/scala/ldbc/tests/model/Country.scala @@ -46,6 +46,12 @@ object Country: given Decoder[Continent] = Decoder[String].map(str => Continent.valueOf(str.replace(" ", "_"))) + given Decoder[Country] = ( + Decoder[String] *: Decoder[String] *: Decoder[Continent] *: Decoder[String] *: Decoder[BigDecimal] *: + Decoder[Option[Short]] *: Decoder[Int] *: Decoder[Option[BigDecimal]] *: Decoder[Option[BigDecimal]] *: + Decoder[Option[BigDecimal]] *: Decoder[String] *: Decoder[String] *: Decoder[Option[String]] *: + Decoder[Option[Int]] *: Decoder[String] + ).to[Country] given Table[Country] = Table.derived[Country]("country") class CountryTable extends SchemaTable[Country]("country"): From 6620423a80009f365f9ff67c2d15a1b9b31aac4a Mon Sep 17 00:00:00 2001 From: takapi327 Date: Mon, 30 Dec 2024 21:19:49 +0900 Subject: [PATCH 25/28] Added Country Encoder --- tests/src/main/scala/ldbc/tests/model/Country.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/src/main/scala/ldbc/tests/model/Country.scala b/tests/src/main/scala/ldbc/tests/model/Country.scala index cd4371817..3a5cecbe8 100644 --- a/tests/src/main/scala/ldbc/tests/model/Country.scala +++ b/tests/src/main/scala/ldbc/tests/model/Country.scala @@ -46,6 +46,12 @@ object Country: given Decoder[Continent] = Decoder[String].map(str => Continent.valueOf(str.replace(" ", "_"))) + given Encoder[Country] = ( + Encoder[String] *: Encoder[String] *: Encoder[Continent] *: Encoder[String] *: Encoder[BigDecimal] *: + Encoder[Option[Short]] *: Encoder[Int] *: Encoder[Option[BigDecimal]] *: Encoder[Option[BigDecimal]] *: + Encoder[Option[BigDecimal]] *: Encoder[String] *: Encoder[String] *: Encoder[Option[String]] *: + Encoder[Option[Int]] *: Encoder[String] + ).to[Country] given Decoder[Country] = ( Decoder[String] *: Decoder[String] *: Decoder[Continent] *: Decoder[String] *: Decoder[BigDecimal] *: Decoder[Option[Short]] *: Decoder[Int] *: Decoder[Option[BigDecimal]] *: Decoder[Option[BigDecimal]] *: From b272c2c89c312135036230b174abb07fed7038ad Mon Sep 17 00:00:00 2001 From: takapi327 Date: Tue, 31 Dec 2024 16:54:40 +0900 Subject: [PATCH 26/28] Change use mirror -> encoder --- .../src/main/scala/ldbc/dsl/package.scala | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala index 4acee0e7f..76712e2ac 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala @@ -8,7 +8,7 @@ package ldbc import java.time.* -import scala.deriving.Mirror +//import scala.deriving.Mirror import cats.{ Foldable, Functor, Reducible } import cats.data.NonEmptyList @@ -72,24 +72,13 @@ package object dsl: // The following helper functions for building SQL models are rewritten from doobie fragments for ldbc SQL models. // see: https://github.com/tpolecat/doobie/blob/main/modules/core/src/main/scala/doobie/util/fragments.scala - /** Returns `VALUES (v0), (v1), ...`. */ - def values[M[_]: Reducible, T](vs: M[T])(using Encoder[T]): Mysql[F] = - sql"VALUES" ++ comma(vs.toNonEmptyList.map(v => parentheses(p"$v"))) - /** Returns `VALUES (v0, v1), (v2, v3), ...`. */ - inline def values[M[_]: Reducible, T <: Product](vs: M[T])(using Mirror.ProductOf[T]): Mysql[F] = - sql"VALUES" ++ comma(vs.toNonEmptyList.map(v => parentheses(values(v)))) - - private inline def values[T <: Product](v: T)(using mirror: Mirror.ProductOf[T]): Mysql[F] = - val tuple = Encoder.fold[mirror.MirroredElemTypes] - val params = tuple.toList - Mysql[F]( - List.fill(params.size)("?").mkString(","), - (Tuple.fromProduct(v).toList zip params).flatMap { - case (value, param) => - Parameter.Dynamic.many(param.asInstanceOf[Encoder[Any]].encode(value.asInstanceOf[Any])) - } - ) + def values[M[_]: Reducible, T <: Product](vs: M[T])(using Encoder[T]): Mysql[F] = + sql"VALUES" ++ comma(vs.toNonEmptyList.map(v => parentheses(values[T](v)))) + + private def values[T <: Product](v: T)(using encoder: Encoder[T]): Mysql[F] = + val params = Parameter.Dynamic.many(encoder.encode(v)) + Mysql[F](List.fill(params.size)("?").mkString(","), params) /** Returns `(sql IN (v0, v1, ...))`. */ def in[T](s: SQL, v0: T, v1: T, vs: T*)(using Encoder[T]): Mysql[F] = From 010b5a8714856548ff2fa84c0b85b98bc0549b59 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Tue, 31 Dec 2024 16:56:16 +0900 Subject: [PATCH 27/28] Delete unused --- .../ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala | 8 -------- 1 file changed, 8 deletions(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala index 00dce470a..d607e3e2e 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/codec/Encoder.scala @@ -8,7 +8,6 @@ package ldbc.dsl.codec import java.time.* -import scala.compiletime.* import scala.deriving.Mirror import cats.ContravariantSemigroupal @@ -136,13 +135,6 @@ object Encoder extends TwiddleSyntax[Encoder]: given [P <: Product](using mirror: Mirror.ProductOf[P], encoder: Encoder[mirror.MirroredElemTypes]): Encoder[P] = encoder.to[P] - type MapToTuple[T] <: Tuple = T match - case EmptyTuple => EmptyTuple - case h *: EmptyTuple => Encoder[h] *: EmptyTuple - case h *: t => Encoder[h] *: MapToTuple[t] - - inline def fold[T]: MapToTuple[T] = summonAll[MapToTuple[T]] - sealed trait Encoded: def product(that: Encoded): Encoded object Encoded: From 9e3d7685e2e4a14a188ee27d752a2211c4017197 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Tue, 31 Dec 2024 17:02:09 +0900 Subject: [PATCH 28/28] Delete Product param --- module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala b/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala index 76712e2ac..8eb18fc75 100644 --- a/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala +++ b/module/ldbc-dsl/src/main/scala/ldbc/dsl/package.scala @@ -73,10 +73,10 @@ package object dsl: // see: https://github.com/tpolecat/doobie/blob/main/modules/core/src/main/scala/doobie/util/fragments.scala /** Returns `VALUES (v0, v1), (v2, v3), ...`. */ - def values[M[_]: Reducible, T <: Product](vs: M[T])(using Encoder[T]): Mysql[F] = - sql"VALUES" ++ comma(vs.toNonEmptyList.map(v => parentheses(values[T](v)))) + def values[M[_]: Reducible, T](vs: M[T])(using Encoder[T]): Mysql[F] = + sql"VALUES" ++ comma(vs.toNonEmptyList.map(v => parentheses(values(v)))) - private def values[T <: Product](v: T)(using encoder: Encoder[T]): Mysql[F] = + private def values[T](v: T)(using encoder: Encoder[T]): Mysql[F] = val params = Parameter.Dynamic.many(encoder.encode(v)) Mysql[F](List.fill(params.size)("?").mkString(","), params)