Skip to content

Instantly share code, notes, and snippets.

@pathikrit
Created April 29, 2020 15:07

Revisions

  1. pathikrit created this gist Apr 29, 2020.
    31 changes: 31 additions & 0 deletions Morph.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    import shapeless._, syntax.singleton._, record._, ops.hlist._

    /**
    * Given an instance A and it's generic representation AR and function f from AR => BR
    * we can covert A to B if we also have the generic representation of BR as B
    * We also handle misalignments using shapeless's align typeclass (https://stackoverflow.com/questions/29242873/shapeless-turn-a-case-class-into-another-with-fields-in-different-order)
    */
    case class Morph[A, AR](a: A)(implicit reprA: LabelledGeneric.Aux[A, AR]) {
    // Why this DSL you say? Hack to get around scalac idiocy: https://stackoverflow.com/a/46614684/471136
    def to[B] = new {
    //TODO: Add a better @ImplicitNotFound compile error message when a typo happens here
    def apply[BR <: HList, BR2 <: HList](f: AR => BR2)(implicit reprB: LabelledGeneric.Aux[B, BR], align: Align[BR2, BR]): B =
    reprB.from(align(f(reprA.to(a))))
    }
    }

    /*
    e.g.
    Morph(arm).to[CanonicalizedArmTransaction](_
    .:+('card_switch ->> arm.crd_port.map(_.take(3)))
    .:+('derived_deci_cd ->> arm.deci_cd.orElse(arm.crd_port.collect{case port if port.startsWith("PAS") => "A"}))
    .:+('canonical_mer_nm ->> canonical)
    .:+('canonical_mer_nm_clean ->> cleaned)
    .:+('canonicalized_acquirer_id ->> arm.acquirer_id.map(_.collapseWhiteSpaces.toUpperCase))
    .:+('canonicalized_crd_port ->> arm.crd_port.map(_.collapseWhiteSpaces.toUpperCase))
    .:+('canonicalized_sic_cd ->> arm.sic_cd.map(_.collapseWhiteSpaces.toUpperCase))
    .:+('canonicalized_mer_id ->> arm.mer_id.map(Canonicalizer.aggressivelySanitize).map(_.toUpperCase))
    )
    */