Beam
RowType[T] provides conversion between Scala type T and a Beam Row, backed by a Beam Schema. Custom support for type T can be added with an implicit instance of RowField[T].
import java.net.URI
case class Inner(long: Long, str: String, uri: URI)
case class Outer(inner: Inner)
val record = Outer(Inner(1L, "hello", URI.create("https://www.spotify.com")))
import magnolify.beam.*
// Encode custom type URI as String
implicit val uriField: RowField[URI] = RowField.from[String](URI.create)(_.toString)
val rowType = RowType[Outer]
val row = rowType.to(record)
val copy: Outer = rowType.from(row)
// Beam Schema
val schema = rowType.schema
Enums
Enum-like types map to the Beam logical Enum type. See EnumType for more details. UnsafeEnum[T] instances are available from import magnolify.beam.unsafe.*.
Time and dates
Java and joda LocalDate types are available via import magnolify.beam.logical.date.*
For date-time, instants, and durations, use import magnolify.beam.logical.millis.*, import magnolify.beam.logical.micros.* or import magnolify.beam.logical.nanos.* as appropriate for your use-case. Note that joda types have only millisecond resolution, so excess precision will be discarded when used with micros or nanos.
Where possible, Beam logical types are used and joda types defer to these implementations:
- Beam’s
DATETIMEprimitive type maps to the millisecond-precision java and jodaInstants and the jodaDateTime. - The
DateTimelogical type is used for millisecond-precision java and jodaLocalDateTime - The
NanosInstantlogical type is used for nanosecond-precision java and jodaInstant - The
Timelogical type is used for nanosecond-precision java and jodaLocalTime - The
NanosDurationlogical type is used for java and jodaDuration
Beam’s MicrosInstant should not be used as it throws exceptions when presented with greater-than-microsecond precision data.
SQL types
SQL-compatible logical types are supported via import magnolify.beam.logical.sql.*
Case mapping
To use a different field case format in target records, add an optional CaseMapper argument to RowType:
import magnolify.beam.*
import magnolify.shared.CaseMapper
import com.google.common.base.CaseFormat
case class LowerCamel(firstName: String, lastName: String)
val toSnakeCase = CaseFormat.LOWER_CAMEL.converterTo(CaseFormat.LOWER_UNDERSCORE).convert _
val rowType = RowType[LowerCamel](CaseMapper(toSnakeCase))
rowType.to(LowerCamel("John", "Doe")) // Row(first_name: John, last_name: Doe)