Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

#211 Add 'make_*' functions to PostgresModule #295

Merged
merged 3 commits into from
Jan 28, 2021
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
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,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.2.18" % Test,
"org.postgresql" % "postgresql" % "42.2.18" % Compile,
"com.dimafeng" %% "testcontainers-scala-postgresql" % testcontainersScalaVersion % Test
)
)
Expand Down
110 changes: 110 additions & 0 deletions core/jvm/src/main/scala/zio/sql/expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,53 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {
) extends InvariantExpr[Features.Union[F1, Features.Union[F2, Features.Union[F3, F4]]], A, Z] {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}

sealed case class FunctionCall5[F1, F2, F3, F4, F5, A, B, C, D, E, F, Z: TypeTag](
param1: Expr[F1, A, B],
param2: Expr[F2, A, C],
param3: Expr[F3, A, D],
param4: Expr[F4, A, E],
param5: Expr[F5, A, F],
function: FunctionDef[(B, C, D, E, F), Z]
) extends InvariantExpr[Features.Union[F1, Features.Union[F2, Features.Union[F3, Features.Union[F4, F5]]]], A, Z] {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}

sealed case class FunctionCall6[F1, F2, F3, F4, F5, F6, A, B, C, D, E, F, G, Z: TypeTag](
param1: Expr[F1, A, B],
param2: Expr[F2, A, C],
param3: Expr[F3, A, D],
param4: Expr[F4, A, E],
param5: Expr[F5, A, F],
param6: Expr[F6, A, G],
function: FunctionDef[(B, C, D, E, F, G), Z]
) extends InvariantExpr[
Features.Union[F1, Features.Union[F2, Features.Union[F3, Features.Union[F4, Features.Union[F5, F6]]]]],
A,
Z
] {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}

sealed case class FunctionCall7[F1, F2, F3, F4, F5, F6, F7, A, B, C, D, E, F, G, H, Z: TypeTag](
param1: Expr[F1, A, B],
param2: Expr[F2, A, C],
param3: Expr[F3, A, D],
param4: Expr[F4, A, E],
param5: Expr[F5, A, F],
param6: Expr[F6, A, G],
param7: Expr[F7, A, H],
function: FunctionDef[(B, C, D, E, F, G, H), Z]
) extends InvariantExpr[
Features.Union[
F1,
Features.Union[F2, Features.Union[F3, Features.Union[F4, Features.Union[F5, Features.Union[F6, F7]]]]]
],
A,
Z
] {
def typeTag: TypeTag[Z] = implicitly[TypeTag[Z]]
}
}

sealed case class AggregationDef[-A, +B](name: FunctionName) { self =>
Expand Down Expand Up @@ -257,6 +304,69 @@ trait ExprModule extends NewtypesModule with FeaturesModule with OpsModule {
self.narrow[(P1, P2, P3, P4)]: FunctionDef[(P1, P2, P3, P4), B1]
)

def apply[F1, F2, F3, F4, F5, Source, P1, P2, P3, P4, P5, B1 >: B](
param1: Expr[F1, Source, P1],
param2: Expr[F2, Source, P2],
param3: Expr[F3, Source, P3],
param4: Expr[F4, Source, P4],
param5: Expr[F5, Source, P5]
)(implicit
ev: (P1, P2, P3, P4, P5) <:< A,
typeTag: TypeTag[B1]
): Expr[F1 :||: F2 :||: F3 :||: F4 :||: F5, Source, B1] =
Expr.FunctionCall5(
param1,
param2,
param3,
param4,
param5,
self.narrow[(P1, P2, P3, P4, P5)]: FunctionDef[(P1, P2, P3, P4, P5), B1]
)

def apply[F1, F2, F3, F4, F5, F6, Source, P1, P2, P3, P4, P5, P6, B1 >: B](
param1: Expr[F1, Source, P1],
param2: Expr[F2, Source, P2],
param3: Expr[F3, Source, P3],
param4: Expr[F4, Source, P4],
param5: Expr[F5, Source, P5],
param6: Expr[F6, Source, P6]
)(implicit
ev: (P1, P2, P3, P4, P5, P6) <:< A,
typeTag: TypeTag[B1]
): Expr[F1 :||: F2 :||: F3 :||: F4 :||: F5 :||: F6, Source, B1] =
Expr.FunctionCall6(
param1,
param2,
param3,
param4,
param5,
param6,
self.narrow[(P1, P2, P3, P4, P5, P6)]: FunctionDef[(P1, P2, P3, P4, P5, P6), B1]
)

def apply[F1, F2, F3, F4, F5, F6, F7, Source, P1, P2, P3, P4, P5, P6, P7, B1 >: B](
param1: Expr[F1, Source, P1],
param2: Expr[F2, Source, P2],
param3: Expr[F3, Source, P3],
param4: Expr[F4, Source, P4],
param5: Expr[F5, Source, P5],
param6: Expr[F6, Source, P6],
param7: Expr[F7, Source, P7]
)(implicit
ev: (P1, P2, P3, P4, P5, P6, P7) <:< A,
typeTag: TypeTag[B1]
): Expr[F1 :||: F2 :||: F3 :||: F4 :||: F5 :||: F6 :||: F7, Source, B1] =
Expr.FunctionCall7(
param1,
param2,
param3,
param4,
param5,
param6,
param7,
self.narrow[(P1, P2, P3, P4, P5, P6, P7)]: FunctionDef[(P1, P2, P3, P4, P5, P6, P7), B1]
)

def narrow[C](implicit ev: C <:< A): FunctionDef[C, B] = {
val _ = ev
self.asInstanceOf[FunctionDef[C, B]]
Expand Down
2 changes: 1 addition & 1 deletion core/jvm/src/main/scala/zio/sql/ops.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package zio.sql

trait OpsModule extends TypeTagModule {
trait OpsModule extends TypeTagModule { self: SelectModule =>

sealed trait Operator {
val symbol: String
Expand Down
24 changes: 23 additions & 1 deletion core/jvm/src/main/scala/zio/sql/select.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package zio.sql
import scala.language.implicitConversions

trait SelectModule { self: ExprModule with TableModule =>

sealed case class SelectBuilder[F, A, B <: SelectionSet[A]](selection: Selection[F, A, B]) {

def from[A1 <: A](table: Table.Aux[A1]): Read.Select[F, A1, B] =
Expand Down Expand Up @@ -194,4 +193,27 @@ trait SelectModule { self: ExprModule with TableModule =>
implicit def exprToOrdering[F, A, B](expr: Expr[F, A, B]): Ordering[Expr[F, A, B]] =
Asc(expr)
}

sealed trait DecodingError extends Exception {
def message: String
}

object DecodingError {
sealed case class UnexpectedNull(column: Either[Int, String]) extends DecodingError {
private def label = column.fold(index => index.toString, name => name)

def message = s"Expected column ${label} to be non-null"
}
sealed case class UnexpectedType(expected: TypeTag[_], actual: Int) extends DecodingError {
def message = s"Expected type ${expected} but found ${actual}"
}
sealed case class MissingColumn(column: Either[Int, String]) extends DecodingError {
private def label = column.fold(index => index.toString, name => name)

def message = s"The column ${label} does not exist"
}
case object Closed extends DecodingError {
def message = s"The ResultSet has been closed, so decoding is impossible"
}
}
}
16 changes: 10 additions & 6 deletions core/jvm/src/main/scala/zio/sql/typetag.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package zio.sql

import java.sql.ResultSet
import java.time._
import java.util.UUID

import zio.Chunk

trait TypeTagModule {
trait TypeTagModule { self: SelectModule =>

type TypeTagExtension[+A] <: Tag[A] with Decodable[A]

type TypeTagExtension[+A]
trait Decodable[+A] {
def decode(column: Either[Int, String], resultSet: ResultSet): Either[DecodingError, A]
}

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

object TypeTag {
sealed trait NotNull[+A] extends TypeTag[A]
Expand All @@ -35,8 +40,7 @@ trait TypeTagModule {
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]] {
sealed case class Nullable[A: NotNull]() extends TypeTag[Option[A]] {
def typeTag: TypeTag[A] = implicitly[TypeTag[A]]
}

Expand Down
28 changes: 3 additions & 25 deletions jdbc/src/main/scala/zio/sql/jdbc.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package zio.sql

import java.sql._
import java.io.IOException
import java.sql._
import java.time.{ OffsetDateTime, OffsetTime, ZoneId, ZoneOffset }

import zio.{ Chunk, Has, IO, Managed, ZIO, ZLayer, ZManaged }
import zio.blocking.Blocking
import zio.stream.{ Stream, ZStream }
Expand Down Expand Up @@ -194,28 +193,6 @@ trait Jdbc extends zio.sql.Sql with TransactionModule {
}
}

sealed trait DecodingError extends Exception {
def message: String
}
object DecodingError {
sealed case class UnexpectedNull(column: Either[Int, String]) extends DecodingError {
private def label = column.fold(index => index.toString, name => name)

def message = s"Expected column ${label} to be non-null"
}
sealed case class UnexpectedType(expected: TypeTag[_], actual: Int) extends DecodingError {
def message = s"Expected type ${expected} but found ${actual}"
}
sealed case class MissingColumn(column: Either[Int, String]) extends DecodingError {
private def label = column.fold(index => index.toString, name => name)

def message = s"The column ${label} does not exist"
}
case object Closed extends DecodingError {
def message = s"The ResultSet has been closed, so decoding is impossible"
}
}

// TODO: Only support indexes!
private[sql] def extractColumn[A](
column: Either[Int, String],
Expand Down Expand Up @@ -302,14 +279,15 @@ trait Jdbc extends zio.sql.Sql with TransactionModule {
java.util.UUID.fromString(column.fold(resultSet.getString(_), resultSet.getString(_)))
)
case TZonedDateTime =>
//2013-07-15 08:15:23.5+00
tryDecode[java.time.ZonedDateTime](
java.time.ZonedDateTime
.ofInstant(
column.fold(resultSet.getTimestamp(_), resultSet.getTimestamp(_)).toInstant,
ZoneId.of(ZoneOffset.UTC.getId)
)
)
case TDialectSpecific(_) => ???
case TDialectSpecific(t) => t.decode(column, resultSet)
case t @ Nullable() => extractColumn(column, resultSet, t.typeTag, false).map(Option(_))
}
}
Expand Down
Loading