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

com.outworkers.phantom.ops.SelectQueryOps.scala Maven / Gradle / Ivy

/*
 * Copyright 2013 - 2020 Outworkers Ltd.
 *
 * 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 com.outworkers.phantom.ops
import com.datastax.driver.core.Session
import com.outworkers.phantom.builder._
import com.outworkers.phantom.builder.query.execution._
import com.outworkers.phantom.builder.query.prepared.{PreparedFlattener, PreparedSelectBlock}
import com.outworkers.phantom.builder.query.{LimitedPart, SelectQuery}
import com.outworkers.phantom.connectors.KeySpace
import com.outworkers.phantom.{CassandraTable, Row}
import shapeless.ops.hlist.Reverse
import shapeless.{=:!=, HList, HNil}

import scala.annotation.implicitNotFound
import scala.concurrent.ExecutionContextExecutor

class SelectQueryOps[
  P[_],
  F[_],
  Table <: CassandraTable[Table, _],
  Record,
  Limit <: LimitBound,
  Order <: OrderBound,
  Status <: ConsistencyBound,
  Chain <: WhereBound,
  PS <: HList,
  TK <: HList
](
  val query: SelectQuery[Table, Record, Limit, Order, Status, Chain, PS]
)(
  implicit adapter: GuavaAdapter[F],
  fMonad: FutureMonad[F]
) extends ResultQueryInterface[F, Table, Record, Limit] {

  /**
    * Returns the first row from the select ignoring everything else
    * @param session The implicit session provided by a [[com.outworkers.phantom.connectors.Connector]].
    * @param ev The implicit limit for the query.
    * @param ec The implicit Scala execution context.
    * @return A Scala future guaranteed to contain a single result wrapped as an Option.
    */
  @implicitNotFound("You have already defined limit on this Query. You cannot specify multiple limits on the same builder.")
  def one()(
    implicit session: Session,
    ev: Limit =:= Unlimited,
    ec: ExecutionContextExecutor
  ): F[Option[Record]] = {
    val enforceLimit = if (query.count) LimitedPart.empty else query.limitedPart append QueryBuilder.limit(1.toString)
    singleFetch(adapter.fromGuava(query.copy(limitedPart = enforceLimit).executableQuery.statement()))
  }

  /**
    * Returns the result of an aggregate function call, provided a single aggregate function was invoked.
    * This is used to circumvent some compiler limitations around HLists being tupled. Phantom relies on HLists
    * to compute a multiple aggregate return function extractor, and if a single aggregate is selected,
    * a Tuple1(value) is returned. This function will extract the content of the Tuple1 to have a more presentable type.
    * @param session The implicit session provided by a [[com.outworkers.phantom.connectors.Connector]].
    * @param ev The implicit limit for the query.
    * @param ec The implicit Scala execution context.
    * @return A Scala future guaranteed to contain a single result wrapped as an Option.
    */
  def aggregate[T]()(
    implicit session: Session,
    ev: Limit =:= Unlimited,
    ec: ExecutionContextExecutor,
    unwrap: Record <:< Tuple1[T]
  ): F[Option[T]] = {
    singleFetch(adapter.fromGuava(query.executableQuery.statement())).map(_.map { case Tuple1(vd: T) => vd })
  }

  /**
    * Returns the first row from the select ignoring everything else
    * @param session The implicit session provided by a [[com.outworkers.phantom.connectors.Connector]].
    * @param ev The implicit limit for the query.
    * @param ec The implicit Scala execution context.
    * @return A Scala future guaranteed to contain a single result wrapped as an Option.
    */
  @implicitNotFound("You have already defined limit on this Query. You cannot specify multiple limits on the same builder.")
  def multiAggregate()(
    implicit session: Session,
    ev: Limit =:= Unlimited,
    ec: ExecutionContextExecutor
  ): F[Option[Record]] = {
    singleFetch(adapter.fromGuava(query.executableQuery.statement()))
  }

  override def fromRow(r: Row): Record = query.fromRow(r)

  def prepareAsync[Rev <: HList]()(
    implicit session: Session,
    executor: ExecutionContextExecutor,
    keySpace: KeySpace,
    ev: PS =:!= HNil,
    rev: Reverse.Aux[PS, Rev],
    fMonad: FutureMonad[F],
    interface: PromiseInterface[P, F]
  ): F[PreparedSelectBlock[Table, Record, Limit, Rev]] = {
    val flatten = new PreparedFlattener(executableQuery.qb)

    flatten.async map { ps =>
      new PreparedSelectBlock[Table, Record, Limit, Rev](
        ps,
        flatten.protocolVersion,
        fromRow,
        executableQuery.options
      )
    }
  }

  override def executableQuery: ExecutableCqlQuery = query.executableQuery
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy