Skip to content

Commit

Permalink
- add show method for statements
Browse files Browse the repository at this point in the history
- add tests on `show` for all sql dialects
- add `show` info in README
  • Loading branch information
GrigoriiBerezin committed Apr 29, 2024
1 parent 15a33a3 commit 79429be
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 5 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

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.

[![Development](https://img.shields.io/badge/Project%20Stage-Development-green.svg)](https://github.com/zio/zio/wiki/Project-Stages) ![CI Badge](https://github.com/zio/zio-sql/workflows/CI/badge.svg) [![Sonatype Releases](https://img.shields.io/nexus/r/https/oss.sonatype.org/dev.zio/zio-sql_2.13.svg?label=Sonatype%20Release)](https://oss.sonatype.org/content/repositories/releases/dev/zio/zio-sql_2.13/) [![Sonatype Snapshots](https://img.shields.io/nexus/s/https/oss.sonatype.org/dev.zio/zio-sql_2.13.svg?label=Sonatype%20Snapshot)](https://oss.sonatype.org/content/repositories/snapshots/dev/zio/zio-sql_2.13/) [![javadoc](https://javadoc.io/badge2/dev.zio/zio-sql-docs_2.13/javadoc.svg)](https://javadoc.io/doc/dev.zio/zio-sql-docs_2.13) [![ZIO SQL](https://img.shields.io/github/stars/zio/zio-sql?style=social)](https://github.com/zio/zio-sql)
[![Development](https://img.shields.io/badge/Project%20Stage-Development-green.svg)](https://github.com/zio/zio/wiki/Project-Stages) ![CI Badge](https://github.com/zio/zio-sql/workflows/CI/badge.svg) [![Sonatype Snapshots](https://img.shields.io/nexus/s/https/oss.sonatype.org/dev.zio/zio-sql_2.13.svg?label=Sonatype%20Snapshot)](https://oss.sonatype.org/content/repositories/snapshots/dev/zio/zio-sql_2.13/) [![ZIO SQL](https://img.shields.io/github/stars/zio/zio-sql?style=social)](https://github.com/zio/zio-sql)

## Introduction

Expand Down Expand Up @@ -63,16 +63,16 @@ ZIO SQL is packaged into separate modules for different databases. Depending on

```scala
//PostgreSQL
libraryDependencies += "dev.zio" %% "zio-sql-postgres" % "0.1.2"
libraryDependencies += "dev.zio" %% "zio-sql-postgres" % "<version>"

//MySQL
libraryDependencies += "dev.zio" %% "zio-sql-mysql" % "0.1.2"
libraryDependencies += "dev.zio" %% "zio-sql-mysql" % "<version>"

//Oracle
libraryDependencies += "dev.zio" %% "zio-sql-oracle" % "0.1.2"
libraryDependencies += "dev.zio" %% "zio-sql-oracle" % "<version>"

//SQL Server
libraryDependencies += "dev.zio" %% "zio-sql-sqlserver" % "0.1.2"
libraryDependencies += "dev.zio" %% "zio-sql-sqlserver" % "<version>"
```

## Imports and modules
Expand Down
16 changes: 16 additions & 0 deletions core/jvm/src/main/scala/zio/sql/Sql.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ trait Sql {

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

implicit class readOps(read: Read[_]) {
def show: String = renderRead(read)
}

implicit class updateOps(update: Update[_]) {
def show: String = renderUpdate(update)
}

implicit class insertOps[A: Schema](insert: Insert[_, A]) {
def show: String = renderInsert(insert).query
}

implicit class deleteOps(delete: Delete[_]) {
def show: String = renderDelete(delete)
}

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

import zio.Scope
import zio.schema.DeriveSchema
import zio.sql.table.Table._
import zio.test._

import java.time._
import java.util.UUID

object MySqlQueryShowSpec extends ZIOSpecDefault with MysqlRenderModule {
final case class Product(id: UUID, name: String, price: Double)

object Product {
implicit val productSchema = DeriveSchema.gen[Product]
val products = defineTableSmart[Product]
val (id, name, price) = products.columns
}

final case class Order(id: UUID, productId: UUID, quantity: Int, orderDate: LocalDate)

object Order {
implicit val orderSchema = DeriveSchema.gen[Order]
val orders = defineTable[Order]
val (orderId, productId, quantity, date) = orders.columns
}

override def spec: Spec[TestEnvironment with Scope, Any] = suite("MySqlQueryShow")(
test("rendering select") {
import Order._
import Product._

val selectQueryRender =
select(orderId, name)
.from(
products
.join(orders)
.on(productId === id)
)
.limit(5)
.offset(10)
.show

val expectedQuery =
"SELECT order.id, products.name FROM products INNER JOIN order ON order.product_id = products.id LIMIT 5 OFFSET 10"

assertTrue(selectQueryRender == expectedQuery)
},
test("rendering insert") {
import Product._

def insertProduct(uuid: UUID) =
insertInto(products)(id, name, price)
.values((uuid, "Zionomicon", 10.5))

val expectedQuery = "INSERT INTO products (id, name, price) VALUES (?, ?, ?);"

assertTrue(insertProduct(UUID.fromString("dd5a7ae7-de19-446a-87a4-576d79de5c83")).show == expectedQuery)
},
test("rendering update") {
import Product._

def updateProduct(uuid: UUID) =
update(products)
.set(name, "foo")
.set(price, price * 1.1)
.where(id === uuid)

val expectedQuery =
"UPDATE products SET products.name = 'foo', products.price = products.price * 1.1 WHERE products.id = 'f1e69839-964f-44b7-b90d-bd5f51700540'"

assertTrue(updateProduct(UUID.fromString("f1e69839-964f-44b7-b90d-bd5f51700540")).show == expectedQuery)
},
test("rendering delete") {
import Product._

def deleteProduct(uuid: UUID) =
deleteFrom(products)
.where(id === uuid)

val expectedQuery = "DELETE FROM products WHERE products.id = '95625b37-e785-4b4f-86b1-69affaf5f848'"

assertTrue(deleteProduct(UUID.fromString("95625b37-e785-4b4f-86b1-69affaf5f848")).show == expectedQuery)
}
)
}
86 changes: 86 additions & 0 deletions oracle/src/test/scala/zio/sql/oracle/OracleSqlQueryShowSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package zio.sql.oracle

import zio.Scope
import zio.schema.DeriveSchema
import zio.sql.table.Table._
import zio.test._

import java.time._
import java.util.UUID

object OracleSqlQueryShowSpec extends ZIOSpecDefault with OracleRenderModule {
final case class Product(id: UUID, name: String, price: Double)

object Product {
implicit val productSchema = DeriveSchema.gen[Product]
val products = defineTableSmart[Product]
val (id, name, price) = products.columns
}

final case class Order(id: UUID, productId: UUID, quantity: Int, orderDate: LocalDate)

object Order {
implicit val orderSchema = DeriveSchema.gen[Order]
val orders = defineTable[Order]
val (orderId, productId, quantity, date) = orders.columns
}

override def spec: Spec[TestEnvironment with Scope, Any] = suite("OracleSqlQueryShow")(
test("rendering select") {
import Order._
import Product._

val selectQueryRender =
select(orderId, name)
.from(
products
.join(orders)
.on(productId === id)
)
.limit(5)
.offset(10)
.show

val expectedQuery =
"SELECT order.id, products.name FROM products INNER JOIN order ON order.product_id = products.id WHERE rownum <= 5"

assertTrue(selectQueryRender == expectedQuery)
},
test("rendering insert") {
import Product._

def insertProduct(uuid: UUID) =
insertInto(products)(id, name, price)
.values((uuid, "Zionomicon", 10.5))

val expectedQuery = "INSERT INTO products (id, name, price) VALUES (?, ?, ?)"

assertTrue(insertProduct(UUID.fromString("dd5a7ae7-de19-446a-87a4-576d79de5c83")).show == expectedQuery)
},
test("rendering update") {
import Product._

def updateProduct(uuid: UUID) =
update(products)
.set(name, "foo")
.set(price, price * 1.1)
.where(id === uuid)

val expectedQuery =
"UPDATE products SET products.name = N'foo', products.price = products.price * 1.1 WHERE products.id = 'f1e69839-964f-44b7-b90d-bd5f51700540'"

assertTrue(updateProduct(UUID.fromString("f1e69839-964f-44b7-b90d-bd5f51700540")).show == expectedQuery)
},
test("rendering delete") {
import Product._

def deleteProduct(uuid: UUID) =
deleteFrom(products)
.where(id === uuid)

val expectedQuery = "DELETE FROM products WHERE products.id = '95625b37-e785-4b4f-86b1-69affaf5f848'"

assertTrue(deleteProduct(UUID.fromString("95625b37-e785-4b4f-86b1-69affaf5f848")).show == expectedQuery)
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package zio.sql.postgresql

import zio.Scope
import zio.schema.DeriveSchema
import zio.sql.table.Table._
import zio.test._

import java.time._
import java.util.UUID

object PostgresSqlQueryShowSpec extends ZIOSpecDefault with PostgresRenderModule {
final case class Product(id: UUID, name: String, price: Double)

object Product {
implicit val productSchema = DeriveSchema.gen[Product]
val products = defineTableSmart[Product]
val (id, name, price) = products.columns
}

final case class Order(id: UUID, productId: UUID, quantity: Int, orderDate: LocalDate)

object Order {
implicit val orderSchema = DeriveSchema.gen[Order]
val orders = defineTable[Order]
val (orderId, productId, quantity, date) = orders.columns
}

override def spec: Spec[TestEnvironment with Scope, Any] = suite("PostgresSqlQueryShow")(
test("rendering select") {
import Order._
import Product._

val selectQueryRender =
select(orderId, name)
.from(
products
.join(orders)
.on(productId === id)
)
.limit(5)
.offset(10)
.show

val expectedQuery =
"SELECT \"order\".\"id\", \"products\".\"name\" FROM \"products\" INNER JOIN \"order\" ON \"order\".\"product_id\" = \"products\".\"id\" LIMIT 5 OFFSET 10"

assertTrue(selectQueryRender == expectedQuery)
},
test("rendering insert") {
import Product._

def insertProduct(uuid: UUID) =
insertInto(products)(id, name, price)
.values((uuid, "Zionomicon", 10.5))

val expectedQuery = "INSERT INTO \"products\" (\"id\", \"name\", \"price\") VALUES (?, ?, ?);"

assertTrue(insertProduct(UUID.fromString("dd5a7ae7-de19-446a-87a4-576d79de5c83")).show == expectedQuery)
},
test("rendering update") {
import Product._

def updateProduct(uuid: UUID) =
update(products)
.set(name, "foo")
.set(price, price * 1.1)
.where(id === uuid)

val expectedQuery =
"UPDATE \"products\" SET \"name\" = 'foo', \"price\" = \"products\".\"price\" * 1.1 WHERE \"products\".\"id\" = 'f1e69839-964f-44b7-b90d-bd5f51700540'"

assertTrue(updateProduct(UUID.fromString("f1e69839-964f-44b7-b90d-bd5f51700540")).show == expectedQuery)
},
test("rendering delete") {
import Product._

def deleteProduct(uuid: UUID) =
deleteFrom(products)
.where(id === uuid)

val expectedQuery = "DELETE FROM \"products\" WHERE \"products\".\"id\" = '95625b37-e785-4b4f-86b1-69affaf5f848'"

assertTrue(deleteProduct(UUID.fromString("95625b37-e785-4b4f-86b1-69affaf5f848")).show == expectedQuery)
}
)
}
Loading

0 comments on commit 79429be

Please sign in to comment.