Skip to content

Commit

Permalink
Merge pull request #858 from jczuchnowski/prepared-statements
Browse files Browse the repository at this point in the history
Use PreparedStatements for Inserts
  • Loading branch information
jdegoes committed May 21, 2023
2 parents 8e2c266 + b98ab18 commit 45f084d
Show file tree
Hide file tree
Showing 21 changed files with 888 additions and 532 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ lazy val examples = project

lazy val driver = project
.in(file("driver"))
.dependsOn(coreJVM)
.settings(stdSettings("zio-sql-driver"))
.settings(buildInfoSettings("zio.sql.driver"))
.settings(
Expand Down
8 changes: 6 additions & 2 deletions core/jvm/src/main/scala/zio/sql/Sql.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package zio.sql

import zio.schema.Schema
import zio.schema.{ Schema, StandardType }
import zio.sql.table._
import zio.sql.update._
import zio.sql.select._
import zio.sql.insert._
import zio.sql.delete._

case class SqlRow(params: List[SqlParameter])
case class SqlParameter(_type: StandardType[_], value: Any)
case class SqlStatement(query: String, rows: List[SqlRow])

trait Sql {

/*
Expand Down Expand Up @@ -48,7 +52,7 @@ trait Sql {

def renderUpdate(update: Update[_]): String

def renderInsert[A: Schema](insert: Insert[_, A]): String
def renderInsert[A: Schema](insert: Insert[_, A]): SqlStatement

// TODO don't know where to put it now
implicit def convertOptionToSome[A](implicit op: Schema[Option[A]]): Schema[Some[A]] =
Expand Down
12 changes: 6 additions & 6 deletions core/jvm/src/test/scala/zio/sql/ProductSchema.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package zio.sql

import zio.schema.Schema
import java.time.LocalDate

import zio.schema.Schema
import zio.schema.DeriveSchema
import zio.schema.StandardType
import zio.sql.table._
Expand All @@ -12,11 +13,10 @@ import zio.sql.delete._

object ProductSchema {
val sql = new Sql { self =>
override def renderDelete(delete: Delete[_]): String = ???
override def renderRead(read: Read[_]): String = ???
override def renderUpdate(update: Update[_]): String = ???

override def renderInsert[A: Schema](insert: Insert[_, A]): String = ???
override def renderDelete(delete: Delete[_]): String = ???
override def renderRead(read: Read[_]): String = ???
override def renderUpdate(update: Update[_]): String = ???
override def renderInsert[A: Schema](insert: Insert[_, A]): SqlStatement = ???
}

import sql._
Expand Down
8 changes: 4 additions & 4 deletions core/jvm/src/test/scala/zio/sql/TestBasicSelectSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import zio.sql.delete._

object TestBasicSelect {
val userSql = new Sql { self =>
override def renderDelete(delete: Delete[_]): String = ???
override def renderRead(read: Read[_]): String = ???
override def renderUpdate(update: Update[_]): String = ???
override def renderInsert[A: Schema](insert: Insert[_, A]): String = ???
override def renderDelete(delete: Delete[_]): String = ???
override def renderRead(read: Read[_]): String = ???
override def renderUpdate(update: Update[_]): String = ???
override def renderInsert[A: Schema](insert: Insert[_, A]): SqlStatement = ???

case class Users(user_id: String, dob: LocalDate, first_name: String, last_name: String)

Expand Down
2 changes: 1 addition & 1 deletion driver/src/main/scala/zio/sql/driver/Renderer.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package zio.sql.driver

private[sql] class Renderer(val builder: StringBuilder) extends AnyVal {
private[sql] class Renderer(val builder: StringBuilder) {
// not using vararg to avoid allocating `Seq`s
def apply(s1: Any): Unit = {
val _ = builder.append(s1)
Expand Down
1 change: 1 addition & 0 deletions examples/src/main/scala/zio/sql/Examples.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ object Examples extends App with PostgresJdbcModule {
val selectWithFunctions =
select(age + 2, ConcatWs3(fName, " ", lName), Abs(-42.0))
.from(users)
.where(age === 10)
.limit(10)
.offset(20)
.orderBy(age.descending)
Expand Down
80 changes: 80 additions & 0 deletions examples/src/main/scala/zio/sql/LiveExample.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package example

import java.util.UUID
import java.time.LocalDate
import java.util.Properties

import zio._
import zio.schema.DeriveSchema
import zio.sql.{ ConnectionPool, ConnectionPoolConfig }
import zio.sql.postgresql.PostgresJdbcModule
import zio.sql.table._

/**
*
* docker run --name zio-sql-db -p 5432:5432 -e POSTGRES_DB=ziosqltest -e POSTGRES_PASSWORD=12345 -d postgres
*
* psql -h localhost -U postgres -p 5432 -d ziosqltest
*
* create table "customers" (
* "id" uuid not null primary key,
* "age" integer not null,
* "dob" date not null,
* "first_name" varchar not null,
* "last_name" varchar not null
* );
*
*/
object LiveExample extends ZIOAppDefault with PostgresJdbcModule {

import Tables._

def run = myAppLogic

val data = Customer(UUID.randomUUID(), 22, LocalDate.ofYearDay(1990, 1), "Ronald", "Russel")

val stmt = insertInto(customers)(
userId,
age,
dob,
fName,
lName
).values(data)

val properties = {
val p = new Properties()
p.setProperty("user", "postgres")
p.setProperty("password", "12345")
p
}

val cpConfig =
ZLayer(
ZIO.succeed(
ConnectionPoolConfig(
url = "jdbc:postgresql://localhost:5432/ziosqltest?loglevel=2",
properties = properties,
autoCommit = true
)
)
)

val myAppLogic =
execute(stmt)
.provide(
SqlDriver.live,
ConnectionPool.live,
cpConfig
)

object Tables {

case class Customer(id: UUID, age: Int, dob: LocalDate, firstName: String, lastName: String)

implicit val customerSchema = DeriveSchema.gen[Customer]

val customers = Table.defineTable[Customer]("customers")

val (userId, age, dob, fName, lName) = customers.columns
}
}
197 changes: 197 additions & 0 deletions examples/src/main/scala/zio/sql/OracleExamples.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// package zio.sql

// import java.util.UUID
// import java.time._
// import zio.sql.oracle.OracleJdbcModule
// import zio.schema.DeriveSchema
// import zio.sql.expr.AggregationDef._
// import zio.sql.expr.FunctionDef._
// import zio.sql.table._

// object OracleExamples extends App with OracleJdbcModule {
// import Orders._
// import Users._
// import OrderDetails._

// val basicSelect =
// select(fName, lName).from(users)

// println(renderRead(basicSelect))

// val selectAll1 = select(*).from(orderDetails)
// val selectAll2 = select(*).from(users)

// // SELECT "users"."age" + 2, concat_ws("users"."first_name",' ',"users"."last_name"), abs(-42.0) FROM "users" ORDER BY "users"."age" DESC LIMIT 10 OFFSET 20
// val selectWithFunctions =
// select(age + 2, ConcatWs3(fName, " ", lName), Abs(-42.0))
// .from(users)
// .where(age === 10)
// .limit(10)
// .offset(20)
// .orderBy(age.descending)
// println(renderRead(selectWithFunctions))

// // SELECT "users"."first_name", "users"."last_name" FROM "users" ORDER BY "users"."last_name", "users"."first_name" DESC LIMIT 2
// val selectWithRefinements =
// select(fName, lName)
// .from(users)
// .orderBy(lName, fName.desc)
// .limit(2)
// println(renderRead(selectWithRefinements))

// case class Person(fname: String, lname: String)

// // execute(selectWithRefinements).to(Person)
// // execute(selectWithRefinements).to((_, _))

// // DELETE FROM "users" WHERE "users"."first_name" = 'Terrence'
// val basicDelete =
// deleteFrom(users).where(fName === "Terrence")
// println(renderDelete(basicDelete))

// /*
// val deleteFromWithSubquery = deleteFrom(orders).where(fkUserId in {
// select(userId as "id") from users where (fName === "Fred") //todo fix issue #36
// }) */

// // SELECT "users"."first_name", "users"."last_name", "orders"."order_date" FROM "users" LEFT JOIN "orders" ON "orders"."usr_id" = "users"."id"
// val basicJoin =
// select(fName, lName, orderDate).from(users.leftOuter(orders).on(fkUserId === userId))
// println(renderRead(basicJoin))

// // UPDATE "users" SET "first_name" = 'foo', "last_name" = 'bar', "age" = "users"."age" + 1 WHERE true and "users"."age" > 100
// val basicUpdate =
// update(users)
// .set(fName, "foo")
// .set(lName, "bar")
// .set(age, age + 1)
// .where(age > 100)
// println(renderUpdate(basicUpdate))

// /*
// SELECT "users"."id", "users"."first_name", "users"."last_name", sum("order_details"."quantity" * "order_details"."unit_price"), sum(abs("order_details"."quantity"))
// FROM "users"x
// INNER JOIN "orders" ON "users"."id" = "orders"."usr_id"
// LEFT JOIN "order_details" ON "orders"."id" = "order_details"."order_id"
// GROUP BY "users"."id", "users"."first_name", "users"."last_name" */
// val orderValues =
// select(
// userId,
// fName,
// lName,
// Sum(quantity * unitPrice),
// Sum(Abs(quantity))
// )
// .from(
// users
// .join(orders)
// .on(userId === fkUserId)
// .leftOuter(orderDetails)
// .on(orderId === fkOrderId)
// )
// .groupBy(userId, fName, lName)
// println(renderRead(orderValues))

// import scala.language.postfixOps

// // SELECT "users"."first_name", "users"."last_name" FROM "users" WHERE true and "users"."first_name" is not null
// val withPropertyOp = select(fName, lName).from(users).where(fName isNotNull)
// println(renderRead(withPropertyOp))

// // IN
// val subselectSurname = select(lName).from(users).where(age > 18)
// val subselectAge = select(age).from(users).where(age > 18)

// select(fName, lName).from(users).where(lName in List("Jaro", "Peter"))

// select(fName).from(users).where(lName in subselectSurname)
// select(fName).from(users).where(age in subselectAge)

// /*
// insert tuples
// INSERT INTO
// users(uuid, age, date_of_birth, first_name, last_name)
// VALUES
// ('60b01fc9-c902-4468-8d49-3c0f989def37', ‘1983-01-05’, 22, 'Ronald', 'Russell')
// */

// val data =
// List(
// (UUID.randomUUID(), 22, LocalDate.ofYearDay(1990, 1), "Ronald1", "Russel1"),
// (UUID.randomUUID(), 32, LocalDate.ofYearDay(1980, 1), "Ronald2", "Russel2"),
// (UUID.randomUUID(), 42, LocalDate.ofYearDay(1970, 1), "Ronald3", "Russel3")
// )
// val insertTuples = insertInto(users)(userId, age, dob, fName, lName)
// .values(data)

// println("***************")
// println(renderInsert(insertTuples))
// // val insertedTupleRows = execute(insertTuples)
// // println(s"$insertedTupleRows rows are inserted!")
// println("***************")

// /*
// insert as case class with schema
// INSERT INTO
// users(uuid, age, date_of_birth, first_name, last_name)
// VALUES
// ('60b01fc9-c902-4468-8d49-3c0f989def37', ‘1983-01-05’, 22, 'Ronald', 'Russell')
// */
// val dataSchema: Users.Users = Users.Users(UUID.randomUUID(), 22, LocalDate.ofYearDay(1990, 1), "Ronald", "Russel")

// val insertSchema = insertInto(users)(
// userId,
// age,
// dob,
// fName,
// lName
// ).values(dataSchema)

// println(renderInsert(insertSchema))
// // val insertedSchemaRows = execute(insertSchema)
// // println(s"$insertedSchemaRows rows are inserted!")

// /* SELECT "users"."user_id" FROM "users"
// UNION
// SELECT "orders"."usr_id" FROM "orders"
// */
// val selectWithUnion = select(userId).from(users).union(select(fkUserId).from(orders))

// /* SELECT "users"."user_id" FROM "users"
// UNION ALL
// SELECT "orders"."usr_id" FROM "orders"
// */
// val selectWithUnionAll = select(userId).from(users).unionAll(select(fkUserId).from(orders))

// object Users {

// case class Users(id: UUID, age: Int, dob: LocalDate, firstName: String, lastName: String)

// implicit val userSchema = DeriveSchema.gen[Users]

// val users = Table.defineTable[Users]

// val (userId, age, dob, fName, lName) = users.columns
// }

// object Orders {

// case class Orders(id: java.util.UUID, userId: java.util.UUID, orderDate: LocalDate)

// implicit val orderSchema = DeriveSchema.gen[Orders]

// val orders = Table.defineTable[Orders]

// val (orderId, fkUserId, orderDate) = orders.columns
// }

// object OrderDetails {
// case class OrderDetail(orderId: java.util.UUID, productId: Int, quantity: Double, unitPrice: Double)

// implicit val orderDetailSchema = DeriveSchema.gen[OrderDetail]

// val orderDetails = Table.defineTable[OrderDetail]

// val (fkOrderId, fkProductId, quantity, unitPrice) = orderDetails.columns
// }
// }
Loading

0 comments on commit 45f084d

Please sign in to comment.