From a0588a9078f363a99603a912c17823fb0a2cbfef Mon Sep 17 00:00:00 2001
From: Jason Liszka
Date: Thu, 7 Jun 2012 01:56:09 -0400
Subject: [PATCH] simplified phantom types
---
.../com/foursquare/rogue/PhantomTypes.scala | 55 +--
.../scala/com/foursquare/rogue/Query.scala | 389 ++++++------------
.../com/foursquare/rogue/QueryExecutor.scala | 55 +--
.../com/foursquare/rogue/QueryHelpers.scala | 12 +-
.../com/foursquare/rogue/QueryOptimizer.scala | 2 +-
.../scala/com/foursquare/rogue/Rogue.scala | 19 +-
.../scala/com/foursquare/rogue/package.scala | 10 +-
.../foursquare/rogue/ExecutableQuery.scala | 59 ++-
.../com/foursquare/rogue/LiftRogue.scala | 34 +-
.../foursquare/rogue/QueryExecutorTest.scala | 2 +-
.../com/foursquare/rogue/QueryTest.scala | 7 +-
11 files changed, 240 insertions(+), 404 deletions(-)
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/PhantomTypes.scala b/rogue-core/src/main/scala/com/foursquare/rogue/PhantomTypes.scala
index a117f3d..a31b62c 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/PhantomTypes.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/PhantomTypes.scala
@@ -6,36 +6,43 @@ package com.foursquare.rogue
// *** Phantom types
// ***************************************************************************
-abstract sealed class MaybeOrdered
-abstract sealed class Ordered extends MaybeOrdered
-abstract sealed class Unordered extends MaybeOrdered
+sealed trait Ordered
+sealed trait Unordered
+sealed trait Ord extends Ordered with Unordered
-abstract sealed class MaybeSelected
-abstract sealed class Selected extends MaybeSelected
-abstract sealed class SelectedOne extends Selected
-abstract sealed class Unselected extends MaybeSelected
+sealed trait Selected
+sealed trait SelectedOne extends Selected
+sealed trait Unselected
+sealed trait Sel extends Selected with SelectedOne with Unselected
-abstract sealed class MaybeLimited
-abstract sealed class Limited extends MaybeLimited
-abstract sealed class Unlimited extends MaybeLimited
+sealed trait Limited
+sealed trait Unlimited
+sealed trait Lim extends Limited with Unlimited
-abstract sealed class MaybeSkipped
-abstract sealed class Skipped extends MaybeSkipped
-abstract sealed class Unskipped extends MaybeSkipped
+sealed trait Skipped
+sealed trait Unskipped
+sealed trait Sk extends Skipped with Unskipped
+
+sealed trait HasOrClause
+sealed trait HasNoOrClause
+sealed trait Or extends HasOrClause with HasNoOrClause
+
+class AddOrder[-In, +Out]
+class AddSelect[-In, +Out, +One]
+class AddLimit[-In, +Out]
+class AddSkip[-In, +Out]
+class AddOrClause[-In, +Out]
-abstract sealed class MaybeHasOrClause
-abstract sealed class HasOrClause extends MaybeHasOrClause
-abstract sealed class HasNoOrClause extends MaybeHasOrClause
sealed trait MaybeIndexed
sealed trait Indexable extends MaybeIndexed
sealed trait IndexScannable extends MaybeIndexed
-abstract sealed class NoIndexInfo extends Indexable with IndexScannable
-abstract sealed class Index extends Indexable with IndexScannable
-abstract sealed class PartialIndexScan extends IndexScannable
-abstract sealed class IndexScan extends IndexScannable
-abstract sealed class DocumentScan extends MaybeIndexed
+sealed trait NoIndexInfo extends Indexable with IndexScannable
+sealed trait Index extends Indexable with IndexScannable
+sealed trait PartialIndexScan extends IndexScannable
+sealed trait IndexScan extends IndexScannable
+sealed trait DocumentScan extends MaybeIndexed
case object NoIndexInfo extends NoIndexInfo
case object Index extends Index
@@ -43,6 +50,6 @@ case object PartialIndexScan extends PartialIndexScan
case object IndexScan extends IndexScan
case object DocumentScan extends DocumentScan
-abstract sealed class MaybeUsedIndex
-abstract sealed class UsedIndex extends MaybeUsedIndex
-abstract sealed class HasntUsedIndex extends MaybeUsedIndex
+sealed trait MaybeUsedIndex
+sealed trait UsedIndex extends MaybeUsedIndex
+sealed trait HasntUsedIndex extends MaybeUsedIndex
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/Query.scala b/rogue-core/src/main/scala/com/foursquare/rogue/Query.scala
index 5935a1e..8908983 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/Query.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/Query.scala
@@ -47,15 +47,7 @@ import scala.collection.immutable.ListMap
* an or-clause. The type system will guarantee that the query and its or-connected query
* have the same types.
*/
-case class BaseQuery[
- M,
- R,
- Ord <: MaybeOrdered,
- Sel <: MaybeSelected,
- Lim <: MaybeLimited,
- Sk <: MaybeSkipped,
- Or <: MaybeHasOrClause
-](
+case class BaseQuery[M, R, +State](
meta: M,
collectionName: String,
lim: Option[Int],
@@ -71,7 +63,7 @@ case class BaseQuery[
private def addClause[F](clause: M => QueryClause[F],
expectedIndexBehavior: MaybeIndexed):
- AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] = {
+ AbstractQuery[M, R, State] = {
val cl = clause(meta)
val newClause = cl.withExpectedIndexBehavior(expectedIndexBehavior)
this.copy(condition = condition.copy(clauses = newClause :: condition.clauses))
@@ -122,7 +114,7 @@ case class BaseQuery[
def scanOpt[V, F](opt: Option[V])(clause: (M, V) => QueryClause[F]) =
addClauseOpt(opt)(clause, expectedIndexBehavior = DocumentScan)
- def raw(f: BasicDBObjectBuilder => Unit): AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] = {
+ def raw(f: BasicDBObjectBuilder => Unit): AbstractQuery[M, R, State] = {
val newClause = new RawQueryClause(f)
this.copy(condition = condition.copy(clauses = newClause :: condition.clauses))
}
@@ -137,10 +129,10 @@ case class BaseQuery[
* you can see that the "MaybeHasOrClause" type parameter is changed, and is now specifically
* bound to "HasOrClause", rather than to a type variable.
*/
- def or(subqueries: (AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] => AbstractQuery[M, R, Ord, Sel, Lim, Sk, _])*)
- (implicit ev: Or =:= HasNoOrClause): AbstractQuery[M, R, Ord, Sel, Lim, Sk, HasOrClause] = {
+ def or[S2](subqueries: (AbstractQuery[M, R, Ordered with Selected with Limited with Skipped with HasNoOrClause] => AbstractQuery[M, R, _])*)
+ (implicit ev: AddOrClause[State, S2]): AbstractQuery[M, R, S2] = {
val queryBuilder =
- this.copy[M, R, Ord, Sel, Lim, Sk, Or](
+ this.copy[M, R, Ordered with Selected with Limited with Skipped with HasNoOrClause](
lim = None,
sk = None,
maxScan = None,
@@ -162,30 +154,30 @@ case class BaseQuery[
* type signature of the returned query is updated so that the "MaybeOrdered" type parameter is
* now Ordered.
*/
- def orderAsc[V](field: M => AbstractQueryField[V, _, M])
- (implicit ev: Ord =:= Unordered): BaseQuery[M, R, Ordered, Sel, Lim, Sk, Or] =
+ def orderAsc[V, S2](field: M => AbstractQueryField[V, _, M])
+ (implicit ev: AddOrder[State, S2]): BaseQuery[M, R, S2] =
this.copy(order = Some(MongoOrder(List((field(meta).field.name, true)))))
- def orderDesc[V](field: M => AbstractQueryField[V, _, M])
- (implicit ev: Ord =:= Unordered): BaseQuery[M, R, Ordered, Sel, Lim, Sk, Or] =
+ def orderDesc[V, S2](field: M => AbstractQueryField[V, _, M])
+ (implicit ev: AddOrder[State, S2]): BaseQuery[M, R, S2] =
this.copy(order = Some(MongoOrder(List((field(meta).field.name, false)))))
def andAsc[V](field: M => AbstractQueryField[V, _, M])
- (implicit ev: Ord =:= Ordered): BaseQuery[M, R, Ordered, Sel, Lim, Sk, Or] =
+ (implicit ev: State <:< Ordered): BaseQuery[M, R, State] =
this.copy(order = Some(MongoOrder((field(meta).field.name, true) :: order.get.terms)))
def andDesc[V](field: M => AbstractQueryField[V, _, M])
- (implicit ev: Ord =:= Ordered): BaseQuery[M, R, Ordered, Sel, Lim, Sk, Or] =
+ (implicit ev: State <:< Ordered): BaseQuery[M, R, State] =
this.copy(order = Some(MongoOrder((field(meta).field.name, false) :: order.get.terms)))
/**
* Natural ordering.
* TODO: doesn't make sense in conjunction with ordering on any other fields. enforce w/ phantom types?
*/
- def orderNaturalAsc[V](implicit ev: Ord =:= Unordered): BaseQuery[M, R, Ordered, Sel, Lim, Sk, Or] =
+ def orderNaturalAsc[V, S2](implicit ev: AddOrder[State, S2]): BaseQuery[M, R, S2] =
this.copy(order = Some(MongoOrder(List(("$natural", true)))))
- def orderNaturalDesc[V](implicit ev: Ord =:= Unordered): BaseQuery[M, R, Ordered, Sel, Lim, Sk, Or] =
+ def orderNaturalDesc[V, S2](implicit ev: AddOrder[State, S2]): BaseQuery[M, R, S2] =
this.copy(order = Some(MongoOrder(List(("$natural", false)))))
/**
@@ -197,10 +189,10 @@ case class BaseQuery[
* type signature of the returned query is updated so that the "MaybeLimited" type parameter is
* now Limited.
*/
- def limit(n: Int)(implicit ev: Lim =:= Unlimited): BaseQuery[M, R, Ord, Sel, Limited, Sk, Or] =
+ def limit[S2](n: Int)(implicit ev: AddLimit[State, S2]): BaseQuery[M, R, S2] =
this.copy(lim = Some(n))
- def limitOpt(n: Option[Int])(implicit ev: Lim =:= Unlimited): BaseQuery[M, R, Ord, Sel, Limited, Sk, Or] =
+ def limitOpt[S2](n: Option[Int])(implicit ev: AddLimit[State, S2]): BaseQuery[M, R, S2] =
this.copy(lim = n)
/**
@@ -212,15 +204,14 @@ case class BaseQuery[
* type signature of the returned query is updated so that the {@link MaybeSkipped} type parameter is
* now {@link Skipped}.
*/
- def skip(n: Int)(implicit ev: Sk =:= Unskipped): BaseQuery[M, R, Ord, Sel, Lim, Skipped, Or] =
+ def skip[S2](n: Int)(implicit ev: AddSkip[State, S2]): BaseQuery[M, R, S2] =
this.copy(sk = Some(n))
- def skipOpt(n: Option[Int])(implicit ev: Sk =:= Unskipped): BaseQuery[M, R, Ord, Sel, Lim, Skipped, Or] =
+ def skipOpt[S2](n: Option[Int])(implicit ev: AddSkip[State, S2]): BaseQuery[M, R, S2] =
this.copy(sk = n)
- def noop()(implicit ev1: Sel =:= Unselected,
- ev2: Lim =:= Unlimited,
- ev3: Sk =:= Unskipped): BaseModifyQuery[M] = BaseModifyQuery(this, MongoModify(Nil)) // TODO: Does this work?
+ def noop()(implicit ev: State <:< Unselected with Unlimited with Unskipped): BaseModifyQuery[M] =
+ BaseModifyQuery(this, MongoModify(Nil)) // TODO: Does this work?
override def toString: String =
MongoBuilder.buildQueryString("find", collectionName, this)
@@ -231,9 +222,9 @@ case class BaseQuery[
def signature(): String =
MongoBuilder.buildSignature(collectionName, this)
- def maxScan(max: Int): AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] = this.copy(maxScan = Some(max))
+ def maxScan(max: Int): AbstractQuery[M, R, State] = this.copy(maxScan = Some(max))
- def comment(c: String): AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] = this.copy(comment = Some(c))
+ def comment(c: String): AbstractQuery[M, R, State] = this.copy(comment = Some(c))
/**
* Set a flag to indicate whether this query should hit primaries or secondaries.
@@ -246,9 +237,9 @@ case class BaseQuery[
* For more info, see
* http://www.mongodb.org/display/DOCS/slaveOk
*/
- def setReadPreference(r: ReadPreference): AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] = this.copy(readPreference = Some(r))
+ def setReadPreference(r: ReadPreference): AbstractQuery[M, R, State] = this.copy(readPreference = Some(r))
- def hint(index: MongoIndex[M]): AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or] = this.copy(hint = Some(index.asListMap))
+ def hint(index: MongoIndex[M]): AbstractQuery[M, R, State] = this.copy(hint = Some(index.asListMap))
/**
* Adds a select clause to the query. The use of this method constrains the type
@@ -261,290 +252,178 @@ case class BaseQuery[
* you can see that the "MaybeSelected" type parameter is changed, and is now specifically
* bound to "Selected", rather than to a type variable.
*/
- def select[F1](f: M => SelectField[F1, M])
- (implicit ev: Sel =:= Unselected): BaseQuery[M, F1, Ord, Selected, Lim, Sk, Or] = {
- selectCase(f, (f: F1) => f)
+
+ /*
+
+ // Code to generate the select() and selectCase() methods:
+
+ def select(n: Int) = {
+ val typeParams = (1 to n).map(i => "F%d".format(i)).mkString(", ")
+ val arguments = (1 to n).map(i => "f%d: M => SelectField[F%d, M]".format(i, i)).mkString(", ")
+ val outParams = if (n == 1) "_, S2" else "S2, _"
+ val resultType = if (n == 1) typeParams else "(%s)".format(typeParams)
+ val vars = (1 to n).map(i => "f%d".format(i)).mkString(", ")
+ val fnArgs = (1 to n).map(i => "f%d: F%d".format(i, i)).mkString(", ")
+ val fnResult = if (n == 1) vars else "(%s)".format(vars)
+ val code = """
+ def select[%s, S2](%s)
+ (implicit ev: AddSelect[State, %s]): BaseQuery[M, %s, S2] = {
+ selectCase(%s, (%s) => %s)
+ }"""
+ code.format(typeParams, arguments, outParams, resultType, vars, fnArgs, fnResult)
+ }
+
+ def selectCase(n: Int) = {
+ val typeParams = (1 to n).map(i => "F%d".format(i)).mkString(", ")
+ val arguments = (1 to n).map(i => "f%d: M => SelectField[F%d, M]".format(i, i)).mkString(", ")
+ val outParams = if (n == 1) "_, S2" else "S2, _"
+ val resultType = if (n == 1) typeParams else "(%s)".format(typeParams)
+ val instCalls = (1 to n).map(i => "f%d(inst)".format(i)).mkString(", ")
+ val createArgs = (1 to n).map(i => "xs(%d).asInstanceOf[F%d]".format(i-1, i)).mkString(", ")
+ val code = """
+ def selectCase[%s, CC, S2](%s,
+ create: %s => CC)(implicit ev: AddSelect[State, %s]): BaseQuery[M, CC, S2] = {
+ val inst = meta
+ val fields = List(%s)
+ val transformer = (xs: List[_]) => create(%s)
+ this.copy(select = Some(MongoSelect(fields, transformer)))
+ }"""
+ code.format(typeParams, arguments, resultType, outParams, instCalls, createArgs)
+ }
+
+ def generate(n: Int) = {
+ (1 to n).foreach(i => println(select(i)))
+ (1 to n).foreach(i => println(selectCase(i)))
+ }
+ */
+
+ def select[F1, S2](f1: M => SelectField[F1, M])
+ (implicit ev: AddSelect[State, _, S2]): BaseQuery[M, F1, S2] = {
+ selectCase(f1, (f1: F1) => f1)
}
- def select[F1, F2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M])
- (implicit ev: Sel =:= Unselected): BaseQuery[M, (F1, F2), Ord, Selected, Lim, Sk, Or] = {
+ def select[F1, F2, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2), S2] = {
selectCase(f1, f2, (f1: F1, f2: F2) => (f1, f2))
}
- def select[F1, F2, F3](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M])
- (implicit ev: Sel =:= Unselected): BaseQuery[M, (F1, F2, F3), Ord, Selected, Lim, Sk, Or] = {
+ def select[F1, F2, F3, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3), S2] = {
selectCase(f1, f2, f3, (f1: F1, f2: F2, f3: F3) => (f1, f2, f3))
}
- def select[F1, F2, F3, F4](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M])
- (implicit ev: Sel =:= Unselected): BaseQuery[M, (F1, F2, F3, F4), Ord, Selected, Lim, Sk, Or] = {
+ def select[F1, F2, F3, F4, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4), S2] = {
selectCase(f1, f2, f3, f4, (f1: F1, f2: F2, f3: F3, f4: F4) => (f1, f2, f3, f4))
}
- def select[F1, F2, F3, F4, F5](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M])
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, (F1, F2, F3, F4, F5), Ord, Selected, Lim, Sk, Or] = {
+ def select[F1, F2, F3, F4, F5, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4, F5), S2] = {
selectCase(f1, f2, f3, f4, f5, (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5) => (f1, f2, f3, f4, f5))
}
- def select[F1, F2, F3, F4, F5, F6](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M])
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, (F1, F2, F3, F4, F5, F6), Ord, Selected, Lim, Sk, Or] = {
+ def select[F1, F2, F3, F4, F5, F6, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4, F5, F6), S2] = {
selectCase(f1, f2, f3, f4, f5, f6, (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6) => (f1, f2, f3, f4, f5, f6))
}
- def select[F1, F2, F3, F4, F5, F6, F7](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M])
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7), Ord, Selected, Lim, Sk, Or] = {
- selectCase(f1, f2, f3, f4, f5, f6, f7,
- (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7) => (f1, f2, f3, f4, f5, f6, f7))
+ def select[F1, F2, F3, F4, F5, F6, F7, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7), S2] = {
+ selectCase(f1, f2, f3, f4, f5, f6, f7, (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7) => (f1, f2, f3, f4, f5, f6, f7))
}
- def select[F1, F2, F3, F4, F5, F6, F7, F8](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- f8: M => SelectField[F8, M])
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7, F8), Ord, Selected, Lim, Sk, Or] = {
- selectCase(f1, f2, f3, f4, f5, f6, f7, f8,
- (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8) => (f1, f2, f3, f4, f5, f6, f7, f8))
+ def select[F1, F2, F3, F4, F5, F6, F7, F8, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M], f8: M => SelectField[F8, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7, F8), S2] = {
+ selectCase(f1, f2, f3, f4, f5, f6, f7, f8, (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8) => (f1, f2, f3, f4, f5, f6, f7, f8))
}
- def select[F1, F2, F3, F4, F5, F6, F7, F8, F9](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- f8: M => SelectField[F8, M],
- f9: M => SelectField[F9, M])
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7, F8, F9), Ord, Selected, Lim, Sk, Or] = {
- selectCase(f1, f2, f3, f4, f5, f6, f7, f8, f9,
- (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8, f9: F9) =>
- (f1, f2, f3, f4, f5, f6, f7, f8, f9))
+ def select[F1, F2, F3, F4, F5, F6, F7, F8, F9, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M], f8: M => SelectField[F8, M], f9: M => SelectField[F9, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7, F8, F9), S2] = {
+ selectCase(f1, f2, f3, f4, f5, f6, f7, f8, f9, (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8, f9: F9) => (f1, f2, f3, f4, f5, f6, f7, f8, f9))
}
- def select[F1, F2, F3, F4, F5, F6, F7, F8, F9, F10](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- f8: M => SelectField[F8, M],
- f9: M => SelectField[F9, M],
- f10: M => SelectField[F10, M])
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7, F8, F9, F10), Ord, Selected, Lim, Sk, Or] = {
- selectCase(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
- (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8, f9: F9, f10: F10) =>
- (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10))
+ def select[F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M], f8: M => SelectField[F8, M], f9: M => SelectField[F9, M], f10: M => SelectField[F10, M])
+ (implicit ev: AddSelect[State, S2, _]): BaseQuery[M, (F1, F2, F3, F4, F5, F6, F7, F8, F9, F10), S2] = {
+ selectCase(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, (f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8, f9: F9, f10: F10) => (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10))
}
- def selectCase[F1, CC](f: M => SelectField[F1, M],
- create: F1 => CC)(implicit ev: Sel =:= Unselected):
- BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, CC, S2](f1: M => SelectField[F1, M],
+ create: F1 => CC)(implicit ev: AddSelect[State, _, S2]): BaseQuery[M, CC, S2] = {
val inst = meta
- val fields = List(f(inst))
- val transformer = (xs: List[_]) => create(xs.head.asInstanceOf[F1])
+ val fields = List(f1(inst))
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- create: (F1, F2) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M],
+ create: (F1, F2) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst))
val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- create: (F1, F2, F3) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M],
+ create: (F1, F2, F3) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- create: (F1, F2, F3, F4) => CC)
- (implicit ev: Sel =:= Unselected):
- BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M],
+ create: (F1, F2, F3, F4) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst), f4(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, F5, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- create: (F1, F2, F3, F4, F5) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, F5, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M],
+ create: (F1, F2, F3, F4, F5) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4],
- xs(4).asInstanceOf[F5])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4], xs(4).asInstanceOf[F5])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, F5, F6, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- create: (F1, F2, F3, F4, F5, F6) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, F5, F6, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M],
+ create: (F1, F2, F3, F4, F5, F6) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst), f6(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4],
- xs(4).asInstanceOf[F5],
- xs(5).asInstanceOf[F6])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4], xs(4).asInstanceOf[F5], xs(5).asInstanceOf[F6])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, F5, F6, F7, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- create: (F1, F2, F3, F4, F5, F6, F7) => CC)
- ( implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, F5, F6, F7, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M],
+ create: (F1, F2, F3, F4, F5, F6, F7) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst), f6(inst), f7(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4],
- xs(4).asInstanceOf[F5],
- xs(5).asInstanceOf[F6],
- xs(6).asInstanceOf[F7])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4], xs(4).asInstanceOf[F5], xs(5).asInstanceOf[F6], xs(6).asInstanceOf[F7])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, F5, F6, F7, F8, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- f8: M => SelectField[F8, M],
- create: (F1, F2, F3, F4, F5, F6, F7, F8) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, F5, F6, F7, F8, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M], f8: M => SelectField[F8, M],
+ create: (F1, F2, F3, F4, F5, F6, F7, F8) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst), f6(inst), f7(inst), f8(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4],
- xs(4).asInstanceOf[F5],
- xs(5).asInstanceOf[F6],
- xs(6).asInstanceOf[F7],
- xs(7).asInstanceOf[F8])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4], xs(4).asInstanceOf[F5], xs(5).asInstanceOf[F6], xs(6).asInstanceOf[F7], xs(7).asInstanceOf[F8])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, F5, F6, F7, F8, F9, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- f8: M => SelectField[F8, M],
- f9: M => SelectField[F9, M],
- create: (F1, F2, F3, F4, F5, F6, F7, F8, F9) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, F5, F6, F7, F8, F9, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M], f8: M => SelectField[F8, M], f9: M => SelectField[F9, M],
+ create: (F1, F2, F3, F4, F5, F6, F7, F8, F9) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst), f6(inst), f7(inst), f8(inst), f9(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4],
- xs(4).asInstanceOf[F5],
- xs(5).asInstanceOf[F6],
- xs(6).asInstanceOf[F7],
- xs(7).asInstanceOf[F8],
- xs(8).asInstanceOf[F9])
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4], xs(4).asInstanceOf[F5], xs(5).asInstanceOf[F6], xs(6).asInstanceOf[F7], xs(7).asInstanceOf[F8], xs(8).asInstanceOf[F9])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
- def selectCase[F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, CC](f1: M => SelectField[F1, M],
- f2: M => SelectField[F2, M],
- f3: M => SelectField[F3, M],
- f4: M => SelectField[F4, M],
- f5: M => SelectField[F5, M],
- f6: M => SelectField[F6, M],
- f7: M => SelectField[F7, M],
- f8: M => SelectField[F8, M],
- f9: M => SelectField[F9, M],
- f10: M => SelectField[F10, M],
- create: (F1, F2, F3, F4, F5, F6, F7, F8, F9, F10) => CC)
- (implicit ev: Sel =:= Unselected): BaseQuery[M, CC, Ord, Selected, Lim, Sk, Or] = {
+ def selectCase[F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, CC, S2](f1: M => SelectField[F1, M], f2: M => SelectField[F2, M], f3: M => SelectField[F3, M], f4: M => SelectField[F4, M], f5: M => SelectField[F5, M], f6: M => SelectField[F6, M], f7: M => SelectField[F7, M], f8: M => SelectField[F8, M], f9: M => SelectField[F9, M], f10: M => SelectField[F10, M],
+ create: (F1, F2, F3, F4, F5, F6, F7, F8, F9, F10) => CC)(implicit ev: AddSelect[State, S2, _]): BaseQuery[M, CC, S2] = {
val inst = meta
- val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst),
- f6(inst), f7(inst), f8(inst), f9(inst), f10(inst))
- val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1],
- xs(1).asInstanceOf[F2],
- xs(2).asInstanceOf[F3],
- xs(3).asInstanceOf[F4],
- xs(4).asInstanceOf[F5],
- xs(5).asInstanceOf[F6],
- xs(6).asInstanceOf[F7],
- xs(7).asInstanceOf[F8],
- xs(8).asInstanceOf[F9],
- xs(9).asInstanceOf[F10])
+ val fields = List(f1(inst), f2(inst), f3(inst), f4(inst), f5(inst), f6(inst), f7(inst), f8(inst), f9(inst), f10(inst))
+ val transformer = (xs: List[_]) => create(xs(0).asInstanceOf[F1], xs(1).asInstanceOf[F2], xs(2).asInstanceOf[F3], xs(3).asInstanceOf[F4], xs(4).asInstanceOf[F5], xs(5).asInstanceOf[F6], xs(6).asInstanceOf[F7], xs(7).asInstanceOf[F8], xs(8).asInstanceOf[F9], xs(9).asInstanceOf[F10])
this.copy(select = Some(MongoSelect(fields, transformer)))
}
}
@@ -554,14 +433,7 @@ case class BaseQuery[
// *******************************************************
case class BaseModifyQuery[M](
- query: BaseQuery[
- M,
- _,
- _ <: MaybeOrdered,
- _ <: MaybeSelected,
- _ <: MaybeLimited,
- _ <: MaybeSkipped,
- _ <: MaybeHasOrClause],
+ query: BaseQuery[M, _, _],
mod: MongoModify
) {
@@ -595,14 +467,7 @@ case class BaseModifyQuery[M](
// *******************************************************
case class BaseFindAndModifyQuery[M, R](
- query: BaseQuery[
- M,
- R,
- _ <: MaybeOrdered,
- _ <: MaybeSelected,
- _ <: MaybeLimited,
- _ <: MaybeSkipped,
- _ <: MaybeHasOrClause],
+ query: BaseQuery[M, R, _],
mod: MongoModify
) {
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/QueryExecutor.scala b/rogue-core/src/main/scala/com/foursquare/rogue/QueryExecutor.scala
index 6259f29..8f6693b 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/QueryExecutor.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/QueryExecutor.scala
@@ -11,7 +11,7 @@ trait RogueSerializer[R] {
def fromDBObject(dbo: DBObject): R
}
-trait QueryExecutor[MB] {
+trait QueryExecutor[MB] extends Rogue {
def adapter: MongoJavaDriverAdapter[MB]
def optimizer: QueryOptimizer = new QueryOptimizer
@@ -23,11 +23,7 @@ trait QueryExecutor[MB] {
select: Option[MongoSelect[R]]
): RogueSerializer[R]
- def count[M <: MB, Lim <: MaybeLimited, Sk <: MaybeSkipped](
- query: AbstractQuery[M, _, _, _, Lim, Sk, _]
- )(
- implicit ev1: Lim =:= Unlimited, ev2: Sk =:= Unskipped
- ): Long = {
+ def count[M <: MB, State](query: AbstractQuery[M, _, State]): Long = {
if (optimizer.isEmptyQuery(query)) {
0L
} else {
@@ -35,22 +31,8 @@ trait QueryExecutor[MB] {
}
}
- def countDistinct[
- M <: MB,
- Sel <: MaybeSelected,
- Lim <: MaybeLimited,
- Sk <: MaybeSkipped,
- V
- ](
- query: AbstractQuery[M, _, _, Sel, Lim, Sk, _]
- )(
- field: M => Field[V, M]
- )(
- implicit
- // ev1: Sel =:= SelectedOne,
- ev2: Lim =:= Unlimited,
- ev3: Sk =:= Unskipped
- ): Long = {
+ def countDistinct[M <: MB, State, V](query: AbstractQuery[M, _, State])
+ (field: M => Field[V, M]): Long = {
if (optimizer.isEmptyQuery(query)) {
0L
} else {
@@ -59,7 +41,7 @@ trait QueryExecutor[MB] {
}
def fetch[M <: MB, R](
- query: AbstractQuery[M, R, _, _, _, _, _],
+ query: AbstractQuery[M, R, _],
readPreference: ReadPreference = defaultReadPreference
): List[R] = {
if (optimizer.isEmptyQuery(query)) {
@@ -72,15 +54,13 @@ trait QueryExecutor[MB] {
}
}
- def fetchOne[M <: MB, R, Lim <: MaybeLimited](
- query: AbstractQuery[M, R, _, _, Lim, _, _],
+ def fetchOne[M <: MB, R](
+ query: AbstractQuery[M, R, Unlimited],
readPreference: ReadPreference = defaultReadPreference
- )(
- implicit ev1: Lim =:= Unlimited
): Option[R] = fetch(query.limit(1), readPreference).headOption
def foreach[M <: MB, R](
- query: AbstractQuery[M, R, _, _, _, _, _],
+ query: AbstractQuery[M, R, _],
readPreference: ReadPreference = defaultReadPreference
)(
f: R => Unit
@@ -107,7 +87,7 @@ trait QueryExecutor[MB] {
}
def fetchBatch[M <: MB, R, T](
- query: AbstractQuery[M, R, _, _, _, _, _],
+ query: AbstractQuery[M, R, _],
batchSize: Int,
readPreference: ReadPreference = defaultReadPreference
)(
@@ -130,14 +110,9 @@ trait QueryExecutor[MB] {
}
}
- def bulkDelete_!![M <: MB, Sel <: MaybeSelected, Lim <: MaybeLimited, Sk <: MaybeSkipped](
- query: AbstractQuery[M, _, _, Sel, Lim, Sk, _],
+ def bulkDelete_!![M <: MB](
+ query: AbstractQuery[M, _, Unselected with Unlimited with Unskipped],
writeConcern: WriteConcern = defaultWriteConcern
- )(
- implicit
- ev1: Sel <:< Unselected,
- ev2: Lim =:= Unlimited,
- ev3: Sk =:= Unskipped
): Unit = {
if (optimizer.isEmptyQuery(query)) {
()
@@ -206,7 +181,7 @@ trait QueryExecutor[MB] {
}
def findAndDeleteOne[M <: MB, R](
- query: AbstractQuery[M, R, _ <: MaybeOrdered, _ <: MaybeSelected, _ <: MaybeLimited, _ <: MaybeSkipped, _ <: MaybeHasOrClause],
+ query: AbstractQuery[M, R, _],
writeConcern: WriteConcern = defaultWriteConcern
): Option[R] = {
if (optimizer.isEmptyQuery(query)) {
@@ -218,12 +193,12 @@ trait QueryExecutor[MB] {
}
}
- def explain[M <: MB](query: AbstractQuery[M, _, _, _, _, _, _]): String = {
+ def explain[M <: MB](query: AbstractQuery[M, _, _]): String = {
adapter.explain(query)
}
def iterate[S, M <: MB, R](
- query: AbstractQuery[M, R, _, _, _, _, _],
+ query: AbstractQuery[M, R, _],
state: S
)(
handler: (S, Rogue.Iter.Event[R]) => Rogue.Iter.Command[S]
@@ -237,7 +212,7 @@ trait QueryExecutor[MB] {
}
def iterateBatch[S, M <: MB, R](
- query: AbstractQuery[M, R, _, _, _, _, _],
+ query: AbstractQuery[M, R, _],
batchSize: Int,
state: S
)(
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/QueryHelpers.scala b/rogue-core/src/main/scala/com/foursquare/rogue/QueryHelpers.scala
index 4587c72..75a66f7 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/QueryHelpers.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/QueryHelpers.scala
@@ -50,7 +50,7 @@ object QueryHelpers {
trait QueryValidator {
def validateList[T](xs: Traversable[T]): Unit
def validateRadius(d: Degrees): Degrees
- def validateQuery[M](query: BaseQuery[M, _, _, _, _, _, _]): Unit
+ def validateQuery[M](query: BaseQuery[M, _, _]): Unit
def validateModify[M](modify: BaseModifyQuery[M]): Unit
def validateFindAndModify[M, R](modify: BaseFindAndModifyQuery[M, R]): Unit
}
@@ -58,7 +58,7 @@ object QueryHelpers {
class DefaultQueryValidator extends QueryValidator {
override def validateList[T](xs: Traversable[T]) {}
override def validateRadius(d: Degrees) = d
- override def validateQuery[M](query: BaseQuery[M, _, _, _, _, _, _]) {}
+ override def validateQuery[M](query: BaseQuery[M, _, _]) {}
override def validateModify[M](modify: BaseModifyQuery[M]) {}
override def validateFindAndModify[M, R](modify: BaseFindAndModifyQuery[M, R]) {}
}
@@ -68,13 +68,13 @@ object QueryHelpers {
var validator: QueryValidator = NoopQueryValidator
trait QueryTransformer {
- def transformQuery[M](query: BaseQuery[M, _, _, _, _, _, _]): BaseQuery[M, _, _, _, _, _, _]
+ def transformQuery[M](query: BaseQuery[M, _, _]): BaseQuery[M, _, _]
def transformModify[M](modify: BaseModifyQuery[M]): BaseModifyQuery[M]
def transformFindAndModify[M, R](modify: BaseFindAndModifyQuery[M, R]): BaseFindAndModifyQuery[M, R]
}
class DefaultQueryTransformer extends QueryTransformer {
- override def transformQuery[M](query: BaseQuery[M, _, _, _, _, _, _]): BaseQuery[M, _, _, _, _, _, _] = { query }
+ override def transformQuery[M](query: BaseQuery[M, _, _]): BaseQuery[M, _, _] = { query }
override def transformModify[M](modify: BaseModifyQuery[M]): BaseModifyQuery[M] = { modify }
override def transformFindAndModify[M, R](modify: BaseFindAndModifyQuery[M, R]): BaseFindAndModifyQuery[M, R] = { modify }
}
@@ -140,10 +140,10 @@ object QueryHelpers {
JObjectParser.parse(Extraction.decompose(x).asInstanceOf[JObject])
}
- def orConditionFromQueries(subqueries: List[AbstractQuery[_, _, _, _, _, _, _]]) = {
+ def orConditionFromQueries(subqueries: List[AbstractQuery[_, _, _]]) = {
MongoHelpers.OrCondition(subqueries.flatMap(subquery => {
subquery match {
- case q: BaseQuery[_, _, _, _, _, _, _] => Some(q.condition)
+ case q: BaseQuery[_, _, _] => Some(q.condition)
case _ => None
}
}))
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/QueryOptimizer.scala b/rogue-core/src/main/scala/com/foursquare/rogue/QueryOptimizer.scala
index 6c76d21..8de36e1 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/QueryOptimizer.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/QueryOptimizer.scala
@@ -9,7 +9,7 @@ class QueryOptimizer {
case _ => false
}
- def isEmptyQuery(query: BaseQuery[_, _, _, _, _, _, _]): Boolean = {
+ def isEmptyQuery(query: BaseQuery[_, _, _]): Boolean = {
query.condition.clauses.exists(isEmptyClause)
}
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/Rogue.scala b/rogue-core/src/main/scala/com/foursquare/rogue/Rogue.scala
index ec10ef4..099170e 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/Rogue.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/Rogue.scala
@@ -19,15 +19,28 @@ import org.bson.types.ObjectId
*@see AbstractQuery for an example of the use of implicit conversions.
*/
trait Rogue {
+
+ implicit def addOrder[Rest >: Sel with Lim with Sk with Or]: AddOrder[Rest with Unordered, Rest with Ordered] = null
+ implicit def addSelect[Rest >: Ord with Lim with Sk with Or]: AddSelect[Rest with Unselected, Rest with Selected, Rest with SelectedOne] = null
+ implicit def addLimit[Rest >: Ord with Sel with Sk with Or]: AddLimit[Rest with Unlimited, Rest with Limited] = null
+ implicit def addSkip[Rest >: Ord with Sel with Lim with Or]: AddSkip[Rest with Unskipped, Rest with Skipped] = null
+ implicit def addOr[Rest >: Ord with Sel with Lim with Sk]: AddOrClause[Rest with HasNoOrClause, Rest with HasOrClause] = null
+
+ implicit def upcastQuery[M, R, S, T](q: AbstractQuery[M, R, S])(implicit ev: S <:< T): AbstractQuery[M, R, T] =
+ q.asInstanceOf[AbstractQuery[M, R, T]]
+
+ type InitialState = Unordered with Unselected with Unlimited with Unskipped with HasNoOrClause
+ type OrderedState = Ordered with Unselected with Unlimited with Unskipped with HasNoOrClause
+
type Query[T] =
- BaseQuery[T, T, Unordered, Unselected, Unlimited, Unskipped, HasNoOrClause]
+ BaseQuery[T, T, InitialState]
type OrderedQuery[T] =
- BaseQuery[T, T, Ordered, Unselected, Unlimited, Unskipped, HasNoOrClause]
+ BaseQuery[T, T, OrderedState]
// type PaginatedQuery[T <: MongoRecord[T]] = BasePaginatedQuery[T, T]
type ModifyQuery[T] = BaseModifyQuery[T]
- type GenericQuery[M, R] = BaseQuery[M, R, _, _, _, _, _]
+ type GenericQuery[M, R] = BaseQuery[M, R, _]
type GenericBaseQuery[M, R] = GenericQuery[M, R]
object Asc extends IndexModifier(1)
diff --git a/rogue-core/src/main/scala/com/foursquare/rogue/package.scala b/rogue-core/src/main/scala/com/foursquare/rogue/package.scala
index 7a17092..da1cd27 100644
--- a/rogue-core/src/main/scala/com/foursquare/rogue/package.scala
+++ b/rogue-core/src/main/scala/com/foursquare/rogue/package.scala
@@ -3,15 +3,7 @@
package com.foursquare
package object rogue {
- type AbstractQuery[
- M,
- R,
- Ord <: MaybeOrdered,
- Sel <: MaybeSelected,
- Lim <: MaybeLimited,
- Sk <: MaybeSkipped,
- Or <: MaybeHasOrClause
- ] = BaseQuery[M, R, Ord, Sel, Lim, Sk, Or]
+ type AbstractQuery[M, R, +State] = BaseQuery[M, R, State]
type ModifyQuery[T] = BaseModifyQuery[T]
type AbstractModifyQuery[M] = BaseModifyQuery[M]
diff --git a/rogue-lift/src/main/scala/com/foursquare/rogue/ExecutableQuery.scala b/rogue-lift/src/main/scala/com/foursquare/rogue/ExecutableQuery.scala
index 48a728f..6654460 100644
--- a/rogue-lift/src/main/scala/com/foursquare/rogue/ExecutableQuery.scala
+++ b/rogue-lift/src/main/scala/com/foursquare/rogue/ExecutableQuery.scala
@@ -4,19 +4,11 @@ package com.foursquare.rogue
import com.foursquare.field.Field
import com.foursquare.rogue.MongoHelpers.MongoSelect
+import com.foursquare.rogue.Rogue._
import com.mongodb.WriteConcern
-case class ExecutableQuery[
- MB,
- M <: MB,
- R,
- Ord <: MaybeOrdered,
- Sel <: MaybeSelected,
- Lim <: MaybeLimited,
- Sk <: MaybeSkipped,
- Or <: MaybeHasOrClause
-](
- query: AbstractQuery[M, R, Ord, Sel, Lim, Sk, Or],
+case class ExecutableQuery[MB, M <: MB, R, State](
+ query: AbstractQuery[M, R, State],
db: QueryExecutor[MB]
) {
@@ -24,22 +16,23 @@ case class ExecutableQuery[
* Gets the size of the query result. This should only be called on queries that do not
* have limits or skips.
*/
- def count()(implicit ev1: Lim =:= Unlimited, ev2: Sk =:= Unskipped): Long =
+ def count(): Long =
db.count(query)
/**
* Returns the number of distinct values returned by a query. The query must not have
* limit or skip clauses.
*/
- def countDistinct[V](field: M => Field[V, _])
- (implicit ev1: Lim =:= Unlimited, ev2: Sk =:= Unskipped): Long =
+ def countDistinct[V](field: M => Field[V, _]): Long =
db.countDistinct(query)(field.asInstanceOf[M => Field[V, M]])
/**
* Checks if there are any records that match this query.
*/
- def exists()(implicit ev1: Lim =:= Unlimited, ev2: Sk =:= Unskipped): Boolean =
- db.fetch(query.copy(select = Some(MongoSelect[Null](Nil, _ => null))).limit(1)).size > 0
+ def exists()(implicit ev: State <:< Unlimited with Unskipped): Boolean = {
+ val q = query.copy(select = Some(MongoSelect[Null](Nil, _ => null)))
+ db.fetch(q.limit(1)).size > 0
+ }
/**
* Executes a function on each record value returned by a query.
@@ -61,8 +54,8 @@ case class ExecutableQuery[
* query must not have a limit clause.
* @param limit the maximum number of records to return.
*/
- def fetch(limit: Int)(implicit ev: Lim =:= Unlimited): List[R] =
- db.fetch(query.limit(limit))
+ def fetch(limit: Int)(implicit ev: State <:< Unlimited): List[R] =
+ db.fetch(upcastQuery(query).limit(limit))
/**
* fetch a batch of results, and execute a function on each element of the list.
@@ -72,22 +65,23 @@ case class ExecutableQuery[
def fetchBatch[T](batchSize: Int)(f: List[R] => List[T]): List[T] =
db.fetchBatch(query, batchSize)(f).toList
+
/**
* Fetches the first record that matches the query. The query must not contain a "limited" clause.
* @return an option record containing either the first result that matches the
* query, or None if there are no records that match.
*/
- def get()(implicit ev: Lim =:= Unlimited): Option[R] =
- db.fetchOne(query)
+ def get()(implicit ev: State <:< Unlimited): Option[R] =
+ db.fetchOne(upcastQuery(query))
/**
* Fetches the records that match the query in paginated form. The query must not contain
* a "limit" clause.
* @param countPerPage the number of records to be contained in each page of the result.
*/
- def paginate(countPerPage: Int)(implicit ev1: Lim =:= Unlimited, ev2: Sk =:= Unskipped) = {
- val q = query.asInstanceOf[AbstractQuery[M, R, Ord, Sel, Unlimited, Unskipped, Or]]
- new BasePaginatedQuery[MB, M, R](q, db, countPerPage)
+ def paginate(countPerPage: Int)
+ (implicit ev: State <:< Unlimited with Unskipped) = {
+ new BasePaginatedQuery[MB, M, R](upcastQuery(query), db, countPerPage)
}
/**
@@ -95,20 +89,17 @@ case class ExecutableQuery[
* "limit", or "select" clauses. Sends the delete operation to mongo, and returns - does
* not wait for the delete to be finished.
*/
- def bulkDelete_!!!()(implicit ev1: Sel <:< Unselected,
- ev2: Lim =:= Unlimited,
- ev3: Sk =:= Unskipped): Unit =
- db.bulkDelete_!!(query)
+ def bulkDelete_!!!()(implicit ev: State <:< Unselected with Unlimited with Unskipped): Unit =
+ db.bulkDelete_!!(upcastQuery(query))
/**
* Delete all of the records that match the query. The query must not contain any "skip",
* "limit", or "select" clauses. Sends the delete operation to mongo, and waits for the
* delete operation to complete before returning to the caller.
*/
- def bulkDelete_!!(concern: WriteConcern)(implicit ev1: Sel <:< Unselected,
- ev2: Lim =:= Unlimited,
- ev3: Sk =:= Unskipped): Unit =
- db.bulkDelete_!!(query, concern)
+ def bulkDelete_!!(concern: WriteConcern)
+ (implicit ev: State <:< Unselected with Unlimited with Unskipped): Unit =
+ db.bulkDelete_!!(upcastQuery(query), concern)
/**
* Finds the first record that matches the query (if any), fetches it, and then deletes it.
@@ -164,7 +155,7 @@ case class ExecutableFindAndModifyQuery[MB, M <: MB, R](
}
class BasePaginatedQuery[MB, M <: MB, R](
- q: AbstractQuery[M, R, _, _, Unlimited, Unskipped, _],
+ q: AbstractQuery[M, R, Unlimited with Unskipped],
db: QueryExecutor[MB],
val countPerPage: Int,
val pageNum: Int = 1
@@ -177,7 +168,9 @@ class BasePaginatedQuery[MB, M <: MB, R](
lazy val countAll: Long = db.count(q)
- def fetch(): List[R] = db.fetch(q.skip(countPerPage * (pageNum - 1)).limit(countPerPage))
+ def fetch[S2, S3](): List[R] = {
+ db.fetch(q.skip(countPerPage * (pageNum - 1)).limit(countPerPage))
+ }
def numPages = math.ceil(countAll.toDouble / countPerPage.toDouble).toInt max 1
}
diff --git a/rogue-lift/src/main/scala/com/foursquare/rogue/LiftRogue.scala b/rogue-lift/src/main/scala/com/foursquare/rogue/LiftRogue.scala
index d650ccf..0688e13 100644
--- a/rogue-lift/src/main/scala/com/foursquare/rogue/LiftRogue.scala
+++ b/rogue-lift/src/main/scala/com/foursquare/rogue/LiftRogue.scala
@@ -19,13 +19,13 @@ import net.liftweb.record.field.EnumField
trait LiftRogue extends Rogue {
def OrQuery[M <: MongoRecord[M], R]
- (subqueries: AbstractQuery[M, R, Unordered, Unselected, Unlimited, Unskipped, _]*)
- : AbstractQuery[M, R, Unordered, Unselected, Unlimited, Unskipped, HasOrClause] = {
+ (subqueries: AbstractQuery[M, R, _]*)
+ : AbstractQuery[M, R, Unordered with Unselected with Unlimited with Unskipped with HasOrClause] = {
subqueries.toList match {
case Nil => throw new RogueException("No subqueries supplied to OrQuery", null)
case q :: qs => {
val orCondition = QueryHelpers.orConditionFromQueries(q :: qs)
- BaseQuery[M, R, Unordered, Unselected, Unlimited, Unskipped, HasOrClause](
+ BaseQuery[M, R, Unordered with Unselected with Unlimited with Unskipped with HasOrClause](
q.meta, q.collectionName, None, None, None, None, None,
AndCondition(Nil, Some(orCondition)), None, None, None)
}
@@ -36,8 +36,8 @@ trait LiftRogue extends Rogue {
* a QueryBuilder. This allows users to write queries as "QueryType where ...".
*/
implicit def metaRecordToQueryBuilder[M <: MongoRecord[M]]
- (rec: M with MongoMetaRecord[M]): BaseQuery[M, M, Unordered, Unselected, Unlimited, Unskipped, HasNoOrClause] =
- BaseQuery[M, M, Unordered, Unselected, Unlimited, Unskipped, HasNoOrClause](
+ (rec: M with MongoMetaRecord[M]): BaseQuery[M, M, InitialState] =
+ BaseQuery[M, M, InitialState](
rec, rec.collectionName, None, None, None, None, None, AndCondition(Nil, None), None, None, None)
implicit def metaRecordToModifyQuery[M <: MongoRecord[M]](rec: M with MongoMetaRecord[M]): AbstractModifyQuery[M] =
@@ -51,9 +51,9 @@ trait LiftRogue extends Rogue {
*/
implicit def queryBuilderToModifyQuery[
M <: MongoRecord[M],
- Or <: MaybeHasOrClause
+ State <: Unordered with Unselected with Unlimited with Unskipped
](
- query: AbstractQuery[M, M, Unordered, Unselected, Unlimited, Unskipped, Or]
+ query: AbstractQuery[M, M, State]
): AbstractModifyQuery[M] = {
BaseModifyQuery[M](query, MongoModify(Nil))
}
@@ -61,11 +61,9 @@ trait LiftRogue extends Rogue {
implicit def queryBuilderToFindAndModifyQuery[
M <: MongoRecord[M],
R,
- Ord <: MaybeOrdered,
- Sel <: MaybeSelected,
- Or <: MaybeHasOrClause
+ State <: Unlimited with Unskipped
](
- query: AbstractQuery[M, R, Ord, Sel, Unlimited, Unskipped, Or]
+ query: AbstractQuery[M, R, State]
): AbstractFindAndModifyQuery[M, R] = {
BaseFindAndModifyQuery[M, R](query, MongoModify(Nil))
}
@@ -73,16 +71,12 @@ trait LiftRogue extends Rogue {
implicit def queryToLiftQuery[
M <: MongoRecord[_],
R,
- Ord <: MaybeOrdered,
- Sel <: MaybeSelected,
- Lim <: MaybeLimited,
- Sk <: MaybeSkipped,
- Or <: MaybeHasOrClause
+ State
](
- query: BaseQuery[M, R, Ord, Sel, Lim, Sk, Or]
- ): ExecutableQuery[MongoRecord[_] with MongoMetaRecord[_], M with MongoMetaRecord[_], R, Ord, Sel, Lim, Sk, Or] = {
+ query: BaseQuery[M, R, State]
+ ): ExecutableQuery[MongoRecord[_] with MongoMetaRecord[_], M with MongoMetaRecord[_], R, State] = {
ExecutableQuery(
- query.asInstanceOf[BaseQuery[M with MongoMetaRecord[_], R, Ord, Sel, Lim, Sk, Or]],
+ query.asInstanceOf[BaseQuery[M with MongoMetaRecord[_], R, State]],
LiftQueryExecutor
)
}
@@ -107,7 +101,7 @@ trait LiftRogue extends Rogue {
implicit def metaRecordToLiftQuery[M <: MongoRecord[M]](
rec: M with MongoMetaRecord[M]
- ): ExecutableQuery[MongoRecord[_] with MongoMetaRecord[_], M with MongoMetaRecord[_], M, Unordered, Unselected, Unlimited, Unskipped, HasNoOrClause] = {
+ ): ExecutableQuery[MongoRecord[_] with MongoMetaRecord[_], M with MongoMetaRecord[_], M, InitialState] = {
val queryBuilder = metaRecordToQueryBuilder(rec)
val liftQuery = queryToLiftQuery(queryBuilder)
liftQuery
diff --git a/rogue-lift/src/test/scala/com/foursquare/rogue/QueryExecutorTest.scala b/rogue-lift/src/test/scala/com/foursquare/rogue/QueryExecutorTest.scala
index 527301e..bf3db3a 100644
--- a/rogue-lift/src/test/scala/com/foursquare/rogue/QueryExecutorTest.scala
+++ b/rogue-lift/src/test/scala/com/foursquare/rogue/QueryExecutorTest.scala
@@ -17,7 +17,7 @@ class LegacyQueryExecutorTest extends SpecsMatchers {
@Test
def testExeptionInRunCommandIsDecorated {
- val query = BaseQuery[Dummy.type, Dummy, Unordered, Unselected, Unlimited, Unskipped, HasNoOrClause](
+ val query = BaseQuery[Dummy.type, Dummy, Rogue.InitialState](
Dummy, "Dummy", None, None, None, None, None, AndCondition(Nil, None), None, None, None)
(LiftAdapter.runCommand("hello", query){
throw new RuntimeException("bang")
diff --git a/rogue-lift/src/test/scala/com/foursquare/rogue/QueryTest.scala b/rogue-lift/src/test/scala/com/foursquare/rogue/QueryTest.scala
index d10b6f4..ba0549c 100644
--- a/rogue-lift/src/test/scala/com/foursquare/rogue/QueryTest.scala
+++ b/rogue-lift/src/test/scala/com/foursquare/rogue/QueryTest.scala
@@ -525,7 +525,7 @@ class QueryTest extends SpecsMatchers {
@Test
def testSetReadPreference: Unit = {
- type Q = BaseQuery[Venue, Venue, _, _, _, _, _]
+ type Q = BaseQuery[Venue, Venue, _]
Venue.where(_.mayor eqs 2).asInstanceOf[Q].readPreference must_== None
Venue.where(_.mayor eqs 2).setReadPreference(ReadPreference.SECONDARY).asInstanceOf[Q].readPreference must_== Some(ReadPreference.SECONDARY)
@@ -602,16 +602,13 @@ class QueryTest extends SpecsMatchers {
//
// Phantom type stuff
//
+
check("""Venue orderAsc(_.legacyid) orderAsc(_.closed)""")
check("""Venue andAsc(_.legacyid)""")
check("""Venue limit(1) limit(5)""")
check("""Venue limit(1) fetch(5)""")
check("""Venue limit(1) get()""")
check("""Venue skip(3) skip(3)""")
- check("""Venue limit(10) count()""")
- check("""Venue skip(10) count()""")
- check("""Venue limit(10) countDistinct(_.legacyid)""")
- check("""Venue skip(10) countDistinct(_.legacyid)""")
check("""Venue select(_.legacyid) select(_.closed)""")
// select case class