record4s

Conversions

From Something

Record.from creates a record from a Product, typically a case class instance.

import com.github.tarao.record4s.Record

case class Person(name: String, age: Int)

Record.from(Person("tarao", 3))
// res0: % {
//   val name: String
//   val age: Int
// } = %(name = tarao, age = 3)

Anything other than Product can be converted to a record if RecordLike instance is given.

To Something

You can use to method to convert a record to a Product.

%(name = "ikura", age = 1).to[Person]
// res1: Person = Person(name = "ikura", age = 1)

A record can be converted to anything other than Product if Converter instance is given.

From / To JSON

Records can be converted from/to JSON using circe. See Integration with circe for the detail.

In Scala.js, fromJSON and toJSON methods are available. See Converting a Record from / to a JSON string for the detail.

From / To JavaScript Objects

In Scala.js, fromJS and toJS methods are available. See Converting a Record from / to a Native JavaScript Object for the detail.

Upcast

Records can implicitly be upcast since their types are represented as structural types in Scala 3.

val person = %(name = "tarao", age = 3)
// person: % {
//   val name: String
//   val age: Int
// } = %(name = tarao, age = 3)

val named: % { val name: String } = person
// named: % {
//   val name: String
// } = %(name = tarao, age = 3)

Note that the runtime value still has statically hidden fields ⸺ age of named in the above example. This is because named points to the same object as person, where it has person.age.

To drop the hidden fields, use as method.

val named2 = person.as[% { val name: String }]
// named2: % {
//   val name: String
// } = %(name = tarao)

In this case, as makes a copy of person only with the visible fields.

Selecting / Unselecting / Reordering / Renaming

It is also possible to shrink a record to have selected fields.

import com.github.tarao.record4s.select

val person = %(name = "tarao", age = 3, email = "tarao@example.com")
// person: % {
//   val name: String
//   val age: Int
//   val email: String
// } = %(name = tarao, age = 3, email = tarao@example.com)

val contact = person(select.name.email)
// contact: % {
//   val name: String
//   val email: String
// } = %(name = tarao, email = tarao@example.com)

Or to unselect some fields.

import com.github.tarao.record4s.unselect

val contact = person(unselect.age)
// contact: % {
//   val name: String
//   val email: String
// } = %(name = tarao, email = tarao@example.com)

Field selection also supports reordering and renaming.

val account = person(
  select
    .email(rename = "login")
    .name(rename = "displayName"),
)
// account: % {
//   val login: String
//   val displayName: String
// } = %(login = tarao@example.com, displayName = tarao)

Note that the field order is semantically insignificant. You can always reorder the static type of the fields.

person
// res3: % {
//   val name: String
//   val age: Int
//   val email: String
// } = %(name = tarao, age = 3, email = tarao@example.com)

val person2: % {
  val email: String
  val age: Int
  val name: String
} = person
// person2: % {
//   val email: String
//   val age: Int
//   val name: String
// } = %(name = tarao, age = 3, email = tarao@example.com)