-
Notifications
You must be signed in to change notification settings - Fork 0
/
DBFunction.scala
201 lines (175 loc) · 9.55 KB
/
DBFunction.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
* Copyright 2022 ABSA Group Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package za.co.absa.fadb
import za.co.absa.fadb.naming.NamingConvention
import scala.concurrent.Future
/**
*
* @param functionNameOverride - in case the class name would not match the database function name, this gives the
* possibility of override
* @param schema - the schema the function belongs into
* @param dBEngine - the database engine that is supposed to execute the function (presumably contains
* connection to the database
* @tparam I - the type covering the input fields of the database function
* @tparam R - the type covering the returned fields from the database function
* @tparam E - the type of the [[DBEngine]] engine
*/
abstract class DBFunction[I, R, E <: DBEngine](functionNameOverride: Option[String] = None, schema: Option[DBSchema])
(implicit val dBEngine: E, val namingConvention: NamingConvention)
extends DBFunctionFabric {
// Alternative constructors for different availability of input parameters
def this(functionNameOverride: String, schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), Option(schema))
}
def this(functionNameOverride: String)
(implicit schema: Option[DBSchema], dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), schema)
}
def this(schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(None, Option(schema))
}
/**
* Function to create the DB function call specific to the provided [[DBEngine]]. Expected to be implemented by the
* DBEngine specific mix-in.
* @param values - the values to pass over to the database function
* @return - the SQL query in the format specific to the provided [[DBEngine]]
*/
protected def query(values: I): dBEngine.QueryType[R]
/**
* Name of the function, based on the class name, unless it is overridden in the constructor
*/
def functionName: String = {
schema match {
case Some(s) if s.schemaName.nonEmpty =>
s"${s.schemaName}.${functionNameOverride.getOrElse(namingConvention.fromClassNamePerConvention(getClass))}"
case _ =>
functionNameOverride.getOrElse(namingConvention.fromClassNamePerConvention(getClass))
}
}
/**
* List of fields to select from the DB function. Expected to be based on the return type `R`
* @return - list of fields to select
*/
override protected def fieldsToSelect: Seq[String] = super.fieldsToSelect //TODO should get the names from R #6
/*these 3 functions has to be defined here and not in the ancestors, as there the query type is not compatible - path-dependent types*/
protected def multipleResults(values: I): Future[Seq[R]] = dBEngine.fetchAll(query(values))
protected def singleResult(values: I): Future[R] = dBEngine.fetchHead(query(values))
protected def optionalResult(values: I): Future[Option[R]] = dBEngine.fetchHeadOption(query(values))
}
object DBFunction {
/**
* Represents a function returning a set (in DB sense) of rows
* @param functionNameOverride - in case the class name would not match the database function name, this gives the
* possibility of override
* @param schema - the schema the function belongs into
* @param dBEngine - the database engine that is supposed to execute the function (presumably contains
* connection to the database
* @tparam I - the type covering the input fields of the database function
* @tparam R - the type covering the returned fields from the database function
* @tparam E - the type of the [[DBEngine]] engine
*/
abstract class DBMultipleResultFunction[I, R, E <: DBEngine](functionNameOverride: Option[String] = None, schema: Option[DBSchema] = None)
(implicit override val dBEngine: E, override val namingConvention: NamingConvention)
extends DBFunction[I, R, E](functionNameOverride, schema) {
def this(functionNameOverride: String, schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), Option(schema))
}
def this(functionNameOverride: String)
(implicit schema: Option[DBSchema], dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), schema)
}
def this(schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(None, Option(schema))
}
/**
* For easy and convenient execution of the DB function call
* @param values - the values to pass over to the database function
* @return - a sequence of values, each coming from a row returned from the DB function transformed to scala
* type `R`
*/
def apply(values: I): Future[Seq[R]] = multipleResults(values)
}
/**
* Represents a function returning exactly one record
* @param functionNameOverride - in case the class name would not match the database function name, this gives the
* possibility of override
* @param schema - the schema the function belongs into
* @param dBEngine - the database engine that is supposed to execute the function (presumably contains
* connection to the database
* @tparam I - the type covering the input fields of the database function
* @tparam R - the type covering the returned fields from the database function
* @tparam E - the type of the [[DBEngine]] engine
*/
abstract class DBSingleResultFunction[I, R, E <: DBEngine](functionNameOverride: Option[String] = None, schema: Option[DBSchema] = None)
(implicit override val dBEngine: E, override val namingConvention: NamingConvention)
extends DBFunction[I, R, E](functionNameOverride, schema) {
def this(functionNameOverride: String, schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), Option(schema))
}
def this(functionNameOverride: String)
(implicit schema: Option[DBSchema], dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), schema)
}
def this(schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(None, Option(schema))
}
/**
* For easy and convenient execution of the DB function call
* @param values - the values to pass over to the database function
* @return - the value returned from the DB function transformed to scala type `R`
*/
def apply(values: I): Future[R] = singleResult(values)
}
/**
* Represents a function returning one optional record
* @param functionNameOverride - in case the class name would not match the database function name, this gives the
* possibility of override
* @param schema - the schema the function belongs into
* @param dBEngine - the database engine that is supposed to execute the function (presumably contains
* connection to the database
* @tparam I - the type covering the input fields of the database function
* @tparam R - the type covering the returned fields from the database function
* @tparam E - the type of the [[DBEngine]] engine
*/
abstract class DBOptionalResultFunction[I, R, E <: DBEngine](functionNameOverride: Option[String] = None, schema: Option[DBSchema] = None)
(implicit override val dBEngine: E, override val namingConvention: NamingConvention)
extends DBFunction[I, R, E](functionNameOverride, schema) {
def this(functionNameOverride: String, schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), Option(schema))
}
def this(functionNameOverride: String)
(implicit schema: Option[DBSchema], dBEngine: E, namingConvention: NamingConvention) = {
this(Option(functionNameOverride), schema)
}
def this(schema: DBSchema)
(implicit dBEngine: E, namingConvention: NamingConvention) = {
this(None, Option(schema))
}
/**
* For easy and convenient execution of the DB function call
* @param values - the values to pass over to the database function
* @return - the value returned from the DB function transformed to scala type `R` if a row is returned, otherwise `None`
*/
def apply(values: I): Future[Option[R]] = optionalResult(values)
}
}