Embedding a language into string interpolator
-
Upload
michael-limansky -
Category
Engineering
-
view
104 -
download
1
Transcript of Embedding a language into string interpolator
![Page 1: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/1.jpg)
N
Embedding a language into stringinterpolator
Mikhail LimanskiyJune 10, 2015
![Page 2: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/2.jpg)
String interpolation is easy
val language = "English"
val embedded = s"Embedded $language"
![Page 3: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/3.jpg)
String interpolation is easy
val language = "English"
val embedded = s"Embedded $language"
![Page 4: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/4.jpg)
MongoDB
MongoDB is a document oriented database, storing BSON documents.db.people.insert({ name: "John Doe", age: 42 })
db.people.insert({name: "William Smith",age: 28,phone: [ "1234567", "7654321" ]})
db.people.insert({name: "Alice White",age: 29,address: {
country: "UK",city: "London"
}})db.people.insert({ name : "Ivan Petrov", age : 28 })
![Page 5: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/5.jpg)
MongoDB
MongoDB is a document oriented database, storing BSON documents.db.people.insert({ name: "John Doe", age: 42 })db.people.insert({
name: "William Smith",age: 28,phone: [ "1234567", "7654321" ]})
db.people.insert({name: "Alice White",age: 29,address: {
country: "UK",city: "London"
}})db.people.insert({ name : "Ivan Petrov", age : 28 })
![Page 6: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/6.jpg)
MongoDB
MongoDB is a document oriented database, storing BSON documents.db.people.insert({ name: "John Doe", age: 42 })db.people.insert({
name: "William Smith",age: 28,phone: [ "1234567", "7654321" ]})
db.people.insert({name: "Alice White",age: 29,address: {
country: "UK",city: "London"
}})
db.people.insert({ name : "Ivan Petrov", age : 28 })
![Page 7: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/7.jpg)
MongoDB
MongoDB is a document oriented database, storing BSON documents.db.people.insert({ name: "John Doe", age: 42 })db.people.insert({
name: "William Smith",age: 28,phone: [ "1234567", "7654321" ]})
db.people.insert({name: "Alice White",age: 29,address: {
country: "UK",city: "London"
}})db.people.insert({ name : "Ivan Petrov", age : 28 })
![Page 8: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/8.jpg)
Search and update
Quering:db.people.find({ name: "John Doe"})db.people.find({ age: { $lt : 30 }})db.people.find({ phone: { $not: { $size : 0 }}})
db.people.update({ age : 42},{ $set : { name : "Ford Prefect" } })
db.people.aggregate([ { $group : { _id : "$age", count : {$sum : 1} } },
{ $sort : { count : -1 } },{ $limit : 5 }
])
![Page 9: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/9.jpg)
Search and update
Quering:db.people.find({ name: "John Doe"})db.people.find({ age: { $lt : 30 }})db.people.find({ phone: { $not: { $size : 0 }}})
db.people.update({ age : 42},{ $set : { name : "Ford Prefect" } })
db.people.aggregate([ { $group : { _id : "$age", count : {$sum : 1} } },
{ $sort : { count : -1 } },{ $limit : 5 }
])
![Page 10: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/10.jpg)
Search and update
Quering:db.people.find({ name: "John Doe"})db.people.find({ age: { $lt : 30 }})db.people.find({ phone: { $not: { $size : 0 }}})
db.people.update({ age : 42},{ $set : { name : "Ford Prefect" } })
db.people.aggregate([ { $group : { _id : "$age", count : {$sum : 1} } },
{ $sort : { count : -1 } },{ $limit : 5 }
])
![Page 11: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/11.jpg)
MongoDB in Scala
There are three main drivers for MongoDB:
I Casbah – synchronous, on top of Java driver.
I ReactiveMongo – asynchronous, built on Akka actors.I Tepkin – reactive, on top of Akka IO and Akka Streams.
![Page 12: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/12.jpg)
MongoDB in Scala
There are three main drivers for MongoDB:
I Casbah – synchronous, on top of Java driver.I ReactiveMongo – asynchronous, built on Akka actors.
I Tepkin – reactive, on top of Akka IO and Akka Streams.
![Page 13: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/13.jpg)
MongoDB in Scala
There are three main drivers for MongoDB:
I Casbah – synchronous, on top of Java driver.I ReactiveMongo – asynchronous, built on Akka actors.I Tepkin – reactive, on top of Akka IO and Akka Streams.
![Page 14: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/14.jpg)
How Casbah API looks like
val name = "John Doe"
people.insert(MongoDBObject("name" -> "James Bond","age" -> 80,"phone" -> List("007007"),"address" -> MongoDBObject("country" -> "UK")))
val a = people.findOne(MongoDBObject("name" -> name))val b = people.find(MongoDBObject("age" ->
MongoDBObject("$lt" -> 30)))
// Using Casbah DSLval c = people.find("age" $lt 30)val d = people.find("phone" -> $not(_ $size 0))
people.update(MongoDBObject("age" -> 42),$set("name" -> "Ford Prefect"))
val e = people.aggregate(List(MongoDBObject("$group" ->
MongoDBObject("_id" -> "$age", "count" ->MongoDBObject("$sum" -> 1))),
MongoDBObject("$sort" -> MongoDBObject("count" -> -1)),MongoDBObject("$limit" -> 5)))
![Page 15: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/15.jpg)
How Casbah API looks like
val name = "John Doe"
people.insert(MongoDBObject("name" -> "James Bond","age" -> 80,"phone" -> List("007007"),"address" -> MongoDBObject("country" -> "UK")))
val a = people.findOne(MongoDBObject("name" -> name))val b = people.find(MongoDBObject("age" ->
MongoDBObject("$lt" -> 30)))
// Using Casbah DSLval c = people.find("age" $lt 30)val d = people.find("phone" -> $not(_ $size 0))
people.update(MongoDBObject("age" -> 42),$set("name" -> "Ford Prefect"))
val e = people.aggregate(List(MongoDBObject("$group" ->
MongoDBObject("_id" -> "$age", "count" ->MongoDBObject("$sum" -> 1))),
MongoDBObject("$sort" -> MongoDBObject("count" -> -1)),MongoDBObject("$limit" -> 5)))
![Page 16: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/16.jpg)
How Casbah API looks like
val name = "John Doe"
people.insert(MongoDBObject("name" -> "James Bond","age" -> 80,"phone" -> List("007007"),"address" -> MongoDBObject("country" -> "UK")))
val a = people.findOne(MongoDBObject("name" -> name))val b = people.find(MongoDBObject("age" ->
MongoDBObject("$lt" -> 30)))
// Using Casbah DSLval c = people.find("age" $lt 30)val d = people.find("phone" -> $not(_ $size 0))
people.update(MongoDBObject("age" -> 42),$set("name" -> "Ford Prefect"))
val e = people.aggregate(List(MongoDBObject("$group" ->
MongoDBObject("_id" -> "$age", "count" ->MongoDBObject("$sum" -> 1))),
MongoDBObject("$sort" -> MongoDBObject("count" -> -1)),MongoDBObject("$limit" -> 5)))
![Page 17: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/17.jpg)
How Casbah API looks like
val name = "John Doe"
people.insert(MongoDBObject("name" -> "James Bond","age" -> 80,"phone" -> List("007007"),"address" -> MongoDBObject("country" -> "UK")))
val a = people.findOne(MongoDBObject("name" -> name))val b = people.find(MongoDBObject("age" ->
MongoDBObject("$lt" -> 30)))
// Using Casbah DSLval c = people.find("age" $lt 30)val d = people.find("phone" -> $not(_ $size 0))
people.update(MongoDBObject("age" -> 42),$set("name" -> "Ford Prefect"))
val e = people.aggregate(List(MongoDBObject("$group" ->
MongoDBObject("_id" -> "$age", "count" ->MongoDBObject("$sum" -> 1))),
MongoDBObject("$sort" -> MongoDBObject("count" -> -1)),MongoDBObject("$limit" -> 5)))
![Page 18: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/18.jpg)
How Casbah API looks like
val name = "John Doe"
people.insert(MongoDBObject("name" -> "James Bond","age" -> 80,"phone" -> List("007007"),"address" -> MongoDBObject("country" -> "UK")))
val a = people.findOne(MongoDBObject("name" -> name))val b = people.find(MongoDBObject("age" ->
MongoDBObject("$lt" -> 30)))
// Using Casbah DSLval c = people.find("age" $lt 30)val d = people.find("phone" -> $not(_ $size 0))
people.update(MongoDBObject("age" -> 42),$set("name" -> "Ford Prefect"))
val e = people.aggregate(List(MongoDBObject("$group" ->
MongoDBObject("_id" -> "$age", "count" ->MongoDBObject("$sum" -> 1))),
MongoDBObject("$sort" -> MongoDBObject("count" -> -1)),MongoDBObject("$limit" -> 5)))
![Page 19: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/19.jpg)
How Casbah API looks like
![Page 20: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/20.jpg)
ReactiveMongo
// Future[BSONDocument]val a = people.find(BSONDocument("name" -> "John Doe"))
.one[BSONDocument]
// Future[List[Person]]val b = people.find(BSONDocument("age" ->
BSONDocument("$lt" -> 30))).cursor[Person].collect[List]()
val futureUpdate = people.update(BSONDocument("age" -> 42),BSONDocument("$set" -> BSONDocument("name" -> "Ford Prefect")))
// Futureval e = db.command(RawCommand(BSONDocument(
"aggregate" -> "people","pipeline" -> BSONArray(
BSONDocument("$group" ->BSONDocument("_id" -> "$age",
"count" -> BSONDocument("$sum" -> 1))),BSONDocument("$sort" -> BSONDocument("count" -> -1)),BSONDocument("$limit" -> 5)))))
![Page 21: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/21.jpg)
Why?
![Page 22: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/22.jpg)
Meet MongoQuery
Using MongoQuery with Casbah:import com.github.limansky.mongoquery.casbah._
val name = "John Doe"
val a = people.findOne(mq"{ name : $name }")
val b = people.find(mq"{age : { $$lt : 30 }}")
val d = people.find(mq"{ phone : { $$not : { $$size : 0 }}}")
people.update(mq"{ age : 42 }",mq"{ $$set { name : 'Ford Prefect' }}")
val e = people.aggregate(List(mq"""{ $$group :
{ _id : "$$age", count : { $$sum : 1 }}}""",mq"{ $$sort : { count : -1 }}",mq"{ $$limit : 5}"))
![Page 23: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/23.jpg)
Meet MongoQuery
Using MongoQuery with Casbah:import com.github.limansky.mongoquery.casbah._
val name = "John Doe"
val a = people.findOne(mq"{ name : $name }")val b = people.find(mq"{age : { $$lt : 30 }}")
val d = people.find(mq"{ phone : { $$not : { $$size : 0 }}}")
people.update(mq"{ age : 42 }",mq"{ $$set { name : 'Ford Prefect' }}")
val e = people.aggregate(List(mq"""{ $$group :
{ _id : "$$age", count : { $$sum : 1 }}}""",mq"{ $$sort : { count : -1 }}",mq"{ $$limit : 5}"))
![Page 24: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/24.jpg)
Meet MongoQuery
Using MongoQuery with Casbah:import com.github.limansky.mongoquery.casbah._
val name = "John Doe"
val a = people.findOne(mq"{ name : $name }")val b = people.find(mq"{age : { $$lt : 30 }}")
val d = people.find(mq"{ phone : { $$not : { $$size : 0 }}}")
people.update(mq"{ age : 42 }",mq"{ $$set { name : 'Ford Prefect' }}")
val e = people.aggregate(List(mq"""{ $$group :
{ _id : "$$age", count : { $$sum : 1 }}}""",mq"{ $$sort : { count : -1 }}",mq"{ $$limit : 5}"))
![Page 25: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/25.jpg)
String interpolation
implicit class MongoHelper(val sc: StringContext)extends AnyVal {
def mq(args: Any*): DBObject = {Parser.parseQuery(sc.parts, args) match {
case Success(v, _) =>createObject(v)
case NoSuccess(msg, _) =>throw new MqException(s"Invalid object: $msg")
}}
}
mq"{ name : $name }"
sc.parts == List("{ name: ", " }")args = List(name)
![Page 26: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/26.jpg)
String interpolation
implicit class MongoHelper(val sc: StringContext)extends AnyVal {
def mq(args: Any*): DBObject = {Parser.parseQuery(sc.parts, args) match {
case Success(v, _) =>createObject(v)
case NoSuccess(msg, _) =>throw new MqException(s"Invalid object: $msg")
}}
}
mq"{ name : $name }"
sc.parts == List("{ name: ", " }")args = List(name)
![Page 27: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/27.jpg)
String interpolation
![Page 28: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/28.jpg)
Wrapping it into macro
implicit class MongoHelper(val sc: StringContext) extends AnyVal {def mq(args: Any*): DBObject = macro MongoHelper.mq_impl
}
object MongoHelper {def mq_impl(c: Context)(args: c.Expr[Any]*):
c.Expr[DBObject] = ???}
![Page 29: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/29.jpg)
Wrapping it into macro
implicit class MongoHelper(val sc: StringContext) extends AnyVal {def mq(args: Any*): DBObject = macro MongoHelper.mq_impl
}
object MongoHelper {def mq_impl(c: Context)(args: c.Expr[Any]*):
c.Expr[DBObject] = {import c.universe._
val q"$cn(scala.StringContext.apply(..$pTrees))"= c.prefix.tree
val parsed = parse(c)(pTrees)wrapObject(c)(parsed, args.map(_.tree).iterator)
}}
![Page 30: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/30.jpg)
Wrapping it into macro
object MongoHelper {
def parse(c: Context)(pTrees: List[c.Tree]) = {import c.universe._
val parts = pTrees map {case Literal(Constant(s: String)) => s
}
parser.parse(parts) match {case Success(v, _) => vcase NoSuccess(msg, reader) =>
val partIndex = reader.asInstanceOf[PartReader].partval pos = pTrees(partIndex).posc.abort(pos.withPoint(pos.point + reader.offset)),
s"Invalid BSON object: $msg")}
}}
![Page 31: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/31.jpg)
Parsing BSON
mq"{ name : $name, age : { $$gte : 18, $$lte : $max }}"
Lexical
List("{", Field("name"), ":", Placeholder , ",", Field("age"),":", "{", Keyword("$gte"), ":", NumericLit(18), ",",Keyword("$lte"), ":", Placeholder , ",", "}", "}")
Syntactical
Object(List((Member("name"), Placeholder),(Member("age"), Object(List(
(Keyword("$gte"), 18),(Keyword("$lte"), Placeholder))
))))
![Page 32: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/32.jpg)
Parsing BSON
mq"{ name : $name, age : { $$gte : 18, $$lte : $max }}"
Lexical
List("{", Field("name"), ":", Placeholder , ",", Field("age"),":", "{", Keyword("$gte"), ":", NumericLit(18), ",",Keyword("$lte"), ":", Placeholder , ",", "}", "}")
Syntactical
Object(List((Member("name"), Placeholder),(Member("age"), Object(List(
(Keyword("$gte"), 18),(Keyword("$lte"), Placeholder))
))))
![Page 33: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/33.jpg)
Parsing BSON
mq"{ name : $name, age : { $$gte : 18, $$lte : $max }}"
Lexical
List("{", Field("name"), ":", Placeholder , ",", Field("age"),":", "{", Keyword("$gte"), ":", NumericLit(18), ",",Keyword("$lte"), ":", Placeholder , ",", "}", "}")
Syntactical
Object(List((Member("name"), Placeholder),(Member("age"), Object(List(
(Keyword("$gte"), 18),(Keyword("$lte"), Placeholder))
))))
![Page 34: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/34.jpg)
Create objects
protected def wrapObject(c: Context)(obj: Object,args: Iterator[c.Tree]): c.Expr[DBType] = {
val dbparts = obj.members.map {case (lv, v) => (lv.asString , wrapValue(c)(v, args))
}
c.Expr(q"com.mongodb.casbah.commons.MongoDBObject(..$dbparts)")}
![Page 35: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/35.jpg)
Wrapping values
protected def wrapValue(c: Context) (value: Any,args: Iterator[c.Tree]): c.Expr[Any] = {
import c.universe._value match {
case BSON.Placeholder =>c.Expr(args.next())
case o: BSON.Object =>wrapObject(c)(o, args)
case BSON.Id(id) =>c.Expr(q"new org.bson.types.ObjectId($id)")
case a: List[_] =>val wrapped = a.map(i => wrapValue(c)(i, args))c.Expr[List[Any]](q"List(..$wrapped)")
case v =>c.Expr[Any](Literal(Constant(v)))
}}
![Page 36: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/36.jpg)
Wrapping values
protected def wrapValue(c: Context) (value: Any,args: Iterator[c.Tree]): c.Expr[Any] = {
import c.universe._value match {
case BSON.Placeholder =>c.Expr(args.next())
case o: BSON.Object =>wrapObject(c)(o, args)
case BSON.Id(id) =>c.Expr(q"new org.bson.types.ObjectId($id)")
case a: List[_] =>val wrapped = a.map(i => wrapValue(c)(i, args))c.Expr[List[Any]](q"List(..$wrapped)")
case v =>c.Expr[Any](Literal(Constant(v)))
}}
![Page 37: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/37.jpg)
Wrapping values
protected def wrapValue(c: Context) (value: Any,args: Iterator[c.Tree]): c.Expr[Any] = {
import c.universe._value match {
case BSON.Placeholder =>c.Expr(args.next())
case o: BSON.Object =>wrapObject(c)(o, args)
case BSON.Id(id) =>c.Expr(q"new org.bson.types.ObjectId($id)")
case a: List[_] =>val wrapped = a.map(i => wrapValue(c)(i, args))c.Expr[List[Any]](q"List(..$wrapped)")
case v =>c.Expr[Any](Literal(Constant(v)))
}}
![Page 38: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/38.jpg)
Wrapping values
protected def wrapValue(c: Context) (value: Any,args: Iterator[c.Tree]): c.Expr[Any] = {
import c.universe._value match {
case BSON.Placeholder =>c.Expr(args.next())
case o: BSON.Object =>wrapObject(c)(o, args)
case BSON.Id(id) =>c.Expr(q"new org.bson.types.ObjectId($id)")
case a: List[_] =>val wrapped = a.map(i => wrapValue(c)(i, args))c.Expr[List[Any]](q"List(..$wrapped)")
case v =>c.Expr[Any](Literal(Constant(v)))
}}
![Page 39: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/39.jpg)
Wrapping values
protected def wrapValue(c: Context) (value: Any,args: Iterator[c.Tree]): c.Expr[Any] = {
import c.universe._value match {
case BSON.Placeholder =>c.Expr(args.next())
case o: BSON.Object =>wrapObject(c)(o, args)
case BSON.Id(id) =>c.Expr(q"new org.bson.types.ObjectId($id)")
case a: List[_] =>val wrapped = a.map(i => wrapValue(c)(i, args))c.Expr[List[Any]](q"List(..$wrapped)")
case v =>c.Expr[Any](Literal(Constant(v)))
}}
![Page 40: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/40.jpg)
Type safety
![Page 41: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/41.jpg)
mqt – typechecking interpolator
case class Phone(kind: String, number: String)case class Person(name: String, age: Int, phone: List[Phone])
// OKpersons.update(mq"{}", mqt"{ $$inc : { age : 1 } }"[Person])persons.find(mqt"{ phone.number : '223322' }"[Person])
// COMPILE ERRORpersons.update(mq"{}", mqt"""{$$set : { nme : "Joe" }}"""[Person])persons.find(mqt"{ name.1 : 'Joe' }"[Person])persons.find(mqt"{ phone.num : '223322' }"[Person])
![Page 42: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/42.jpg)
mqt – typechecking interpolator
case class Phone(kind: String, number: String)case class Person(name: String, age: Int, phone: List[Phone])
// OKpersons.update(mq"{}", mqt"{ $$inc : { age : 1 } }"[Person])persons.find(mqt"{ phone.number : '223322' }"[Person])
// COMPILE ERRORpersons.update(mq"{}", mqt"""{$$set : { nme : "Joe" }}"""[Person])persons.find(mqt"{ name.1 : 'Joe' }"[Person])persons.find(mqt"{ phone.num : '223322' }"[Person])
![Page 43: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/43.jpg)
mqt – typechecking interpolator
case class Phone(kind: String, number: String)case class Person(name: String, age: Int, phone: List[Phone])
// OKpersons.update(mq"{}", mqt"{ $$inc : { age : 1 } }"[Person])persons.find(mqt"{ phone.number : '223322' }"[Person])
// COMPILE ERRORpersons.update(mq"{}", mqt"""{$$set : { nme : "Joe" }}"""[Person])persons.find(mqt"{ name.1 : 'Joe' }"[Person])persons.find(mqt"{ phone.num : '223322' }"[Person])
![Page 44: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/44.jpg)
Passing type into intepolator
implicit class MongoHelper(val sc: StringContext) extends AnyVal {def mq(args: Any*): DBObject = macro MongoHelper.mq_impl
def mqt(args: Any*) = new QueryWrapper}
class QueryWrapper {def apply[T]: DBObject = macro MongoHelper.mqt_impl[T]
}
object MongoHelper {
def mqt_impl[T: c.WeakTypeTag](c: Context):c.Expr[DBObject] = ???
}
![Page 45: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/45.jpg)
Inside mqt_impl
def mqt_impl[T: c.WeakTypeTag](c: Context): c.Expr[DBObject] = {val q"$cn(scala.StringContext.apply(..$pTrees)).mqt(..$aTrees)"
= c.prefix.treeval args = aTrees.map(c.Expr(_))val parsed = parse(c)(pTrees)
checkObject(c)(c.weakTypeOf[T], parsed)
wrapObject(c)(parsed, args.iterator)}
![Page 46: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/46.jpg)
Verifing the type
def checkType(c: Context)(tpe: c.Type, obj: Object) = {import c.universe._
val ctor = tpe.decl(termNames.CONSTRUCTOR).asMethodval params = ctor.paramLists.headval className = t.typeSymbol.name.toString
val fields = params.map(s => s.name.toString -> s).toMap
obj.members.foreach { case (m, _) =>if (!fields.contains(m.name)) {
c.abort(c.enclosingPosition ,s"Class $className doesn't contain field '${m.name}'")
}}
}
![Page 47: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/47.jpg)
Testing interpolator
it should "support nested objects" in {val q = mq"""{ user : "Joe", age : {$$gt : 25}}"""q should equal(MongoDBObject("user" -> "Joe",
"age" -> MongoDBObject("$gt" -> 25)))}
![Page 48: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/48.jpg)
Testing error scenarios
import scala.reflect.runtime.{ universe => ru }
class CompileTest extends FlatSpec {
val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader]val cp = cl.getURLs.map(_.getFile).mkString(File.pathSeparator)val mirror = ru.runtimeMirror(cl)val tb = mirror.mkToolBox(options = s"-cp $cp")
def getError(q: String): String = {val e = intercept[ToolBoxError] {
tb.eval(tb.parse(q))}e.message
}
it should "fail on malformed BSON objects" in {val e = getError("""mq"{ test 5 }" """)e should include("`:' expected, but 5 found")
}}
![Page 49: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/49.jpg)
Testing error scenarios
import scala.reflect.runtime.{ universe => ru }
class CompileTest extends FlatSpec {
val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader]val cp = cl.getURLs.map(_.getFile).mkString(File.pathSeparator)val mirror = ru.runtimeMirror(cl)val tb = mirror.mkToolBox(options = s"-cp $cp")
def getError(q: String): String = {val e = intercept[ToolBoxError] {
tb.eval(tb.parse(q))}e.message
}
it should "fail on malformed BSON objects" in {val e = getError("""mq"{ test 5 }" """)e should include("`:' expected, but 5 found")
}}
![Page 50: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/50.jpg)
Testing error scenarios
import scala.reflect.runtime.{ universe => ru }
class CompileTest extends FlatSpec {
val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader]val cp = cl.getURLs.map(_.getFile).mkString(File.pathSeparator)val mirror = ru.runtimeMirror(cl)val tb = mirror.mkToolBox(options = s"-cp $cp")
def getError(q: String): String = {val e = intercept[ToolBoxError] {
tb.eval(tb.parse(q))}e.message
}
it should "fail on malformed BSON objects" in {val e = getError("""mq"{ test 5 }" """)e should include("`:' expected, but 5 found")
}}
![Page 51: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/51.jpg)
Summary
ConsI Not easy to implement
I Not highlighted in IDE
Pros
I Less limitations on language structureI Can preserve existing languageI Martin said that string interpolation is cool
![Page 52: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/52.jpg)
Summary
ConsI Not easy to implementI Not highlighted in IDE
Pros
I Less limitations on language structureI Can preserve existing languageI Martin said that string interpolation is cool
![Page 53: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/53.jpg)
Summary
ConsI Not easy to implementI Not highlighted in IDE
Pros
I Less limitations on language structureI Can preserve existing languageI Martin said that string interpolation is cool
![Page 54: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/54.jpg)
Summary
ConsI Not easy to implementI Not highlighted in IDE
ProsI Less limitations on language structure
I Can preserve existing languageI Martin said that string interpolation is cool
![Page 55: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/55.jpg)
Summary
ConsI Not easy to implementI Not highlighted in IDE
ProsI Less limitations on language structureI Can preserve existing language
I Martin said that string interpolation is cool
![Page 56: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/56.jpg)
Summary
ConsI Not easy to implementI Not highlighted in IDE
ProsI Less limitations on language structureI Can preserve existing languageI Martin said that string interpolation is cool
![Page 57: Embedding a language into string interpolator](https://reader034.fdocuments.us/reader034/viewer/2022052401/55cad7d4bb61eb1a0d8b457c/html5/thumbnails/57.jpg)
k
Thanks. Questions?