All Downloads are FREE. Search and download functionalities are using the official Maven repository.

neo4s.query.ExtractionProvider.scala Maven / Gradle / Ivy

The newest version!
package neo4s.query

import neo4s.query.QueryTools.ExtractionBehavior
import shapeless.labelled.{FieldType, field}
import shapeless.{::, HList, HNil, LabelledGeneric, Lazy, Typeable, Witness}

trait ExtractionProvider[T <: Product] {
  def from[R <: HList](values: Map[String, Any]): Option[T]
}

/** Factory for [[ExtractionProvider]] instances */
object ExtractionProvider {

  trait FromMap[L <: HList] {
    def apply(m: Map[String, Any]): Option[L]
  }

  trait LowPriorityFromMap {
    implicit def hconsFromMap1[K <: Symbol, V, T <: HList](implicit
      witness: Witness.Aux[K],
      typeable: Typeable[V],
      fromMapT: Lazy[FromMap[T]]
    ): FromMap[FieldType[K, V] :: T] = new FromMap[FieldType[K, V] :: T] {
      def apply(m: Map[String, Any]): Option[FieldType[K, V] :: T] = {

        def getOption(m: Map[String, Any], key: String): Option[Any] = {
          if (typeable.describe.take(6) == "Option") {
            if (m.contains(key)) m(key) match {
              case some@Some(_) => Some(some)
              case None => Some(None)
              case v => Some(Option(v))
            } else Some(None)
          } else m.get(key)
        }

        for {
          v <- getOption(m,witness.value.name)
          h <- typeable.cast(v)
          t <- fromMapT.value(m)
        } yield field[K](h) :: t
      }
    }
  }

  object FromMap extends LowPriorityFromMap {
    implicit val hnilFromMap: FromMap[HNil] = new FromMap[HNil] {
      def apply(m: Map[String, Any]): Option[HNil] = Some(HNil)
    }

    implicit def hconsFromMap0[K <: Symbol, V, R <: HList, T <: HList](implicit
      witness: Witness.Aux[K],
      gen: LabelledGeneric.Aux[V, R],
      fromMapH: FromMap[R],
      fromMapT: FromMap[T]
    ): FromMap[FieldType[K, V] :: T] = (m: Map[String, Any]) => {

      for {
        v <- m.get(witness.value.name)
        r <- Typeable[Map[String, Any]].cast(v)
        h <- fromMapH(r)
        t <- fromMapT(m)
      } yield field[K](gen.from(h)) :: t
    }
  }

  private [query] def defaultTypeMapper: PartialFunction[(String,Any),(String,Any)] = {
    case (name,value) => name->value
  }

  def apply[T <: Product](implicit extractionProvider: ExtractionProvider[T]): ExtractionProvider[T] = extractionProvider

  /** Default [[ExtractionProvider]] implementation
   * this is served implicitly whenever an implicit instance of [[ExtractionProvider]] is required but unavailable
   *
   * @param lGen implicit [[LabelledGeneric]] to extract [[HList]] from case class.
   * @tparam T type of element instance
   * @tparam R expected type of HList
   * @return [[ExtractionProvider]] instance
   */
  implicit def makeExtractionProvider[T <: Product, R <: HList](implicit lGen: LabelledGeneric.Aux[T, R], fromMap: FromMap[R], extractionBehavior: ExtractionBehavior = ExtractionBehavior()): ExtractionProvider[T] =
    new ExtractionProvider[T] {
      private def mapType: PartialFunction[(String,Any),(String,Any)] = extractionBehavior.typeMapper orElse defaultTypeMapper

      override def from[R <: HList](values: Map[String, Any]): Option[T] = {
        val mapped = values.map(mapType)
        fromMap(mapped).map(lGen.from)
      }

    }

  def extractorFor[T <: Product](implicit extractionProvider: ExtractionProvider[T]): ExtractionProvider[T] = extractionProvider

}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy