ldbc v0.3.0-beta10 is released.
This release includes new feature additions, enhancements to existing features, disruptive changes and much more.
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-beta9.
Adding Codec
If both Encoder and Decoder were needed, each had to be defined. With this modification, a new Codec has been added, allowing Encoder and Decoder to be defined together.
enum Status:
case Active, InActive
-given Encoder[Status] = Encoder[Boolean].contramap {
- case Status.Active => true
- case Status.InActive => false
-}
-given Decoder[Status] = Decoder[Boolean].map {
- case true => Status.Active
- case false => Status.InActive
-}
+given Codec[Status] = Codec[Boolean].imap {
+ case true => Status.Active
+ case false => Status.InActive
+} {
+ case Status.Active => true
+ case Status.InActive => false
+}
It can also be used in place of a Decoder or Encoder by building a Codec.
-given Decoder[City] = (Decoder[Int] *: Decoder[String] *: Decoder[Int]).to[City]
+given Codec[City] = (Codec[Int] *: Codec[String] *: Codec[Int]).to[City]
Modified to allow Either to be used during Decoder construction.
This allows us to construct a process for cases that do not match the following pattern
enum Status(val code: Int):
case InActive extends Status(0)
case Active extends Status(1)
given Decoder[Status] = Decoder[Int].emap {
case 0 => Right(Status.InActive)
case 1 => Right(Status.Active)
case unknown => Left(s"$unknown is Unknown Status code")
}
This modification allows Codec to use Either for construction.
given Codec[Status] = Codec[Int].eimap {
case 0 => Right(Status.InActive)
case 1 => Right(Status.Active)
case unknown => Left(s"$unknown is Unknown Status code")
}(_.code)
Additional function
Allow additional conditions of Where to be conditionally excluded
TableQuery[City]
.select(_.name)
.where(_.population > 1000000)
.and(_.name == "Tokyo", false)
// SELECT name FROM city WHERE population > ?
Added a function to the Where conditional statement to determine whether to add a condition to the statement depending on the Option value.
val opt: Option[String] = ???
TableQuery[City]
.select(_.name)
.whereOpt(city => opt.map(value => city.name === value))
TableQuery[City]
.select(_.name)
.whereOpt(opt)((city, value) => city.name === value)
💣 Breaking Change
Modification of Encoder and Decoder into a composable form using twiddles.
The method of building custom-type Decoders has changed. With this modification, Decoder can be converted to any type using the map function.
- given Decoder.Elem[Continent] = Decoder.Elem.mapping[String, Continent](str => Continent.valueOf(str.replace(" ", "_")))
+ given Decoder[Continent] = Decoder[String].map(str => Continent.valueOf(str.replace(" ", "_")))
Decoder is still constructed implicitly.
case class City(id: Int, name: String, age: Int)
sql"SELECT id, name, age FROM city LIMIT 1"
.query[City]
.to[Option]
.readOnly(conn)
However, implicit searches may fail if there are many properties in the model.
[error] |Implicit search problem too large.
[error] |an implicit search was terminated with failure after trying 100000 expressions.
[error] |The root candidate for the search was:
[error] |
[error] | given instance given_Decoder_P in object Decoder for ldbc.dsl.codec.Decoder[City]}
In such cases, raising the search limit in the compilation options may resolve the problem.
scalacOptions += "-Ximplicit-search-limit:100000"
However, it may lead to amplification of compilation time. In that case, it can also be resolved by manually building the Decoder as follows.
given Decoder[City] = (Decoder[Int] *: Decoder[String] *: Decoder[Int]).to[City]
This is true not only for Decoder but also for Encoder.
Rename Executor to DBIO
The type used to represent IO to the DB was Executor, but this was changed because the DBIO type is more intuitive for the user.
- trait Executor[F[_]: Temporal, T]:
+ trait DBIO[F[_]: Temporal, T]:
Migrate table name designation to derived
The method of specifying the table name using query builder has been changed from passing it as an argument of TableQuery to passing it as an argument of Table's derived.
Before
case class City(
id: Int,
name: String,
countryCode: String,
district: String,
population: Int
) derives Table
val table = TableQuery[Test]("city")
After
case class City(
id: Int,
name: String,
countryCode: String,
district: String,
population: Int
)
object City:
given Table[City] = Table.derived[City]("city")
Renewal of Schema project
This modification changes the way Table types are constructed using the Schema project.
Below we will look at the construction of the Table type corresponding to the User model.
case class User(
id: Long,
name: String,
age: Option[Int],
)
Before
Until now, we had to create instances of Table directly; the arguments of Table had to be passed the corresponding columns in the same order as the properties possessed by the User class, and the data type of the columns had to be set as well, which was mandatory.
The TableQuery using this table type was implemented using Dynamic, which allows type-safe access, but the development tools could not do the completion.
This method of construction was also a bit slower in compile time than class generation
val userTable = Table[User]("user")(
column("id", BIGINT, AUTO_INCREMENT, PRIMARY_KEY),
column("name", VARCHAR(255)),
column("age", INT.UNSIGNED.DEFAULT(None)),
)
After
In this modification, Table type generation has been changed to a method of creating a class by extending Table. In addition, the data type of a column is no longer required, but can be set arbitrarily by the implementer.
This change to a construction method similar to that of Slick has made it more familiar to implementers.
class UserTable extends Table[User]("user"):
def id: Column[Long] = column[Long]("id")
def name: Column[String] = column[String]("name")
def age: Column[Option[Int]] = column[Option[Int]]("age")
override def * : Column[User] = (id *: name *: age).to[User]
The data type of the columns can still be set. This setting is used, for example, when generating a schema using this table class.
class UserTable extends Table[User]("user"):
def id: Column[Long] = column[Long]("id", BIGINT, AUTO_INCREMENT, PRIMARY_KEY)
def name: Column[String] = column[String]("name", VARCHAR(255))
def age: Column[Option[Int]] = column[Option[Int]]("age", INT.UNSIGNED.DEFAULT(None))
override def * : Column[User] = (id *: name *: age).to[User]
🚀 Features
- Feature/2024 12 create codec by @takapi327 in #349
💪 Enhancement
- Enhancement/2024 12 added where condition by @takapi327 in #338
- Enhancement/2024 12 encoder extensions by @takapi327 in #347
- Enhancement/2024 12 make encoder and decoder compatible with twiddles by @takapi327 in #348
- Enhancement/2025 01 make decoder support either by @takapi327 in #350
- Enhancement/2025 01 update where statement by @takapi327 in #353
🪲 Bug Fixes
- Bugfix/2024 12 fixed single column insert by @takapi327 in #343
- Bugfix/2025 01 table query macro error by @takapi327 in #354
🔧 Refactoring
- Refactor/2024 12 schema migration by @takapi327 in #333
- Refactor/2024 12 change use schema by @takapi327 in #334
- Reafactor/2024 12 schema project replacement by @takapi327 in #336
- Refactor/2024 12 migrate table name designation to derived by @takapi327 in #337
- Fixed column comment by @takapi327 in #339
- Fixed Encoder fold use summonAll by @takapi327 in #340
- Refactor/2024 12 change test specs2 to scalatest by @takapi327 in #341
- Refactor/2024 12 fixed on duplicate key update parameter by @takapi327 in #342
- Refactor/2024 12 rename executor by @takapi327 in #344
- Refactor/2025 01 fixed dbio warning by @takapi327 in #351
- Refactor/2025 01 added import sort rule by @takapi327 in #355
⛓️ Dependency update
- Update HikariCP from 6.1.0 to 6.2.1 by @scala-steward in #327
- Update otel4s-core-trace from 0.11.1 to 0.11.2 by @scala-steward in #332
- Update sbt, scripted-plugin from 1.10.6 to 1.10.7 by @scala-steward in #345
- Update sbt-typelevel, sbt-typelevel-site from 0.7.4 to 0.7.5 by @scala-steward in #346
- Dependencies/2025 01 update scala3 compiler 3.6.2 by @takapi327 in #352
Full Changelog: v0.3.0-beta9...v0.3.0-beta10