Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented issue/feature 645 #705

Merged
merged 3 commits into from
Jun 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions jdbc/src/main/scala/zio/sql/SqlDriverLiveModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import zio.schema.Schema
trait SqlDriverLiveModule { self: Jdbc =>
private[sql] trait SqlDriverCore {

def deleteOnBatch(delete: List[Delete[_]], conn: Connection): IO[Exception, List[Int]]

def updateOnBatch(update: List[Update[_]], conn: Connection): IO[Exception, List[Int]]

def insertOnBatch[A: Schema](insert: List[Insert[_, A]], conn: Connection): IO[Exception, List[Int]]

def deleteOn(delete: Delete[_], conn: Connection): IO[Exception, Int]

def updateOn(update: Update[_], conn: Connection): IO[Exception, Int]
Expand All @@ -22,25 +28,41 @@ trait SqlDriverLiveModule { self: Jdbc =>
def delete(delete: Delete[_]): IO[Exception, Int] =
ZIO.scoped(pool.connection.flatMap(deleteOn(delete, _)))

def delete(delete: List[Delete[_]]): IO[Exception, List[Int]] =
ZIO.scoped(pool.connection.flatMap(deleteOnBatch(delete, _)))

def deleteOn(delete: Delete[_], conn: Connection): IO[Exception, Int] =
ZIO.attemptBlocking {
val query = renderDelete(delete)
val statement = conn.createStatement()
statement.executeUpdate(query)
}.refineToOrDie[Exception]

def deleteOnBatch(delete: List[Delete[_]], conn: Connection): IO[Exception, List[Int]] =
ZIO.attemptBlocking {
val statement = conn.createStatement()
delete.map(delete_ => statement.addBatch(renderDelete(delete_)))
statement.executeBatch().toList
}.refineToOrDie[Exception]

def update(update: Update[_]): IO[Exception, Int] =
ZIO.scoped(pool.connection.flatMap(updateOn(update, _)))

def updateOn(update: Update[_], conn: Connection): IO[Exception, Int] =
ZIO.attemptBlocking {

val query = renderUpdate(update)

val query = renderUpdate(update)
val statement = conn.createStatement()

statement.executeUpdate(query)
}.refineToOrDie[Exception]

def update(update: List[Update[_]]): IO[Exception, List[Int]] =
ZIO.scoped(pool.connection.flatMap(updateOnBatch(update, _)))

def updateOnBatch(update: List[Update[_]], conn: Connection): IO[Exception, List[Int]] =
ZIO.attemptBlocking {
val statement = conn.createStatement()
update.map(update_ => statement.addBatch(renderUpdate(update_)))
statement.executeBatch().toList
}.refineToOrDie[Exception]

def read[A](read: Read[A]): Stream[Exception, A] =
Expand Down Expand Up @@ -93,9 +115,19 @@ trait SqlDriverLiveModule { self: Jdbc =>
statement.executeUpdate(query)
}.refineToOrDie[Exception]

override def insertOnBatch[A: Schema](insert: List[Insert[_, A]], conn: Connection): IO[Exception, List[Int]] =
ZIO.attemptBlocking {
val statement = conn.createStatement()
insert.map(insert_ => statement.addBatch(renderInsert(insert_)))
statement.executeBatch().toList
}.refineToOrDie[Exception]

override def insert[A: Schema](insert: Insert[_, A]): IO[Exception, Int] =
ZIO.scoped(pool.connection.flatMap(insertOn(insert, _)))

def insert[A: Schema](insert: List[Insert[_, A]]): IO[Exception, List[Int]] =
ZIO.scoped(pool.connection.flatMap(insertOnBatch(insert, _)))

override def transact[R, A](tx: ZTransaction[R, Exception, A]): ZIO[R, Throwable, A] =
ZIO.scoped[R] {
for {
Expand Down
15 changes: 15 additions & 0 deletions jdbc/src/main/scala/zio/sql/TransactionModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,31 @@ trait TransactionModule { self: Jdbc =>
ZTransaction.fromEffect(coreDriver.updateOn(update, connection))
}

def batchUpdate(update: List[self.Update[_]]): ZTransaction[Any, Exception, List[Int]] =
txn.flatMap { case Txn(connection, coreDriver) =>
ZTransaction.fromEffect(coreDriver.updateOnBatch(update, connection))
}

def apply[Z: Schema](insert: self.Insert[_, Z]): ZTransaction[Any, Exception, Int] =
txn.flatMap { case Txn(connection, coreDriver) =>
ZTransaction.fromEffect(coreDriver.insertOn(insert, connection))
}

def batchInsert[Z: Schema](insert: List[self.Insert[_, Z]]): ZTransaction[Any, Exception, List[Int]] =
txn.flatMap { case Txn(connection, coreDriver) =>
ZTransaction.fromEffect(coreDriver.insertOnBatch(insert, connection))
}

def apply(delete: self.Delete[_]): ZTransaction[Any, Exception, Int] =
txn.flatMap { case Txn(connection, coreDriver) =>
ZTransaction.fromEffect(coreDriver.deleteOn(delete, connection))
}

def batchDelete(delete: List[self.Delete[_]]): ZTransaction[Any, Exception, List[Int]] =
txn.flatMap { case Txn(connection, coreDriver) =>
ZTransaction.fromEffect(coreDriver.deleteOnBatch(delete, connection))
}

def succeed[A](a: => A): ZTransaction[Any, Nothing, A] = fromEffect(ZIO.succeed(a))

def fail[E](e: => E): ZTransaction[Any, E, Nothing] = fromEffect(ZIO.fail(e))
Expand Down
16 changes: 16 additions & 0 deletions jdbc/src/main/scala/zio/sql/jdbc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ trait Jdbc extends zio.sql.Sql with TransactionModule with JdbcInternalModule wi
trait SqlDriver {
def delete(delete: Delete[_]): IO[Exception, Int]

def delete(delete: List[Delete[_]]): IO[Exception, List[Int]]

def update(update: Update[_]): IO[Exception, Int]

def update(update: List[Update[_]]): IO[Exception, List[Int]]

def read[A](read: Read[A]): Stream[Exception, A]

def transact[R, A](tx: ZTransaction[R, Exception, A]): ZIO[R, Throwable, A]

def insert[A: Schema](insert: Insert[_, A]): IO[Exception, Int]

def insert[A: Schema](insert: List[Insert[_, A]]): IO[Exception, List[Int]]
}
object SqlDriver {

val live: ZLayer[ConnectionPool, Nothing, SqlDriver] =
ZLayer(ZIO.serviceWith[ConnectionPool](new SqlDriverLive(_)))
}
Expand All @@ -32,9 +39,18 @@ trait Jdbc extends zio.sql.Sql with TransactionModule with JdbcInternalModule wi
def execute(delete: Delete[_]): ZIO[SqlDriver, Exception, Int] =
ZIO.serviceWithZIO(_.delete(delete))

def executeBatchDelete(delete: List[Delete[_]]): ZIO[SqlDriver, Exception, List[Int]] =
ZIO.serviceWithZIO(_.delete(delete))

def execute[A: Schema](insert: Insert[_, A]): ZIO[SqlDriver, Exception, Int] =
ZIO.serviceWithZIO(_.insert(insert))

def executeBatchInsert[A: Schema](insert: List[Insert[_, A]]): ZIO[SqlDriver, Exception, List[Int]] =
ZIO.serviceWithZIO(_.insert(insert))

def execute(update: Update[_]): ZIO[SqlDriver, Exception, Int] =
ZIO.serviceWithZIO(_.update(update))

def executeBatchUpdate(update: List[Update[_]]): ZIO[SqlDriver, Exception, List[Int]] =
ZIO.serviceWithZIO(_.update(update))
}
15 changes: 15 additions & 0 deletions postgres/src/test/scala/zio/sql/postgresql/DbSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package zio.sql.postgresql

import zio.sql.Jdbc

import java.time.{ LocalDate, ZonedDateTime }
import java.util.UUID

trait DbSchema extends Jdbc { self =>
import self.ColumnSet._

Expand All @@ -17,6 +20,16 @@ trait DbSchema extends Jdbc { self =>
}

object Customers {
case class Customer(
id: UUID,
fname: String,
lname: String,
verified: Boolean,
dateOfBirth: LocalDate,
created: String,
created2: ZonedDateTime
)

// https://github.com/zio/zio-sql/issues/320 Once Insert is supported, we can remove created_timestamp_string
val customers =
(uuid("Id") ++ localDate("Dob") ++ string("First_name") ++ string("Last_name") ++ boolean(
Expand All @@ -26,6 +39,8 @@ trait DbSchema extends Jdbc { self =>

val (customerId, dob, fName, lName, verified, createdString, createdTimestamp) =
customers.columns

val ALL = customerId ++ fName ++ lName ++ verified ++ dob ++ createdString ++ createdTimestamp
}
object Orders {
val orders = (uuid("id") ++ uuid("customer_id") ++ localDate("order_date")).table("orders")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package zio.sql.postgresql

import zio.Cause
import zio.test.Assertion._
import zio.test._

import java.time.{ LocalDate, ZonedDateTime }
import java.util.UUID

object DeleteBatchSpec extends PostgresRunnableSpec with DbSchema {

import Customers._

private def delete_(c: Customer): Delete[customers.TableType] =
deleteFrom(customers).where((verified.isTrue) && (customerId === c.id))

override def specLayered = suite("Postgres module batch delete")(
test("Can delete more than one customer from single table with a condition") {
val query = deleteFrom(customers).where(verified.isNotTrue)

val result = executeBatchDelete(List(query))

val assertion = for {
r <- result
} yield assert(r)(equalTo(List(1)))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("Can insert more than one customer into single table prior to deleting them") {
val id1 = UUID.randomUUID()
val id2 = UUID.randomUUID()
val id3 = UUID.randomUUID()
val id4 = UUID.randomUUID()
val c1 = Customer(
id1,
"fnameCustomer1",
"lnameCustomer1",
true,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)
val c2 = Customer(
id2,
"fnameCustomer2",
"lnameCustomer2",
true,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)
val c3 = Customer(
id3,
"fnameCustomer3",
"lnameCustomer3",
true,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)
val c4 = Customer(
id4,
"fnameCustomer4",
"lnameCustomer4",
false,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)

val allCustomer = List(c1, c2, c3, c4)
val data = allCustomer.map(Customer.unapply(_).get)
val query = insertInto(customers)(ALL).values(data)
val resultInsert = execute(query)

val insertAssertion = for {
r <- resultInsert
} yield assert(r)(equalTo(4))
insertAssertion.mapErrorCause(cause => Cause.stackless(cause.untraced))

val selectAll = select(ALL).from(customers)
val result_ = execute(selectAll.to((Customer.apply _).tupled)).runCollect

val assertion_ = for {
x <- result_
updated = x.toList.map(delete_)
result <- executeBatchDelete(updated).map(l => l.fold(0)((a, b) => a + b))
} yield assert(result)(equalTo(4))
assertion_.mapErrorCause(cause => Cause.stackless(cause.untraced))

}
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package zio.sql.postgresql

import zio.Cause
import zio.test.Assertion._
import zio.test._

import java.time.{ LocalDate, ZonedDateTime }
import java.util.UUID

object InsertBatchSpec extends PostgresRunnableSpec with DbSchema {

import Customers._

override def specLayered = suite("Postgres module batch insert")(
test("Can insert more than one customer into a table with a condition") {
val id1 = UUID.randomUUID()
val id2 = UUID.randomUUID()
val id3 = UUID.randomUUID()
val id4 = UUID.randomUUID()
val c1 = Customer(
id1,
"fnameCustomer1",
"lnameCustomer1",
true,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)
val c2 = Customer(
id2,
"fnameCustomer2",
"lnameCustomer2",
true,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)
val c3 = Customer(
id3,
"fnameCustomer3",
"lnameCustomer3",
true,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)
val c4 = Customer(
id4,
"fnameCustomer4",
"lnameCustomer4",
false,
LocalDate.now(),
LocalDate.now().toString,
ZonedDateTime.now()
)

val allCustomer = List(c1, c2, c3, c4)
val data = allCustomer.map(Customer.unapply(_).get)
val query = insertInto(customers)(ALL).values(data)

val resultInsert = execute(query)

val insertAssertion = for {
result <- resultInsert
} yield assert(result)(equalTo(4))
insertAssertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
}
)

}
Loading