icon

See original announcement on the Scala user list. For more information, see gallia-core documentation, in particular the Macros section.

Description

Allows the following:

import aptus._
import gallia._
import gallia.macros._

// ======================================================================
// single object

assert(  toHeadMacro        (johnStatic).forceAObj == johnHead.forceAObj)
assert(fromHeadMacro[Person](johnHead)             == johnStatic)

// ----------------------------------------------------------------------
assert(  toAObjMacro        (johnStatic)           == johnDynamic)
assert(fromAObjMacro[Person](johnDynamic)          == johnStatic)

// ----------------------------------------------------------------------
// data only
assert(  toObjMacro         (johnStatic)           == johnDynamic.data)
assert(fromObjMacro[Person] (johnDynamic.data)     == johnStatic)

// ----------------------------------------------------------------------
// schema
assert(  toClsMacro         (johnStatic)           == johnDynamic.schema)
assert(  toClsMacro         [Person]               == johnDynamic.schema)
// a "from" counterpart wouldn't make much sense

// ===========================================================================
// multiple objects

// ... same as above but with:
//   - List[Person] instead of Person
//   - AObjs/Objs   instead of AObj/Obj

Assumming the following metadata (schemas):

case class Person(name: String, age: Int, phones: Seq[String], addresses: Seq[Address])
  case class Address(street: String, city: String, primary: Boolean)    

case class PersonAlt(first: String, last: String, phones: Seq[String], addresses: Seq[Address])

// ---------------------------------------------------------------------------
private val PersonGalliaClass = 
  cls(
      "name"      .string,
      "age"       .int,
      "phones"    .strings,
      "addresses" .clss(
          "street" .string,
          "city"   .string,
          "primary".boolean))

and data:

private val johnStatic: Person =
  Person(
      name      = "John Smith",
      age       = 32,
      phones    = Seq("123-456-7890", "098-765-4321"),
      addresses = Seq(
        Address("3 Orion Street", "Toronto", primary = true),
        Address("2 Belle Blvd"  , "Lyon",    primary = false)))

// ---------------------------------------------------------------------------
private val johnDynamic: AObj =
  aobj(PersonGalliaClass)(obj(
    "name"      -> "John Smith",
    "age"       -> 32,
    "phones"    -> Seq("123-456-7890", "098-765-4321"),
    "addresses" -> Seq(
        obj("street" -> "3 Orion Street", "city" -> "Toronto", "primary" -> true),
        obj("street" -> "2 Belle Blvd"  , "city" -> "Lyon",    "primary" -> false))) )
        
// ---------------------------------------------------------------------------
val johnHead: HeadO = johnDynamic // for readability        

Of course the point is actually to apply transformations, eg:

toHeadMacro(johnStatic)
  .toUpperCase('name)
  // ...
  .printCompactJson()    

Preferably to other case classes after a long and convoluted journey:

toHeadMacro(johnStatic)
    .fission(_.string("name")).as("first", "last").using(_.splitBy(" ", 2).force.tuple2)
    // ...
  .pipe(fromHeadMacro[PersonAlt](_))
  .assert(_ == PersonAlt("John", "Smith", johnStatic.phones, johnStatic.addresses))

Limitations

  • Error handling is minimal at this point, and error messages are not easy to interpret as a result
  • Case classes are expected to be in scope for now , that is one must use import my.pck.MyCC; toHeadMacro(MyCC(foo = "bar"))), not toHeadMacro(my.pck.MyCC(foo = "bar"))) (see corresponding task)
  • There is no proper check of schema compliance for the data (more generally relates to this task)

These will be addressed in the future.

Contact

You may contact the author at: