Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lenientString to SqlRow #84

Merged
merged 1 commit into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 6 additions & 27 deletions relate/src/main/scala/com/lucidchart/relate/SqlRow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,7 @@ class SqlRow(val resultSet: java.sql.ResultSet) extends ResultSetWrapper {
implicitly[ColReader[A]].read(col, this)

def string(column: String): String = stringOption(column).get
def stringOption(column: String): Option[String] = {
extractOption(column) {
case x: String => x
case x: java.sql.Clob => x.getSubString(1, x.length.asInstanceOf[Int])
}
}
def stringOption(column: String): Option[String] = getResultSetOption(resultSet.getString(column))

def int(column: String): Int = intOption(column).get
def intOption(column: String): Option[Int] = getResultSetOption(resultSet.getInt(column))
Expand All @@ -115,49 +110,33 @@ class SqlRow(val resultSet: java.sql.ResultSet) extends ResultSetWrapper {
def boolOption(column: String): Option[Boolean] = getResultSetOption(resultSet.getBoolean(column))

def long(column: String): Long = longOption(column).get
def longOption(column: String): Option[Long] = {
extractOption(column) {
case x: Long => x
case x: Int => x.toLong
}
}
def longOption(column: String): Option[Long] = getResultSetOption(resultSet.getLong(column))

def bigInt(column: String): BigInt = bigIntOption(column).get
def bigIntOption(column: String): Option[BigInt] = {
extractOption(column) {
case x: java.math.BigInteger => BigInt(x)
case x: Int => BigInt(x)
case x: Long => BigInt(x)
case x: String => BigInt(x)
case x: java.math.BigInteger => BigInt(x.toString)
}
}

def bigDecimal(column: String): BigDecimal = bigDecimalOption(column).get
def bigDecimalOption(column: String): Option[BigDecimal] = {
extractOption(column) {
case x: Int => BigDecimal(x)
case x: Long => BigDecimal(x)
case x: String => BigDecimal(x)
case x: java.math.BigDecimal => BigDecimal(x.toString)
}
}
def bigDecimalOption(column: String): Option[BigDecimal] = javaBigDecimalOption(column).map(BigDecimal.apply)

def javaBigInteger(column: String): java.math.BigInteger = javaBigIntegerOption(column).get
def javaBigIntegerOption(column: String): Option[java.math.BigInteger] = {
extractOption(column) {
case x: java.math.BigInteger => x
case x: Int => java.math.BigInteger.valueOf(x)
case x: Long => java.math.BigInteger.valueOf(x)
case x: String => new java.math.BigInteger(x)
}
}

def javaBigDecimal(column: String): java.math.BigDecimal = javaBigDecimalOption(column).get
def javaBigDecimalOption(column: String): Option[java.math.BigDecimal] = {
extractOption(column) {
case x: java.math.BigDecimal => x
case x: Double => new java.math.BigDecimal(x)
}
}
def javaBigDecimalOption(column: String): Option[java.math.BigDecimal] = getResultSetOption(resultSet.getBigDecimal(column))

def date(column: String): Date = dateOption(column).get
// Timestamp documentation says that "it is recommended that code not view Timestamp values generically as an instance
Expand Down
18 changes: 9 additions & 9 deletions relate/src/test/scala/ImplicitParsingTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2
rs.next returns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world"
rs.getString("name") returns "hello" thenReturns "world"

result.as[List[TestRecord]] mustEqual List(
TestRecord("hello"),
Expand All @@ -53,7 +53,7 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2
rs.next returns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world"
rs.getString("name") returns "hello" thenReturns "world"

result.as[Seq[TestRecord]] mustEqual Seq(
TestRecord("hello"),
Expand All @@ -68,7 +68,7 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2
rs.next returns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world"
rs.getString("name") returns "hello" thenReturns "world"

result.as[Iterable[TestRecord]] mustEqual Iterable(
TestRecord("hello"),
Expand All @@ -83,7 +83,7 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2
rs.next returns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world"
rs.getString("name") returns "hello" thenReturns "world"

result.as[Iterable[TestRecord]] mustEqual Iterable(
TestRecord("hello"),
Expand All @@ -98,8 +98,8 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2
rs.next returns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world"
rs.getObject("key") returns "1" thenReturns "2"
rs.getString("name") returns "hello" thenReturns "world"
rs.getString("key") returns "1" thenReturns "2"

result.as[Map[TestKey, TestRecord]] mustEqual Map(
TestKey("1") -> TestRecord("hello"),
Expand All @@ -112,8 +112,8 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2 thenReturns 3
rs.next returns true thenReturns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world" thenReturns "relate"
rs.getObject("key") returns "1" thenReturns "2" thenReturns "1"
rs.getString("name") returns "hello" thenReturns "world" thenReturns "relate"
rs.getString("key") returns "1" thenReturns "2" thenReturns "1"

result.as[Map[TestKey, Set[TestRecord]]] mustEqual Map(
TestKey("1") -> Set(TestRecord("hello"), TestRecord("relate")),
Expand All @@ -126,7 +126,7 @@ class ImplicitParsingTest extends Specification with Mockito {

rs.getRow returns 0 thenReturns 1 thenReturns 2 thenReturns 3
rs.next returns true thenReturns true thenReturns true thenReturns false
rs.getObject("name") returns "hello" thenReturns "world" thenReturns "relate"
rs.getString("name") returns "hello" thenReturns "world" thenReturns "relate"

result.as[Option[TestRecord]] mustEqual Some(TestRecord("hello"))
}
Expand Down
87 changes: 36 additions & 51 deletions relate/src/test/scala/SqlResultSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class SqlResultSpec extends Specification with Mockito {

rs.getRow returns 0 thenReturn 1
rs.next returns true thenReturns false
rs.getObject("id") returns (100L: java.lang.Long)
rs.getObject("name") returns "the name"
rs.getLong("id") returns (100L: java.lang.Long)
rs.getString("name") returns "the name"

result.asSingle(parser) mustEqual TestRecord(100L, "the name")
}
Expand All @@ -64,8 +64,8 @@ class SqlResultSpec extends Specification with Mockito {

rs.getRow returns 0 thenReturn 1
rs.next returns true thenReturns false
rs.getObject("id") returns (100L: java.lang.Long)
rs.getObject("name") returns "the name"
rs.getLong("id") returns (100L: java.lang.Long)
rs.getString("name") returns "the name"

result.asSingle[TestRecord] mustEqual TestRecord(100L, "the name")
}
Expand All @@ -75,8 +75,8 @@ class SqlResultSpec extends Specification with Mockito {
def init(rs: java.sql.ResultSet, next: Boolean) = {
rs.getRow returns 0 thenReturn 1
rs.next returns next
rs.getObject("id") returns (100L: java.lang.Long)
rs.getObject("name") returns "the name"
rs.getLong("id") returns (100L: java.lang.Long)
rs.getString("name") returns "the name"
}

"return a single row with an explicit parser" in {
Expand Down Expand Up @@ -114,8 +114,8 @@ class SqlResultSpec extends Specification with Mockito {

rs.getRow returns 0 thenReturn 1 thenReturn 2 thenReturn 3
rs.next returns true thenReturn true thenReturn true thenReturn false
rs.getObject("id") returns (100L: java.lang.Long)
rs.getObject("name") returns "the name"
rs.getLong("id") returns (100L: java.lang.Long)
rs.getString("name") returns "the name"

result.asList(parser) mustEqual List(TestRecord(100L, "the name"), TestRecord(100L, "the name"), TestRecord(100L, "the name"))
}
Expand All @@ -134,8 +134,8 @@ class SqlResultSpec extends Specification with Mockito {

rs.getRow returns 0 thenReturn 1 thenReturn 2 thenReturn 3
rs.next returns true thenReturn true thenReturn true thenReturn false
rs.getObject("id") returns (100L: java.lang.Long)
rs.getObject("name") returns "the name"
rs.getLong("id") returns (100L: java.lang.Long)
rs.getString("name") returns "the name"

result.asList[TestRecord] mustEqual List(TestRecord(100L, "the name"), TestRecord(100L, "the name"), TestRecord(100L, "the name"))
}
Expand All @@ -153,12 +153,11 @@ class SqlResultSpec extends Specification with Mockito {
"asMap" should {
"return a map of 3 elements with an explicit parser" in {
val (rs, _, result) = getMocks
import java.lang.{Long => L}

rs.getRow returns 0 thenReturn 1 thenReturn 2 thenReturn 3
rs.next returns true thenReturn true thenReturn true thenReturn false
rs.getObject("id") returns (1: L) thenReturns (2: L) thenReturns (3: L)
rs.getObject("name") returns "the name"
rs.getLong("id") returns 1L thenReturns 2L thenReturns 3L
rs.getString("name") returns "the name"

val res = result.asMap(pairparser)
res(1L) mustEqual TestRecord(1L, "the name")
Expand Down Expand Up @@ -186,8 +185,8 @@ class SqlResultSpec extends Specification with Mockito {

rs.getRow returns 0 thenReturn 1 thenReturn 2 thenReturn 3
rs.next returns true thenReturn true thenReturn true thenReturn false
rs.getObject("id") returns (1: L) thenReturns (2: L) thenReturns (3: L)
rs.getObject("name") returns "the name"
rs.getLong("id") returns (1: L) thenReturns (2: L) thenReturns (3: L)
rs.getString("name") returns "the name"

val res = result.asMap[Long, TestRecord]
res(1L) mustEqual TestRecord(1L, "the name")
Expand All @@ -210,8 +209,8 @@ class SqlResultSpec extends Specification with Mockito {

rs.getRow returns 0 thenReturn 1 thenReturn 2 thenReturn 3 thenReturn 4
rs.next returns true thenReturn true thenReturn true thenReturn true thenReturn false
rs.getObject("id") returns "1" thenReturns "2" thenReturns "1" thenReturns "2"
rs.getObject("name") returns "one" thenReturns "two" thenReturns "three" thenReturns "four"
rs.getString("id") returns "1" thenReturns "2" thenReturns "1" thenReturns "2"
rs.getString("name") returns "one" thenReturns "two" thenReturns "three" thenReturns "four"

val res = result.asMultiMap { row =>
row.string("id") -> row.string("name")
Expand Down Expand Up @@ -651,7 +650,7 @@ class SqlResultSpec extends Specification with Mockito {
val (rs, row, _) = getMocks

val res = "hello"
rs.getObject("string") returns res
rs.getString("string") returns res
row.string("string") mustEqual res
row.stringOption("string") must beSome(res)
}
Expand Down Expand Up @@ -734,8 +733,8 @@ class SqlResultSpec extends Specification with Mockito {
"return the correct value" in {
val (rs, row, _) = getMocks

val res: Object = 100000L: java.lang.Long
rs.getObject("long") returns res
val res: java.lang.Long = 100000L
rs.getLong("long") returns res
row.long("long") mustEqual res
row.longOption("long") must beSome(res)
}
Expand Down Expand Up @@ -775,23 +774,8 @@ class SqlResultSpec extends Specification with Mockito {

val number = 1.013

val int: Object = number.toInt: java.lang.Integer
rs.getObject("bigDecimal") returns int
row.bigDecimal("bigDecimal") mustEqual BigDecimal(number.toInt)
row.bigDecimalOption("bigDecimal") must beSome(BigDecimal(number.toInt))

val long: Object = number.toLong: java.lang.Long
rs.getObject("bigDecimal") returns long
row.bigDecimal("bigDecimal") mustEqual BigDecimal(number.toLong)
row.bigDecimalOption("bigDecimal") must beSome(BigDecimal(number.toLong))

val string: Object = number.toString
rs.getObject("bigDecimal") returns string
row.bigDecimal("bigDecimal") mustEqual BigDecimal(number)
row.bigDecimalOption("bigDecimal") must beSome(BigDecimal(number))

val bigint: Object = new java.math.BigDecimal(number.toString)
rs.getObject("bigDecimal") returns bigint
val bigint = new java.math.BigDecimal(number.toString)
rs.getBigDecimal("bigDecimal") returns bigint
row.bigDecimal("bigDecimal") mustEqual BigDecimal(number)
row.bigDecimalOption("bigDecimal") must beSome(BigDecimal(number))
}
Expand All @@ -802,21 +786,27 @@ class SqlResultSpec extends Specification with Mockito {
val (rs, row, _) = getMocks

val number = 1010101
val bigNumber = java.math.BigInteger.valueOf(number)

val int: Object = number.toInt: java.lang.Integer
rs.getObject("javaBigInteger") returns int
row.javaBigInteger("javaBigInteger") mustEqual new java.math.BigInteger(number.toString)
row.javaBigIntegerOption("javaBigInteger") must beSome(new java.math.BigInteger(number.toString))
row.javaBigInteger("javaBigInteger") mustEqual bigNumber
row.javaBigIntegerOption("javaBigInteger") must beSome(bigNumber)

val long: Object = number.toLong: java.lang.Long
rs.getObject("javaBigInteger") returns long
row.javaBigInteger("javaBigInteger") mustEqual new java.math.BigInteger(number.toString)
row.javaBigIntegerOption("javaBigInteger") must beSome(new java.math.BigInteger(number.toString))
row.javaBigInteger("javaBigInteger") mustEqual bigNumber
row.javaBigIntegerOption("javaBigInteger") must beSome(bigNumber)

val bigint: Object = new java.math.BigInteger(number.toString)
rs.getObject("javaBigInteger") returns bigint
row.javaBigInteger("javaBigInteger") mustEqual new java.math.BigInteger(number.toString)
row.javaBigIntegerOption("javaBigInteger") must beSome(new java.math.BigInteger(number.toString))
row.javaBigInteger("javaBigInteger") mustEqual bigNumber
row.javaBigIntegerOption("javaBigInteger") must beSome(bigNumber)

val str: Object = number.toString
rs.getObject("javaBigInteger") returns str
row.javaBigInteger("javaBigInteger") mustEqual bigNumber
row.javaBigIntegerOption("javaBigInteger") must beSome(bigNumber)
}
}

Expand All @@ -826,13 +816,8 @@ class SqlResultSpec extends Specification with Mockito {

val number = 1

val double: Object = number.toDouble: java.lang.Double
rs.getObject("javaBigDecimal") returns double
row.javaBigDecimal("javaBigDecimal") mustEqual new java.math.BigDecimal(number.toString)
row.javaBigDecimalOption("javaBigDecimal") must beSome(new java.math.BigDecimal(number.toString))

val bigdec: Object = new java.math.BigDecimal(number.toString)
rs.getObject("javaBigDecimal") returns bigdec
val bigdec = java.math.BigDecimal.valueOf(number)
rs.getBigDecimal("javaBigDecimal") returns bigdec
row.javaBigDecimal("javaBigDecimal") mustEqual new java.math.BigDecimal(number.toString)
row.javaBigDecimalOption("javaBigDecimal") must beSome(new java.math.BigDecimal(number.toString))
}
Expand Down Expand Up @@ -926,7 +911,7 @@ class SqlResultSpec extends Specification with Mockito {
val (rs, row, _) = getMocks

val res = "000102030405060708090a0b0c0d0e0f"
rs.getObject("uuidFromString") returns res
rs.getString("uuidFromString") returns res
row.uuidFromString("uuidFromString") mustEqual new UUID(283686952306183L, 579005069656919567L)
row.uuidFromStringOption("uuidFromString") must beSome(new UUID(283686952306183L, 579005069656919567L))
}
Expand Down