Skip to content

Instantly share code, notes, and snippets.

@ktoso
Last active December 10, 2015 03:28
Show Gist options
  • Save ktoso/4374274 to your computer and use it in GitHub Desktop.
Save ktoso/4374274 to your computer and use it in GitHub Desktop.
A basic "rogue" (from foursquare) MongoDB querying library. It'll be used to display how rogue does things, but keeping all stuff nice and simple and in just 80 lines of code. I'll be presenting about this and rogue on the upcoming ScalaCamp Kraków.package pl.project13.scala.workshop.rogue.ourown
package pl.project13.scala.workshop.rogue.model
import net.liftweb.mongodb.record.{MongoMetaRecord, MongoRecord}
import net.liftweb.mongodb.record.field.{MongoListField, IntPk}
import net.liftweb.record.field._
import pl.project13.scala.workshop.mongo.MongoConfig.MainMongoIdentifier
class Person extends MongoRecord[Person] with IntPk[Person] {
override val meta = Person
object name extends StringField(this, 16)
object middleName extends OptionalStringField(this, 16) {
override val name = "middle_name"
}
object lastName extends StringField(this, 64)
object age extends IntField(this)
object hobbies extends MongoListField[Person, String](this)
}
object Person extends Person with MongoMetaRecord[Person] {
override def mongoIdentifier = MainMongoIdentifier
override def collectionName = "persons"
def ensureIndexes() {
// todo ensure indexes
}
// todo add finders
def ??? = throw new RuntimeException("Not Implemented Yet!") // in case you're not 2.10 ;-)
def findByName(name: String) = {
import pl.project13.scala.workshop.rogue.ourown.OwnRogueDSL._
meta where(_.name eqs name) findAll()
}
def findByAge(min: Int, max: Option[Int] = None) = ???
}
import net.liftweb.mongodb.record._
import field.MongoListField
import net.liftweb.record.field._
import net.liftweb.record.{Field, Record, BaseField}
import net.liftweb.json.JsonAST.JValue
import net.liftweb.mongodb.MongoDB
import com.mongodb.BasicDBObject
trait WhereDSLImplicits {
// entry points ...
implicit def addRogueDSL[M <: MongoRecord[M]](meta: MongoMetaRecord[M]) =
new OwnRogueMonad(meta, meta.createRecord)
// fields ...
implicit def addStringFieldClauses[M <: MongoRecord[M]](field: StringField[M]) =
new StringFieldClauses(field)
implicit def addStringListFieldClauses[M <: MongoRecord[M]](field: MongoListField[M, String]) = // hardcoded List[String]
new SimpleListFieldClauses(field)
}
trait OwnRogueDSL
extends WhereDSLImplicits
trait QueryField {
def field: BaseField
}
trait DefaultQueryField extends QueryField {
def eqs(value: String) = WhereQuery(field.name, value)
def neqs(value: String) = WhereQuery(field.name, "neqs", value)
}
trait NumericQueryField extends QueryField {
def gt(value: String) = WhereQuery(field.name, "gt", value)
def gte(value: String) = WhereQuery(field.name, "gte", value)
def lt(value: String) = WhereQuery(field.name, "lt", value)
def lte(value: String) = WhereQuery(field.name, "lte", value)
}
case class StringFieldClauses(override val field: BaseField) extends DefaultQueryField
case class SimpleListFieldClauses(override val field: BaseField) extends QueryField {
def contains(s: String) = WhereQuery(field.name, s)
def size(size: Int) = WhereQuery(field.name, "$size", size.toString)
def doesntContain(s: String) = WhereQuery(field.name, "$ne", s)
}
class OwnRogueMonad[Owner <: MongoRecord[Owner]](
meta: MongoMetaRecord[Owner],
record: Owner,
val whereParts: List[WhereQuery] = Nil) {
def where(queryOn: Owner => WhereQuery) =
new OwnRogueMonad(
meta,
meta.createRecord,
whereParts = queryOn(record) :: whereParts
)
def findAll(): List[Owner] = {
MongoDB.useCollection(meta.mongoIdentifier, meta.collectionName) { db =>
val queryObject = new BasicDBObject()
whereParts
val cursor = db.find(queryObject)
import collection.JavaConversions._
cursor.iterator.map(meta.fromDBObject).toList
}
}
@inline def get(): Option[Owner] = findOne()
def findOne(): Option[Owner] = {
MongoDB.useCollection(meta.mongoIdentifier, meta.collectionName) { db =>
val queryObject = new BasicDBObject()
whereParts
val cursor = db.find(queryObject)
import collection.JavaConversions._
cursor.headOption.map(meta.fromDBObject)
}
}
}
object OwnRogueDSL extends OwnRogueDSL
// clauses -------------------------------------------------------------------------------------------------------------
sealed abstract class Query
case class WhereQuery(json: JValue) extends Query
object WhereQuery {
import net.liftweb.json.JsonDSL._
def apply(field: String, value: String) =
new WhereQuery(field -> value)
def apply(field: String, value: Number) =
new WhereQuery(field -> value)
def apply(field: String, operator: String, value: String) =
new WhereQuery(field -> (operator -> value))
def apply(field: String, operator: String, value: Number) =
new WhereQuery(field -> (operator -> value))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment