public
Created

neo4j fields and records with shapeless

  • Download Gist
neo4jTypes.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
import shapeless._
import shapeless.TypeOperators._
import shapeless.Record._
import shapeless.BasisConstraint._
import Neo4jTypesConstraints.OfNeo4jFieldsConstraint._
import Neo4jTypesConstraints._
import Neo4jTypes._
 
 
object Neo4jTypes {
 
// set of valid value types for a neo4j field
type ValueTypes = Int :: Boolean :: String :: Byte :: Long :: Float ::
Array[String] :: Array[Byte] :: Array[Long] ::
HNil
 
// set of valid key types for a neo4j field
type KeyTypes = String
 
// field schemas; they're declared as objects extending this class
class Neo4jField[V](label: KeyTypes)(implicit ev: OfNeo4jValueTypes[V]) extends Field[V] {}
 
trait Neo4jRecordAux {
type Fields <: HList
}
// record schemas; they're declared as objects extending this class
class Neo4jRecord[L <: HList](val fields: L)(implicit ev: OfNeo4jFields[L]) extends Neo4jRecordAux { override type Fields = L }
 
}
 
object Neo4jTypesConstraints {
 
// a value of this type is evidence of L having all elements Neo4jFields
trait OfNeo4jFieldsConstraint[L <: HList]
 
object OfNeo4jFieldsConstraint {
 
// an empty list is ok
implicit def hnilOfNeo4jFields = new OfNeo4jFieldsConstraint[HNil] {}
// head should be a field
implicit def hlistOfNeo4jFields[H <: Neo4jField[_], T <: HList](implicit ct: OfNeo4jFieldsConstraint[T]) =
new OfNeo4jFieldsConstraint[H :: T] {}
 
// accepts an HList where every element is x: Neo4jField[X]
def ofNeo4jFields[L <: HList](l: L)(implicit ev: OfNeo4jFields[L]) = true
}
 
// // a value of this type is evidence of V contained in Neo4jTypes.ValueTypes
type OfNeo4jValueTypes[V] = BasisConstraint[V :: HNil, ValueTypes]
// value of this type is evidence of L being of neo4j field schemas
type OfNeo4jFields[L <: HList] = OfNeo4jFieldsConstraint[L]
}
 
object FieldsTest {
// sample fields
case object age extends Neo4jField[Int](label = "age")
case object name extends Neo4jField[String](label = "name")
case object id extends Neo4jField[Int](label = "id")
// wrong value type, doesn't compile
// case object wrongField extends Neo4jField[URL](label = "uh")
// wrong key type, doesn't compile
// object data extends Neo4jField[Byte](label = 32)
 
// value checks
val x: age.valueType = 132
val anAgeEntry: FieldEntry[age.type] = (age -> 142)
// val nono: FieldEntry[age.type] = (age -> "uh")
}
 
object RecordsTest {
 
import FieldsTest._
 
// sample records
case object userProps extends Neo4jRecord(id :: name :: age :: HNil)
case object idProps extends Neo4jRecord(id :: HNil)
// you need to pass in Neo4jFields
// case object wrongRecord extends Neo4jRecord(id :: "yeah" :: HNil)
}
notWorking.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
import shapeless._
import shapeless.Record._
 
// this doesn't work, don't know why
object RecordConstraints {
 
import Neo4jTypes._
// witness of E being an entry of schema R
trait RecordConstraint[E <: HList, R <: HList]
type EntryOf[R <: HList] = {
type λ[E <: HList] = RecordConstraint[E, R]
}
 
// hnil is ok for every schema
implicit def hnilSchema[R <: HList] = new RecordConstraint[HNil, R] {}
// hcons
implicit def hlistSchema[F <: Neo4jField[_], V <: FieldEntry[F], T <: HList, R <: HList]
(implicit bct : RecordConstraint[T, R],
sel : Selector[R, F]
) = new RecordConstraint[ V :: T, R] {}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.