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

quasar.mimir.MimirCake.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014–2018 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.mimir

import quasar.contrib.scalaz._
import quasar.fp.ski.κ
import quasar.qscript._
import quasar.yggdrasil.TableModule.{DesiredSortOrder, SortAscending}

import delorean._
import matryoshka._
import matryoshka.implicits._
import matryoshka.data._
import matryoshka.patterns._
import scalaz._, Scalaz._
import scalaz.Leibniz.===
import scalaz.concurrent.Task

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object MimirCake {

  type Cake = Precog with Singleton

  type MT[F[_], A] = Kleisli[F, Cake, A]
  type CakeM[A] = MT[Task, A]

  def cake[F[_]](implicit F: MonadReader_[F, Cake]): F[Cake] = F.ask

  // EquiJoin results are sorted by both keys at the same time, so we need to keep track of both
  final case class SortOrdering[TS1](sortKeys: Set[TS1], sortOrder: DesiredSortOrder, unique: Boolean) {
    def sort(src: Cake)(table: src.Table)(implicit ev: TS1 === src.trans.TransSpec1): Future[src.Table] =
      if (sortKeys.isEmpty) {
        Future.successful(table)
      } else {
        table.sort(ev(sortKeys.head), sortOrder, unique)
      }
  }

  final case class SortState[TS1](bucket: Option[TS1], orderings: List[SortOrdering[TS1]])

  def interpretMapFunc[T[_[_]], F[_]: Monad]
    (P: Precog, planner: MapFuncPlanner[T, F, MapFunc[T, ?]])
    (fm: FreeMap[T])
      : F[P.trans.TransSpec1] =
    fm.cataM[F, P.trans.TransSpec1](
      interpretM(
        κ(P.trans.TransSpec1.Id.point[F]),
        planner.plan(P)[P.trans.Source1](P.trans.TransSpec1.Id)))

  def combineTransSpecs(P: Precog)(specs: Seq[P.trans.TransSpec1]): P.trans.TransSpec1 = {
    import P.trans._

    if (specs.isEmpty)
      TransSpec1.Id
    else if (specs.lengthCompare(1) == 0)
      WrapArray(specs.head)
    else
      OuterArrayConcat(specs.map(WrapArray(_): TransSpec1) : _*)
  }

  // sort by one dimension
  def sortT[P0 <: Cake](c: MimirRepr.Aux[P0])(
      table: c.P.Table,
      sortKey: c.P.trans.TransSpec1,
      sortOrder: DesiredSortOrder = SortAscending,
      unique: Boolean = false): Task[MimirRepr.Aux[c.P.type]] = {

    val newRepr =
      SortState[c.P.trans.TransSpec1](
        bucket = None,
        orderings = SortOrdering(Set(sortKey), sortOrder, unique) :: Nil)

    if (c.lastSort.fold(true)(needToSort(c.P)(_, newSort = newRepr))) {
      table.sort(sortKey, sortOrder, unique).toTask map { sorted =>
        MimirRepr.withSort(c.P)(sorted)(Some(newRepr))
      }
    } else {
      Task.now(MimirRepr.withSort(c.P)(table)(Some(newRepr)))
    }
  }

  def needToSort(p: Precog)(oldSort: SortState[p.trans.TransSpec1], newSort: SortState[p.trans.TransSpec1])
      : Boolean = {
    (oldSort.orderings.length != newSort.orderings.length || oldSort.bucket != newSort.bucket) || {
      def requiresSort(oldOrdering: SortOrdering[p.trans.TransSpec1], newOrdering: SortOrdering[p.trans.TransSpec1]) = {
        (oldOrdering.sortKeys & newOrdering.sortKeys).isEmpty ||
          (oldOrdering.sortOrder != newOrdering.sortOrder) ||
          (oldOrdering.unique && !newOrdering.unique)
      }

      (oldSort.bucket != newSort.bucket) || {
        val allOrderings = oldSort.orderings.zip(newSort.orderings)
        allOrderings.exists { case (o, n) => requiresSort(o, n) }
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy