Skip to content

Commit

Permalink
simplified phantom types
Browse files Browse the repository at this point in the history
  • Loading branch information
jliszka committed Jun 14, 2012
1 parent 2fce930 commit a0588a9
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 404 deletions.
55 changes: 31 additions & 24 deletions rogue-core/src/main/scala/com/foursquare/rogue/PhantomTypes.scala
Expand Up @@ -6,43 +6,50 @@ 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
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
389 changes: 127 additions & 262 deletions rogue-core/src/main/scala/com/foursquare/rogue/Query.scala

Large diffs are not rendered by default.

55 changes: 15 additions & 40 deletions rogue-core/src/main/scala/com/foursquare/rogue/QueryExecutor.scala
Expand Up @@ -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

Expand All @@ -23,34 +23,16 @@ 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 {
adapter.count(query)
}
}

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 {
Expand All @@ -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)) {
Expand All @@ -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
Expand All @@ -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
)(
Expand All @@ -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)) {
()
Expand Down Expand Up @@ -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)) {
Expand All @@ -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]
Expand All @@ -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
)(
Expand Down
Expand Up @@ -50,15 +50,15 @@ 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
}

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]) {}
}
Expand All @@ -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 }
}
Expand Down Expand Up @@ -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
}
}))
Expand Down
Expand Up @@ -9,7 +9,7 @@ class QueryOptimizer {
case _ => false
}

def isEmptyQuery(query: BaseQuery[_, _, _, _, _, _, _]): Boolean = {
def isEmptyQuery(query: BaseQuery[_, _, _]): Boolean = {
query.condition.clauses.exists(isEmptyClause)
}

Expand Down
19 changes: 16 additions & 3 deletions rogue-core/src/main/scala/com/foursquare/rogue/Rogue.scala
Expand Up @@ -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)
Expand Down
10 changes: 1 addition & 9 deletions rogue-core/src/main/scala/com/foursquare/rogue/package.scala
Expand Up @@ -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]
Expand Down

0 comments on commit a0588a9

Please sign in to comment.