Skip to content

Commit

Permalink
Fix option null values failing to put (#42)
Browse files Browse the repository at this point in the history
This PR fixes the error described in
#41

Additionally it fixes it for Enum values on Postgres (which I'm fairly
sure had the same error)

It appears keeping record of the JDBCType on TypeMappers is not
necessary anymore, but nonetheless I kept the value there to touch as
little as possible. I did update the DocString.
  • Loading branch information
jlvertol authored Oct 21, 2024
1 parent 0e4e39b commit 8091ae3
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 3 deletions.
80 changes: 80 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10159,6 +10159,86 @@ OptCols.select.sortBy(_.myInt).desc.nullsFirst
### Optional.sorting.roundTripOptionalValues
This example demonstrates a range of different data types being written
as options, both with Some(v) and None values
```scala
object MyEnum extends Enumeration {
val foo, bar, baz = Value
implicit def make: String => Value = withName
}
case class OptDataTypes[T[_]](
myTinyInt: T[Option[Byte]],
mySmallInt: T[Option[Short]],
myInt: T[Option[Int]],
myBigInt: T[Option[Long]],
myDouble: T[Option[Double]],
myBoolean: T[Option[Boolean]],
myLocalDate: T[Option[LocalDate]],
myLocalTime: T[Option[LocalTime]],
myLocalDateTime: T[Option[LocalDateTime]],
myUtilDate: T[Option[Date]],
myInstant: T[Option[Instant]],
myVarBinary: T[Option[geny.Bytes]],
myUUID: T[Option[java.util.UUID]],
myEnum: T[Option[MyEnum.Value]]
)
object OptDataTypes extends Table[OptDataTypes] {
override def tableName: String = "data_types"
}
val rowSome = OptDataTypes[Sc](
myTinyInt = Some(123.toByte),
mySmallInt = Some(12345.toShort),
myInt = Some(12345678),
myBigInt = Some(12345678901L),
myDouble = Some(3.14),
myBoolean = Some(true),
myLocalDate = Some(LocalDate.parse("2023-12-20")),
myLocalTime = Some(LocalTime.parse("10:15:30")),
myLocalDateTime = Some(LocalDateTime.parse("2011-12-03T10:15:30")),
myUtilDate = Some(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2011-12-03T10:15:30.000")
),
myInstant = Some(Instant.parse("2011-12-03T10:15:30Z")),
myVarBinary = Some(new geny.Bytes(Array[Byte](1, 2, 3, 4, 5, 6, 7, 8))),
myUUID = Some(new java.util.UUID(1234567890L, 9876543210L)),
myEnum = Some(MyEnum.bar)
)
val rowNone = OptDataTypes[Sc](
myTinyInt = None,
mySmallInt = None,
myInt = None,
myBigInt = None,
myDouble = None,
myBoolean = None,
myLocalDate = None,
myLocalTime = None,
myLocalDateTime = None,
myUtilDate = None,
myInstant = None,
myVarBinary = None,
myUUID = None,
myEnum = None
)
db.run(
OptDataTypes.insert.values(rowSome, rowNone)
) ==> 2
db.run(OptDataTypes.select) ==> Seq(rowSome, rowNone)
```
## PostgresDialect
Operations specific to working with Postgres Databases
### PostgresDialect.distinctOn
Expand Down
3 changes: 1 addition & 2 deletions scalasql/core/src/TypeMapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ import java.util.UUID
trait TypeMapper[T] { outer =>

/**
* The JDBC type of this type. Used for `setNull` which needs to know the
* `java.sql.Types` integer ID of the type to set it properly
* The JDBC type of this type.
*/
def jdbcType: JDBCType

Expand Down
2 changes: 1 addition & 1 deletion scalasql/src/dialects/Dialect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ trait Dialect extends DialectTypeMappers {

def put(r: PreparedStatement, idx: Int, v: Option[T]): Unit = {
v match {
case None => r.setNull(idx, jdbcType.getVendorTypeNumber)
case None => r.setNull(idx, JDBCType.NULL.getVendorTypeNumber)
case Some(value) => inner.put(r, idx, value)
}
}
Expand Down
89 changes: 89 additions & 0 deletions scalasql/test/src/datatypes/OptionalTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ import utest._
import utils.ScalaSqlSuite
import sourcecode.Text

import java.time.{
Instant,
LocalDate,
LocalDateTime,
LocalTime,
OffsetDateTime,
ZoneId,
ZonedDateTime
}
import java.util.Date
import java.text.SimpleDateFormat
import java.util.UUID

case class OptCols[T[_]](myInt: T[Option[Int]], myInt2: T[Option[Int]])

object OptCols extends Table[OptCols]
Expand Down Expand Up @@ -516,6 +529,82 @@ trait OptionalTests extends ScalaSqlSuite {
OptCols[Sc](Some(1), Some(2))
)
)
test("roundTripOptionalValues") - checker.recorded(
"""
This example demonstrates a range of different data types being written
as options, both with Some(v) and None values
""",
Text {
object MyEnum extends Enumeration {
val foo, bar, baz = Value

implicit def make: String => Value = withName
}
case class OptDataTypes[T[_]](
myTinyInt: T[Option[Byte]],
mySmallInt: T[Option[Short]],
myInt: T[Option[Int]],
myBigInt: T[Option[Long]],
myDouble: T[Option[Double]],
myBoolean: T[Option[Boolean]],
myLocalDate: T[Option[LocalDate]],
myLocalTime: T[Option[LocalTime]],
myLocalDateTime: T[Option[LocalDateTime]],
myUtilDate: T[Option[Date]],
myInstant: T[Option[Instant]],
myVarBinary: T[Option[geny.Bytes]],
myUUID: T[Option[java.util.UUID]],
myEnum: T[Option[MyEnum.Value]]
)

object OptDataTypes extends Table[OptDataTypes] {
override def tableName: String = "data_types"
}

val rowSome = OptDataTypes[Sc](
myTinyInt = Some(123.toByte),
mySmallInt = Some(12345.toShort),
myInt = Some(12345678),
myBigInt = Some(12345678901L),
myDouble = Some(3.14),
myBoolean = Some(true),
myLocalDate = Some(LocalDate.parse("2023-12-20")),
myLocalTime = Some(LocalTime.parse("10:15:30")),
myLocalDateTime = Some(LocalDateTime.parse("2011-12-03T10:15:30")),
myUtilDate = Some(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2011-12-03T10:15:30.000")
),
myInstant = Some(Instant.parse("2011-12-03T10:15:30Z")),
myVarBinary = Some(new geny.Bytes(Array[Byte](1, 2, 3, 4, 5, 6, 7, 8))),
myUUID = Some(new java.util.UUID(1234567890L, 9876543210L)),
myEnum = Some(MyEnum.bar)
)

val rowNone = OptDataTypes[Sc](
myTinyInt = None,
mySmallInt = None,
myInt = None,
myBigInt = None,
myDouble = None,
myBoolean = None,
myLocalDate = None,
myLocalTime = None,
myLocalDateTime = None,
myUtilDate = None,
myInstant = None,
myVarBinary = None,
myUUID = None,
myEnum = None
)

db.run(
OptDataTypes.insert.values(rowSome, rowNone)
) ==> 2

db.run(OptDataTypes.select) ==> Seq(rowSome, rowNone)
}
)

}
}
}

0 comments on commit 8091ae3

Please sign in to comment.