Permalink
Browse files

[reactivemongo] Refactor DSL and better support for Count command

  • Loading branch information...
cchantep
cchantep committed Sep 25, 2014
1 parent cb826da commit 646c8f57fccf605d97e2318adebb4b2540d5514b
View
@@ -10,7 +10,7 @@ object Acolyte extends Build with Dependencies
aggregate(scalacPlugin, reactiveMongo, jdbcDriver, jdbcScala, studio).
settings(
organization in ThisBuild := "org.eu.acolyte",
- version in ThisBuild := "1.0.25",
+ version in ThisBuild := "1.0.26",
javaOptions in ThisBuild ++= Seq("-source", "1.6", "-target", "1.6"),
scalaVersion in ThisBuild := "2.10.4",
crossScalaVersions in ThisBuild := Seq("2.10.4", "2.11.2"),
View
@@ -32,13 +32,13 @@ val res: Future[String] = withDriver(yourConnectionHandler) { d =>
As in previous example, main API object is [AcolyteDSL](https://github.com/cchantep/acolyte/blob/master/reactive-mongo/src/main/scala/acolyte/reactivemongo/AcolyteDSL.scala).
-Dependency can be added to SBT project with `"org.eu.acolyte" %% "reactive-mongo" % "1.0.25"`, and in a Maven one as following:
+Dependency can be added to SBT project with `"org.eu.acolyte" %% "reactive-mongo" % "1.0.26"`, and in a Maven one as following:
```xml
<dependency>
<groupId>org.eu.acolyte</groupId>
<artifactId>reactive-mongo</artifactId>
- <version>1.0.25</version>
+ <version>1.0.26</version>
</dependency>
```
@@ -63,14 +63,19 @@ Acolyte provides several ways to initialize Mongo resources (driver, connection,
- `withConnection` and `withFlatConnection`,
- `withDB` and `withFlatDB`,
- `withCollection` and `withFlatCollection`,
-- `withQueryResult` and `withFlatQueryResult`.
+- `withQueryHandler` and `withFlatQueryHandler`,
+- `withQueryResult` and `withFlatQueryResult`,
+- `withWriteHandler` and `withFlatWriteHandler`,
+- `withWriteResult` and `withFlatWriteResult`.
> Naming convention is `withX(...) { a => b }` to use with your Mongo function which doesn't return `Future` result, and `withFlatX(...) { a => b }` when your Mongo function return result (to flatten `withFlatX` result as `Future[YourReturnType]`, not having for example `Future[Future[YourReturnType]]`).
```scala
import reactivemongo.api.{ MongoConnection, MongoDriver }
import reactivemongo.bson.BSONDocument
-import acolyte.reactivemongo.AcolyteDSL
+import acolyte.reactivemongo.{
+ AcolyteDSL, QueryResponse, PreparedResponse, Request, WriteOp
+}
// Simple cases
AcolyteDSL.withDriver(yourHandler) { d =>
@@ -89,10 +94,19 @@ AcolyteDSL.withCollection(yourHandler, "colName") { col =>
yourFunctionWorkingWithCol(col)
}
+AcolyteDSL.withQueryHandler({ req: Request =>
+ val resp: PreparedResponse = QueryResponse.empty // empty doc list
+ resp
+}) { d => yourFunctionWorkingWithDriver(d) }
+
AcolyteDSL.withQueryResult(queryResultForAll) { d =>
yourFunctionWorkingWithDriver(d)
}
+AcolyteDSL.withWriteHandler({ cmd: (WriteOp, Request) => aResp }) { d =>
+ yourFunctionWorkingWithDriver(d)
+}
+
AcolyteDSL.withWriteResult(writeResultForAll) { d =>
yourFunctionWorkingWithDriver(d)
}
@@ -248,6 +262,10 @@ val queryHandler = QueryHandler { queryRequest =>
// a operator property "$gt" having an integer value, and an "email"
// property (at the same level as age), without order constraint.
resultJ
+
+ case CountRequest(colName, ("email", "em@il.net") :: Nil) =>
+ // Matching on count query
+ resultK
}
}
```
@@ -307,14 +325,17 @@ val success3 = QueryResponse(Seq(
val success4 = QueryResponse.successful(
BSONDocument("name" -> "singleResult"), BSONDocument("price" -> 1.2D))
-val countResponse = QueryResponse.count(4)
+val success5 = QueryResponse.empty // successful empty response
+val success6 = QueryResponse(List.empty[BSONDocument]) // equivalent
+
+val countResponse = QueryResponse.count(4) // response to Mongo Count
```
When a handler supports some query cases, but not other, it can return an undefined response, to let the chance other handlers would manage it.
```scala
val undefined1 = QueryResponse(None)
-val undefined2 = QueryResponse.empty
+val undefined2 = QueryResponse.undefined
```
### Result creation for write operation
@@ -339,7 +360,7 @@ When a handler supports some write cases, but not other, it can return an undefi
```scala
val undefined1 = WriteResponse(None)
-val undefined2 = WriteResponse.empty
+val undefined2 = WriteResponse.undefined
```
## Build
@@ -1,10 +1,8 @@
package acolyte.reactivemongo
-/**
- * Acolyte DSL for ReactiveMongo.
- */
+/** Acolyte DSL for ReactiveMongo. */
object AcolyteDSL extends WithDriver
- with WithDB with WithCollection with WithResult {
+ with WithDB with WithCollection with WithHandler with WithResult {
/**
* Creates an empty connection handler.
@@ -34,8 +34,11 @@ object QueryResponse {
def count(result: Int = 0) = apply(BSONDocument("ok" -> 1, "n" -> result))
/**
- * Empty/undefined response, returned by handler no supporting
+ * Undefined response, returned by handler no supporting
* a specific query that may be handled by others.
*/
- lazy val empty = apply(None)
+ lazy val undefined = apply(None)
+
+ /** Successful empty response (list of zero document). */
+ lazy val empty = apply(List.empty[BSONDocument])
}
@@ -2,7 +2,7 @@ package acolyte.reactivemongo
import org.jboss.netty.buffer.ChannelBuffer
-import reactivemongo.bson.{ BSONDocument, BSONValue }
+import reactivemongo.bson.{ BSONDocument, BSONString, BSONValue }
import reactivemongo.bson.buffer.{
ArrayBSONBuffer,
ReadableBuffer,
@@ -101,14 +101,34 @@ object ValueDocument {
* }
* }}}
*
- * @see ValueDocument
+ * @see [[ValueDocument]]
+ * @see [[CountRequest]]
*/
object RequestBody {
+ /**
+ * @return Collection name -> request body (BSON properties)
+ */
def unapply(q: Request): Option[(String, List[(String, BSONValue)])] =
Some(q.collection -> q.body.elements.toList)
}
+/**
+ * Request extractor for Count command.
+ * @see [[RequestBody]]
+ */
+object CountRequest {
+ /**
+ * @return Collection name -> query body (count BSON properties)
+ */
+ def unapply(q: Request): Option[(String, List[(String, BSONValue)])] =
+ q match {
+ case RequestBody(col, ("count", BSONString(_)) ::
+ ("query", ValueDocument(query)) :: Nil) Some(col -> query)
+ case _ None
+ }
+}
+
/**
* Meta-extractor, to combine extractor on BSON properties.
* @see RequestBody
@@ -0,0 +1,98 @@
+package acolyte.reactivemongo
+
+import scala.concurrent.{ ExecutionContext, Future }
+
+import reactivemongo.api.{ MongoConnection, MongoDriver }
+
+/** Functions to work with handler (provided driver functions). */
+trait WithHandler { up: WithDriver
+
+ /**
+ * Works with a Mongo driver handling only queries,
+ * using given query `handler`.
+ * Driver and associated resources are released
+ * after the function `f` the result `Future` is completed.
+ *
+ * {{{
+ * import reactivemongo.api.MongoDriver
+ * import acolyte.reactivemongo.{ AcolyteDSL, Request }
+ *
+ * AcolyteDSL.withQueryHandler({ req: Request ⇒ aResponse }) { d =>
+ * val driver: MongoDriver = d
+ * "aResult"
+ * }
+ * }}}
+ *
+ * @see [[AcolyteDSL.withDriver]]
+ * @see [[AcolyteDSL.handleQuery]]
+ * @see [[AcolyteDSL.withQueryResult]]
+ */
+ def withQueryHandler[T](handler: Request PreparedResponse)(f: MongoDriver T)(implicit m: DriverManager[ConnectionHandler], c: ExecutionContext): Future[T] = withDriver(AcolyteDSL handleQuery QueryHandler(handler))(f)
+
+ /**
+ * Works with a Mongo driver handling only queries,
+ * using given query `handler`.
+ * Driver and associated resources are released
+ * after the function `f` the result `Future` is completed.
+ *
+ * {{{
+ * import reactivemongo.api.MongoDriver
+ * import acolyte.reactivemongo.{ AcolyteDSL, Request }
+ *
+ * AcolyteDSL.withFlatQueryHandler({ req: Request ⇒ aResponse }) { d =>
+ * val driver: MongoDriver = d
+ * Future(1+2)
+ * }
+ * }}}
+ *
+ * @see [[AcolyteDSL.withFlatDriver]]
+ * @see [[AcolyteDSL.handleQuery]]
+ * @see [[AcolyteDSL.withQueryResult]]
+ */
+ def withFlatQueryHandler[T](handler: Request PreparedResponse)(f: MongoDriver Future[T])(implicit m: DriverManager[ConnectionHandler], c: ExecutionContext): Future[T] = withFlatDriver(AcolyteDSL handleQuery QueryHandler(handler))(f)
+
+ /**
+ * Works with a Mongo driver handling only write operations,
+ * using given write `handler`.
+ * Driver and associated resources are released
+ * after the function `f` the result `Future` is completed.
+ *
+ * {{{
+ * import reactivemongo.api.MongoDriver
+ * import acolyte.reactivemongo.{ AcolyteDSL, Request, WriteOp }
+ *
+ * AcolyteDSL.withWriteHandler({ cmd: (WriteOp, Request) ⇒ aResp }) { d =>
+ * val driver: MongoDriver = d
+ * "aResult"
+ * }
+ * }}}
+ *
+ * @see [[AcolyteDSL.withDriver]]
+ * @see [[AcolyteDSL.handleWrite]]
+ * @see [[AcolyteDSL.withWriteResult]
+ */
+ def withWriteHandler[T](handler: (WriteOp, Request) PreparedResponse)(f: MongoDriver T)(implicit m: DriverManager[ConnectionHandler], c: ExecutionContext): Future[T] = withDriver(AcolyteDSL handleWrite handler)(f)
+
+ /**
+ * Works with a Mongo driver handling only write operations,
+ * using given write `handler`.
+ * Driver and associated resources are released
+ * after the function `f` the result `Future` is completed.
+ *
+ * {{{
+ * import reactivemongo.api.MongoDriver
+ * import acolyte.reactivemongo.{ AcolyteDSL, Request, WriteOp }
+ *
+ * AcolyteDSL.withWriteHandler({ cmd: (WriteOp, Request) ⇒ aResp }) { d =>
+ * val driver: MongoDriver = d
+ * Future(1+2)
+ * }
+ * }}}
+ *
+ * @see [[AcolyteDSL.withFlatDriver]]
+ * @see [[AcolyteDSL.handleWrite]]
+ * @see [[AcolyteDSL.withFlatWriteResult]
+ */
+ def withFlatWriteHandler[T](handler: (WriteOp, Request) PreparedResponse)(f: MongoDriver Future[T])(implicit m: DriverManager[ConnectionHandler], c: ExecutionContext): Future[T] = withFlatDriver(AcolyteDSL handleWrite handler)(f)
+
+}
@@ -5,72 +5,54 @@ import scala.concurrent.{ ExecutionContext, Future }
import reactivemongo.api.{ MongoConnection, MongoDriver }
/** Functions to work with result (provided collection functions). */
-trait WithResult { up: WithDriver
+trait WithResult { withHandler: WithHandler
/**
* Works with a Mongo driver handling only queries,
* and returning given `result` for all of them.
* Driver and associated resources are released
* after the function `f` the result `Future` is completed.
*
- * {{{
- * import acolyte.reactivemongo.AcolyteDSL
- *
- * }}}
* @see [[AcolyteDSL.withDriver]]
* @see [[AcolyteDSL.handleQuery]]
+ * @see [[AcolyteDSL.withQueryHandler]]
*/
- def withQueryResult[A, B](result: A)(f: MongoDriver B)(implicit m: DriverManager[ConnectionHandler], mk: QueryResponseMaker[A], c: ExecutionContext): Future[B] = withDriver(
- AcolyteDSL handleQuery { _: Request QueryResponse(result) })(f)
+ def withQueryResult[A, B](result: A)(f: MongoDriver B)(implicit m: DriverManager[ConnectionHandler], mk: QueryResponseMaker[A], c: ExecutionContext): Future[B] = withQueryHandler({ _: Request QueryResponse(result) })(f)
/**
* Works with a Mongo driver handling only queries,
* and returning given `result` for all of them.
* Driver and associated resources are released
* after the function `f` the result `Future` is completed.
*
- * {{{
- * import acolyte.reactivemongo.AcolyteDSL
- *
- * }}}
* @see [[AcolyteDSL.withFlatDriver]]
* @see [[AcolyteDSL.handleQuery]]
*/
- def withFlatQueryResult[A, B](result: A)(f: MongoDriver Future[B])(implicit m: DriverManager[ConnectionHandler], mk: QueryResponseMaker[A], c: ExecutionContext): Future[B] = withFlatDriver(
- AcolyteDSL handleQuery { _: Request QueryResponse(result) })(f)
+ def withFlatQueryResult[A, B](result: A)(f: MongoDriver Future[B])(implicit m: DriverManager[ConnectionHandler], mk: QueryResponseMaker[A], c: ExecutionContext): Future[B] =
+ withFlatQueryHandler({ _: Request QueryResponse(result) })(f)
/**
* Works with a Mongo driver handling only write operations,
* and returning given `result` for all of them.
* Driver and associated resources are released
* after the function `f` the result `Future` is completed.
*
- * {{{
- * import acolyte.reactivemongo.AcolyteDSL
- *
- * }}}
* @see [[AcolyteDSL.withDriver]]
* @see [[AcolyteDSL.handleWrite]]
+ * @see [[AcolyteDSL.withWriteHandler]]
*/
- def withWriteResult[A, B](result: A)(f: MongoDriver B)(implicit m: DriverManager[ConnectionHandler], mk: WriteResponseMaker[A], c: ExecutionContext): Future[B] = withDriver(AcolyteDSL handleWrite { (_: WriteOp, _: Request)
- WriteResponse(result)
- })(f)
+ def withWriteResult[A, B](result: A)(f: MongoDriver B)(implicit m: DriverManager[ConnectionHandler], mk: WriteResponseMaker[A], c: ExecutionContext): Future[B] = withWriteHandler(
+ { (_: WriteOp, _: Request) WriteResponse(result) })(f)
/**
* Works with a Mongo driver handling only write operations,
* and returning given `result` for all of them.
* Driver and associated resources are released
* after the function `f` the result `Future` is completed.
*
- * {{{
- * import acolyte.reactivemongo.AcolyteDSL
- *
- * }}}
* @see [[AcolyteDSL.withFlatDriver]]
* @see [[AcolyteDSL.handleWrite]]
*/
- def withFlatWriteResult[A, B](result: A)(f: MongoDriver Future[B])(implicit m: DriverManager[ConnectionHandler], mk: WriteResponseMaker[A], c: ExecutionContext): Future[B] = withFlatDriver(
- AcolyteDSL handleWrite {
- (_: WriteOp, _: Request) WriteResponse(result)
- })(f)
+ def withFlatWriteResult[A, B](result: A)(f: MongoDriver Future[B])(implicit m: DriverManager[ConnectionHandler], mk: WriteResponseMaker[A], c: ExecutionContext): Future[B] = withFlatWriteHandler(
+ { (_: WriteOp, _: Request) WriteResponse(result) })(f)
}
@@ -37,8 +37,8 @@ object WriteResponse {
apply(count -> updatedExisting)
/**
- * Empty/undefined response, returned by handler no supporting
+ * Undefined response, returned by handler no supporting
* a specific write operation that may be handled by others.
*/
- lazy val empty = apply(None)
+ lazy val undefined = apply(None)
}
Oops, something went wrong.

0 comments on commit 646c8f5

Please sign in to comment.