Skip to content

Commit

Permalink
#35: Simplify working with the query results in the DB tests (#37)
Browse files Browse the repository at this point in the history
* method `@=` for Option types as a synonym for `contains`
* method 'noMore` as an alias for `hasMore` in `QueryResult` class
* enhanced tests for `QueryResultRowIntegration`
* changed the return type of `QueryResultRow.apply` from `Option[Object]` to `Option[Any]`
  • Loading branch information
benedeki authored Oct 1, 2024
1 parent 7298aaf commit 471bb02
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ class QueryResult(resultSet: ResultSet) extends Iterator[QueryResultRow] {
throw new NoSuchElementException("No more rows in the result set")
}
}

/**
* A naturally easily understandable opposite of `hasNext`
*/
def noMore: Boolean = !hasNext
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,27 @@ class QueryResultRow private[classes](val rowNumber: Int,
def columnCount: Int = fields.length
def columnNumber(columnLabel: String): Int = columnNames(columnLabel.toLowerCase)

def apply(column: Int): Option[Object] = fields(column - 1)
def apply(columnLabel: String): Option[Object] = apply(columnNumber(columnLabel))

def getAs[T](column: Int, transformer: TransformerFnc[T]): Option[T] = apply(column).map(transformer)
def getAs[T](column: Int): Option[T] = apply(column)map(_.asInstanceOf[T])
/**
* Extracts a value from the row by column number.
* @param column - the number of the column, 1 based
* @return - the value stored in the column, type `Any` is for warningless comparison with any type
*/
def apply(column: Int): Option[Any] = getObject(column - 1)
/**
* Extracts a value from the row by column name.
* @param columnLabel - the name of the column
* @return - the value stored in the column, type `Any` is for warningless comparison with any type
*/
def apply(columnLabel: String): Option[Any] = getObject(columnNumber(columnLabel))

def getAs[T](column: Int, transformer: TransformerFnc[T]): Option[T] = getObject(column).map(transformer)
def getAs[T](column: Int): Option[T] = getObject(column)map(_.asInstanceOf[T])

def getAs[T](columnLabel: String, transformer: TransformerFnc[T]): Option[T] = getAs(columnNumber(columnLabel), transformer)
def getAs[T](columnLabel: String): Option[T] = apply(columnNumber(columnLabel)).map(_.asInstanceOf[T])
def getAs[T](columnLabel: String): Option[T] = getObject(columnNumber(columnLabel)).map(_.asInstanceOf[T])

def getObject(column: Int): Option[Object] = fields(column - 1)
def getObject(columnLabel: String): Option[Object] = getObject(columnNumber(columnLabel))

def getBoolean(column: Int): Option[Boolean] = getAs(column: Int, {item: Object => item.asInstanceOf[Boolean]})
def getBoolean(columnLabel: String): Option[Boolean] = getBoolean(columnNumber(columnLabel))
Expand All @@ -59,7 +72,6 @@ class QueryResultRow private[classes](val rowNumber: Int,
}
def getChar(columnLabel: String): Option[Char] = getChar(columnNumber(columnLabel))


def getString(column: Int): Option[String] = getAs(column: Int, {item: Object => item.asInstanceOf[String]})
def getString(columnLabel: String): Option[String] = getString(columnNumber(columnLabel))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

package za.co.absa.db.balta.classes.setter

import java.sql.{Date, PreparedStatement, Time, Timestamp, Types => SqlTypes}
import java.sql.{Date, PreparedStatement, Time, Types => SqlTypes}
import java.util.UUID
import org.postgresql.util.PGobject
import za.co.absa.db.balta.classes.simple.JsonBString

import java.time.{Instant, LocalDate, LocalTime, OffsetDateTime, ZoneId, ZoneOffset}
import java.time.{Instant, LocalDate, LocalTime, OffsetDateTime, ZoneOffset}

/**
* This is a trait representing a function that sets a value in a prepared statement.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2023 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.db.balta.implicits

object OptionImplicits {
implicit class OptionEnhancements[T](val option: Option[T]) extends AnyVal {
/**
* Gets the `option` value or throws the provided exception
*
* @param exception the exception to throw in case the `option` is None
* @return
*/
def getOrThrow(exception: => Throwable): T = {
option.getOrElse(throw exception)
}

/**
* The function is an alias for `contains` method, but shorter and suitable for inflix usage
*
* @param value the value to check if present in the `option`
* @return true if the `option` is defined and contains the provided value, false otherwise
*/
def @=(value: T): Boolean = option.contains(value)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ class QueryResultRowIntegrationTests extends AnyFunSuiteLike with DBTestingConne
assert(result == expecedResult)
}

test("columnCount") {
assert(tableRows.head.columnCount == 14)
}

test("rowNumber") {
assert(tableRows.head.rowNumber == 1)
assert(tableRows.tail.head.rowNumber == 2)
}

test("getLong") {
//first row
assert(tableRows.head.getLong(1).contains(1))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2023 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.db.balta.implicits

import org.scalatest.funsuite.AnyFunSuiteLike
import za.co.absa.db.balta.implicits.OptionImplicits.OptionEnhancements


class OptionImplicitsUnitTests extends AnyFunSuiteLike {
test("getOrThrow returns the value if it is defined") {
val opt = Some(true)
assert(opt.getOrThrow(new Exception("Foo")))
}

test("getOrThrow throws an exception if the value is not defined") {
val opt = None
assertThrows[Exception](opt.getOrThrow(new Exception("Foo")))
}

test("@= returns true if the value is defined and equals the provided value") {
val opt = Some(42)
assert(opt @= 42)
}

test("@= returns false if the value is defined but does not equal the provided value") {
val opt = Some(42)
assert(!(opt @= 43))
}

test("@= returns false if the value is not defined") {
val opt = None
assert(!(opt @= 42))
}

}

0 comments on commit 471bb02

Please sign in to comment.