Skip to content

v0.3.0-beta8

Latest
Compare
Choose a tag to compare
@takapi327 takapi327 released this 29 Sep 08:24
· 237 commits to master since this release
9bd7404

ldbc v0.3.0-beta8 is released.
This release adds enhancements to existing features.

Note

ldbc is pre-1.0 software and is still undergoing active development. New versions are not binary compatible with prior versions, although in most cases user code will be source compatible.
The major version will be the stable version.

What's Changed

Caution

This version is not compatible with the previous version, v0.3.0-beta7.

Bug Fix

The process to retrieve records by matching the table name and column name, such as when using JOIN, does not work as intended.

sql"SELECT c.Id, c.Name, ct.Code, ct.Name FROM city AS c JOIN country AS ct ON c.CountryCode = ct.Code"
  .query[(Int, String, String, String)]

There is no problem in retrieving records by specifying the Index, but when retrieving records by specifying the column name internally, the records are not retrieved correctly because they are retrieved as Id instead of c.Id.

JDBC allows the retrieval of records by the combination of table name and column name, so the modification was made accordingly.

https://github.com/mysql/mysql-connector-j/blob/release/8.x/src/main/core-impl/java/com/mysql/cj/result/DefaultColumnDefinition.java#L204-L210

Support for custom data types (Breaking change)

When using user-defined data types, custom data types were supported using ResultSetReader and Parameter.

With this update, the method of supporting custom data types using ResultSetReader and Parameter has changed.

Encoder

Change from Parameter to Encoder for dynamic embedding in query strings.

This eliminates the need for the user to write a redundant process to receive the Effect Type, and allows for simpler implementation and use of custom data types as parameters.

enum Status(val code: Int, val name: String):
  case Active   extends Status(1, "Active")
  case InActive extends Status(2, "InActive")

Before

given Parameter[Status] with
  override def bind[F[_]](
    statement: PreparedStatement[F],
    index: Int,
    status: Status
  ): F[Unit] = statement.setInt(index, status.code)

After

given Encoder[Status] with
  override def encode(status: Status): Int = status.done

Encoder's encoding process can only return Scala types that can be handled by PreparedStatement.

The following types are supported at this time.

Scala Type Methods called in PreparedStatement
Boolean setBoolean
Byte setByte
Short setShort
Int setInt
Long setLong
Float setFloat
Double setDouble
BigDecimal setBigDecimal
String setString
Array[Byte] setBytes
java.time.LocalDate setDate
java.time.LocalTime setTime
java.time.LocalDateTime setTimestamp
None setNull

Decoder

Change the process of getting data from ResultSet from ResultSetReader to Decoder.

This allows users to convert retrieved records into nested hierarchical data.

case class City(id: Int, name: String, countryCode: String)
case class Country(code: String, name: String)
case class CityWithCountry(city: City, country: Country)

sql"SELECT city.Id, city.Name, city.CountryCode, country.Code, country.Name FROM city JOIN country ON city.CountryCode = country.Code".query[CityWithCountry]

Using Query Builder

case class City(id: Int, name: String, countryCode: String) derives Table
case class Country(code: String, name: String) derives Table

val city = Table[City]
val country = Table[Country]

city.join(country).join((city, country) => city.countryCode === country.code)
  .select((city, country) => (city.name, country.name))
  .query // (String, String)
  .to[Option]
  

city.join(country).join((city, country) => city.countryCode === country.code)
  .selectAll
  .query // (City, Country)
  .to[Option]
Custom type decoding

Decoding of custom types will change from ResultSetReader to the following

Before

enum Custom:
  case ...

given ResultSetReader[IO, Custom] =
  ResultSetReader.mapping[IO, str, Custom](str => Custom.valueOf(str))

After

enum Custom:
  case ...

given Decoder.Elem[Custom] =
  Decoder.Elem.mapping[String, Custom](str => Custom.valueOf(str))

Query (Breaking Change)

When using selectAll in a query built with Query Builder, the type that could be obtained with query was a Tuple type consisting of all records in the selected table. Therefore, conversion to the model corresponding to the table had to be done explicitly using queryTo.

This was redundant, and if the user wanted to retrieve all the records, the application would have taken that model as the income.

Therefore, the change has been made so that selections made with selectAll are converted directly into models when query is used. If you use select to retrieve only specific records, the query will still be of type Tuple. Conversion to the specified model can still be done using queryTo.

Before

case class City(id: Int, name: String, countryCode: String) derives Table

city.selectAll.query // (Int, String, String)

After

case class City(id: Int, name: String, countryCode: String) derives Table

city.selectAll.query // City

🪲 Bug Fixes

🔧 Refactoring

⛓️ Dependency update

Full Changelog: v0.3.0-beta7...v0.3.0-beta8