DSL extraction class field name

I am trying to create a DSL, but I have a problem: it applies to case classes, but I would like to know how the easiest way to extract the field names of the case class. One idea that I had in mind was to use a macro to enrich the type of my Case class, but I would rather not.

trait QueryDSL[CC] {

  def meta: CC

  implicit object StringIsFieldType extends Field[CC, String] {
    def name = "FakeNAME"
  }

  implicit def implQuery[V](b: V): Query[CC] = new Query[CC](meta)
  implicit def implField[V](b: V)(implicit ev: Field[CC, V]): QueryField[CC, V] = new QueryField(ev)
}

case class Query[CC](meta: CC, clauses: List[Clause[_]] = Nil) {

  def setProperty[F](clause: CC ⇒ Clause[F]): Query[CC] = copy(clauses = clause(meta) :: clauses)
}

trait Field[V, M] extends scala.AnyRef {
  def name: scala.Predef.String
}

abstract class Clause[V](val fieldName: String, value: V)
case class EqClause[V](override val fieldName: String, value: V) extends Clause[V](fieldName, value)

class QueryField[CC, M](field: Field[CC, M]) {
  def eqs(v: M) = EqClause(field.name, v)
}

/// #################

case class TestingCaseClass(displayName:String = "Bonjour", active:Boolean = false)
object Testing extends QueryDSL[TestingCaseClass] {
  def meta = new TestingCaseClass
}

import Testing._

val query = Testing setProperty(_.displayName eqs "Hallo")

I would like query.clauses to be: List (EqClause (displayName, Hallo)) at the moment it is: List (EqClause (FakeNAME, Hallo))

+4
source share
1 answer

Some thoughts

Given that I correctly tracked the conversion stream. Last lines

import Testing._
val query = Testing setProperty(_.displayName eqs "Hallo")

QueryDSL. Testing setProperty, Query implQuery. displayName, eqs, QueryField, implField, Field[TestingCaseClass, String]. StringIsFieldType.

val query = Testing.implQuery[QueryDSL[TestingCaseClass]](Testing).setProperty {
 (cc : TestingCaseClass) => Testing.implField[String](cc.displayName)(Testing.StringIsFieldType).eqs("Hallo")
}

, -

trait Field[CaseClassType, FieldName] {
  type typeOfThisField
}

FieldName String(name) ( , , ).

,

2.2.5 singleton-typed-literals:

import shapeless._

// Clauses

abstract class Clause[V](val fieldName: String, value: V)
case class EqClause[V](override val fieldName: String, value: V) extends Clause[V](fieldName, value)


// Fields

sealed abstract class Field[CC, FieldName] {
  // The name of the field
  val  fieldName: String

  // The type of the field
  type fieldType

  // How to extract this field
  def  get(cc : CC) : fieldType
}

object Field {
  // fieldType is existencial in Field but parametric in Fied.Aux
  // used to explict constraints on fieldType
  type Aux[CC, FieldName, fieldType_] = Field[CC, FieldName] {
    type fieldType = fieldType_
  }

  def apply[CC, fieldType_](fieldWitness : Witness.Lt[String], ext : CC => fieldType_) : Field.Aux[CC, fieldWitness.T, fieldType_] =
    new Field[CC, fieldWitness.T] {
      val fieldName  : String = fieldWitness.value
      type fieldType = fieldType_
      def get(cc : CC) : fieldType = ext(cc)
    }
}

// Queries

case class Query[CC](meta: CC, clauses: List[Clause[_]] = Nil) {
  def setProperty[F](clause: CC ⇒ Clause[F]): Query[CC] = copy(clauses = clause(meta) :: clauses)
}

class QueryField[CC, M](field: Field.Aux[CC, _, M]) {
  def eqs(v: M) = EqClause(field.fieldName, v)
}


trait QueryDSL[CC] {

  def meta: CC

  implicit def implQuery[V](b: V): Query[CC] = new Query[CC](meta)
  implicit def implField[fieldName, V](b: V)(implicit ev:     Field.Aux[CC, fieldName, V]): QueryField[CC, V] = new QueryField(ev)
}

/// #################


object Example extends App {

  case class TestingCaseClass(displayName:String = "Bonjour",     active:Boolean = false)

  implicit val displayName = Field(Witness("displayName"), (cc : TestingCaseClass) => cc.displayName)
  implicit val active      = Field(Witness("active")     , (cc : TestingCaseClass) => cc.active     )


  object Testing extends QueryDSL[TestingCaseClass] {
    def meta = new TestingCaseClass
  }

  import Testing._

  val queryDisplayName = Testing setProperty(_.displayName eqs "Hallo")
  println(s"queryDisplayName = $queryDisplayName")

  val queryActive = Testing setProperty(_.active eqs true)
  println(s"queryActive = $queryActive")
}
+5

Source: https://habr.com/ru/post/1598345/


All Articles