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

Implement renderInsert for Oracle #695

Merged
merged 22 commits into from
Jul 2, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
merge master
  • Loading branch information
peixunzhang committed Jun 5, 2022
commit 3d30f7999aa9568ca5ee8ceaff2fdf1ea6463fa2
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ Connection pool | :white_check_mark:

#### Db-specific features:

Feature | PostgreSQL | SQL Server | Oracle | MySQL
:------------ | :-------------| :-------------| :-------------| :-------------
Render Read | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
Render Delete | :heavy_check_mark: | :heavy_check_mark: | | :white_check_mark: |
Render Update | :heavy_check_mark: | | | :white_check_mark: |
Render Insert | :heavy_check_mark: | | |
Feature | PostgreSQL | SQL Server | Oracle | MySQL
:------------ | :-------------| :-------------|:-------------------| :-------------
Render Read | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
Render Delete | :heavy_check_mark: | :heavy_check_mark: | :white_check_mark: | :white_check_mark: |
Render Update | :heavy_check_mark: | | :white_check_mark: | :white_check_mark: |
Render Insert | :heavy_check_mark: | | | :white_check_mark: |
Functions | :heavy_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Types | :white_check_mark: | | | :white_check_mark: |
Operators | | | |
Types | :white_check_mark: | | | :white_check_mark: |
Operators | | | | |

## What is ZIO SQL?
ZIO SQL lets you write type-safe, type-inferred, and composable SQL queries in ordinary Scala, helping you prevent persistence bugs before they happen, and leverage your IDE to make writing SQL productive, safe, and fun.
Expand Down
29 changes: 2 additions & 27 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import BuildHelper._
import InfrastructureHelper._
import explicitdeps.ExplicitDepsPlugin.autoImport.moduleFilterRemoveValue
import sbtcrossproject.CrossPlugin.autoImport.crossProject

Expand Down Expand Up @@ -29,30 +28,6 @@ val zioSchemaVersion = "0.1.9"
val testcontainersVersion = "1.17.2"
val testcontainersScalaVersion = "0.40.7"

lazy val startPostgres = taskKey[Unit]("Start up Postgres")
startPostgres := startService(Database.Postgres, streams.value)

lazy val stopPostgres = taskKey[Unit]("Shut down Postgres")
stopPostgres := stopService(Database.Postgres, streams.value)

lazy val startMySQL = taskKey[Unit]("Start up MySQL")
startMySQL := startService(Database.MySQL, streams.value)

lazy val stopMySQL = taskKey[Unit]("Shut down MySQL")
stopMySQL := stopService(Database.MySQL, streams.value)

lazy val startMsSQL = taskKey[Unit]("Start up Microsoft SQL Server")
startMsSQL := startService(Database.MSSQL, streams.value)

lazy val stopMsSQL = taskKey[Unit]("Shut down Microsoft SQL Server")
stopMsSQL := stopService(Database.MSSQL, streams.value)

lazy val startOracle = taskKey[Unit]("Start up Oracle")
startOracle := startService(Database.Oracle, streams.value)

lazy val stopOracle = taskKey[Unit]("Shut down Oracle")
stopOracle := stopService(Database.Oracle, streams.value)

lazy val root = project
.in(file("."))
.settings(
Expand Down Expand Up @@ -141,7 +116,7 @@ lazy val jdbc = project
libraryDependencies ++= Seq(
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
"org.postgresql" % "postgresql" % "42.3.5" % Test,
"org.postgresql" % "postgresql" % "42.3.6" % Test,
"com.dimafeng" %% "testcontainers-scala-postgresql" % testcontainersScalaVersion % Test
)
)
Expand Down Expand Up @@ -203,7 +178,7 @@ lazy val postgres = project
"org.testcontainers" % "database-commons" % testcontainersVersion % Test,
"org.testcontainers" % "postgresql" % testcontainersVersion % Test,
"org.testcontainers" % "jdbc" % testcontainersVersion % Test,
"org.postgresql" % "postgresql" % "42.3.5" % Compile,
"org.postgresql" % "postgresql" % "42.3.6" % Compile,
"com.dimafeng" %% "testcontainers-scala-postgresql" % testcontainersScalaVersion % Test
)
)
Expand Down
45 changes: 0 additions & 45 deletions docker-compose.yml

This file was deleted.

5 changes: 5 additions & 0 deletions driver/src/main/scala/zio/sql/driver/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ private[sql] class Renderer(val builder: StringBuilder) extends AnyVal {

private[sql] object Renderer {
def apply(): Renderer = new Renderer(new StringBuilder)

implicit class Extensions(val value: String) {
def doubleQuoted: String = s""""$value""""
def singleQuoted: String = s"'$value'"
}
}
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))
}
1 change: 1 addition & 0 deletions mysql/src/main/scala/zio/sql/mysql/MysqlSqlModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ trait MysqlSqlModule extends Sql { self =>
val MakeTime = FunctionDef[(Int, Int, Double), LocalTime](FunctionName("maketime"))
val Now = FunctionDef[Any, ZonedDateTime](FunctionName("now"))
val Pi = Expr.FunctionCall0[Double](FunctionDef[Any, Double](FunctionName("pi")))
val Soundex = FunctionDef[String, String](FunctionName("soundex"))
val Rand = FunctionDef[Int, Double](FunctionName("rand"))
val RPad = FunctionDef[(String, Int, String), String](FunctionName("rpad"))
val Uuid = Expr.FunctionCall0[UUID](FunctionDef[Any, UUID](FunctionName("uuid")))
Expand Down
32 changes: 32 additions & 0 deletions mysql/src/test/scala/zio/sql/mysql/FunctionDefSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,38 @@ object FunctionDefSpec extends MysqlRunnableSpec with ShopSchema {

assertZIO(testResult.runHead.some)(equalTo(expected))
},
test("soundex outputs should not match for non-similar-sounding strings") {
val queryForRobert = select(Soundex("Robert"))
val queryForTam = select(Soundex("Tam"))

val resultForRobert = execute(queryForRobert)
val resultForTam = execute(queryForTam)

for {
robertResult <- resultForRobert.runCollect
tamResult <- resultForTam.runCollect
} yield assert(robertResult.head.equals(tamResult.head))(equalTo(false))
},
test("soundex outputs should match for equivalent strings") {
val queryForRobert = select(Soundex("Robert"))
val queryForRupert = select(Soundex("Rupert"))

val resultForRobert = execute(queryForRobert)
val resultForRupert = execute(queryForRupert)

for {
robertResult <- resultForRobert.runCollect
rupertResult <- resultForRupert.runCollect
} yield assert(robertResult.head.equals(rupertResult.head))(equalTo(true))
},
test("soundex") {
val query = select(Soundex("Robert"))
val expected = "R163"

val testResult = execute(query)

assertZIO(testResult.runHead.some)(equalTo(expected))
},
test("current_date") {
val query = select(CurrentDate)

Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.