Skip to content

Commit

Permalink
zio-archive#732 Mssql (in progress)
Browse files Browse the repository at this point in the history
bogatyra committed Jul 29, 2022

Verified

This commit was signed with the committer’s verified signature.
AdmiralCurtiss Admiral H. Curtiss
1 parent d02c7a4 commit b79014c
Showing 2 changed files with 374 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@ import zio.Chunk
import zio.schema.StandardType._
import zio.schema._
import zio.sql.driver.Renderer
import zio.sql.driver.Renderer.Extensions

import java.time.format.{ DateTimeFormatter, DateTimeFormatterBuilder }
import java.time._
@@ -107,6 +106,49 @@ trait SqlServerRenderModule extends SqlServerSqlModule { self =>
render(" (", values.mkString(","), ") ") // todo fix needs escaping
}

private def renderLit(lit: self.Expr.Literal[_])(implicit render: Renderer): Unit = {
import TypeTag._
val value = lit.value
lit.typeTag match {
case TInstant =>
render(s"'${fmtDateTimeOffset.format(value.asInstanceOf[Instant])}'")
case TLocalTime =>
render(s"'${DateTimeFormatter.ISO_LOCAL_TIME.format(value.asInstanceOf[LocalTime])}'")
case TLocalDate =>
render(s"'${DateTimeFormatter.ISO_LOCAL_DATE.format(value.asInstanceOf[LocalDate])}'")
case TLocalDateTime =>
render(s"'${DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value.asInstanceOf[LocalDateTime])}'")
case TZonedDateTime =>
render(s"'${fmtDateTimeOffset.format(value.asInstanceOf[ZonedDateTime])}'")
case TOffsetTime =>
render(s"'${fmtTimeOffset.format(value.asInstanceOf[OffsetTime])}'")
case TOffsetDateTime =>
render(s"'${fmtDateTimeOffset.format(value.asInstanceOf[OffsetDateTime])}'")

case TBoolean =>
val b = value.asInstanceOf[Boolean]
if (b) {
render('1')
} else {
render('0')
}
case TUUID => render(s"'$value'")

case TBigDecimal => render(value)
case TByte => render(value)
case TDouble => render(value)
case TFloat => render(value)
case TInt => render(value)
case TLong => render(value)
case TShort => render(value)

case TChar => render(s"N'$value'")
case TString => render(s"N'$value'")

case _ => render(s"'$value'")
}
}

private def buildExpr[A, B](expr: self.Expr[_, A, B])(implicit render: Renderer): Unit = expr match {
case Expr.Subselect(subselect) =>
render(" (")
@@ -145,33 +187,7 @@ trait SqlServerRenderModule extends SqlServerSqlModule { self =>
case Expr.In(value, set) =>
buildExpr(value)
renderReadImpl(set)
case literal @ Expr.Literal(value) =>
val lit = literal.typeTag match {
case TypeTag.TBoolean =>
// MSSQL server variant of true/false
if (value.asInstanceOf[Boolean]) {
"0 = 0"
} else {
"0 = 1"
}
case TypeTag.TLocalDateTime =>
val x = value
.asInstanceOf[java.time.LocalDateTime]
.format(java.time.format.DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"))
s"'$x'"
case TypeTag.TZonedDateTime =>
val x = value
.asInstanceOf[java.time.ZonedDateTime]
.format(java.time.format.DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"))
s"'$x'"
case TypeTag.TOffsetDateTime =>
val x = value
.asInstanceOf[java.time.OffsetDateTime]
.format(java.time.format.DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"))
s"'$x'"
case _ => value.toString.singleQuoted
}
render(lit)
case literal: Expr.Literal[_] => renderLit(literal)
case Expr.AggregationCall(param, aggregation) =>
render(aggregation.name.name)
render("(")
330 changes: 330 additions & 0 deletions sqlserver/src/test/scala/zio/sql/sqlserver/CommonFunctionDefSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
package zio.sql.sqlserver

import zio.Cause
import zio.stream.ZStream
import zio.test.Assertion._
import zio.test._

object CommonFunctionDefSpec extends SqlServerRunnableSpec with DbSchema {
import FunctionDef.{CharLength => _, _}
import DbSchema._

private def collectAndCompare[R, E](
expected: Seq[String],
testResult: ZStream[R, E, String]
) =
assertZIO(testResult.runCollect)(hasSameElementsDistinct(expected))

override def specLayered = suite("Postgres Common FunctionDef")(
suite("Schema dependent tests")(
test("concat_ws #2 - combine columns") {

// note: you can't use customerId here as it is a UUID, hence not a string in our book
val query = select(ConcatWs3(fName, fName, lName)) from customers

val expected = Seq(
"RonaldRonaldRussell",
"TerrenceTerrenceNoel",
"MilaMilaPaterso",
"AlanaAlanaMurray",
"JoseJoseWiggins"
)

val testResult = execute(query)
collectAndCompare(expected, testResult)
},
test("concat_ws #3 - combine columns and flat values") {
import Expr._

val query = select(ConcatWs4(" ", "Person:", fName, lName)) from customers

val expected = Seq(
"Person: Ronald Russell",
"Person: Terrence Noel",
"Person: Mila Paterso",
"Person: Alana Murray",
"Person: Jose Wiggins"
)

val testResult = execute(query)
collectAndCompare(expected, testResult)
},
test("concat_ws #3 - combine function calls together") {
import Expr._

val query = select(
ConcatWs3(" and ", Concat("Name: ", fName), Concat("Surname: ", lName))
) from customers

val expected = Seq(
"Name: Ronald and Surname: Russell",
"Name: Terrence and Surname: Noel",
"Name: Mila and Surname: Paterso",
"Name: Alana and Surname: Murray",
"Name: Jose and Surname: Wiggins"
)

val testResult = execute(query)
collectAndCompare(expected, testResult)
},
test("lower") {
val query = select(Lower(fName)) from customers limit (1)

val expected = "ronald"

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("Can concat strings with concat function") {

val query = select(Concat(fName, lName) as "fullname") from customers

val expected = Seq("RonaldRussell", "TerrenceNoel", "MilaPaterso", "AlanaMurray", "JoseWiggins")

val result = execute(query)

val assertion = for {
r <- result.runCollect
} yield assert(r)(hasSameElementsDistinct(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("replace") {
val lastNameReplaced = Replace(lName, "ll", "_") as "lastNameReplaced"
val computedReplace = Replace("special ::ąę::", "ąę", "__") as "computedReplace"

val query = select(lastNameReplaced, computedReplace) from customers

val expected = ("Russe_", "special ::__::")

val testResult =
execute(query).map { case row =>
(row._1, row._2)
}

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
}
),
suite("Schema independent tests")(
test("concat_ws #1 - combine flat values") {
import Expr._

// note: a plain number (3) would and should not compile
val query = select(ConcatWs4("+", "1", "2", "3"))

val expected = Seq("1+2+3")

val testResult = execute(query)
collectAndCompare(expected, testResult)
},
test("ltrim") {
assertZIO(execute(select(Ltrim(" hello "))).runHead.some)(equalTo("hello "))
},
test("rtrim") {
assertZIO(execute(select(Rtrim(" hello "))).runHead.some)(equalTo(" hello"))
},
test("abs") {
assertZIO(execute(select(Abs(-3.14159))).runHead.some)(equalTo(3.14159))
},
/* test("log") {
assertZIO(execute(select(Log(32.0, 2.0))).runHead.some)(equalTo(5.0))
},*/
test("acos") {
assertZIO(execute(select(Acos(-1.0))).runHead.some)(equalTo(3.141592653589793))
},
test("asin") {
assertZIO(execute(select(Asin(0.5))).runHead.some)(equalTo(0.5235987755982989))
},
/* test("ln") {
assertZIO(execute(select(Ln(3.0))).runHead.some)(equalTo(1.0986122886681097))
},*/
test("atan") {
assertZIO(execute(select(Atan(10.0))).runHead.some)(equalTo(1.4711276743037347))
},
test("cos") {
assertZIO(execute(select(Cos(3.141592653589793))).runHead.some)(equalTo(-1.0))
},
test("exp") {
assertZIO(execute(select(Exp(1.0))).runHead.some)(equalTo(2.718281828459045))
},
test("floor") {
assertZIO(execute(select(Floor(-3.14159))).runHead.some)(equalTo(-4.0))
},
/* test("ceil") {
assertZIO(execute(select(Ceil(53.7), Ceil(-53.7))).runHead.some)(equalTo((54.0, -53.0)))
},*/
test("sin") {
assertZIO(execute(select(Sin(1.0))).runHead.some)(equalTo(0.8414709848078965))
},
test("sqrt") {
val query = select(Sqrt(121.0))

val expected = 11.0

val testResult = execute(query)

assertZIO(testResult.runHead.some)(equalTo(expected))
},
test("round") {
val query = select(Round(10.8124, 2))

val expected = 10.81
println(renderRead(query))

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("sign positive") {
val query = select(Sign(3.0))

val expected = 1

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("sign negative") {
val query = select(Sign(-3.0))

val expected = -1

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("sign zero") {
val query = select(Sign(0.0))

val expected = 0

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("power") {
val query = select(Power(7.0, 3.0))

val expected = 343.000000000000000

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
/* test("mod") {
val query = select(Mod(-15.0, -4.0))
val expected = -3.0
val testResult = execute(query)
val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))
assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},*/
test("octet_length") {
val query = select(OctetLength("josé"))

val expected = 5

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("ascii") {
val query = select(Ascii("""x"""))

val expected = 120

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("upper") {
val query = (select(Upper("ronald"))).limit(1)

val expected = "RONALD"

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("width_bucket") {
val query = select(WidthBucket(5.35, 0.024, 10.06, 5))

val expected = 3

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("tan") {
val query = select(Tan(0.7853981634))

val expected = 1.0000000000051035

val testResult = execute(query)

val assertion = for {
r <- testResult.runCollect
} yield assert(r.head)(equalTo(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
test("trim") {
assertZIO(execute(select(Trim(" 1234 "))).runHead.some)(equalTo("1234"))
},
test("lower") {
assertZIO(execute(select(Lower("YES"))).runHead.some)(equalTo("yes"))
}
)
)

}

0 comments on commit b79014c

Please sign in to comment.