RonStein2000 / mongoquery

Scala MongoDB query builder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MongoQuery

Build Status Coverage Status

MongoQuery is a macro based MongoDB query builder for Scala.

Currently the MongoDB queries API requires to construct DBObjects explicitly. This makes even simple queries bulky. Even though you are using Casbah DSL it often still requires to create MongoDBObjects, and also requires to study new syntax, instead of using MongoDB queries. The purpose of this project is to provide a simple API for creating queries from strings. The goal is to make compile time queries syntax checking (as much as possible).

How to use

mq interpolator

The mq string interpolator converts string to the BSON objects. If you use Casbah it creates DBObjects:

import com.github.limansky.mongoquery.casbah._

def findByName(name: String) = {
  myCollection.find(mq"{ name : $name}")
}

For ReactiveMongo it creates BSONDocuments:

import com.github.limansky.mongoquery.reactive._

collection.
  find(mq"""{ firstName : "Jack" }""", mq"{ lastName : 1, _id : 1 }").
  cursor[BSONDocument].
  enumerate().apply(Iteratee.foreach { doc =>
  println("found document: " + BSONDocument.pretty(doc))
})

Since the query is defined inside of the string interpolator, the words started with $ are handled as variable references. To type MongoDB operator use $$, e.g:

def makeOlder(age: Int) = {
  people.update(mq"""{ age : { $$lt : $age } }""",
                mq"""{ $$inc : { age : 1 }}""",
                multi = 1)
}

Since the interpolator is implemented using macro it can perform compile time checks of provided queries. The code will not compile if the query is malformed. Also MongoQuery checks if all MongoDB operators are known.

[error] Test.scala:44: Unknown operator '$kte'. Possible you mean '$lte'
[error]     val query = mq"{start : {$$kte : $start}}"
[error]                              ^

[error] Test.scala:49: '{' expected, but Variable found
[error]     val q = mq"{ color : {$$in : $colors}"
[error]                                ^

Unfortunately, some errors messages does not reflect the error itself. I'm working on it, but it seems like the issue in the Scala Parser Combinators library.

mqt interpolator

mqt is another one interpolator adding type checking feature. If you have a model classes, you can check if the query contains only fields available in the class. E.g.:

case class Phone(kind: String, number: String)
case class Person(name: String, age: Int, phones: List[Phone])

// OK
persons.update(mq"{}", mqt"{$$inc : { age : 1 }}"[Person])

// Failed, person doesn't contain field 'nme'
persons.update(mq"{}", mqt"""{$$set : { nme : "Joe" }}"""[Person])

//Failed, name is not indexed field
persons.find(mqt"{ name.1 : 'Joe' }"[Person])

// OK
persons.find(mqt"{ phone.number : '223322' }"[Person])

// Failed, Phone doesn't contain field num
persons.find(mqt"{ phone.num : '223322' }"[Person])

Installation

MongoQuery is published to Sonatype maven repository. Add following dependency to libraryDependencies in your SBT build file:

"com.github.limansky" %% "mongoquery-casbah" % "0.4"    // for Casbah users
"com.github.limansky" %% "mongoquery-reactive" % "0.4"  // for ReactiveMongo users

If you want use latest development version:

"com.github.limansky" %% "mongoquery-casbah" % "0.5-SNAPSHOT"    // Casbah users
"com.github.limansky" %% "mongoquery-reactive" % "0.5-SNAPSHOT"  // ReactiveMongo users

Feedback

Any feedback is very welcome! You can ask any questions in MongoQuery mailing list.

About

Scala MongoDB query builder

License:Apache License 2.0


Languages

Language:Scala 100.0%