Skip to content

Step #10 : Entity mapping

mandubian edited this page Nov 15, 2012 · 3 revisions
  // Dog definition
  case class Dog(name: String, age: Int)
  object DogSchema {
    val name = Attribute( KW(":dog/name"), SchemaType.string, Cardinality.one).withDoc("Dog's name")
    val age = Attribute( KW(":dog/age"), SchemaType.long, Cardinality.one).withDoc("Dog's age")

    val schema = Seq(name, age)
  }

  // Person definition
  case class Person(name: String, age: Int, dogs: Set[Ref[Dog]])

  object PersonSchema {
    val name = Attribute( KW(":person/name"), SchemaType.string, Cardinality.one).withDoc("Person's name")
    val age = Attribute( KW(":person/age"), SchemaType.long, Cardinality.one).withDoc("Person's age")
    val dogs = Attribute( KW(":person/dogs"), SchemaType.ref, Cardinality.many).withDoc("Person's dogs")

    val schema = Seq(name, age, dogs)
  }

  // provisions schemas (blocking here to simplify code ;) )
  Await.result(
    transact(PersonSchema.schema ++ DogSchema.schema),
    Duration("2 seconds")
  )

  // Typesafe Dog mappers based on Schema
  implicit val dogReader = (
    DogSchema.name.read[String] and 
    DogSchema.age.read[Int]
  )(Dog)

  implicit val dogWriter = (
    DogSchema.name.write[String] and 
    DogSchema.age.write[Int]
  )(unlift(Dog.unapply))

  // Typesafe Person mappers based on Schema
  implicit val personReader = (
    PersonSchema.name.read[String] and 
    PersonSchema.age.read[Int] and
    PersonSchema.dogs.read[Set[Ref[Dog]]]
  )(Person)

  implicit val personDogListWriter = (
    PersonSchema.name.write[String] and 
    PersonSchema.age.write[Int] and
    PersonSchema.dogs.write[Set[Ref[Dog]]]
  )(unlift(Person.unapply))


  // Creates Scala Data
  val medor = Dog("medor", 5)
  val tmpMedorId = DId(Partition.USER) // Temporary Id

  val brutus = Dog("brutus", 3)
  val tmpBrutusId = DId(Partition.USER)  // Temporary Id
      
  // creates person using previous tempids
  val toto = Person("toto", 30, Set(Ref(tmpMedorId)(medor), Ref(tmpBrutusId)(brutus)))
  val tmpTotoId = DId(Partition.USER) // Temporary Id

  // Provisioning Data to Datomic
  transact(
    toAddEntity(tmpMedorId)(medor),
    toAddEntity(tmpBrutusId)(brutus),
    toAddEntity(tmpTotoId)(toto)       // using temporary Id
  ).map{ tx =>
    // resolving final Ids
    tx.resolve(tmpMedorId, tmpBrutusId, tmpTotoId) match {
      case (Some(medorId), Some(brutusId), Some(totoId)) => 
        fromEntity[Person]( database.entity(totoId) ).map{ person => 
          person must beEqualTo(
            Person(
              "toto", 
              30, 
              Set(Ref(DId(medorId))(medor), Ref(DId(brutusId))(brutus)) // USING FINAL IDS 
           )
        )
      }
   }