1616
1717package za .co .absa .fadb
1818
19+ import za .co .absa .fadb .naming_conventions .NamingConvention
20+
1921import scala .concurrent .Future
2022
2123/**
22- * The most general abstraction of database function representation
23- * The database name of the function is derives from the class name based on the provided naming convention (in schema)
2424 *
25- * @param schema - the schema the function belongs into
2625 * @param functionNameOverride - in case the class name would not match the database function name, this gives the
2726 * possibility of override
28- * @tparam E - the type of the [[DBExecutor ]] engine
29- * @tparam T - the type covering the input fields of the database function
27+ * @param schema - the schema the function belongs into
28+ * @param dBEngine - the database engine that is supposed to execute the function (presumably contains
29+ * connection to the database
30+ * @tparam I - the type covering the input fields of the database function
3031 * @tparam R - the type covering the returned fields from the database function
32+ * @tparam E - the type of the [[DBEngine ]] engine
3133 */
32- abstract class DBFunction [E , T , R ](schema : DBSchema [E ], functionNameOverride : Option [String ] = None ) extends DBFunctionFabric {
34+ abstract class DBFunction [I , R , E <: DBEngine ](functionNameOverride : Option [String ] = None )
35+ (implicit val schema : DBSchema , val dBEngine : E ) extends DBFunctionFabric {
36+
37+ /* alternative constructors for different availability of input parameters */
38+ def this (schema : DBSchema , functionNameOverride : String )
39+ (implicit dBEngine : E ) = {
40+ this (Option (functionNameOverride))(schema, dBEngine)
41+ }
42+
43+ /* only one constructor of a class can have default values for parameters*/
44+ def this (schema : DBSchema )
45+ (implicit dBEngine : E ) = {
46+ this (None )(schema, dBEngine)
47+ }
48+
49+ def this (dBEngine : E , functionNameOverride : String )
50+ (implicit schema : DBSchema ) = {
51+ this (Option (functionNameOverride))(schema, dBEngine)
52+ }
53+
54+ def this (dBEngine : E )
55+ (implicit schema : DBSchema ) = {
56+ this (None )(schema, dBEngine)
57+ }
58+
59+ /**
60+ * Function to create the DB function call specific to the provided [[DBEngine ]]. Expected to be implemented by the
61+ * DBEngine specific mix-in.
62+ * @param values - the values to pass over to the database function
63+ * @return - the SQL query in the format specific to the provided [[DBEngine ]]
64+ */
65+ protected def query (values : I ): dBEngine.QueryType [R ]
66+
67+ /**
68+ * Name of the function, based on the class name, unless it is overridden in the constructor
69+ */
3370 val functionName : String = {
3471 val fn = functionNameOverride.getOrElse(schema.objectNameFromClassName(getClass))
3572 if (schema.schemaName.isEmpty) {
@@ -39,65 +76,149 @@ abstract class DBFunction[E, T, R](schema: DBSchema[E], functionNameOverride: Op
3976 }
4077 }
4178
79+ def namingConvention : NamingConvention = schema.namingConvention
80+
4281 /**
43- * For the given output it returns a function to execute the SQL query and interpret the results.
44- * Basically it should create a function which contains a query to be executable and executed on on the [[DBExecutor ]]
45- * and transforming the result of that query to result type.
46- * @param values - the input values of the DB function (stored procedure)
47- * @return - the query function that when provided an executor will return the result of the DB function call
82+ * List of fields to select from the DB function. Expected to be based on the return type `R`
83+ * @return - list of fields to select
4884 */
49- protected def queryFunction (values : T ): QueryFunction [E , R ]
85+ override protected def fieldsToSelect : Seq [String ] = super .fieldsToSelect // TODO should get the names from R #6
86+
87+ /* these 3 functions has to be defined here and not in the ancestors, as there the query type is not compatible - path-dependent types*/
88+ protected def execute (values : I ): Future [Seq [R ]] = dBEngine.execute[R ](query(values))
89+ protected def unique (values : I ): Future [R ] = dBEngine.unique(query(values))
90+ protected def option (values : I ): Future [Option [R ]] = dBEngine.option(query(values))
91+
5092}
5193
5294object DBFunction {
5395 /**
5496 * Represents a function returning a set (in DB sense) of rows
55- *
56- * @param schema - the schema the function belongs into
5797 * @param functionNameOverride - in case the class name would not match the database function name, this gives the
5898 * possibility of override
59- * @tparam E - the type of the [[DBExecutor ]] engine
60- * @tparam T - the type covering the input fields of the database function
99+ * @param schema - the schema the function belongs into
100+ * @param dBEngine - the database engine that is supposed to execute the function (presumably contains
101+ * connection to the database
102+ * @tparam I - the type covering the input fields of the database function
61103 * @tparam R - the type covering the returned fields from the database function
104+ * @tparam E - the type of the [[DBEngine ]] engine
62105 */
63- abstract class DBSeqFunction [E , T , R ](schema : DBSchema [E ], functionNameOverride : Option [String ] = None )
64- extends DBFunction [E , T , R ](schema, functionNameOverride) {
65- def apply (values : T ): Future [Seq [R ]] = {
66- schema.execute(queryFunction(values))
106+ abstract class DBSeqFunction [I , R , E <: DBEngine ](functionNameOverride : Option [String ] = None )
107+ (implicit schema : DBSchema , dBEngine : E )
108+ extends DBFunction [I , R , E ](functionNameOverride) {
109+
110+ def this (schema : DBSchema , functionNameOverride : String )
111+ (implicit dBEngine : E ) = {
112+ this (Option (functionNameOverride))(schema, dBEngine)
113+ }
114+
115+ def this (schema : DBSchema )
116+ (implicit dBEngine : E ) = {
117+ this (None )(schema, dBEngine)
67118 }
119+
120+ def this (dBEngine : E , functionNameOverride : String )
121+ (implicit schema : DBSchema ) = {
122+ this (Option (functionNameOverride))(schema, dBEngine)
123+ }
124+
125+ def this (dBEngine : E )
126+ (implicit schema : DBSchema ) = {
127+ this (None )(schema, dBEngine)
128+ }
129+
130+ /**
131+ * For easy and convenient execution of the DB function call
132+ * @param values - the values to pass over to the database function
133+ * @return - a sequence of values, each coming from a row returned from the DB function transformed to scala
134+ * type `R`
135+ */
136+ def apply (values : I ): Future [Seq [R ]] = execute(values)
68137 }
69138
70139 /**
71140 * Represents a function returning exactly one record
72- *
73- * @param schema - the schema the function belongs into
74141 * @param functionNameOverride - in case the class name would not match the database function name, this gives the
75142 * possibility of override
76- * @tparam E - the type of the [[DBExecutor ]] engine
77- * @tparam T - the type covering the input fields of the database function
143+ * @param schema - the schema the function belongs into
144+ * @param dBEngine - the database engine that is supposed to execute the function (presumably contains
145+ * connection to the database
146+ * @tparam I - the type covering the input fields of the database function
78147 * @tparam R - the type covering the returned fields from the database function
148+ * @tparam E - the type of the [[DBEngine ]] engine
79149 */
80- abstract class DBUniqueFunction [E , T , R ](schema : DBSchema [E ], functionNameOverride : Option [String ] = None )
81- extends DBFunction [E , T , R ](schema, functionNameOverride) {
82- def apply (values : T ): Future [R ] = {
83- schema.unique(queryFunction(values))
150+ abstract class DBUniqueFunction [I , R , E <: DBEngine ](functionNameOverride : Option [String ] = None )
151+ (implicit schema : DBSchema , dBEngine : E )
152+ extends DBFunction [I , R , E ](functionNameOverride) {
153+
154+ def this (schema : DBSchema , functionNameOverride : String )
155+ (implicit dBEngine : E ) = {
156+ this (Option (functionNameOverride))(schema, dBEngine)
157+ }
158+
159+ def this (schema : DBSchema )
160+ (implicit dBEngine : E ) = {
161+ this (None )(schema, dBEngine)
84162 }
163+
164+ def this (dBEngine : E , functionNameOverride : String )
165+ (implicit schema : DBSchema ) = {
166+ this (Option (functionNameOverride))(schema, dBEngine)
167+ }
168+
169+ def this (dBEngine : E )
170+ (implicit schema : DBSchema ) = {
171+ this (None )(schema, dBEngine)
172+ }
173+
174+ /**
175+ * For easy and convenient execution of the DB function call
176+ * @param values - the values to pass over to the database function
177+ * @return - the value returned from the DB function transformed to scala type `R`
178+ */
179+ def apply (values : I ): Future [R ] = unique(values)
85180 }
86181
87182 /**
88183 * Represents a function returning one optional record
89- *
90- * @param schema - the schema the function belongs into
91184 * @param functionNameOverride - in case the class name would not match the database function name, this gives the
92185 * possibility of override
93- * @tparam E - the type of the [[DBExecutor ]] engine
94- * @tparam T - the type covering the input fields of the database function
186+ * @param schema - the schema the function belongs into
187+ * @param dBEngine - the database engine that is supposed to execute the function (presumably contains
188+ * connection to the database
189+ * @tparam I - the type covering the input fields of the database function
95190 * @tparam R - the type covering the returned fields from the database function
191+ * @tparam E - the type of the [[DBEngine ]] engine
96192 */
97- abstract class DBOptionFunction [E , T , R ](schema : DBSchema [E ], functionNameOverride : Option [String ] = None )
98- extends DBFunction [E , T , R ](schema, functionNameOverride) {
99- def apply (values : T ): Future [Option [R ]] = {
100- schema.option(queryFunction(values))
193+ abstract class DBOptionFunction [I , R , E <: DBEngine ](functionNameOverride : Option [String ] = None )
194+ (implicit schema : DBSchema , dBEngine : E )
195+ extends DBFunction [I , R , E ](functionNameOverride) {
196+
197+ def this (schema : DBSchema , functionNameOverride : String )
198+ (implicit dBEngine : E ) = {
199+ this (Option (functionNameOverride))(schema, dBEngine)
200+ }
201+
202+ def this (schema : DBSchema )
203+ (implicit dBEngine : E ) = {
204+ this (None )(schema, dBEngine)
205+ }
206+
207+ def this (dBEngine : E , functionNameOverride : String )
208+ (implicit schema : DBSchema ) = {
209+ this (Option (functionNameOverride))(schema, dBEngine)
101210 }
211+
212+ def this (dBEngine : E )
213+ (implicit schema : DBSchema ) = {
214+ this (None )(schema, dBEngine)
215+ }
216+
217+ /**
218+ * For easy and convenient execution of the DB function call
219+ * @param values - the values to pass over to the database function
220+ * @return - the value returned from the DB function transformed to scala type `R` if a row is returned, otherwise `None`
221+ */
222+ def apply (values : I ): Future [Option [R ]] = option(values)
102223 }
103224}
0 commit comments