From 478b6b7258f22f52f429b1df3991d57efe0bb8d2 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:17:40 +0900 Subject: [PATCH 01/13] Create Query --- .../src/main/scala/ldbc/sql/Query.scala | 85 +++++++++++++++++++ .../src/main/scala/ldbc/sql/SQL.scala | 24 +++--- 2 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala new file mode 100644 index 000000000..61889a174 --- /dev/null +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2023-2024 by Takahiko Tominaga + * This software is licensed under the MIT License (MIT). + * For more information see LICENSE or https://opensource.org/licenses/MIT + */ + +package ldbc.sql + +import cats.* + +trait Query[F[_], T]: + + def run: Connection[F] => F[T] + + def map[B](f: T => B)(using Functor[F]): Query[F, B] = + new Query[F, B]: + override def run: Connection[F] => F[B] = conn => Functor[F].map(Query.this.run(conn))(f) + override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(Query.this.readOnly(connection))(f) + override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(Query.this.autoCommit(connection))(f) + override def transaction(connection: Connection[F]): F[B] = Functor[F].map(Query.this.transaction(connection))(f) + override def rollback(connection: Connection[F]): F[B] = Functor[F].map(Query.this.rollback(connection))(f) + + def flatMap[B](f: T => Query[F, B])(using Monad[F]): Query[F, B] = + new Query[F, B]: + override def run: Connection[F] => F[B] = conn => Monad[F].flatMap(Query.this.run(conn))(a => f(a).run(conn)) + override def readOnly(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.readOnly(connection))(a => f(a).readOnly(connection)) + override def autoCommit(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.autoCommit(connection))(a => f(a).autoCommit(connection)) + override def transaction(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.transaction(connection))(a => f(a).transaction(connection)) + override def rollback(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.rollback(connection))(a => f(a).rollback(connection)) + + /** + * Functions for managing the processing of connections in a read-only manner. + */ + def readOnly(connection: Connection[F]): F[T] + + /** + * Functions to manage the processing of connections for writing. + */ + def autoCommit(connection: Connection[F]): F[T] + + /** + * Functions to manage the processing of connections in a transaction. + */ + def transaction(connection: Connection[F]): F[T] + + /** + * Functions to manage the processing of connections, always rolling back. + */ + def rollback(connection: Connection[F]): F[T] + +object Query: + + given [F[_]: Functor]: Functor[[T] =>> Query[F, T]] with + override def map[A, B](fa: Query[F, A])(f: A => B): Query[F, B] = + new Query[F, B]: + override def run: Connection[F] => F[B] = conn => Functor[F].map(fa.run(conn))(f) + override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(fa.readOnly(connection))(f) + override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(fa.autoCommit(connection))(f) + override def transaction(connection: Connection[F]): F[B] = Functor[F].map(fa.transaction(connection))(f) + override def rollback(connection: Connection[F]): F[B] = Functor[F].map(fa.rollback(connection))(f) + + given [F[_]: Monad]: Monad[[T] =>> Query[F, T]] with + override def pure[A](x: A): Query[F, A] = + new Query[F, A]: + override def run: Connection[F] => F[A] = _ => Monad[F].pure(x) + override def readOnly(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def autoCommit(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def transaction(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def rollback(connection: Connection[F]): F[A] = Monad[F].pure(x) + + override def flatMap[A, B](fa: Query[F, A])(f: A => Query[F, B]): Query[F, B] = + new Query[F, B]: + override def run: Connection[F] => F[B] = conn => Monad[F].flatMap(fa.run(conn))(a => f(a).run(conn)) + override def readOnly(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.readOnly(connection))(a => f(a).readOnly(connection)) + override def autoCommit(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.autoCommit(connection))(a => f(a).autoCommit(connection)) + override def transaction(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.transaction(connection))(a => f(a).transaction(connection)) + override def rollback(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.rollback(connection))(a => f(a).rollback(connection)) + + override def tailRecM[A, B](a: A)(f: A => Query[F, Either[A, B]]): Query[F, B] = + new Query[F, B]: + override def run: Connection[F] => F[B] = conn => Monad[F].tailRecM(a)(a =>f(a).run(conn)) + override def readOnly(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).readOnly(connection)) + override def autoCommit(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).autoCommit(connection)) + override def transaction(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).transaction(connection)) + override def rollback(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).rollback(connection)) diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala index 85e8dc7f8..0b06c09e5 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala @@ -41,7 +41,7 @@ trait SQL[F[_]: Monad]: /** * Methods for returning an array of data to be retrieved from the database. */ - inline def toList[T <: Tuple](using FactoryCompat[T, List[T]], LogHandler[F]): Kleisli[F, Connection[F], List[T]] = + inline def toList[T <: Tuple](using FactoryCompat[T, List[T]], LogHandler[F]): Query[F, List[T]] = given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => ResultSetReader .fold[F, T] @@ -59,7 +59,7 @@ trait SQL[F[_]: Monad]: mirror: Mirror.ProductOf[P], logHandler: LogHandler[F], factory: FactoryCompat[P, List[P]] - ): Kleisli[F, Connection[F], List[P]] = + ): Query[F, List[P]] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader .fold[F, mirror.MirroredElemTypes] @@ -77,7 +77,7 @@ trait SQL[F[_]: Monad]: * A method to return the data to be retrieved from the database as Option type. If there are multiple data, the * first one is retrieved. */ - inline def headOption[T <: Tuple](using LogHandler[F]): Kleisli[F, Connection[F], Option[T]] = + inline def headOption[T <: Tuple](using LogHandler[F]): Query[F, Option[T]] = given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => ResultSetReader .fold[F, T] @@ -94,7 +94,7 @@ trait SQL[F[_]: Monad]: inline def headOption[P <: Product](using mirror: Mirror.ProductOf[P], logHandler: LogHandler[F] - ): Kleisli[F, Connection[F], Option[P]] = + ): Query[F, Option[P]] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader .fold[F, mirror.MirroredElemTypes] @@ -112,7 +112,7 @@ trait SQL[F[_]: Monad]: * A method to return the data to be retrieved from the database as is. If the data does not exist, an exception is * raised. Use the [[headOption]] method if you want to retrieve individual data. */ - inline def unsafe[T <: Tuple](using MonadError[F, Throwable], LogHandler[F]): Kleisli[F, Connection[F], T] = + inline def unsafe[T <: Tuple](using MonadError[F, Throwable], LogHandler[F]): Query[F, T] = given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => ResultSetReader .fold[F, T] @@ -130,7 +130,7 @@ trait SQL[F[_]: Monad]: mirror: Mirror.ProductOf[P], logHandler: LogHandler[F], ev: MonadError[F, Throwable] - ): Kleisli[F, Connection[F], P] = + ): Query[F, P] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader .fold[F, mirror.MirroredElemTypes] @@ -147,18 +147,18 @@ trait SQL[F[_]: Monad]: /** * A method to return the number of rows updated by the SQL statement. */ - def update(using logHandler: LogHandler[F]): Kleisli[F, Connection[F], Int] + def update(using logHandler: LogHandler[F]): Query[F, Int] def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T], logHandler: LogHandler[F] - ): Kleisli[F, Connection[F], T] + ): Query[F, T] private[ldbc] def connection[T]( statement: String, params: Seq[ParameterBinder[F]], consumer: ResultSetConsumer[F, T] - )(using logHandler: LogHandler[F]): Kleisli[F, Connection[F], T] + )(using logHandler: LogHandler[F]): Query[F, T] /** * Methods for returning an array of data to be retrieved from the database. @@ -166,7 +166,7 @@ trait SQL[F[_]: Monad]: private def connectionToList[T]( statement: String, params: Seq[ParameterBinder[F]] - )(using Kleisli[F, ResultSet[F], T], LogHandler[F], FactoryCompat[T, List[T]]): Kleisli[F, Connection[F], List[T]] = + )(using Kleisli[F, ResultSet[F], T], LogHandler[F], FactoryCompat[T, List[T]]): Query[F, List[T]] = connection[List[T]](statement, params, summon[ResultSetConsumer[F, List[T]]]) /** @@ -176,7 +176,7 @@ trait SQL[F[_]: Monad]: private def connectionToHeadOption[T]( statement: String, params: Seq[ParameterBinder[F]] - )(using Kleisli[F, ResultSet[F], T], LogHandler[F]): Kleisli[F, Connection[F], Option[T]] = + )(using Kleisli[F, ResultSet[F], T], LogHandler[F]): Query[F, Option[T]] = connection[Option[T]](statement, params, summon[ResultSetConsumer[F, Option[T]]]) /** @@ -186,5 +186,5 @@ trait SQL[F[_]: Monad]: private def connectionToUnsafe[T]( statement: String, params: Seq[ParameterBinder[F]] - )(using Kleisli[F, ResultSet[F], T], LogHandler[F], MonadError[F, Throwable]): Kleisli[F, Connection[F], T] = + )(using Kleisli[F, ResultSet[F], T], LogHandler[F], MonadError[F, Throwable]): Query[F, T] = connection[T](statement, params, summon[ResultSetConsumer[F, T]]) From d1757bc1e51d5370d5c0713677aa6d31bf2c578e Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:17:53 +0900 Subject: [PATCH 02/13] Create QueryImpl --- .../main/scala/ldbc/connector/QueryImpl.scala | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala new file mode 100644 index 000000000..da5fdf542 --- /dev/null +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2023-2024 by Takahiko Tominaga + * This software is licensed under the MIT License (MIT). + * For more information see LICENSE or https://opensource.org/licenses/MIT + */ + +package ldbc.connector + +import cats.syntax.all.* +import cats.effect.{Temporal, Resource} +import cats.effect.kernel.Resource.ExitCase + +import ldbc.sql.* + +private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T]) extends Query[F, T]: + + override def readOnly(connection: Connection[F]): F[T] = + for + _ <- connection.setReadOnly(true) + result <- run(connection) + yield result + + override def autoCommit(connection: Connection[F]): F[T] = + for + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(true) + result <- run(connection) + yield result + + override def transaction(connection: Connection[F]): F[T] = + val acquire = connection.setReadOnly(false) >> connection.setAutoCommit(false) >> Temporal[F].pure(connection) + + val release = (connection: Connection[F], exitCase: ExitCase) => exitCase match { + case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) + case _ => connection.commit() + } + + Resource.makeCase(acquire)(release).use(run) + + override def rollback(connection: Connection[F]): F[T] = + for + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(false) + result <- run(connection) + _ <- connection.rollback() + yield result From db608876169b9a986bd7491906db3a54f65065b8 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:18:04 +0900 Subject: [PATCH 03/13] Fixed Mysql --- .../shared/src/main/scala/ldbc/connector/Mysql.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala index 5ce28aaad..086e89aee 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala @@ -33,7 +33,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def ++(sql: SQL[F]): SQL[F] = Mysql[F](statement ++ " " ++ sql.statement, params ++ sql.params) - override def update(using logHandler: LogHandler[F]): Kleisli[F, Connection[F], Int] = Kleisli { connection => + override def update(using logHandler: LogHandler[F]): Query[F, Int] = QueryImpl[F, Int] { connection => (for statement <- connection.prepareStatement(statement) result <- params.zipWithIndex.traverse { @@ -47,7 +47,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T], logHandler: LogHandler[F] - ): Kleisli[F, Connection[F], T] = Kleisli { connection => + ): Query[F, T] = QueryImpl[F, T] { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) } @@ -67,8 +67,8 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ statement: String, params: Seq[ParameterBinder[F]], consumer: ResultSetConsumer[F, T] - )(using logHandler: LogHandler[F]): Kleisli[F, Connection[F], T] = - Kleisli { connection => + )(using logHandler: LogHandler[F]): Query[F, T] = + QueryImpl[F, T] { connection => for prepareStatement <- connection.prepareStatement(statement) resultSet <- params.zipWithIndex.traverse { From ab7a990dffd00d48541655ebe9afdc7fa9ad0796 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:18:16 +0900 Subject: [PATCH 04/13] Fixed connector test --- .../connector/SQLStringContextQueryTest.scala | 66 +++++++++---------- .../SQLStringContextUpdateTest.scala | 6 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextQueryTest.scala b/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextQueryTest.scala index 77428f0bd..8d8f26f43 100644 --- a/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextQueryTest.scala +++ b/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextQueryTest.scala @@ -37,7 +37,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: result1 <- sql"SELECT 1".toList[Tuple1[Int]] result2 <- sql"SELECT 2".headOption[Tuple1[Int]] result3 <- sql"SELECT 3".unsafe[Tuple1[Int]] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(Tuple1(1)), Some(Tuple1(2)), Tuple1(3)) ) @@ -50,7 +50,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: result1 <- sql"SELECT `bit`, `bit_null` FROM `connector_test`.`all_types`".toList[(Byte, Byte)] result2 <- sql"SELECT `bit`, `bit_null` FROM `connector_test`.`all_types`".headOption[(Byte, Byte)] result3 <- sql"SELECT `bit`, `bit_null` FROM `connector_test`.`all_types`".unsafe[(Byte, Byte)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((1.toByte, 0.toByte)), Some((1.toByte, 0.toByte)), (1.toByte, 0.toByte)) ) @@ -65,7 +65,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: sql"SELECT `tinyint`, `tinyint_null` FROM `connector_test`.`all_types` WHERE `tinyint` = ${ 127.toByte }" .headOption[(Byte, Byte)] result3 <- sql"SELECT `tinyint`, `tinyint_null` FROM `connector_test`.`all_types`".unsafe[(Byte, Byte)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((127.toByte, 0.toByte)), Some((127.toByte, 0.toByte)), (127.toByte, 0.toByte)) ) @@ -82,7 +82,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(Short, Short)] result3 <- sql"SELECT `tinyint_unsigned`, `tinyint_unsigned_null` FROM `connector_test`.`all_types`" .unsafe[(Short, Short)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((255.toShort, 0.toShort)), Some((255.toShort, 0.toShort)), (255.toShort, 0.toShort)) ) @@ -98,7 +98,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(Short, Short)] result3 <- sql"SELECT `smallint`, `smallint_null` FROM `connector_test`.`all_types`".unsafe[(Short, Short)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((32767.toShort, 0.toShort)), Some((32767.toShort, 0.toShort)), (32767.toShort, 0.toShort)) ) @@ -115,7 +115,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(Int, Int)] result3 <- sql"SELECT `smallint_unsigned`, `smallint_unsigned_null` FROM `connector_test`.`all_types`" .unsafe[(Int, Int)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((65535, 0)), Some((65535, 0)), (65535, 0)) ) @@ -130,7 +130,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: sql"SELECT `mediumint`, `mediumint_null` FROM `connector_test`.`all_types` WHERE `mediumint` = ${ 8388607 }" .headOption[(Int, Int)] result3 <- sql"SELECT `mediumint`, `mediumint_null` FROM `connector_test`.`all_types`".unsafe[(Int, Int)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((8388607, 0)), Some((8388607, 0)), (8388607, 0)) ) @@ -144,7 +144,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: result2 <- sql"SELECT `int`, `int_null` FROM `connector_test`.`all_types` WHERE `int` = ${ 2147483647 }" .headOption[(Int, Int)] result3 <- sql"SELECT `int`, `int_null` FROM `connector_test`.`all_types`".unsafe[(Int, Int)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((2147483647, 0)), Some((2147483647, 0)), (2147483647, 0)) ) @@ -161,7 +161,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(Long, Long)] result3 <- sql"SELECT `int_unsigned`, `int_unsigned_null` FROM `connector_test`.`all_types`".unsafe[(Long, Long)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((4294967295L, 0L)), Some((4294967295L, 0L)), (4294967295L, 0L)) ) @@ -176,7 +176,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: sql"SELECT `bigint`, `bigint_null` FROM `connector_test`.`all_types` WHERE `bigint` = ${ 9223372036854775807L }" .headOption[(Long, Long)] result3 <- sql"SELECT `bigint`, `bigint_null` FROM `connector_test`.`all_types`".unsafe[(Long, Long)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((9223372036854775807L, 0L)), Some((9223372036854775807L, 0L)), (9223372036854775807L, 0L)) ) @@ -193,7 +193,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `bigint_unsigned`, `bigint_unsigned_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("18446744073709551615", None)), Some(("18446744073709551615", None)), ("18446744073709551615", None)) ) @@ -207,7 +207,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: result2 <- sql"SELECT `float`, `float_null` FROM `connector_test`.`all_types` WHERE `float` >= ${ 3.3f }" .headOption[(Float, Float)] result3 <- sql"SELECT `float`, `float_null` FROM `connector_test`.`all_types`".unsafe[(Float, Float)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((3.40282e38f, 0f)), Some((3.40282e38f, 0f)), (3.40282e38f, 0f)) ) @@ -222,7 +222,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: sql"SELECT `double`, `double_null` FROM `connector_test`.`all_types` WHERE `double` = ${ 1.7976931348623157e308 }" .headOption[(Double, Double)] result3 <- sql"SELECT `double`, `double_null` FROM `connector_test`.`all_types`".unsafe[(Double, Double)] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, ( List((1.7976931348623157e308, 0.toDouble)), @@ -243,7 +243,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(BigDecimal, Option[BigDecimal])] result3 <- sql"SELECT `decimal`, `decimal_null` FROM `connector_test`.`all_types`" .unsafe[(BigDecimal, Option[BigDecimal])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, ( List((BigDecimal.decimal(9999999.99), None)), @@ -264,7 +264,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(LocalDate, Option[LocalDate])] result3 <- sql"SELECT `date`, `date_null` FROM `connector_test`.`all_types`".unsafe[(LocalDate, Option[LocalDate])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((LocalDate.of(2020, 1, 1), None)), Some((LocalDate.of(2020, 1, 1), None)), (LocalDate.of(2020, 1, 1), None)) ) @@ -281,7 +281,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(LocalTime, Option[LocalTime])] result3 <- sql"SELECT `time`, `time_null` FROM `connector_test`.`all_types`".unsafe[(LocalTime, Option[LocalTime])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((LocalTime.of(12, 34, 56), None)), Some((LocalTime.of(12, 34, 56), None)), (LocalTime.of(12, 34, 56), None)) ) @@ -299,7 +299,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(LocalDateTime, Option[LocalDateTime])] result3 <- sql"SELECT `datetime`, `datetime_null` FROM `connector_test`.`all_types`" .unsafe[(LocalDateTime, Option[LocalDateTime])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, ( List((LocalDateTime.of(2020, 1, 1, 12, 34, 56), None)), @@ -321,7 +321,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(LocalDateTime, Option[LocalDateTime])] result3 <- sql"SELECT `timestamp`, `timestamp_null` FROM `connector_test`.`all_types`" .unsafe[(LocalDateTime, Option[LocalDateTime])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, ( List((LocalDateTime.of(2020, 1, 1, 12, 34, 56), None)), @@ -341,7 +341,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(Short, Option[Short])] result3 <- sql"SELECT `year`, `year_null` FROM `connector_test`.`all_types`".unsafe[(Short, Option[Short])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List((2020.toShort, None)), Some((2020.toShort, None)), (2020.toShort, None)) ) @@ -357,7 +357,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `char`, `char_null` FROM `connector_test`.`all_types`".unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("char", None)), Some(("char", None)), ("char", None)) ) @@ -374,7 +374,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `varchar`, `varchar_null` FROM `connector_test`.`all_types`".unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("varchar", None)), Some(("varchar", None)), ("varchar", None)) ) @@ -394,7 +394,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: result1.map { case (v1, v2) => (v1.mkString(":"), v2) }, result2.map { case (v1, v2) => (v1.mkString(":"), v2) }, (result3._1.mkString(":"), result3._2) - )).run(conn) + )).readOnly(conn) }, ( List((Array[Byte](98, 105, 110, 97, 114, 121, 0, 0, 0, 0).mkString(":"), None)), @@ -415,7 +415,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `varbinary`, `varbinary_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("varbinary", None)), Some(("varbinary", None)), ("varbinary", None)) ) @@ -432,7 +432,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `mediumblob`, `mediumblob_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("mediumblob", None)), Some(("mediumblob", None)), ("mediumblob", None)) ) @@ -449,7 +449,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `longblob`, `longblob_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("longblob", None)), Some(("longblob", None)), ("longblob", None)) ) @@ -466,7 +466,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `tinytext`, `tinytext_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("tinytext", None)), Some(("tinytext", None)), ("tinytext", None)) ) @@ -482,7 +482,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `text`, `text_null` FROM `connector_test`.`all_types`".unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("text", None)), Some(("text", None)), ("text", None)) ) @@ -500,7 +500,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: result3 <- sql"SELECT `mediumtext`, `mediumtext_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] yield (result1, result2, result3)) - .run(conn) + .readOnly(conn) }, (List(("mediumtext", None)), Some(("mediumtext", None)), ("mediumtext", None)) ) @@ -517,7 +517,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `longtext`, `longtext_null` FROM `connector_test`.`all_types`" .unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("longtext", None)), Some(("longtext", None)), ("longtext", None)) ) @@ -533,7 +533,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `enum`, `enum_null` FROM `connector_test`.`all_types`".unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("a", None)), Some(("a", None)), ("a", None)) ) @@ -549,7 +549,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[(String, Option[String])] result3 <- sql"SELECT `set`, `set_null` FROM `connector_test`.`all_types`".unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("a,b", None)), Some(("a,b", None)), ("a,b", None)) ) @@ -564,7 +564,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: sql"SELECT `json`, `json_null` FROM `connector_test`.`all_types`".headOption[(String, Option[String])] result3 <- sql"SELECT `json`, `json_null` FROM `connector_test`.`all_types`".unsafe[(String, Option[String])] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(("{\"a\": 1}", None)), Some(("{\"a\": 1}", None)), ("{\"a\": 1}", None)) ) @@ -581,7 +581,7 @@ class SQLStringContextQueryTest extends CatsEffectSuite: .headOption[LongClass] result3 <- sql"SELECT `int_unsigned`, `int_unsigned_null` FROM `connector_test`.`all_types`".unsafe[LongClass] - yield (result1, result2, result3)).run(conn) + yield (result1, result2, result3)).readOnly(conn) }, (List(LongClass(4294967295L, None)), Some(LongClass(4294967295L, None)), LongClass(4294967295L, None)) ) diff --git a/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextUpdateTest.scala b/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextUpdateTest.scala index ccf9d6274..d3ef6c6a8 100644 --- a/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextUpdateTest.scala +++ b/module/ldbc-connector/shared/src/test/scala/ldbc/connector/SQLStringContextUpdateTest.scala @@ -36,7 +36,7 @@ class SQLStringContextUpdateTest extends CatsEffectSuite: _ <- sql"CREATE TABLE `string_context_bit_table1`(`bit_column` BIT NOT NULL)".update count <- sql"INSERT INTO `string_context_bit_table1`(`bit_column`) VALUES (b'1')".update _ <- sql"DROP TABLE `string_context_bit_table1`".update - yield count).run(conn) + yield count).transaction(conn) }, 1 ) @@ -49,7 +49,7 @@ class SQLStringContextUpdateTest extends CatsEffectSuite: _ <- sql"CREATE TABLE `string_context_bit_table2`(`bit_column` BIT NOT NULL)".update count <- sql"INSERT INTO `string_context_bit_table2`(`bit_column`) VALUES (b'0'),(b'1')".update _ <- sql"DROP TABLE `string_context_bit_table2`".update - yield count).run(conn) + yield count).transaction(conn) }, 2 ) @@ -64,7 +64,7 @@ class SQLStringContextUpdateTest extends CatsEffectSuite: _ <- sql"INSERT INTO `returning_auto_inc`(`id`, `c1`) VALUES ($None, ${ "column 1" })".update generated <- sql"INSERT INTO `returning_auto_inc`(`id`, `c1`) VALUES ($None, ${ "column 2" })".returning[Long] _ <- sql"DROP TABLE `returning_auto_inc`".update - yield generated).run(conn) + yield generated).transaction(conn) }, 2L ) From ca9ea03b88be836cac5f60f3a9931456a1bbe010 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:21:02 +0900 Subject: [PATCH 05/13] Create QueryImpl for dsl --- .../src/main/scala/ldbc/dsl/Mysql.scala | 8 ++-- .../src/main/scala/ldbc/dsl/QueryImpl.scala | 46 +++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala index 40d159f04..812a4447e 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala @@ -33,7 +33,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def ++(sql: SQL[F]): SQL[F] = Mysql[F](statement ++ " " ++ sql.statement, params ++ sql.params) - override def update(using logHandler: LogHandler[F]): Kleisli[F, Connection[F], Int] = Kleisli { connection => + override def update(using logHandler: LogHandler[F]): Query[F, Int] = QueryImpl[F, Int] { connection => (for statement <- connection.prepareStatement(statement) result <- params.zipWithIndex.traverse { @@ -47,7 +47,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T], logHandler: LogHandler[F] - ): Kleisli[F, Connection[F], T] = Kleisli { connection => + ): Query[F, T] = QueryImpl[F, T] { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) } @@ -67,8 +67,8 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ statement: String, params: Seq[ParameterBinder[F]], consumer: ResultSetConsumer[F, T] - )(using logHandler: LogHandler[F]): Kleisli[F, Connection[F], T] = - Kleisli { connection => + )(using logHandler: LogHandler[F]): Query[F, T] = + QueryImpl[F, T] { connection => for prepareStatement <- connection.prepareStatement(statement) resultSet <- params.zipWithIndex.traverse { diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala new file mode 100644 index 000000000..d9ee3c956 --- /dev/null +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2023-2024 by Takahiko Tominaga + * This software is licensed under the MIT License (MIT). + * For more information see LICENSE or https://opensource.org/licenses/MIT + */ + +package ldbc.dsl + +import cats.effect.kernel.Resource.ExitCase +import cats.effect.{Resource, Temporal} +import cats.syntax.all.* + +import ldbc.sql.* + +private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T]) extends Query[F, T]: + + override def readOnly(connection: Connection[F]): F[T] = + for + _ <- connection.setReadOnly(true) + result <- run(connection) + yield result + + override def autoCommit(connection: Connection[F]): F[T] = + for + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(true) + result <- run(connection) + yield result + + override def transaction(connection: Connection[F]): F[T] = + val acquire = connection.setReadOnly(false) >> connection.setAutoCommit(false) >> Temporal[F].pure(connection) + + val release = (connection: Connection[F], exitCase: ExitCase) => exitCase match { + case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) + case _ => connection.commit() + } + + Resource.makeCase(acquire)(release).use(run) + + override def rollback(connection: Connection[F]): F[T] = + for + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(false) + result <- run(connection) + _ <- connection.rollback() + yield result From 185a53d7c7eaf019a3ee74208d7c7d9619c7fc26 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:21:27 +0900 Subject: [PATCH 06/13] Action sbt scalafmtAll --- .../main/scala/ldbc/connector/QueryImpl.scala | 23 +++++---- .../src/main/scala/ldbc/dsl/QueryImpl.scala | 23 +++++---- .../src/main/scala/ldbc/sql/Query.scala | 50 +++++++++++-------- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala index da5fdf542..44dfa93e7 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala @@ -7,7 +7,7 @@ package ldbc.connector import cats.syntax.all.* -import cats.effect.{Temporal, Resource} +import cats.effect.{ Temporal, Resource } import cats.effect.kernel.Resource.ExitCase import ldbc.sql.* @@ -16,31 +16,32 @@ private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T] override def readOnly(connection: Connection[F]): F[T] = for - _ <- connection.setReadOnly(true) + _ <- connection.setReadOnly(true) result <- run(connection) yield result override def autoCommit(connection: Connection[F]): F[T] = for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(true) + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(true) result <- run(connection) yield result override def transaction(connection: Connection[F]): F[T] = val acquire = connection.setReadOnly(false) >> connection.setAutoCommit(false) >> Temporal[F].pure(connection) - val release = (connection: Connection[F], exitCase: ExitCase) => exitCase match { - case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) - case _ => connection.commit() - } + val release = (connection: Connection[F], exitCase: ExitCase) => + exitCase match { + case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) + case _ => connection.commit() + } Resource.makeCase(acquire)(release).use(run) override def rollback(connection: Connection[F]): F[T] = for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(false) + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(false) result <- run(connection) - _ <- connection.rollback() + _ <- connection.rollback() yield result diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala index d9ee3c956..162b78d0e 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala @@ -7,7 +7,7 @@ package ldbc.dsl import cats.effect.kernel.Resource.ExitCase -import cats.effect.{Resource, Temporal} +import cats.effect.{ Resource, Temporal } import cats.syntax.all.* import ldbc.sql.* @@ -16,31 +16,32 @@ private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T] override def readOnly(connection: Connection[F]): F[T] = for - _ <- connection.setReadOnly(true) + _ <- connection.setReadOnly(true) result <- run(connection) yield result override def autoCommit(connection: Connection[F]): F[T] = for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(true) + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(true) result <- run(connection) yield result override def transaction(connection: Connection[F]): F[T] = val acquire = connection.setReadOnly(false) >> connection.setAutoCommit(false) >> Temporal[F].pure(connection) - val release = (connection: Connection[F], exitCase: ExitCase) => exitCase match { - case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) - case _ => connection.commit() - } + val release = (connection: Connection[F], exitCase: ExitCase) => + exitCase match { + case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) + case _ => connection.commit() + } Resource.makeCase(acquire)(release).use(run) override def rollback(connection: Connection[F]): F[T] = for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(false) + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(false) result <- run(connection) - _ <- connection.rollback() + _ <- connection.rollback() yield result diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala index 61889a174..f9a9ed2bc 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala @@ -15,18 +15,22 @@ trait Query[F[_], T]: def map[B](f: T => B)(using Functor[F]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Functor[F].map(Query.this.run(conn))(f) - override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(Query.this.readOnly(connection))(f) - override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(Query.this.autoCommit(connection))(f) + override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(Query.this.readOnly(connection))(f) + override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(Query.this.autoCommit(connection))(f) override def transaction(connection: Connection[F]): F[B] = Functor[F].map(Query.this.transaction(connection))(f) - override def rollback(connection: Connection[F]): F[B] = Functor[F].map(Query.this.rollback(connection))(f) + override def rollback(connection: Connection[F]): F[B] = Functor[F].map(Query.this.rollback(connection))(f) def flatMap[B](f: T => Query[F, B])(using Monad[F]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Monad[F].flatMap(Query.this.run(conn))(a => f(a).run(conn)) - override def readOnly(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.readOnly(connection))(a => f(a).readOnly(connection)) - override def autoCommit(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.autoCommit(connection))(a => f(a).autoCommit(connection)) - override def transaction(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.transaction(connection))(a => f(a).transaction(connection)) - override def rollback(connection: Connection[F]): F[B] = Monad[F].flatMap(Query.this.rollback(connection))(a => f(a).rollback(connection)) + override def readOnly(connection: Connection[F]): F[B] = + Monad[F].flatMap(Query.this.readOnly(connection))(a => f(a).readOnly(connection)) + override def autoCommit(connection: Connection[F]): F[B] = + Monad[F].flatMap(Query.this.autoCommit(connection))(a => f(a).autoCommit(connection)) + override def transaction(connection: Connection[F]): F[B] = + Monad[F].flatMap(Query.this.transaction(connection))(a => f(a).transaction(connection)) + override def rollback(connection: Connection[F]): F[B] = + Monad[F].flatMap(Query.this.rollback(connection))(a => f(a).rollback(connection)) /** * Functions for managing the processing of connections in a read-only manner. @@ -54,32 +58,38 @@ object Query: override def map[A, B](fa: Query[F, A])(f: A => B): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Functor[F].map(fa.run(conn))(f) - override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(fa.readOnly(connection))(f) - override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(fa.autoCommit(connection))(f) + override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(fa.readOnly(connection))(f) + override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(fa.autoCommit(connection))(f) override def transaction(connection: Connection[F]): F[B] = Functor[F].map(fa.transaction(connection))(f) - override def rollback(connection: Connection[F]): F[B] = Functor[F].map(fa.rollback(connection))(f) + override def rollback(connection: Connection[F]): F[B] = Functor[F].map(fa.rollback(connection))(f) given [F[_]: Monad]: Monad[[T] =>> Query[F, T]] with override def pure[A](x: A): Query[F, A] = new Query[F, A]: override def run: Connection[F] => F[A] = _ => Monad[F].pure(x) - override def readOnly(connection: Connection[F]): F[A] = Monad[F].pure(x) - override def autoCommit(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def readOnly(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def autoCommit(connection: Connection[F]): F[A] = Monad[F].pure(x) override def transaction(connection: Connection[F]): F[A] = Monad[F].pure(x) - override def rollback(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def rollback(connection: Connection[F]): F[A] = Monad[F].pure(x) override def flatMap[A, B](fa: Query[F, A])(f: A => Query[F, B]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Monad[F].flatMap(fa.run(conn))(a => f(a).run(conn)) - override def readOnly(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.readOnly(connection))(a => f(a).readOnly(connection)) - override def autoCommit(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.autoCommit(connection))(a => f(a).autoCommit(connection)) - override def transaction(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.transaction(connection))(a => f(a).transaction(connection)) - override def rollback(connection: Connection[F]): F[B] = Monad[F].flatMap(fa.rollback(connection))(a => f(a).rollback(connection)) + override def readOnly(connection: Connection[F]): F[B] = + Monad[F].flatMap(fa.readOnly(connection))(a => f(a).readOnly(connection)) + override def autoCommit(connection: Connection[F]): F[B] = + Monad[F].flatMap(fa.autoCommit(connection))(a => f(a).autoCommit(connection)) + override def transaction(connection: Connection[F]): F[B] = + Monad[F].flatMap(fa.transaction(connection))(a => f(a).transaction(connection)) + override def rollback(connection: Connection[F]): F[B] = + Monad[F].flatMap(fa.rollback(connection))(a => f(a).rollback(connection)) override def tailRecM[A, B](a: A)(f: A => Query[F, Either[A, B]]): Query[F, B] = new Query[F, B]: - override def run: Connection[F] => F[B] = conn => Monad[F].tailRecM(a)(a =>f(a).run(conn)) + override def run: Connection[F] => F[B] = conn => Monad[F].tailRecM(a)(a => f(a).run(conn)) override def readOnly(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).readOnly(connection)) - override def autoCommit(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).autoCommit(connection)) - override def transaction(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).transaction(connection)) + override def autoCommit(connection: Connection[F]): F[B] = + Monad[F].tailRecM(a)(a => f(a).autoCommit(connection)) + override def transaction(connection: Connection[F]): F[B] = + Monad[F].tailRecM(a)(a => f(a).transaction(connection)) override def rollback(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).rollback(connection)) From 880fd5f0c29af88e3fd307d2dfd467fac3d58c16 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:28:41 +0900 Subject: [PATCH 07/13] Fixed Join --- .../src/main/scala/ldbc/query/builder/statement/Join.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/statement/Join.scala b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/statement/Join.scala index 3fcd5b705..3937004c8 100644 --- a/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/statement/Join.scala +++ b/module/ldbc-query-builder/src/main/scala/ldbc/query/builder/statement/Join.scala @@ -11,7 +11,7 @@ import scala.deriving.Mirror import ldbc.core.* import ldbc.core.interpreter.{ ExtractOption, Tuples as CoreTuples } -import ldbc.sql.* +import ldbc.sql.ParameterBinder import ldbc.query.builder.interpreter.Tuples import ldbc.query.builder.{ TableQuery, ColumnQuery } From 993ecfba3791016f48160ea66a33bfe8d8b0fc83 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:43:57 +0900 Subject: [PATCH 08/13] Replace LogHandler SQL -> Query --- .../src/main/scala/ldbc/sql/Query.scala | 58 ++++++++++--------- .../src/main/scala/ldbc/sql/SQL.scala | 23 +++----- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala index f9a9ed2bc..ba362dd10 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala @@ -8,6 +8,8 @@ package ldbc.sql import cats.* +import ldbc.sql.logging.LogHandler + trait Query[F[_], T]: def run: Connection[F] => F[T] @@ -15,42 +17,42 @@ trait Query[F[_], T]: def map[B](f: T => B)(using Functor[F]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Functor[F].map(Query.this.run(conn))(f) - override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(Query.this.readOnly(connection))(f) - override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(Query.this.autoCommit(connection))(f) - override def transaction(connection: Connection[F]): F[B] = Functor[F].map(Query.this.transaction(connection))(f) - override def rollback(connection: Connection[F]): F[B] = Functor[F].map(Query.this.rollback(connection))(f) + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.readOnly(connection))(f) + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.autoCommit(connection))(f) + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.transaction(connection))(f) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.rollback(connection))(f) def flatMap[B](f: T => Query[F, B])(using Monad[F]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Monad[F].flatMap(Query.this.run(conn))(a => f(a).run(conn)) - override def readOnly(connection: Connection[F]): F[B] = + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(Query.this.readOnly(connection))(a => f(a).readOnly(connection)) - override def autoCommit(connection: Connection[F]): F[B] = + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(Query.this.autoCommit(connection))(a => f(a).autoCommit(connection)) - override def transaction(connection: Connection[F]): F[B] = + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(Query.this.transaction(connection))(a => f(a).transaction(connection)) - override def rollback(connection: Connection[F]): F[B] = + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(Query.this.rollback(connection))(a => f(a).rollback(connection)) /** * Functions for managing the processing of connections in a read-only manner. */ - def readOnly(connection: Connection[F]): F[T] + def readOnly(connection: Connection[F])(using LogHandler[F]): F[T] /** * Functions to manage the processing of connections for writing. */ - def autoCommit(connection: Connection[F]): F[T] + def autoCommit(connection: Connection[F])(using LogHandler[F]): F[T] /** * Functions to manage the processing of connections in a transaction. */ - def transaction(connection: Connection[F]): F[T] + def transaction(connection: Connection[F])(using LogHandler[F]): F[T] /** * Functions to manage the processing of connections, always rolling back. */ - def rollback(connection: Connection[F]): F[T] + def rollback(connection: Connection[F])(using LogHandler[F]): F[T] object Query: @@ -58,38 +60,38 @@ object Query: override def map[A, B](fa: Query[F, A])(f: A => B): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Functor[F].map(fa.run(conn))(f) - override def readOnly(connection: Connection[F]): F[B] = Functor[F].map(fa.readOnly(connection))(f) - override def autoCommit(connection: Connection[F]): F[B] = Functor[F].map(fa.autoCommit(connection))(f) - override def transaction(connection: Connection[F]): F[B] = Functor[F].map(fa.transaction(connection))(f) - override def rollback(connection: Connection[F]): F[B] = Functor[F].map(fa.rollback(connection))(f) + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.readOnly(connection))(f) + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.autoCommit(connection))(f) + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.transaction(connection))(f) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.rollback(connection))(f) given [F[_]: Monad]: Monad[[T] =>> Query[F, T]] with override def pure[A](x: A): Query[F, A] = new Query[F, A]: override def run: Connection[F] => F[A] = _ => Monad[F].pure(x) - override def readOnly(connection: Connection[F]): F[A] = Monad[F].pure(x) - override def autoCommit(connection: Connection[F]): F[A] = Monad[F].pure(x) - override def transaction(connection: Connection[F]): F[A] = Monad[F].pure(x) - override def rollback(connection: Connection[F]): F[A] = Monad[F].pure(x) + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[A] = Monad[F].pure(x) + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[A] = Monad[F].pure(x) + override def transaction(connection: Connection[F])(using LogHandler[F]): F[A] = Monad[F].pure(x) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[A] = Monad[F].pure(x) override def flatMap[A, B](fa: Query[F, A])(f: A => Query[F, B]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Monad[F].flatMap(fa.run(conn))(a => f(a).run(conn)) - override def readOnly(connection: Connection[F]): F[B] = + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(fa.readOnly(connection))(a => f(a).readOnly(connection)) - override def autoCommit(connection: Connection[F]): F[B] = + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(fa.autoCommit(connection))(a => f(a).autoCommit(connection)) - override def transaction(connection: Connection[F]): F[B] = + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(fa.transaction(connection))(a => f(a).transaction(connection)) - override def rollback(connection: Connection[F]): F[B] = + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].flatMap(fa.rollback(connection))(a => f(a).rollback(connection)) override def tailRecM[A, B](a: A)(f: A => Query[F, Either[A, B]]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Monad[F].tailRecM(a)(a => f(a).run(conn)) - override def readOnly(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).readOnly(connection)) - override def autoCommit(connection: Connection[F]): F[B] = + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).readOnly(connection)) + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).autoCommit(connection)) - override def transaction(connection: Connection[F]): F[B] = + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).transaction(connection)) - override def rollback(connection: Connection[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).rollback(connection)) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).rollback(connection)) diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala index 0b06c09e5..218ca68a4 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala @@ -14,7 +14,6 @@ import cats.data.Kleisli import cats.syntax.all.* import ldbc.sql.util.FactoryCompat -import ldbc.sql.logging.* /** * A model with a query string and parameters to be bound to the query string that is executed by PreparedStatement, @@ -41,7 +40,7 @@ trait SQL[F[_]: Monad]: /** * Methods for returning an array of data to be retrieved from the database. */ - inline def toList[T <: Tuple](using FactoryCompat[T, List[T]], LogHandler[F]): Query[F, List[T]] = + inline def toList[T <: Tuple](using FactoryCompat[T, List[T]]): Query[F, List[T]] = given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => ResultSetReader .fold[F, T] @@ -57,7 +56,6 @@ trait SQL[F[_]: Monad]: inline def toList[P <: Product](using mirror: Mirror.ProductOf[P], - logHandler: LogHandler[F], factory: FactoryCompat[P, List[P]] ): Query[F, List[P]] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => @@ -77,7 +75,7 @@ trait SQL[F[_]: Monad]: * A method to return the data to be retrieved from the database as Option type. If there are multiple data, the * first one is retrieved. */ - inline def headOption[T <: Tuple](using LogHandler[F]): Query[F, Option[T]] = + inline def headOption[T <: Tuple]: Query[F, Option[T]] = given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => ResultSetReader .fold[F, T] @@ -92,8 +90,7 @@ trait SQL[F[_]: Monad]: connectionToHeadOption[T](statement, params) inline def headOption[P <: Product](using - mirror: Mirror.ProductOf[P], - logHandler: LogHandler[F] + mirror: Mirror.ProductOf[P] ): Query[F, Option[P]] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader @@ -112,7 +109,7 @@ trait SQL[F[_]: Monad]: * A method to return the data to be retrieved from the database as is. If the data does not exist, an exception is * raised. Use the [[headOption]] method if you want to retrieve individual data. */ - inline def unsafe[T <: Tuple](using MonadError[F, Throwable], LogHandler[F]): Query[F, T] = + inline def unsafe[T <: Tuple](using MonadError[F, Throwable]): Query[F, T] = given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => ResultSetReader .fold[F, T] @@ -128,7 +125,6 @@ trait SQL[F[_]: Monad]: inline def unsafe[P <: Product](using mirror: Mirror.ProductOf[P], - logHandler: LogHandler[F], ev: MonadError[F, Throwable] ): Query[F, P] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => @@ -147,18 +143,17 @@ trait SQL[F[_]: Monad]: /** * A method to return the number of rows updated by the SQL statement. */ - def update(using logHandler: LogHandler[F]): Query[F, Int] + def update: Query[F, Int] def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T], - logHandler: LogHandler[F] ): Query[F, T] private[ldbc] def connection[T]( statement: String, params: Seq[ParameterBinder[F]], consumer: ResultSetConsumer[F, T] - )(using logHandler: LogHandler[F]): Query[F, T] + ): Query[F, T] /** * Methods for returning an array of data to be retrieved from the database. @@ -166,7 +161,7 @@ trait SQL[F[_]: Monad]: private def connectionToList[T]( statement: String, params: Seq[ParameterBinder[F]] - )(using Kleisli[F, ResultSet[F], T], LogHandler[F], FactoryCompat[T, List[T]]): Query[F, List[T]] = + )(using Kleisli[F, ResultSet[F], T], FactoryCompat[T, List[T]]): Query[F, List[T]] = connection[List[T]](statement, params, summon[ResultSetConsumer[F, List[T]]]) /** @@ -176,7 +171,7 @@ trait SQL[F[_]: Monad]: private def connectionToHeadOption[T]( statement: String, params: Seq[ParameterBinder[F]] - )(using Kleisli[F, ResultSet[F], T], LogHandler[F]): Query[F, Option[T]] = + )(using Kleisli[F, ResultSet[F], T]): Query[F, Option[T]] = connection[Option[T]](statement, params, summon[ResultSetConsumer[F, Option[T]]]) /** @@ -186,5 +181,5 @@ trait SQL[F[_]: Monad]: private def connectionToUnsafe[T]( statement: String, params: Seq[ParameterBinder[F]] - )(using Kleisli[F, ResultSet[F], T], LogHandler[F], MonadError[F, Throwable]): Query[F, T] = + )(using Kleisli[F, ResultSet[F], T], MonadError[F, Throwable]): Query[F, T] = connection[T](statement, params, summon[ResultSetConsumer[F, T]]) From 3a9588ec1f0d6ca4c6663856e06fec79f6c87646 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:44:15 +0900 Subject: [PATCH 09/13] Fixed QueryImpl --- .../src/main/scala/ldbc/connector/Mysql.scala | 29 +++++----------- .../main/scala/ldbc/connector/QueryImpl.scala | 33 ++++++++++++------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala index 086e89aee..c9220d917 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala @@ -14,7 +14,6 @@ import cats.syntax.all.* import cats.effect.Temporal import ldbc.sql.* -import ldbc.sql.logging.* /** * A model with a query string and parameters to be bound to the query string that is executed by PreparedStatement, @@ -33,53 +32,43 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def ++(sql: SQL[F]): SQL[F] = Mysql[F](statement ++ " " ++ sql.statement, params ++ sql.params) - override def update(using logHandler: LogHandler[F]): Query[F, Int] = QueryImpl[F, Int] { connection => - (for + override def update: Query[F, Int] = QueryImpl[F, Int](statement, params.map(_.parameter).toList) { connection => + for statement <- connection.prepareStatement(statement) result <- params.zipWithIndex.traverse { case (param, index) => param.bind(statement, index + 1) } >> statement.executeUpdate() <* statement.close() - yield result) - .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params.map(_.parameter).toList, ex))) - <* logHandler.run(LogEvent.Success(statement, params.map(_.parameter).toList)) + yield result } override def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T], - logHandler: LogHandler[F] - ): Query[F, T] = QueryImpl[F, T] { connection => + ): Query[F, T] = QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) } - (for + for statement <- connection.prepareStatement(statement, Statement.RETURN_GENERATED_KEYS) resultSet <- params.zipWithIndex.traverse { case (param, index) => param.bind(statement, index + 1) } >> statement.executeUpdate() >> statement.getGeneratedKeys() result <- summon[ResultSetConsumer[F, T]].consume(resultSet) <* statement.close() - yield result) - .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params.map(_.parameter).toList, ex))) - <* logHandler.run(LogEvent.Success(statement, params.map(_.parameter).toList)) + yield result } private[ldbc] override def connection[T]( statement: String, params: Seq[ParameterBinder[F]], consumer: ResultSetConsumer[F, T] - )(using logHandler: LogHandler[F]): Query[F, T] = - QueryImpl[F, T] { connection => + ): Query[F, T] = + QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => for prepareStatement <- connection.prepareStatement(statement) resultSet <- params.zipWithIndex.traverse { case (param, index) => param.bind(prepareStatement, index + 1) } >> prepareStatement .executeQuery() - result <- - consumer - .consume(resultSet) - .onError(ex => logHandler.run(LogEvent.ProcessingFailure(statement, params.map(_.parameter).toList, ex))) - <* prepareStatement.close() - <* logHandler.run(LogEvent.Success(statement, params.map(_.parameter).toList)) + result <- consumer.consume(resultSet) <* prepareStatement.close() yield result } diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala index 44dfa93e7..8f0b5391a 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala @@ -11,23 +11,30 @@ import cats.effect.{ Temporal, Resource } import cats.effect.kernel.Resource.ExitCase import ldbc.sql.* +import ldbc.sql.logging.* -private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T]) extends Query[F, T]: +private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: List[Any])(func: Connection[F] => F[T]) extends Query[F, T]: - override def readOnly(connection: Connection[F]): F[T] = - for + override def run: Connection[F] => F[T] = func + + override def readOnly(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = + (for _ <- connection.setReadOnly(true) result <- run(connection) - yield result + yield result) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) - override def autoCommit(connection: Connection[F]): F[T] = - for + override def autoCommit(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = + (for _ <- connection.setReadOnly(false) _ <- connection.setAutoCommit(true) result <- run(connection) - yield result + yield result) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) - override def transaction(connection: Connection[F]): F[T] = + override def transaction(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = val acquire = connection.setReadOnly(false) >> connection.setAutoCommit(false) >> Temporal[F].pure(connection) val release = (connection: Connection[F], exitCase: ExitCase) => @@ -37,11 +44,15 @@ private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T] } Resource.makeCase(acquire)(release).use(run) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) - override def rollback(connection: Connection[F]): F[T] = - for + override def rollback(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = + (for _ <- connection.setReadOnly(false) _ <- connection.setAutoCommit(false) result <- run(connection) _ <- connection.rollback() - yield result + yield result) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) From 633dabb66bb7d1795558f87d3e771a70d09c806f Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:46:26 +0900 Subject: [PATCH 10/13] Fixed QueryImpl for dsl --- .../src/main/scala/ldbc/dsl/Mysql.scala | 24 +++------ .../src/main/scala/ldbc/dsl/QueryImpl.scala | 49 ++++++++++++------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala index 812a4447e..0ec00c705 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala @@ -14,7 +14,6 @@ import cats.syntax.all.* import cats.effect.Temporal import ldbc.sql.* -import ldbc.sql.logging.* /** * A model with a query string and parameters to be bound to the query string that is executed by PreparedStatement, @@ -33,42 +32,37 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def ++(sql: SQL[F]): SQL[F] = Mysql[F](statement ++ " " ++ sql.statement, params ++ sql.params) - override def update(using logHandler: LogHandler[F]): Query[F, Int] = QueryImpl[F, Int] { connection => - (for + override def update: Query[F, Int] = QueryImpl[F, Int](statement, params.map(_.parameter).toList) { connection => + for statement <- connection.prepareStatement(statement) result <- params.zipWithIndex.traverse { case (param, index) => param.bind(statement, index + 1) } >> statement.executeUpdate() <* statement.close() - yield result) - .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params.map(_.parameter).toList, ex))) - <* logHandler.run(LogEvent.Success(statement, params.map(_.parameter).toList)) + yield result } override def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T], - logHandler: LogHandler[F] - ): Query[F, T] = QueryImpl[F, T] { connection => + ): Query[F, T] = QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) } - (for + for statement <- connection.prepareStatement(statement, Statement.RETURN_GENERATED_KEYS) resultSet <- params.zipWithIndex.traverse { case (param, index) => param.bind(statement, index + 1) } >> statement.executeUpdate() >> statement.getGeneratedKeys() result <- summon[ResultSetConsumer[F, T]].consume(resultSet) <* statement.close() - yield result) - .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params.map(_.parameter).toList, ex))) - <* logHandler.run(LogEvent.Success(statement, params.map(_.parameter).toList)) + yield result } private[ldbc] override def connection[T]( statement: String, params: Seq[ParameterBinder[F]], consumer: ResultSetConsumer[F, T] - )(using logHandler: LogHandler[F]): Query[F, T] = - QueryImpl[F, T] { connection => + ): Query[F, T] = + QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => for prepareStatement <- connection.prepareStatement(statement) resultSet <- params.zipWithIndex.traverse { @@ -78,8 +72,6 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ result <- consumer .consume(resultSet) - .onError(ex => logHandler.run(LogEvent.ProcessingFailure(statement, params.map(_.parameter).toList, ex))) <* prepareStatement.close() - <* logHandler.run(LogEvent.Success(statement, params.map(_.parameter).toList)) yield result } diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala index 162b78d0e..94b187121 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala @@ -11,37 +11,48 @@ import cats.effect.{ Resource, Temporal } import cats.syntax.all.* import ldbc.sql.* +import ldbc.sql.logging.* -private[ldbc] case class QueryImpl[F[_]: Temporal, T](run: Connection[F] => F[T]) extends Query[F, T]: +private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: List[Any])(func: Connection[F] => F[T]) extends Query[F, T]: - override def readOnly(connection: Connection[F]): F[T] = - for - _ <- connection.setReadOnly(true) - result <- run(connection) - yield result + override def run: Connection[F] => F[T] = func - override def autoCommit(connection: Connection[F]): F[T] = - for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(true) + override def readOnly(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = + (for + _ <- connection.setReadOnly(true) + result <- run(connection) + yield result) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) + + override def autoCommit(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = + (for + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(true) result <- run(connection) - yield result + yield result) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) - override def transaction(connection: Connection[F]): F[T] = + override def transaction(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = val acquire = connection.setReadOnly(false) >> connection.setAutoCommit(false) >> Temporal[F].pure(connection) val release = (connection: Connection[F], exitCase: ExitCase) => exitCase match { case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) - case _ => connection.commit() + case _ => connection.commit() } Resource.makeCase(acquire)(release).use(run) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) - override def rollback(connection: Connection[F]): F[T] = - for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(false) + override def rollback(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = + (for + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(false) result <- run(connection) - _ <- connection.rollback() - yield result + _ <- connection.rollback() + yield result) + .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) + <* logHandler.run(LogEvent.Success(statement, params)) From 414cf72b9f04a9c38153b3dca1d45aaabb733e84 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 22:46:39 +0900 Subject: [PATCH 11/13] Action sbt scalafmtAll --- .../src/main/scala/ldbc/connector/Mysql.scala | 2 +- .../main/scala/ldbc/connector/QueryImpl.scala | 7 +++-- .../src/main/scala/ldbc/dsl/Mysql.scala | 2 +- .../src/main/scala/ldbc/dsl/QueryImpl.scala | 21 +++++++------ .../src/main/scala/ldbc/sql/Query.scala | 30 ++++++++++++------- .../src/main/scala/ldbc/sql/SQL.scala | 12 ++++---- 6 files changed, 45 insertions(+), 29 deletions(-) diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala index c9220d917..322048887 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala @@ -42,7 +42,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ } override def returning[T <: String | Int | Long](using - reader: ResultSetReader[F, T], + reader: ResultSetReader[F, T] ): Query[F, T] = QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala index 8f0b5391a..e74a6072a 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/QueryImpl.scala @@ -13,7 +13,8 @@ import cats.effect.kernel.Resource.ExitCase import ldbc.sql.* import ldbc.sql.logging.* -private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: List[Any])(func: Connection[F] => F[T]) extends Query[F, T]: +private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: List[Any])(func: Connection[F] => F[T]) + extends Query[F, T]: override def run: Connection[F] => F[T] = func @@ -43,7 +44,9 @@ private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: case _ => connection.commit() } - Resource.makeCase(acquire)(release).use(run) + Resource + .makeCase(acquire)(release) + .use(run) .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) <* logHandler.run(LogEvent.Success(statement, params)) diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala index 0ec00c705..e569f970a 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala @@ -42,7 +42,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ } override def returning[T <: String | Int | Long](using - reader: ResultSetReader[F, T], + reader: ResultSetReader[F, T] ): Query[F, T] = QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala index 94b187121..ba2a8ee4f 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/QueryImpl.scala @@ -13,13 +13,14 @@ import cats.syntax.all.* import ldbc.sql.* import ldbc.sql.logging.* -private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: List[Any])(func: Connection[F] => F[T]) extends Query[F, T]: +private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: List[Any])(func: Connection[F] => F[T]) + extends Query[F, T]: override def run: Connection[F] => F[T] = func override def readOnly(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = (for - _ <- connection.setReadOnly(true) + _ <- connection.setReadOnly(true) result <- run(connection) yield result) .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) @@ -27,8 +28,8 @@ private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: override def autoCommit(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = (for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(true) + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(true) result <- run(connection) yield result) .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) @@ -40,19 +41,21 @@ private[ldbc] case class QueryImpl[F[_]: Temporal, T](statement: String, params: val release = (connection: Connection[F], exitCase: ExitCase) => exitCase match { case ExitCase.Errored(ex) => connection.rollback() *> Temporal[F].raiseError(ex) - case _ => connection.commit() + case _ => connection.commit() } - Resource.makeCase(acquire)(release).use(run) + Resource + .makeCase(acquire)(release) + .use(run) .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) <* logHandler.run(LogEvent.Success(statement, params)) override def rollback(connection: Connection[F])(using logHandler: LogHandler[F]): F[T] = (for - _ <- connection.setReadOnly(false) - _ <- connection.setAutoCommit(false) + _ <- connection.setReadOnly(false) + _ <- connection.setAutoCommit(false) result <- run(connection) - _ <- connection.rollback() + _ <- connection.rollback() yield result) .onError(ex => logHandler.run(LogEvent.ExecFailure(statement, params, ex))) <* logHandler.run(LogEvent.Success(statement, params)) diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala index ba362dd10..3b7915a2b 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala @@ -17,10 +17,14 @@ trait Query[F[_], T]: def map[B](f: T => B)(using Functor[F]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Functor[F].map(Query.this.run(conn))(f) - override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.readOnly(connection))(f) - override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.autoCommit(connection))(f) - override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.transaction(connection))(f) - override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(Query.this.rollback(connection))(f) + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(Query.this.readOnly(connection))(f) + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(Query.this.autoCommit(connection))(f) + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(Query.this.transaction(connection))(f) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(Query.this.rollback(connection))(f) def flatMap[B](f: T => Query[F, B])(using Monad[F]): Query[F, B] = new Query[F, B]: @@ -60,10 +64,14 @@ object Query: override def map[A, B](fa: Query[F, A])(f: A => B): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Functor[F].map(fa.run(conn))(f) - override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.readOnly(connection))(f) - override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.autoCommit(connection))(f) - override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.transaction(connection))(f) - override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Functor[F].map(fa.rollback(connection))(f) + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(fa.readOnly(connection))(f) + override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(fa.autoCommit(connection))(f) + override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(fa.transaction(connection))(f) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = + Functor[F].map(fa.rollback(connection))(f) given [F[_]: Monad]: Monad[[T] =>> Query[F, T]] with override def pure[A](x: A): Query[F, A] = @@ -89,9 +97,11 @@ object Query: override def tailRecM[A, B](a: A)(f: A => Query[F, Either[A, B]]): Query[F, B] = new Query[F, B]: override def run: Connection[F] => F[B] = conn => Monad[F].tailRecM(a)(a => f(a).run(conn)) - override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).readOnly(connection)) + override def readOnly(connection: Connection[F])(using LogHandler[F]): F[B] = + Monad[F].tailRecM(a)(a => f(a).readOnly(connection)) override def autoCommit(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).autoCommit(connection)) override def transaction(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).transaction(connection)) - override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = Monad[F].tailRecM(a)(a => f(a).rollback(connection)) + override def rollback(connection: Connection[F])(using LogHandler[F]): F[B] = + Monad[F].tailRecM(a)(a => f(a).rollback(connection)) diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala index 218ca68a4..5c889acc6 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala @@ -55,8 +55,8 @@ trait SQL[F[_]: Monad]: connectionToList[T](statement, params) inline def toList[P <: Product](using - mirror: Mirror.ProductOf[P], - factory: FactoryCompat[P, List[P]] + mirror: Mirror.ProductOf[P], + factory: FactoryCompat[P, List[P]] ): Query[F, List[P]] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader @@ -90,7 +90,7 @@ trait SQL[F[_]: Monad]: connectionToHeadOption[T](statement, params) inline def headOption[P <: Product](using - mirror: Mirror.ProductOf[P] + mirror: Mirror.ProductOf[P] ): Query[F, Option[P]] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader @@ -124,8 +124,8 @@ trait SQL[F[_]: Monad]: connectionToUnsafe[T](statement, params) inline def unsafe[P <: Product](using - mirror: Mirror.ProductOf[P], - ev: MonadError[F, Throwable] + mirror: Mirror.ProductOf[P], + ev: MonadError[F, Throwable] ): Query[F, P] = given Kleisli[F, ResultSet[F], P] = Kleisli { resultSet => ResultSetReader @@ -146,7 +146,7 @@ trait SQL[F[_]: Monad]: def update: Query[F, Int] def returning[T <: String | Int | Long](using - reader: ResultSetReader[F, T], + reader: ResultSetReader[F, T] ): Query[F, T] private[ldbc] def connection[T]( From 29884b09478204d2c04696342fc9bae5c5539ab9 Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 23:03:33 +0900 Subject: [PATCH 12/13] Added comment --- .../src/main/scala/ldbc/sql/Query.scala | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala index 3b7915a2b..8d5e5440c 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/Query.scala @@ -10,6 +10,23 @@ import cats.* import ldbc.sql.logging.LogHandler +/** + * The `Query` trait represents a database query operation that can be run against a connection. + * It is parameterized by the effect type `F[_]` and the result type `T`. + * + * The `run` method is the main method that executes the query against a given connection and returns a result of type `T`. + * + * The `map` and `flatMap` methods are used to transform the result of the query operation. + * + * The `readOnly`, `autoCommit`, `transaction`, and `rollback` methods are used to manage the processing of connections in different modes. + * `readOnly` is for managing the processing of connections in a read-only manner. + * `autoCommit` is for managing the processing of connections for writing. + * `transaction` is for managing the processing of connections in a transaction. + * `rollback` is for managing the processing of connections, always rolling back. + * + * @tparam F + * The effect type + */ trait Query[F[_], T]: def run: Connection[F] => F[T] From 72fa541bbce0476209395450af51d8440495b78e Mon Sep 17 00:00:00 2001 From: takapi327 Date: Thu, 23 May 2024 23:06:08 +0900 Subject: [PATCH 13/13] Change Seq to List --- .../shared/src/main/scala/ldbc/connector/Mysql.scala | 6 +++--- module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala | 2 +- module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala index 322048887..b0329900a 100644 --- a/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala +++ b/module/ldbc-connector/shared/src/main/scala/ldbc/connector/Mysql.scala @@ -26,13 +26,13 @@ import ldbc.sql.* * @tparam F * The effect type */ -case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[F]]) extends SQL[F]: +case class Mysql[F[_]: Temporal](statement: String, params: List[ParameterBinder[F]]) extends SQL[F]: @targetName("combine") override def ++(sql: SQL[F]): SQL[F] = Mysql[F](statement ++ " " ++ sql.statement, params ++ sql.params) - override def update: Query[F, Int] = QueryImpl[F, Int](statement, params.map(_.parameter).toList) { connection => + override def update: Query[F, Int] = QueryImpl[F, Int](statement, params.map(_.parameter)) { connection => for statement <- connection.prepareStatement(statement) result <- params.zipWithIndex.traverse { @@ -43,7 +43,7 @@ case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[ override def returning[T <: String | Int | Long](using reader: ResultSetReader[F, T] - ): Query[F, T] = QueryImpl[F, T](statement, params.map(_.parameter).toList) { connection => + ): Query[F, T] = QueryImpl[F, T](statement, params.map(_.parameter)) { connection => given Kleisli[F, ResultSet[F], T] = Kleisli { resultSet => reader.read(resultSet, 1) } diff --git a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala index e569f970a..6fea2c2db 100644 --- a/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala +++ b/module/ldbc-dsl/shared/src/main/scala/ldbc/dsl/Mysql.scala @@ -26,7 +26,7 @@ import ldbc.sql.* * @tparam F * The effect type */ -case class Mysql[F[_]: Temporal](statement: String, params: Seq[ParameterBinder[F]]) extends SQL[F]: +case class Mysql[F[_]: Temporal](statement: String, params: List[ParameterBinder[F]]) extends SQL[F]: @targetName("combine") override def ++(sql: SQL[F]): SQL[F] = diff --git a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala index 5c889acc6..d5c923c76 100644 --- a/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala +++ b/module/ldbc-sql/src/main/scala/ldbc/sql/SQL.scala @@ -32,7 +32,7 @@ trait SQL[F[_]: Monad]: /** * statement has '?' that the statement has. */ - def params: Seq[ParameterBinder[F]] + def params: List[ParameterBinder[F]] @targetName("combine") def ++(sql: SQL[F]): SQL[F]