Skip to content

Instantly share code, notes, and snippets.

@eparejatobes
Created February 17, 2012 17:48
Show Gist options
  • Save eparejatobes/1854586 to your computer and use it in GitHub Desktop.
Save eparejatobes/1854586 to your computer and use it in GitHub Desktop.
neo4j fields and records with shapeless
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)
}
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] {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment