Skip to content

Commit b0538d6

Browse files
authored
#43: Upgrade Slick version and add Slick-pg dependency - integration test (#46)
* test for `FaDbPostgresProfile` * test changed into integration test * added test for NULL/Option verification of types * fixed Option[UUID] parameter setting
1 parent 1bb5136 commit b0538d6

File tree

6 files changed

+335
-7
lines changed

6 files changed

+335
-7
lines changed

build.sbt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,41 @@ lazy val parent = (project in file("."))
5555
libraryDependencies ++= rootDependencies(scalaVersion.value),
5656
javacOptions ++= commonJavacOptions,
5757
scalacOptions ++= commonScalacOptions,
58-
publish / skip := true
58+
publish / skip := true,
59+
Defaults.itSettings
5960
)
6061

6162
lazy val faDbCore = (project in file("core"))
63+
.configs(IntegrationTest)
6264
.settings(
6365
name := "core",
6466
libraryDependencies ++= coreDependencies(scalaVersion.value),
6567
javacOptions ++= commonJavacOptions,
6668
scalacOptions ++= commonScalacOptions,
67-
(Compile / compile) := ((Compile / compile) dependsOn printScalaVersion).value // printScalaVersion is run with compile
69+
(Compile / compile) := ((Compile / compile) dependsOn printScalaVersion).value, // printScalaVersion is run with compile
6870
)
6971
.settings(
7072
jacocoReportSettings := commonJacocoReportSettings.withTitle(s"fa-db:core Jacoco Report - scala:${scalaVersion.value}"),
7173
jacocoExcludes := commonJacocoExcludes
7274
)
7375

7476
lazy val faDBSlick = (project in file("slick"))
77+
.configs(IntegrationTest)
7578
.settings(
7679
name := "slick",
7780
libraryDependencies ++= slickDependencies(scalaVersion.value),
7881
javacOptions ++= commonJavacOptions,
7982
scalacOptions ++= commonScalacOptions,
80-
(Compile / compile) := ((Compile / compile) dependsOn printScalaVersion).value // printScalaVersion is run with compile
83+
(Compile / compile) := ((Compile / compile) dependsOn printScalaVersion).value, // printScalaVersion is run with compile
84+
Defaults.itSettings,
8185
).dependsOn(faDbCore)
8286
.settings(
8387
jacocoReportSettings := commonJacocoReportSettings.withTitle(s"fa-db:slick Jacoco Report - scala:${scalaVersion.value}"),
8488
jacocoExcludes := commonJacocoExcludes
8589
)
8690

8791
lazy val faDBExamples = (project in file("examples"))
92+
.configs(IntegrationTest)
8893
.settings(
8994
name := "examples",
9095
libraryDependencies ++= examplesDependencies(scalaVersion.value),

project/Dependencies.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ object Dependencies {
2020

2121

2222
private def commonDependencies(scalaVersion: String): Seq[ModuleID] = Seq(
23-
"org.scalatest" %% "scalatest" % "3.1.0" % Test,
24-
"org.scalatest" %% "scalatest-flatspec" % "3.2.0" % Test,
25-
"org.scalatestplus" %% "mockito-1-10" % "3.1.0.0" % Test
23+
"org.scalatest" %% "scalatest" % "3.1.0" % "test,it",
24+
"org.scalatest" %% "scalatest-flatspec" % "3.2.0" % "test,it",
25+
"org.scalatestplus" %% "mockito-1-10" % "3.1.0.0" % "test,it"
2626
)
2727

2828
def rootDependencies(scalaVersion: String): Seq[ModuleID] = Seq()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
postgrestestdb = {
2+
connectionPool = "HikariCP" //use HikariCP for our connection pool
3+
dataSourceClass = "org.postgresql.ds.PGSimpleDataSource" //Simple datasource with no connection pooling. The connection pool has already been specified with HikariCP.
4+
properties = {
5+
serverName = "localhost"
6+
portNumber = "5432"
7+
databaseName = "postgres"
8+
user = "postgres"
9+
password = "changeme"
10+
}
11+
numThreads = 10
12+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2022 ABSA Group Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
CREATE EXTENSION IF NOT EXISTS hstore;
19+
20+
CREATE EXTENSION IF NOT EXISTS ltree;
21+
22+
CREATE OR REPLACE FUNCTION public.test_function(
23+
IN i_uuid1 UUID,
24+
IN i_dateTime1 DATE,
25+
IN i_dateTime2 TIME,
26+
IN i_dateTime3 TIMESTAMP WITHOUT TIME ZONE,
27+
IN i_dateTime4 INTERVAL,
28+
IN i_dateTime5 TIMESTAMP WITH TIME ZONE,
29+
IN i_dateTime6 TIMESTAMP WITH TIME ZONE,
30+
IN i_range1 INT4RANGE,
31+
IN i_ltree1 LTREE,
32+
IN i_map1 HSTORE,
33+
IN i_inet1 INET,
34+
IN i_macaddr1 MACADDR,
35+
OUT uuid1 UUID,
36+
OUT dateTime1 DATE,
37+
OUT dateTime2 TIME,
38+
OUT dateTime3 TIMESTAMP WITHOUT TIME ZONE,
39+
OUT dateTime4 INTERVAL,
40+
OUT dateTime5 TIMESTAMP WITH TIME ZONE,
41+
OUT dateTime6 TIMESTAMP WITH TIME ZONE,
42+
OUT range1 INT4RANGE,
43+
OUT ltree1 LTREE,
44+
OUT map1 HSTORE,
45+
OUT inet1 INET,
46+
OUT macaddr1 MACADDR
47+
) RETURNS record AS
48+
$$
49+
-------------------------------------------------------------------------------
50+
--
51+
-- Function: test_function(12)
52+
-- A function to test Fa-Db Slick Posgres special time enhancement. Function wors as a mirror. Retruns what came in.
53+
--
54+
--
55+
-- Returns:
56+
-- input is returned unchanged
57+
--
58+
-------------------------------------------------------------------------------
59+
DECLARE
60+
BEGIN
61+
uuid1 := i_uuid1;
62+
dateTime1 := i_dateTime1;
63+
dateTime2 := i_dateTime2;
64+
dateTime3 := i_dateTime3;
65+
dateTime4 := i_dateTime4;
66+
dateTime5 := i_dateTime5;
67+
dateTime6 := i_dateTime6;
68+
range1 := i_range1;
69+
ltree1 := i_ltree1;
70+
map1 := i_map1;
71+
inet1 := i_inet1;
72+
macaddr1 := i_macaddr1;
73+
74+
RETURN;
75+
END;
76+
$$
77+
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
78+
79+
GRANT EXECUTE ON FUNCTION test_function(
80+
UUID,
81+
DATE,
82+
TIME,
83+
TIMESTAMP WITHOUT TIME ZONE,
84+
INTERVAL,
85+
TIMESTAMP WITH TIME ZONE,
86+
TIMESTAMP WITH TIME ZONE,
87+
INT4RANGE,
88+
LTREE,
89+
HSTORE,
90+
INET,
91+
MACADDR
92+
) TO postgres;
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright 2022 ABSA Group Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package za.co.absa.fadb.slick
18+
19+
import za.co.absa.fadb.naming.implementations.SnakeCaseNaming.Implicits._
20+
import za.co.absa.fadb.slick.FaDbPostgresProfile.api._
21+
import org.scalatest.funsuite.AnyFunSuite
22+
import slick.jdbc.{GetResult, SQLActionBuilder}
23+
import za.co.absa.fadb.DBFunction.DBSingleResultFunction
24+
import za.co.absa.fadb.DBSchema
25+
import com.github.tminglei.slickpg.{InetString, LTree, MacAddrString, Range}
26+
27+
import java.time.{Duration, LocalDate, LocalDateTime, LocalTime, OffsetDateTime, ZonedDateTime}
28+
import java.util.UUID
29+
import java.util.concurrent.TimeUnit
30+
import scala.concurrent.Await
31+
import scala.concurrent.duration.{FiniteDuration, Duration => ScalaDuration}
32+
import scala.language.implicitConversions
33+
import scala.concurrent.ExecutionContext.Implicits.global
34+
35+
class FaDbPostgresProfileSuite extends AnyFunSuite {
36+
37+
implicit def javaDurationToScalaDuration(duration: Duration): ScalaDuration = {
38+
FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS)
39+
}
40+
private val database = Database.forConfig("postgrestestdb")
41+
private val testDBEngine: SlickPgEngine = new SlickPgEngine(database)
42+
43+
44+
test("Test query types support with actual values") {
45+
46+
case class InputOutput(
47+
uuid1: UUID, //uuid
48+
dateTime1: LocalDate, //date
49+
dateTime2: LocalTime, //time
50+
dateTime3: LocalDateTime, //timestamp
51+
dateTime4: Duration, //interval
52+
dateTime5: ZonedDateTime, //timestamptz
53+
dateTime6: OffsetDateTime, //timestamptz
54+
range1: Range[Int], //range
55+
lTree1: LTree, //ltree
56+
map1: Map[String, String],//hstore
57+
inet1: InetString, //inet
58+
macaddr1: MacAddrString //macaddr
59+
)
60+
61+
class TestFunction(implicit override val schema: DBSchema, override val dbEngine: SlickPgEngine)
62+
extends DBSingleResultFunction[InputOutput, InputOutput, SlickPgEngine]
63+
with SlickFunction[InputOutput, InputOutput] {
64+
65+
override protected def sql(values: InputOutput): SQLActionBuilder = {
66+
sql"""SELECT #$selectEntry
67+
FROM #$functionName(
68+
${values.uuid1},
69+
${values.dateTime1},
70+
${values.dateTime2},
71+
${values.dateTime3},
72+
${values.dateTime4},
73+
${values.dateTime5},
74+
${values.dateTime6},
75+
${values.range1},
76+
${values.lTree1},
77+
${values.map1},
78+
${values.inet1},
79+
${values.macaddr1}
80+
) #$alias;"""
81+
}
82+
83+
override protected def slickConverter: GetResult[InputOutput] = GetResult{r => InputOutput(
84+
r.<<,
85+
r.<<,
86+
r.<<,
87+
r.<<,
88+
r.<<,
89+
r.<<,
90+
r.<<,
91+
r.<<,
92+
r.<<,
93+
r.<<,
94+
r.<<,
95+
r.<<
96+
)}
97+
}
98+
99+
class TestSchema (implicit dBEngine: SlickPgEngine) extends DBSchema("public"){
100+
101+
val testFunction = new TestFunction
102+
}
103+
104+
105+
val input = InputOutput(
106+
UUID.randomUUID(),
107+
LocalDate.now(),
108+
LocalTime.now(),
109+
LocalDateTime.now(),
110+
Duration.ofMinutes(42),
111+
ZonedDateTime.now(),
112+
OffsetDateTime.now(),
113+
range1 = Range(7, 13),
114+
LTree(List("This", "is", "an", "LTree")),
115+
Map("a" -> "Hello", "bb" -> "beautiful", "ccc" -> "world"),
116+
InetString("168.0.0.1"),
117+
MacAddrString("12:34:56:78:90:ab")
118+
)
119+
// because postgres does not fully support time zone as Java, so we need to clear it for later successful assert
120+
val expected = input.copy(dateTime5 = input.dateTime5.toOffsetDateTime.toZonedDateTime)
121+
122+
123+
val timeout = Duration.ofMinutes(1)
124+
val result = Await.result(new TestSchema()(testDBEngine).testFunction(input), timeout)
125+
assert(result == expected)
126+
}
127+
128+
test("Test query types support with NULL values") {
129+
130+
case class InputOutput(
131+
uuid1: Option[UUID], //uuid
132+
dateTime1: Option[LocalDate], //date
133+
dateTime2: Option[LocalTime], //time
134+
dateTime3: Option[LocalDateTime], //timestamp
135+
dateTime4: Option[Duration], //interval
136+
dateTime5: Option[ZonedDateTime], //timestamptz
137+
dateTime6: Option[OffsetDateTime], //timestamptz
138+
range1: Option[Range[Int]], //range
139+
lTree1: Option[LTree], //ltree
140+
map1: Option[Map[String, String]], //hstore
141+
inet1: Option[InetString], //inet
142+
macaddr1: Option[MacAddrString] //macaddr
143+
)
144+
145+
class TestFunction(implicit override val schema: DBSchema, override val dbEngine: SlickPgEngine)
146+
extends DBSingleResultFunction[InputOutput, InputOutput, SlickPgEngine]
147+
with SlickFunction[InputOutput, InputOutput] {
148+
149+
override protected def sql(values: InputOutput): SQLActionBuilder = {
150+
sql"""SELECT #$selectEntry
151+
FROM #$functionName(
152+
${values.uuid1},
153+
${values.dateTime1},
154+
${values.dateTime2},
155+
${values.dateTime3},
156+
${values.dateTime4},
157+
${values.dateTime5},
158+
${values.dateTime6},
159+
${values.range1},
160+
${values.lTree1},
161+
${values.map1},
162+
${values.inet1},
163+
${values.macaddr1}
164+
) #$alias;"""
165+
}
166+
167+
override protected def slickConverter: GetResult[InputOutput] = GetResult{r => InputOutput(
168+
r.<<,
169+
r.<<,
170+
r.<<,
171+
r.<<,
172+
r.<<,
173+
r.<<,
174+
r.<<,
175+
r.<<,
176+
r.<<,
177+
r.nextHStoreOption(),
178+
r.<<,
179+
r.nextMacAddrOption()
180+
)}
181+
}
182+
183+
class TestSchema (implicit dBEngine: SlickPgEngine) extends DBSchema("public"){
184+
185+
val testFunction = new TestFunction
186+
}
187+
188+
189+
val inputOutput = InputOutput(
190+
None,
191+
None,
192+
None,
193+
None,
194+
None,
195+
None,
196+
None,
197+
None,
198+
None,
199+
None,
200+
None,
201+
None
202+
)
203+
204+
val timeout = Duration.ofMinutes(1)
205+
val result = Await.result(new TestSchema()(testDBEngine).testFunction(inputOutput), timeout)
206+
assert(result == inputOutput)
207+
}
208+
209+
}
210+

slick/src/main/scala/za/co/absa/fadb/slick/support/PgUUIDSupport.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,16 @@ trait PgUUIDSupport extends PgCommonJdbcTypes { driver: PostgresProfile =>
4949
implicit val getUUID: GetResult[UUID] = mkGetResult(_.nextUUID)
5050
implicit val getUUIDOption: GetResult[Option[UUID]] = mkGetResult(_.nextUUIDOption)
5151
implicit val setUUID: SetParameter[UUID] = new SetParameter[UUID] { def apply(v: UUID, pp: PositionedParameters): Unit = { pp.setObject(v, JDBCType.BINARY.getVendorTypeNumber) } }
52-
implicit val setUUIDOption: SetParameter[Option[UUID]] = new SetParameter[Option[UUID]] { def apply(v: Option[UUID], pp: PositionedParameters): Unit = { pp.setObject(v.orNull, JDBCType.BINARY.getVendorTypeNumber) } }
52+
implicit val setUUIDOption: SetParameter[Option[UUID]] = new SetParameter[Option[UUID]] {
53+
def apply(v: Option[UUID], pp: PositionedParameters): Unit = {
54+
v.map(
55+
pp.setObject(_, JDBCType.BINARY.getVendorTypeNumber)
56+
).getOrElse(
57+
pp.setNull(java.sql.Types.OTHER)
58+
)
59+
60+
}
61+
}
5362

5463
}
5564
}

0 commit comments

Comments
 (0)