All Downloads are FREE. Search and download functionalities are using the official Maven repository.

quasar.physical.mongodb.workflowtask.ast.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.workflowtask

import slamdata.Predef._
import quasar.{RenderTree, Terminal, NonTerminal}
import quasar.javascript._
import quasar.physical.mongodb.{Bson, Collection, MapReduce, Selector}
import quasar.physical.mongodb.workflow._
import MapReduce._

import matryoshka.Delay
import scalaz._, Scalaz._

/** A WorkflowTask approximately represents one request to MongoDB. */
sealed abstract class WorkflowTaskF[A]
object WorkflowTaskF {
  /** A task that returns a necessarily small amount of raw data. */
  final case class PureTaskF[A](value: Bson) extends WorkflowTaskF[A]

  /** A task that merely sources data from some specified collection. */
  final case class ReadTaskF[A](value: Collection) extends WorkflowTaskF[A]

  /** A task that executes a Mongo read query. */
  final case class QueryTaskF[A](
    source: A, query: Selector, skip: Option[Int], limit: Option[Int])
      extends WorkflowTaskF[A]

  /** A task that executes a Mongo pipeline aggregation. */
  final case class PipelineTaskF[A](source: A, pipeline: Pipeline)
      extends WorkflowTaskF[A]

  /** A task that executes a Mongo map/reduce job. */
  final case class MapReduceTaskF[A](source: A, mapReduce: MapReduce, outAct: Option[Action])
      extends WorkflowTaskF[A]

  /** A task that executes a sequence of other tasks, one at a time, collecting
    * the results in the same collection. The first task must produce a new
    * collection, and the remaining tasks must be able to merge their results
    * into an existing collection.
    */
  final case class FoldLeftTaskF[A](head: A, tail: NonEmptyList[A])
      extends WorkflowTaskF[A]

  /** A task that evaluates some code on the server. The JavaScript function
    * must accept two parameters: the source collection, and the destination
    * collection.
    */
  // final case class EvalTaskF[A](source: A, code: Js.FuncDecl)
  //     extends WorkflowTaskF[A]

  implicit def traverse: Traverse[WorkflowTaskF] =
    new Traverse[WorkflowTaskF] {
      def traverseImpl[G[_], A, B](fa: WorkflowTaskF[A])(f: A => G[B])(implicit G: Applicative[G]):
          G[WorkflowTaskF[B]] =
        fa match {
          case PureTaskF(bson) => G.point(PureTaskF[B](bson))
          case ReadTaskF(coll) => G.point(ReadTaskF[B](coll))
          case QueryTaskF(src, query, skip, limit) =>
            f(src).map(QueryTaskF(_, query, skip, limit))
          case PipelineTaskF(src, pipe) => f(src).map(PipelineTaskF(_, pipe))
          case MapReduceTaskF(src, mr, oa) => f(src).map(MapReduceTaskF(_, mr, oa))
          case FoldLeftTaskF(h, t) =>
            (f(h) |@| t.traverse(f))(FoldLeftTaskF(_, _))
        }
    }

  implicit val renderTree: Delay[RenderTree, WorkflowTaskF] =
    new Delay[RenderTree, WorkflowTaskF] {
      def apply[A](ra: RenderTree[A]) = new RenderTree[WorkflowTaskF[A]] {
        val RC = RenderTree[Collection]
        val RO = RenderTree[WorkflowF[Unit]]
        val RJ = RenderTree[Js]
        val RS = RenderTree[Selector]

        val WorkflowTaskNodeType = "WorkflowTask" :: "Workflow" :: Nil

        def render(task: WorkflowTaskF[A]) = task match {
          case PureTaskF(bson) => Terminal("PureTask" :: WorkflowTaskNodeType,
            Some(bson.shows))
          case ReadTaskF(value) => RC.render(value).copy(nodeType = "ReadTask" :: WorkflowTaskNodeType)

          case QueryTaskF(source, query, skip, limit) =>
            val nt = "PipelineTask" :: WorkflowTaskNodeType
            NonTerminal(nt, (skip.shows + ", " + limit.shows).some,
              ra.render(source) ::
                Terminal("Selector" :: nt, query.shows.some) ::
                Nil)

          case PipelineTaskF(source, pipeline) =>
            val nt = "PipelineTask" :: WorkflowTaskNodeType
            NonTerminal(nt, None,
              ra.render(source) ::
              NonTerminal("Pipeline" :: nt, None, pipeline.map(p => RO.render(p.op))) ::
                Nil)

          case MapReduceTaskF(source, MapReduce(map, reduce, selectorOpt, sortOpt, limitOpt, finalizerOpt, scopeOpt, jsModeOpt, verboseOpt), outAct) =>
            val nt = "MapReduceTask" :: WorkflowTaskNodeType
            NonTerminal(nt, None, List(
              ra.render(source),
              RJ.render(map),
              RJ.render(reduce),
              selectorOpt.fold(Terminal("None" :: Nil, None))(RS.render(_)),
              sortOpt.fold(Terminal("None" :: Nil, None))(keys =>
                NonTerminal("Sort" :: nt, None, keys.list.toList map { case (expr, ot) =>
                  Terminal("Key" :: "Sort" :: nt, Some(expr.shows + " -> " + ot.shows))
                })),
              Terminal("Limit" :: nt, limitOpt ∘ (_.shows)),
              finalizerOpt.fold(Terminal("None" :: Nil, None))(RJ.render(_)),
              Terminal("Scope" :: nt, Some(scopeOpt.toString)),
              Terminal("JsMode" :: nt, jsModeOpt ∘ (_.shows))
            ) ::: outAct.map(act => Terminal("Out" :: nt, Some(Action.bsonFieldName(act)))).toList)

          case FoldLeftTaskF(head, tail) =>
            NonTerminal("FoldLeftTask" :: WorkflowTaskNodeType, None, ra.render(head) :: tail.toList.map(ra.render))
        }
      }
    }
}

object PureTaskF {
  def apply[A](bson: Bson): WorkflowTaskF[A] = WorkflowTaskF.PureTaskF[A](bson)
  def unapply[A](obj: WorkflowTaskF[A]): Option[Bson] = obj match {
    case WorkflowTaskF.PureTaskF(bson) => Some(bson)
    case _                             => None
  }
}

object ReadTaskF {
  def apply[A](coll: Collection): WorkflowTaskF[A] =
    WorkflowTaskF.ReadTaskF[A](coll)
  def unapply[A](obj: WorkflowTaskF[A]): Option[Collection] = obj match {
    case WorkflowTaskF.ReadTaskF(coll) => Some(coll)
    case _                             => None
  }
}

object QueryTaskF {
  def apply[A](
    source: A, query: Selector, skip: Option[Int], limit: Option[Int]):
      WorkflowTaskF[A] =
    WorkflowTaskF.QueryTaskF[A](source, query, skip, limit)
  def unapply[A](obj: WorkflowTaskF[A]):
      Option[(A, Selector, Option[Int], Option[Int])] =
    obj match {
      case WorkflowTaskF.QueryTaskF(source, query, skip, limit) =>
        Some((source, query, skip, limit))
      case _ => None
    }
}

object PipelineTaskF {
  def apply[A](source: A, pipeline: Pipeline): WorkflowTaskF[A] =
    WorkflowTaskF.PipelineTaskF[A](source, pipeline)
  def unapply[A](obj: WorkflowTaskF[A]): Option[(A, Pipeline)] = obj match {
    case WorkflowTaskF.PipelineTaskF(source, pipeline) =>
      Some((source, pipeline))
    case _ => None
  }
}

object MapReduceTaskF {
  import MapReduce._
  def apply[A](source: A, mapReduce: MapReduce, outAct: Option[Action]): WorkflowTaskF[A] =
    WorkflowTaskF.MapReduceTaskF[A](source, mapReduce, outAct)
  def unapply[A](obj: WorkflowTaskF[A]): Option[(A, MapReduce, Option[Action])] = obj match {
    case WorkflowTaskF.MapReduceTaskF(source, mapReduce, outAct) =>
      Some((source, mapReduce, outAct))
    case _ => None
  }
}

object FoldLeftTaskF {
  def apply[A](head: A, tail: NonEmptyList[A]): WorkflowTaskF[A] =
    WorkflowTaskF.FoldLeftTaskF[A](head, tail)
  def unapply[A](obj: WorkflowTaskF[A]): Option[(A, NonEmptyList[A])] =
    obj match {
      case WorkflowTaskF.FoldLeftTaskF(head, tail) => Some((head, tail))
      case _                                       => None
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy