Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into issue/183
Browse files Browse the repository at this point in the history
  • Loading branch information
pjazdzewski1990 committed Nov 29, 2020
2 parents 7899c12 + b60d869 commit 2de8db4
Show file tree
Hide file tree
Showing 36 changed files with 2,453 additions and 303 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@
| --- | --- |
| [![Build Status][badge-ci]][link-ci] | [![badge-discord]][link-discord] |

## Current status: pre-0.1 (no release yet)

### Progress report towards 0.1

:heavy_check_mark: - good to go

:white_check_mark: - some more work needed

#### General features:
Feature | Progress
:------------ | :-------------
Type-safe schema | :heavy_check_mark:
Type-safe DSL | :white_check_mark:
Running Reads | :heavy_check_mark:
Running Deletes | :heavy_check_mark:
Running Updates | :heavy_check_mark:
Running Inserts |
Transactions |
Connection pool |

#### Db-specific features:

Feature | PostgreSQL | SQL Server | Oracle | MySQL
:------------ | :-------------| :-------------| :-------------| :-------------
Render Read | :white_check_mark: | :white_check_mark: | |
Render Delete | :white_check_mark: | | |
Render Update | :white_check_mark: | | |
Render Insert | | | |
Functions | :white_check_mark: | | |
Types | | | |
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
58 changes: 38 additions & 20 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ inThisBuild(
)
)

addCommandAlias("fmt", "all scalafmtSbt scalafmt test:scalafmt")
addCommandAlias("fmtOnce", "all scalafmtSbt scalafmt test:scalafmt")
addCommandAlias("fmt", "fmtOnce;fmtOnce")
addCommandAlias("check", "all scalafmtSbtCheck scalafmtCheck test:scalafmtCheck")

val zioVersion = "1.0.3"
val testcontainersVersion = "1.15.0"
val zioVersion = "1.0.3"
val testcontainersVersion = "1.15.0"
val testcontainersScalaVersion = "1.0.0-alpha1"

lazy val startPostgres = taskKey[Unit]("Start up Postgres")
startPostgres := startService(Database.Postgres, streams.value)
Expand Down Expand Up @@ -151,9 +153,15 @@ lazy val mysql = project
.settings(buildInfoSettings("zio.sql.mysql"))
.settings(
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test"
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test",
"org.testcontainers" % "testcontainers" % testcontainersVersion % Test,
"org.testcontainers" % "database-commons" % testcontainersVersion % Test,
"org.testcontainers" % "jdbc" % testcontainersVersion % Test,
"org.testcontainers" % "mysql" % testcontainersVersion % Test,
"mysql" % "mysql-connector-java" % "8.0.22" % Test,
"com.dimafeng" %% "testcontainers-scala-mysql" % testcontainersScalaVersion % Test
)
)
.settings(testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"))
Expand All @@ -166,9 +174,15 @@ lazy val oracle = project
.settings(buildInfoSettings("zio.sql.oracle"))
.settings(
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test"
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test",
"org.testcontainers" % "testcontainers" % testcontainersVersion % Test,
"org.testcontainers" % "database-commons" % testcontainersVersion % Test,
"org.testcontainers" % "oracle-xe" % testcontainersVersion % Test,
"org.testcontainers" % "jdbc" % testcontainersVersion % Test,
"com.oracle.database.jdbc" % "ojdbc8" % "19.8.0.0" % Test,
"com.dimafeng" %% "testcontainers-scala-oracle-xe" % "0.38.6" % Test
)
)
.settings(testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"))
Expand All @@ -182,14 +196,14 @@ lazy val postgres = project
.settings(
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
"org.testcontainers" % "testcontainers" % testcontainersVersion % Test,
"org.testcontainers" % "database-commons" % testcontainersVersion % Test,
"org.testcontainers" % "postgresql" % testcontainersVersion % Test,
"org.testcontainers" % "jdbc" % testcontainersVersion % Test,
"org.postgresql" % "postgresql" % "42.2.18" % Test,
"com.dimafeng" %% "testcontainers-scala-postgresql" % "1.0.0-alpha1" % Test
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
"org.testcontainers" % "testcontainers" % testcontainersVersion % Test,
"org.testcontainers" % "database-commons" % testcontainersVersion % Test,
"org.testcontainers" % "postgresql" % testcontainersVersion % Test,
"org.testcontainers" % "jdbc" % testcontainersVersion % Test,
"org.postgresql" % "postgresql" % "42.2.18" % Test,
"com.dimafeng" %% "testcontainers-scala-postgresql" % testcontainersScalaVersion % Test
)
)
.settings(testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"))
Expand All @@ -202,9 +216,13 @@ lazy val sqlserver = project
.settings(buildInfoSettings("zio.sql.sqlserver"))
.settings(
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test"
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test",
"org.testcontainers" % "testcontainers" % testcontainersVersion % Test,
"org.testcontainers" % "database-commons" % testcontainersVersion % Test,
"org.testcontainers" % "mssqlserver" % testcontainersVersion % Test,
"org.testcontainers" % "jdbc" % testcontainersVersion % Test
)
)
.settings(testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"))
Expand Down
23 changes: 23 additions & 0 deletions core/jvm/src/main/scala/zio/sql/Renderer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package zio.sql

class Renderer(val builder: StringBuilder) extends AnyVal {
//not using vararg to avoid allocating `Seq`s
def apply(s1: Any): Unit = {
val _ = builder.append(s1)
}
def apply(s1: Any, s2: Any): Unit = {
val _ = builder.append(s1).append(s2)
}
def apply(s1: Any, s2: Any, s3: Any): Unit = {
val _ = builder.append(s1).append(s2).append(s3)
}
def apply(s1: Any, s2: Any, s3: Any, s4: Any): Unit = {
val _ = builder.append(s1).append(s2).append(s3).append(s4)
}

override def toString: String = builder.toString()
}

object Renderer {
def apply(): Renderer = new Renderer(new StringBuilder)
}
7 changes: 6 additions & 1 deletion core/jvm/src/main/scala/zio/sql/Sql.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ trait Sql extends SelectModule with DeleteModule with UpdateModule with ExprModu
def select[F, A, B <: SelectionSet[A]](selection: Selection[F, A, B]): SelectBuilder[F, A, B] =
SelectBuilder(selection)

def deleteFrom[F[_], A, B](table: Table.Source.Aux[F, A, B]): DeleteBuilder[F, A, B] = DeleteBuilder(table)
def deleteFrom[F[_], A, B](table: Table.Source.Aux[F, A, B]): Delete[A] = Delete(table, true)

def update[A](table: Table.Aux[A]): UpdateBuilder[A] = UpdateBuilder(table)

def renderDelete(delete: self.Delete[_]): String

def renderRead(read: self.Read[_]): String

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

}
7 changes: 2 additions & 5 deletions core/jvm/src/main/scala/zio/sql/delete.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package zio.sql

trait DeleteModule { self: ExprModule with TableModule =>

sealed case class DeleteBuilder[F[_], A, B](table: Table.Aux[A]) {
def where[F1](expr: Expr[F1, A, Boolean]): Delete[F1, A] = Delete(table, expr)
sealed case class Delete[A](table: Table.Aux[A], whereExpr: Expr[_, A, Boolean]) {
def where[F](expr: Expr[F, A, Boolean]): Delete[A] = Delete(table, expr)
}

sealed case class Delete[F, A](table: Table.Aux[A], whereExpr: Expr[F, A, Boolean])

}
18 changes: 14 additions & 4 deletions core/jvm/src/main/scala/zio/sql/expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {
def *[F2, A1 <: A, B1 >: B](that: Expr[F2, A1, B1])(implicit ev: IsNumeric[B1]): Expr[F :||: F2, A1, B1] =
Expr.Binary(self, that, BinaryOp.Mul[B1]())

//todo do something special for divide by 0? also Mod/log/whatever else is really a partial function.. PartialExpr?
def /[F2, A1 <: A, B1 >: B](that: Expr[F2, A1, B1])(implicit ev: IsNumeric[B1]): Expr[F :||: F2, A1, B1] =
Expr.Binary(self, that, BinaryOp.Div[B1]())

Expand Down Expand Up @@ -53,6 +54,9 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {
def <=[F2, A1 <: A, B1 >: B](that: Expr[F2, A1, B1]): Expr[F :||: F2, A1, Boolean] =
Expr.Relational(self, that, RelationalOp.LessThanEqual)

def like[F2, A1 <: A, B1 >: B](that: Expr[F2, A1, B1]): Expr[F :||: F2, A1, Boolean] =
Expr.Relational(self, that, RelationalOp.Like)

def &[F2, A1 <: A, B1 >: B](that: Expr[F2, A1, B1])(implicit ev: IsIntegral[B1]): Expr[F :||: F2, A1, B1] =
Expr.Binary(self, that, BinaryOp.AndBit[B1]())

Expand Down Expand Up @@ -158,7 +162,13 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}

sealed case class FunctionCall0[F, A, B, Z: TypeTag](function: FunctionDef[B, Z]) extends InvariantExpr[F, A, Z] {
sealed case class ParenlessFunctionCall0[Z: TypeTag](function: FunctionName)
extends InvariantExpr[Features.Function0, Any, Z] {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}

sealed case class FunctionCall0[Z: TypeTag](function: FunctionDef[Any, Z])
extends InvariantExpr[Features.Function0, Any, Z] {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}

Expand Down Expand Up @@ -214,8 +224,8 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {

sealed case class FunctionDef[-A, +B](name: FunctionName) { self =>

def apply[Source, B1 >: B]()(implicit typeTag: TypeTag[B1]): Expr[Unit, Source, B1] =
Expr.FunctionCall0(self: FunctionDef[A, B1])
def apply[B1 >: B]()(implicit ev: Any <:< A, typeTag: TypeTag[B1]): Expr[Features.Function0, Any, B1] =
Expr.FunctionCall0(self.asInstanceOf[FunctionDef[Any, B1]])

def apply[F, Source, B1 >: B](param1: Expr[F, Source, A])(implicit typeTag: TypeTag[B1]): Expr[F, Source, B1] =
Expr.FunctionCall1(param1, self: FunctionDef[A, B1])
Expand Down Expand Up @@ -278,7 +288,7 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {
//string functions
val Ascii = FunctionDef[String, Int](FunctionName("ascii"))
val CharLength = FunctionDef[String, Int](FunctionName("character_length"))
val Concat = FunctionDef[(String, String), String](FunctionName("concat"))
val Concat = FunctionDef[(String, String), String](FunctionName("concat")) //todo varargs
val ConcatWs2 = FunctionDef[(String, String), String](FunctionName("concat_ws"))
val ConcatWs3 = FunctionDef[(String, String, String), String](FunctionName("concat_ws"))
val ConcatWs4 = FunctionDef[(String, String, String, String), String](FunctionName("concat_ws"))
Expand Down
1 change: 1 addition & 0 deletions core/jvm/src/main/scala/zio/sql/features.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ trait FeaturesModule {
type Union[_, _]
type Source
type Literal
type Function0

sealed trait IsAggregated[A]

Expand Down
3 changes: 3 additions & 0 deletions core/jvm/src/main/scala/zio/sql/ops.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ trait OpsModule extends TypeTagModule {
case object NotEqual extends RelationalOp {
override val symbol: String = "<>"
}
case object Like extends RelationalOp {
override val symbol: String = "like"
}
}

}
46 changes: 24 additions & 22 deletions core/jvm/src/main/scala/zio/sql/typetag.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,32 @@ trait TypeTagModule {

type TypeTagExtension[+A]

sealed trait TypeTag[A]
sealed trait TypeTag[+A] {
private[zio] def cast(a: Any): A = a.asInstanceOf[A]
}

object TypeTag {
sealed trait NotNull[A] extends TypeTag[A]
implicit case object TBigDecimal extends NotNull[BigDecimal]
implicit case object TBoolean extends NotNull[Boolean]
implicit case object TByte extends NotNull[Byte]
implicit case object TByteArray extends NotNull[Chunk[Byte]]
implicit case object TChar extends NotNull[Char]
implicit case object TDouble extends NotNull[Double]
implicit case object TFloat extends NotNull[Float]
implicit case object TInstant extends NotNull[Instant]
implicit case object TInt extends NotNull[Int]
implicit case object TLocalDate extends NotNull[LocalDate]
implicit case object TLocalDateTime extends NotNull[LocalDateTime]
implicit case object TLocalTime extends NotNull[LocalTime]
implicit case object TLong extends NotNull[Long]
implicit case object TOffsetDateTime extends NotNull[OffsetDateTime]
implicit case object TOffsetTime extends NotNull[OffsetTime]
implicit case object TShort extends NotNull[Short]
implicit case object TString extends NotNull[String]
implicit case object TUUID extends NotNull[UUID]
implicit case object TZonedDateTime extends NotNull[ZonedDateTime]
sealed case class TDialectSpecific[A](typeTagExtension: TypeTagExtension[A]) extends NotNull[A]
sealed trait NotNull[+A] extends TypeTag[A]
implicit case object TBigDecimal extends NotNull[BigDecimal]
implicit case object TBoolean extends NotNull[Boolean]
implicit case object TByte extends NotNull[Byte]
implicit case object TByteArray extends NotNull[Chunk[Byte]]
implicit case object TChar extends NotNull[Char]
implicit case object TDouble extends NotNull[Double]
implicit case object TFloat extends NotNull[Float]
implicit case object TInstant extends NotNull[Instant]
implicit case object TInt extends NotNull[Int]
implicit case object TLocalDate extends NotNull[LocalDate]
implicit case object TLocalDateTime extends NotNull[LocalDateTime]
implicit case object TLocalTime extends NotNull[LocalTime]
implicit case object TLong extends NotNull[Long]
implicit case object TOffsetDateTime extends NotNull[OffsetDateTime]
implicit case object TOffsetTime extends NotNull[OffsetTime]
implicit case object TShort extends NotNull[Short]
implicit case object TString extends NotNull[String]
implicit case object TUUID extends NotNull[UUID]
implicit case object TZonedDateTime extends NotNull[ZonedDateTime]
sealed case class TDialectSpecific[+A](typeTagExtension: TypeTagExtension[A]) extends NotNull[A]

sealed case class Nullable[A: NotNull]() extends TypeTag[Option[A]] {
def typeTag: TypeTag[A] = implicitly[TypeTag[A]]
Expand Down
4 changes: 3 additions & 1 deletion core/jvm/src/test/scala/zio/sql/GroupByHavingSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ object GroupByHavingSpec extends DefaultRunnableSpec {

object AggregatedProductSchema {
val sqldsl = new Sql {
override def renderRead(read: this.Read[_]): String = ???
override def renderDelete(delete: this.Delete[_]): String = ???
override def renderRead(read: this.Read[_]): String = ???
override def renderUpdate(update: Update[_]): String = ???
}
import sqldsl.ColumnSet._
import sqldsl.AggregationDef._
Expand Down
4 changes: 4 additions & 0 deletions core/jvm/src/test/scala/zio/sql/LogicalOpsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class LogicalOpsSpec extends DefaultRunnableSpec {
test("not works on boolean column") {
val selectNotDeleted = selectAll.where(deleted.not)
assert(selectNotDeleted)(anything)
},
test("like works on a string column") {
val query = selectAll.where(name like "%")
assert(query)(anything)
}
)
}
4 changes: 3 additions & 1 deletion core/jvm/src/test/scala/zio/sql/ProductSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package zio.sql

object ProductSchema {
val sql = new Sql {
override def renderRead(read: this.Read[_]): String = ???
override def renderDelete(delete: this.Delete[_]): String = ???
override def renderRead(read: this.Read[_]): String = ???
override def renderUpdate(update: this.Update[_]): String = ???
}
import sql.ColumnSet._
import sql._
Expand Down
4 changes: 3 additions & 1 deletion core/jvm/src/test/scala/zio/sql/TestBasicSelectSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ object TestBasicSelect {
val userSql = new Sql { self =>
import self.ColumnSet._

override def renderRead(read: this.Read[_]): String = ???
override def renderDelete(delete: this.Delete[_]): String = ???
override def renderRead(read: this.Read[_]): String = ???
override def renderUpdate(update: this.Update[_]): String = ???

val userTable =
(string("user_id") ++ localDate("dob") ++ string("first_name") ++ string("last_name")).table("users")
Expand Down
5 changes: 4 additions & 1 deletion examples/src/main/scala/Example1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import zio.sql.Sql
object Example1 extends Sql {
import ColumnSet._

def renderRead(read: Example1.Read[_]): String = ???
def renderRead(read: this.Read[_]): String = ???
def renderDelete(delete: this.Delete[_]): String = ???

def renderUpdate(update: Example1.Update[_]): String = ???

val columnSet = int("age") ++ string("name")

Expand Down
Loading

0 comments on commit 2de8db4

Please sign in to comment.