quasar.physical.mongodb.execution.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014–2017 SlamData Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package quasar.physical.mongodb
import slamdata.Predef._
import quasar.common.SortDir
import quasar.fp._
import quasar.physical.mongodb.accumulator._
import quasar.physical.mongodb.expression._
import quasar.physical.mongodb.workflow._
import scalaz._, Scalaz._
private[mongodb] object execution {
final case class Count(
query: Option[Selector],
skip: Option[Long],
limit: Option[Long])
final case class Distinct(
field: BsonField.Name,
query: Option[Selector])
final case class Find(
query: Option[Selector],
projection: Option[Bson.Doc],
sort: Option[NonEmptyList[(BsonField, SortDir)]],
skip: Option[Long],
limit: Option[Long])
// NB: need to construct core exprs in the type used for pipeline ops.
// FIXME: For now, that's just the core type itself.
import fixExprOp._
/** Extractor to determine whether a `$GroupF` represents a simple `count()`. */
object Countable {
def unapply(op: PipelineOp): Option[BsonField.Name] = op match {
case PipelineOpCore($GroupF((), Grouped(map), \/-($literal(Bson.Null)))) if map.size ≟ 1 =>
map.headOption
.filter(_._2 == $sum($literal(Bson.Int32(1))))
.map(_._1)
case _ => None
}
}
object Distinctable {
def unapply(pipeline: workflowtask.Pipeline): Option[(BsonField.Name, BsonField.Name)] =
pipeline match {
case List(
PipelineOpCore($GroupF((), Grouped(map), by)),
PipelineOpCore($ProjectF((), Reshape(fields), IgnoreId | ExcludeId)))
if map.isEmpty && fields.size ≟ 1 =>
fields.headOption.fold[Option[(BsonField.Name, BsonField.Name)]] (None)(field =>
(by, field) match {
case (\/-($var(DocField(origField @ BsonField.Name(_)))), (newField, \/-($var(DocField(IdName))))) =>
(origField, newField).some
case (-\/(Reshape(map)), (newField, \/-($var(DocField(BsonField.Path(NonEmptyList(IdName, ICons(x, INil())))))))) if map.size ≟ 1 =>
map.get(x).flatMap {
case \/-($var(DocField(origField @ BsonField.Name(_)))) => (origField, newField).some
case _ => None
}
case _ => None
})
case _ => None
}
}
object Projectable {
def unapply(op: PipelineOp): Option[Bson.Doc] = op match {
case PipelineOpCore(proj @ $ProjectF((), Reshape(map), _))
if map.all(_ == \/-($include())) =>
proj.pipelineRhs.some
case _ => None
}
}
object SingleListMap {
def unapply[A, B](lm: ListMap[A, B]): Option[(A, B)] =
if (lm.size <= 1) lm.headOption else None
}
object SimpleRename {
/**
* Extractor that recognizes a $ProjectF reshaping a single `BsonField.Name` - `BsonField` entry.
* Conceptually this can be seen as a rename from a single `BsonField` to a `BsonField.Name`.
*/
def unapply(op: PipelineOp): Option[(BsonField.Name, BsonField)] = op match {
case PipelineOpCore(proj @ $ProjectF((), Reshape(SingleListMap(bn @ BsonField.Name(_), \/-($var(DocField(bf))))), IgnoreId | ExcludeId)) =>
(bn, bf).some
case _ => None
}
}
object CountableRename {
/**
* Extractor that recognizes a Countable(field), optionally followed by a
* `SimpleRename` from that same `field` to a new name.
* In case there is such a rename then effectively that's the same as
* recognizing a Countable of that new name.
*/
def unapply(pipeline: workflowtask.Pipeline): Option[BsonField.Name] =
pipeline match {
case List(Countable(field)) =>
field.some
case List(Countable(field), SimpleRename(name, f))
if (field: BsonField) ≟ f =>
name.some
case _ => None
}
}
@SuppressWarnings(Array("org.wartremover.warts.Recursion"))
def extractRange(pipeline: workflowtask.Pipeline):
((workflowtask.Pipeline, workflowtask.Pipeline),
(Option[Long], Option[Long])) =
pipeline match {
case Nil => ((Nil, Nil), (None, None))
case PipelineOpCore($LimitF((), l)) ::
PipelineOpCore($SkipF((), s)) ::
t => ((Nil, t), (s.some, (l - s).some))
case PipelineOpCore($LimitF((), l)) ::
t => ((Nil, t), (None, l.some))
case PipelineOpCore($SkipF((), s)) ::
t => ((Nil, t), (s.some, None))
case h ::
t => (h :: (_: workflowtask.Pipeline)).first.first(extractRange(t))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy