json and sql db serialization introduction with play! and slick

19
JSON OBJECTS RDBMS TO TO Stephen Kemmerling @42eng

Upload: stephen-kemmerling

Post on 10-May-2015

6.818 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Json and SQL DB serialization Introduction with Play! and Slick

JSON OBJECTS RDBMSTO TO

Stephen Kemmerling@42eng

Page 3: Json and SQL DB serialization Introduction with Play! and Slick

•OO Representation

•Handle JSON requests and convert to OO

•Save to DB/Load from DB

What do we need?

Page 4: Json and SQL DB serialization Introduction with Play! and Slick

• OO Representation

•Handle JSON requests and convert to OO

•Save to DB/Load from DB

What do we need?

Page 5: Json and SQL DB serialization Introduction with Play! and Slick

SCALA REPRESENTATION

case class Email(addr: String)

case class Contact( name: String, phone: Option[Int], email: Option[Email])

Page 6: Json and SQL DB serialization Introduction with Play! and Slick

•OO Representation

• Handle JSON requests and convert to OO

•Save to DB/Load from DB

What do we need?

Page 7: Json and SQL DB serialization Introduction with Play! and Slick

SENDING JSON RESPONSES

def lookup(name: String) = Action { request => val contacts : Seq[Contact] = loadFromDb(name) val contactsJson : Seq[JsValue] = contacts.map(Json.toJson(_)) Ok(JsArray(contactsJson))}

Page 8: Json and SQL DB serialization Introduction with Play! and Slick

TO/FROM JSON

trait Format[T] { def reads(json: JsValue): JsResult[T] def writes(obj: T): JsValue}

Page 9: Json and SQL DB serialization Introduction with Play! and Slick

MACROS!

object Contact { implicit val format: Format[Contact] = Json.format[Contact]}

Almost, but not quite: Can’t deal with Email

case class Email(addr: String)

case class Contact( name: String, phone: Option[Int], email: Option[Email])

MAGIC!

Page 10: Json and SQL DB serialization Introduction with Play! and Slick

FORMAT BY HAND

object Email { implicit format : Format[Email] = Json.format[Email]}

Let’s not be lazy

Page 11: Json and SQL DB serialization Introduction with Play! and Slick

FORMAT BY HANDobject Email { implicit val format = new Format[Email]{ def reads(json: JsValue) : JsResult[Email] = { json match{ case JsString(s) => JsSuccess(Email(s)) case _ => JsError() } }

def writes(email: Email) : JsValue = { JsString(email.addr) } }}

Page 12: Json and SQL DB serialization Introduction with Play! and Slick

ACCEPTING JSON REQUESTS

def store(name: String) = Action(parse.tolerantJson) { request => val phoneJson : JsValue = request.body \ "phone" val phone : Option[Int] = phoneJson.asOpt[Int] val email = (request.body \ "email").asOpt[Email] val contact = Contact(name, phone, email) saveToDb(contact)

Ok(“”)}

Page 13: Json and SQL DB serialization Introduction with Play! and Slick

ALL TOGETHER NOWdef lookup(name: String) = Action { request => val contacts : Seq[Contact] = loadFromDb(name) val contactsJson : Seq[JsValue] = contacts.map(Json.toJson(_)) Ok(JsArray(contactsJson))}

def store(name: String) = Action(parse.tolerantJson) { request => val phoneJson : JsValue = request.body \ "phone" val phone : Option[Int] = phoneJson.asOpt[Int] val email = (request.body \ "email").asOpt[Email] val contact = Contact(name, phone, email) saveToDb(contact) Ok(“”)}

Page 14: Json and SQL DB serialization Introduction with Play! and Slick

•OO Representation

•Handle JSON requests and convert to OO

• Save to DB/Load from DB

What do we need?

Page 15: Json and SQL DB serialization Introduction with Play! and Slick

SLICK TABLE DEFINITION

object Contacts extends Table[Contact]("contacts") { def name = column[String]("name", O.PrimaryKey) def phone = column[Int]("phone", O.Nullable) def email = column[Email]("email", O.Nullable) def * = name ~ phone.? ~ email.? <> (Contact.apply _, Contact.unapply _)}

Page 16: Json and SQL DB serialization Introduction with Play! and Slick

INSERTS AND LOOKUPS

def saveToDb(contact: Contact) = database.withSession{ implicit session: Session => Contacts.*.insert(contact) }

def loadFromDb(name: String) = database.withSession{ implicit session: Session => (for (row <- Contacts if row.name===name) yield row).list}

Page 17: Json and SQL DB serialization Introduction with Play! and Slick

SLICK TABLE DEFINITIONobject Contacts extends Table[Contact]("contacts") { def name = column[String]("name", O.PrimaryKey) def phone = column[Int]("phone", O.Nullable) def email = column[Email]("email", O.Nullable) def * = name ~ phone.? ~ email.? <> (Contact.apply _, Contact.unapply _)}

def saveToDb(contact: Contact) = database.withSession{ implicit session: Session => Contacts.*.insert(contact) }

def loadFromDb(name: String) = database.withSession{ implicit session: Session => (for (row <- Contacts if row.name===name) yield row).list}

Page 18: Json and SQL DB serialization Introduction with Play! and Slick

TYPE MAPPERimplicit object typeMapper extends BaseTypeMapper[Email] { def apply(profile: BasicProfile) : TypeMapperDelegate[Email] = { val delegate = profile.typeMapperDelegates.stringTypeMapperDelegate new TypeMapperDelegate[Email] { def sqlType = delegate.sqlType def setValue(value: Email, p: PositionedParameters) = delegate.setValue(value.addr, p) def setOption(valueOpt: Option[Email], p: PositionedParameters) = delegate.setOption(valueOpt.map(_.addr), p) def nextValue(r: PositionedResult): Email = Email(delegate.nextValue(r)) def sqlTypeName = delegate.sqlTypeName def updateValue(value: Email, r: PositionedResult) = delegate.updateValue(value.addr, r) def zero = Email("[email protected]") } }}

Page 19: Json and SQL DB serialization Introduction with Play! and Slick

case class Email(addr: String)

object Email { implicit val format = new

Format[Email]{ def reads(json: JsValue) :

JsResult[Email] = { json match{ case JsString(s) =>

JsSuccess(Email(s)) case _ => JsError()

} } def writes(email: Email) :

JsValue = { JsString(email.addr)

}

lookup(name: String) =

Action(parse.json) { request =>

contacts : Seq[Contact] =

loadFromDb(name) contactsJson : Seq[JsValue] =

contacts.map(Json.toJson(_))

Ok(JsArray(contactsJson)) store(name: String)

parse.json

object Contacts extends

Table[Contact]("contacts") {

def name = column[String]

("name", O.PrimaryKey)

def phone = column[Int]

("phone", O.Nullable) def email = column[Email]

("email", O.Nullable) def * = name ~ phone.? ~

email.? <> (Contact.apply _,

Contact.unapply _)}

def saveToDb(contact: Contact) =

database.withSession{ implicit

session: Session => Contacts.*.insert(contact

}

def

p: PositionedParameters) =

addr, p)

setOption(valueOpt: Option[Email], p:

PositionedParameters) = delegate.setOption(valueOpt.map(_.addr),

def nextValue(r: PositionedResult): Email =

Email(delegate.nextValue(r))

def sqlTypeName = delegate.sqlTypeName

def updateValue(value: Email, r: PositionedResult) =

delegate.updateValue(value.addr, r)

def zero = Email("[email protected]")

} }}

case class Contact( name: String, phone: Option[Int], email: Option[Email]

)

object Contact { implicit format : Format[Contact] = Json.

}

SOURCE: https://github.com/FortyTwoEng/Contacts-As-A-ServiceFOLLOW US: @42ENGJOIN US: 42GO.COM/JOIN_US.HTML