Skip to content

Commit fa3c6ed

Browse files
committed
* fixed IT tests
* code improvements
1 parent 4e3f5c1 commit fa3c6ed

File tree

7 files changed

+75
-52
lines changed

7 files changed

+75
-52
lines changed

balta/src/main/scala/za/co/absa/db/balta/classes/DBFunction.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ sealed abstract class DBFunction private(functionName: SqlEntry,
4444
columnName.sqlEntry := queryParamValue.sqlEntry
4545
}
4646
val paramEntries = positionedParamEntries ++ namedParamEntries
47-
val paramsLine = paramEntries.mkString(",")
48-
SELECT(ALL) FROM functionName(paramsLine) ORDER BY (orderBy)
47+
SELECT(ALL) FROM functionName(paramEntries) ORDER BY (orderBy)
4948
}
5049

5150
/**

balta/src/main/scala/za/co/absa/db/balta/classes/DBQuerySupport.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ trait DBQuerySupport {
2929
(implicit connection: DBConnection): R = {
3030
val preparedStatement = connection.connection.prepareStatement(sql.entry)
3131

32+
println(sql)
3233
queryValues.foldLeft(1) { case (parameterIndex, queryValue) =>
3334
queryValue.assign match { // this is better readable-wise than map + getOrElse
3435
case Some(assignFnc) =>

balta/src/main/scala/za/co/absa/db/balta/classes/DBTable.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ case class DBTable(tableName: String) extends DBQuerySupport{
3939
*/
4040
def insert(values: Params)(implicit connection: DBConnection): QueryResultRow = {
4141
val columns = values match {
42-
case namedParams: NamedParams => namedParams.paramNames.map(_.sqlEntry).mkString("(", ",", ")")
43-
case _: OrderedParams => ""
42+
case namedParams: NamedParams =>
43+
val x = namedParams.paramNames.map(_.sqlEntry)
44+
x
45+
case _: OrderedParams => Vector.empty
4446
}
4547

46-
val paramStr = values.values.map(_.sqlEntry).mkString(",")
47-
val sql = INSERT INTO table(columns) VALUES(paramStr) RETURNING ALL
48+
val paramValues = values.values.map(_.sqlEntry)
49+
val sql = INSERT INTO table(columns) VALUES(paramValues) RETURNING ALL
4850
runQuery(sql, values.values){_.next()}
4951
}
5052

@@ -243,6 +245,6 @@ case class DBTable(tableName: String) extends DBQuerySupport{
243245
val condition = columnName.sqlEntry + value.equalityOperator + value.sqlEntry
244246
condition :: acc
245247
}
246-
resultList.toSqlEntry(" AND ")
248+
resultList.mkSqlEntry(" AND ")
247249
}
248250
}

balta/src/main/scala/za/co/absa/db/mag/core/SqlEntry.scala

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,20 @@ class SqlEntry(val entry: String) extends AnyVal {
3333
def ==(other: String): Boolean = this.entry == other
3434
def :=(other: SqlEntry): SqlEntry = this + SqlEntry(":=") + other
3535
def apply(params: String*): SqlEntry = {
36-
val paramsStr = params.mkString(", ")
37-
val paramsEntry = SqlEntry(paramsStr).toOption.encase("(", ")")
38-
this + paramsEntry.getOrElse(SqlEntry(""))
36+
val paramsStr = params.mkString("(", ",", ")")
37+
this + SqlEntry(paramsStr)
38+
}
39+
40+
/** Translates a sequence of SqlEntry entries into a single SqlEntry formatted as a parameter list
41+
*
42+
* @param params - A sequence of SqlEntry to be included as parameters.
43+
* @param foo - A bogus parameter do differentiate this method from the `apply(params: String*)` method, as their
44+
* signatures would be same otherwise after type erasure.
45+
* @return A new SqlEntry that combines the input as a list of parameters/columns for a function or table.
46+
*/
47+
def apply(params: Seq[SqlEntry], foo: String = ""): SqlEntry = {
48+
val paramsEntry = params.mkSqlEntry("(", ",", ")")
49+
this + paramsEntry
3950
}
4051

4152
def toOption: Option[SqlEntry] = {
@@ -56,11 +67,7 @@ object SqlEntry {
5667
def apply(maybeEntry: Option[String]): Option[SqlEntry] = maybeEntry.map(SqlEntry(_))
5768

5869
implicit class SqlEntryOptionEnhancement(val sqlEntry: Option[SqlEntry]) extends AnyVal {
59-
def prefix(withEntry: String): Option[SqlEntry] = sqlEntry.map(SqlEntry(withEntry) + _)
60-
def suffix(withEntry: String): Option[SqlEntry] = sqlEntry.map(_ + SqlEntry(withEntry))
61-
def encase(withEntryLeft: String, withEntryRight: String): Option[SqlEntry] = {
62-
sqlEntry.map(SqlEntry(withEntryLeft) + _ + SqlEntry(withEntryRight))
63-
}
70+
def prefix(withEntry: SqlEntry): Option[SqlEntry] = sqlEntry.map(withEntry + _)
6471

6572
def + (other: Option[SqlEntry]): Option[SqlEntry] = concat(sqlEntry, other)
6673

@@ -71,9 +78,12 @@ object SqlEntry {
7178
}
7279
}
7380

74-
implicit class SqlEntryListEnhancement(val sqlEntries: List[SqlEntry]) extends AnyVal {
75-
def toSqlEntry(separator: String = ", "): SqlEntry = {
76-
val entriesStr = sqlEntries.map(_.entry).mkString(separator)
81+
implicit class SqlEntryListEnhancement(val sqlEntries: Seq[SqlEntry]) extends AnyVal {
82+
def mkSqlEntry(separator: String): SqlEntry = {
83+
mkSqlEntry("", separator, "")
84+
}
85+
def mkSqlEntry(start: String, separator: String = ", ", end: String): SqlEntry = {
86+
val entriesStr = sqlEntries.map(_.entry).mkString(start, separator, end)
7787
SqlEntry(entriesStr)
7888
}
7989
}

balta/src/main/scala/za/co/absa/db/mag/core/SqlEntryComposition.scala

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,49 @@
11
package za.co.absa.db.mag.core
22

33
import scala.language.implicitConversions
4+
import za.co.absa.db.mag.core.SqlEntry._
45

56
object SqlEntryComposition {
67

7-
private def columnsToSqlEntry(fields: Seq[ColumnReference]): Option[SqlEntry] = {
8-
if (fields.isEmpty) {
9-
None
10-
} else {
11-
val fieldEntries = fields.map(_.sqlEntry.entry)
12-
Some(SqlEntry(fieldEntries.mkString(", ")))
13-
}
14-
}
15-
168
sealed class SelectFragment private[SqlEntryComposition]() {
17-
private val select = SqlEntry("SELECT")
18-
199
def apply(firstField: ColumnReference, fields: ColumnReference*): SelectWithFieldsFragment = {
2010
val allFields = firstField +: fields
21-
new SelectWithFieldsFragment(select + columnsToSqlEntry(allFields))
11+
new SelectWithFieldsFragment(select + allFields.map(_.sqlEntry).mkSqlEntry(", "))
2212
}
2313

2414
def apply(sqlConstant: SqlEntryConstant): SelectWithFieldsFragment = new SelectWithFieldsFragment(select + sqlConstant.sqlConstant)
2515
}
2616

2717
sealed class InsertFragment private[SqlEntryComposition]() {
2818
def INTO(intoEntry: SqlEntry): QueryInsertIntoFragment = {
29-
new QueryInsertIntoFragment(SqlEntry("INSERT INTO") + intoEntry)
19+
new QueryInsertIntoFragment(insertInto + intoEntry)
3020
}
3121
}
3222

3323
sealed class QueryInsertIntoFragment private[SqlEntryComposition](sqlEntry: SqlEntry) {
34-
def VALUES(firstValue: String, otherValues: String*): QueryInsert = {
35-
val valuesLine = (firstValue +: otherValues).mkString(", ")
36-
new QueryInsert(sqlEntry + SqlEntry(s"VALUES($valuesLine)"))
24+
def VALUES(firstValue: SqlEntry, otherValues: SqlEntry*): QueryInsert = {
25+
VALUES(firstValue +: otherValues)
26+
}
27+
def VALUES(values: Seq[SqlEntry]): QueryInsert = {
28+
val valuesEntry = values.mkSqlEntry("VALUES(", ", ", ")")
29+
new QueryInsert(sqlEntry + valuesEntry)
3730
}
3831
}
3932

4033
sealed class DeleteFragment private[SqlEntryComposition]() {
41-
def FROM(fromEntry: SqlEntry): QueryDelete = new QueryDelete(SqlEntry("DELETE FROM") + fromEntry)
34+
def FROM(fromEntry: SqlEntry): QueryDelete = new QueryDelete(deleteFrom + fromEntry)
4235
}
4336

4437
private object SelectFragment extends SelectFragment()
4538
private object InsertFragment extends InsertFragment()
4639
private object DeleteFragment extends DeleteFragment
4740

4841
sealed class SelectWithFieldsFragment private[SqlEntryComposition](val sql: SqlEntry) {
49-
def FROM(fromEntry: SqlEntry): QuerySelect = new QuerySelect(sql + SqlEntry("FROM") + fromEntry)
42+
def FROM(fromEntry: SqlEntry): QuerySelect = new QuerySelect(sql + from + fromEntry)
5043
}
5144

5245
sealed class OrderByFragment private[SqlEntryComposition](orderingEntry: Option[SqlEntry]) {
53-
val sqlEntry: Option[SqlEntry] = orderingEntry.prefix("ORDER BY")
46+
val sqlEntry: Option[SqlEntry] = orderingEntry.prefix(orderBy)
5447
}
5548

5649
trait OrderByMixIn {
@@ -60,12 +53,12 @@ object SqlEntryComposition {
6053

6154
trait ReturningMixIn {
6255
def sqlEntry: SqlEntry
63-
def RETURNING(returning: SqlEntryConstant): QueryWithReturning = {
64-
new QueryWithReturning(sqlEntry + SqlEntry("RETURNING") + returning.sqlConstant)
56+
def RETURNING(returningFields: SqlEntryConstant): QueryWithReturning = {
57+
new QueryWithReturning(sqlEntry + returning + returningFields.sqlConstant)
6558
}
6659
def RETURNING(firstField: ColumnReference, otherFields: ColumnReference*): QueryWithReturning = {
6760
val allFields = firstField +: otherFields
68-
new QueryWithReturning(sqlEntry + SqlEntry("RETURNING") + columnsToSqlEntry(allFields))
61+
new QueryWithReturning(sqlEntry + returning + columnsToSqlEntry(allFields))
6962
}
7063
}
7164

@@ -75,9 +68,8 @@ object SqlEntryComposition {
7568
extends Query(sqlEntry) with OrderByMixIn {
7669
def WHERE(condition: SqlEntry): QuerySelectConditioned = WHERE(condition.toOption)
7770
def WHERE(condition: Option[SqlEntry]): QuerySelectConditioned = {
78-
new QuerySelectConditioned(sqlEntry + condition.prefix("WHERE"))
71+
new QuerySelectConditioned(sqlEntry + condition.prefix(where))
7972
}
80-
// def apply(paramsLine: String): QuerySelectWithParams = new QuerySelectWithParams(sqlEntry + SqlEntry(s"($paramsLine)"))
8173
}
8274

8375
sealed class QuerySelectConditioned private[SqlEntryComposition](sqlEntry: SqlEntry)
@@ -91,7 +83,7 @@ object SqlEntryComposition {
9183
sealed class QueryDelete private[SqlEntryComposition](sqlEntry: SqlEntry) extends Query(sqlEntry) with ReturningMixIn {
9284
def WHERE(condition: SqlEntry): QueryDeleteConditioned = WHERE(condition.toOption)
9385
def WHERE(condition: Option[SqlEntry]): QueryDeleteConditioned = {
94-
new QueryDeleteConditioned(sqlEntry + condition.prefix("WHERE"))
86+
new QueryDeleteConditioned(sqlEntry + condition.prefix(where))
9587
}
9688
}
9789

@@ -116,5 +108,23 @@ object SqlEntryComposition {
116108
def BY(columns: ColumnReference*): OrderByFragment= new OrderByFragment(columnsToSqlEntry(columns))
117109

118110
implicit def QueryToSqlEntry(query: Query): SqlEntry = query.sqlEntry
111+
implicit def StringToSqlEntry(string: String): SqlEntry = SqlEntry(string)
112+
113+
private val select = SqlEntry("SELECT")
114+
private val insertInto = SqlEntry("INSERT INTO")
115+
private val deleteFrom = SqlEntry("DELETE FROM")
116+
private val from = SqlEntry("FROM")
117+
private val where = SqlEntry("WHERE")
118+
private val orderBy = SqlEntry("ORDER BY")
119+
private val returning = SqlEntry("RETURNING")
120+
121+
private def columnsToSqlEntry(fields: Seq[ColumnReference]): Option[SqlEntry] = {
122+
if (fields.isEmpty) {
123+
None
124+
} else {
125+
val fieldEntries = fields.map(_.sqlEntry.entry)
126+
Some(SqlEntry(fieldEntries.mkString(", ")))
127+
}
128+
}
119129

120130
}

balta/src/test/scala/za/co/absa/db/balta/classes/DBTableIntegrationTests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ class DBTableIntegrationTests extends AnyFunSuiteLike with DBTestingConnection{
6565
queryResult.next().assertTo(1, "textA", booleanField = true)
6666
queryResult.next().assertTo(4, "textA", booleanField = false)
6767
assert(queryResult.noMore)
68-
"Hello world"
68+
"Some returned value"
6969
}
70-
assert(returnedValue == "Hello world")
70+
assert(returnedValue == "Some returned value")
7171

7272
table.where(Params.add("text_field", "textB").add("boolean_field", false)) { queryResult =>
7373
queryResult.next().assertTo(2, "textB", booleanField = false)

balta/src/test/scala/za/co/absa/db/mag/core/SqlEntryCompositionUnitTests.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,20 @@ class SqlEntryCompositionUnitTests extends AnyFunSuiteLike {
5757
assert(query.sqlEntry.entry == expectedSql)
5858
}
5959

60+
test("Composition of `SELECT ... FROM ...` using function call without providing parameters") {
61+
val query = SELECT(ALL) FROM functionName()
62+
val expectedSql = "SELECT * FROM my_function()"
63+
assert(query.sqlEntry.entry == expectedSql)
64+
}
65+
66+
6067
test("Composition of `INSERT INTO ...`") {
6168
val query = INSERT INTO tableName VALUES("100", "'Sample Text'")
6269
val expectedSql = "INSERT INTO my_table VALUES(100, 'Sample Text')"
6370
assert(query.sqlEntry.entry == expectedSql)
6471
}
6572

66-
test("Composition of `INSERT INTO ... VALUES RETURNING ...`") {
73+
test("Composition of `INSERT INTO ... VALUES RETURNING ...` not providing any field names") {
6774
val query = INSERT INTO tableName VALUES(param) RETURNING(ALL)
6875
val expectedSql = "INSERT INTO my_table VALUES(42) RETURNING *"
6976
assert(query.sqlEntry.entry == expectedSql)
@@ -76,12 +83,6 @@ class SqlEntryCompositionUnitTests extends AnyFunSuiteLike {
7683
assert(query.sqlEntry.entry == expectedSql)
7784
}
7885

79-
test("Composition of `INSERT INTO ...() VALUES ... RETURNING ...` not providing any field names") {
80-
val query = INSERT INTO tableName() VALUES("42") RETURNING(field1)
81-
val expectedSql = "INSERT INTO my_table VALUES(42) RETURNING field1"
82-
assert(query.sqlEntry.entry == expectedSql)
83-
}
84-
8586
test("Composition of `DELETE ... FROM ...`") {
8687
val query = DELETE FROM tableName
8788
val expectedSql = "DELETE FROM my_table"

0 commit comments

Comments
 (0)