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

com.outworkers.phantom.builder.query.DeleteQuery.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.builder.query

import com.datastax.driver.core.{ConsistencyLevel, Session}
import com.outworkers.phantom.CassandraTable
import com.outworkers.phantom.builder._
import com.outworkers.phantom.builder.clauses._
import com.outworkers.phantom.builder.ops.{MapKeyUpdateClause, TokenizerKey}
import com.outworkers.phantom.builder.query.engine.CQLQuery
import com.outworkers.phantom.builder.query.execution._
import com.outworkers.phantom.builder.query.prepared.{PreparedBlock, PreparedFlattener}
import com.outworkers.phantom.column.AbstractColumn
import com.outworkers.phantom.connectors.KeySpace
import org.joda.time.DateTime
import shapeless.ops.hlist.{Prepend, Reverse}
import shapeless.{=:!=, HList, HNil}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContextExecutor

case class DeleteQuery[
  Table <: CassandraTable[Table, _],
  Record,
  Limit <: LimitBound,
  Order <: OrderBound,
  Status <: ConsistencyBound,
  Chain <: WhereBound,
  PS <: HList
](table: Table,
  init: CQLQuery,
  tokens: List[TokenizerKey] = Nil,
  wherePart : WherePart = WherePart.empty,
  casPart : CompareAndSetPart = CompareAndSetPart.empty,
  usingPart: UsingPart = UsingPart.empty,
  options: QueryOptions = QueryOptions.empty
) extends RootQuery[Table, Record, Status] with Batchable {

  def prepare[Rev <: HList]()(
    implicit session: Session,
    keySpace: KeySpace,
    ev: PS =:!= HNil,
    rev: Reverse.Aux[PS, Rev]
  ): PreparedBlock[Rev] = {
    val flatten = new PreparedFlattener(qb)
    new PreparedBlock(flatten.query, flatten.protocolVersion, options)
  }

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

    flatten.async() map { ps =>
      new PreparedBlock(ps, flatten.protocolVersion, options)
    }
  }

  def timestamp(time: Duration): DeleteQuery[Table, Record, Limit, Order, Status, Chainned, PS] = {
    copy(usingPart = usingPart append QueryBuilder.timestamp(time))
  }

  def timestamp(time: DateTime): DeleteQuery[Table, Record, Limit, Order, Status, Chainned, PS] = {
    timestamp((time.getMillis * 1000).micros)
  }

  /**
    * The where method of a select query.
    *
    * @param condition A where clause condition restricted by path dependant types.
    * @param ev        An evidence request guaranteeing the user cannot chain multiple where clauses on the same query.
    * @return
    */
  def where[
    RR,
    HL <: HList,
    Token <: HList,
    Out <: HList,
    OutTk <: HList
  ](condition: (Table) => QueryCondition[HL])(
    implicit ev: =:=[Chain, Unchainned],
    prepend: Prepend.Aux[HL, PS, Out]
  ): DeleteQuery[Table, Record, Limit, Order, Status, Chainned, Out] = {
    copy(
      wherePart = wherePart append QueryBuilder.Update.where(condition(table).qb),
      tokens = tokens ::: condition(table).tokens
    )
  }

  /**
    * The where method of a select query.
    *
    * @param condition A where clause condition restricted by path dependant types.
    * @param ev An evidence request guaranteeing the user cannot chain multiple where clauses on the same query.
    * @return
    */
  def and[
    RR,
    HL <: HList,
    Out <: HList
  ](condition: (Table) => QueryCondition[HL])(
    implicit ev: Chain =:= Chainned,
    prepend: Prepend.Aux[HL, PS, Out]
  ): DeleteQuery[Table, Record, Limit, Order, Status, Chainned, Out] = {
    copy(
      wherePart = wherePart append QueryBuilder.Update.and(condition(table).qb),
      tokens = tokens ::: condition(table).tokens
    )
  }

  def withOptions(opts: QueryOptions => QueryOptions): DeleteQuery[Table, Record, Limit, Order, Status, Chain, PS] = {
    copy(options = opts(this.options))
  }

  def consistencyLevel_=(level: ConsistencyLevel)(
    implicit ev: Status =:= Unspecified, session: Session
  ): DeleteQuery[Table, Record, Limit, Order, Specified, Chain, PS] = {
    if (session.protocolConsistency) {
      copy(options = options.consistencyLevel_=(level))
    } else {
      copy(usingPart = usingPart append QueryBuilder.consistencyLevel(level.toString))
    }
  }

  def ifExists: DeleteQuery[Table, Record, Limit, Order, Status, Chain, PS] = {
    copy(casPart = casPart append QueryBuilder.Update.ifExists)
  }

  /**
   * Generates a conditional query clause based on CQL lightweight transactions.
   * Compare and set transactions only get executed if a particular condition is true.
   *
   * @param clause The Compare-And-Set clause to append to the builder.
   * @return A conditional query, now bound by a compare-and-set part.
   */
  def onlyIf(
    clause: Table => CompareAndSetClause.Condition
  ): ConditionalDeleteQuery[Table, Record, Limit, Order, Status, Chain, PS] = {
    ConditionalDeleteQuery(
      table = table,
      init = init,
      tokens,
      wherePart = wherePart,
      casPart = casPart append QueryBuilder.Update.onlyIf(clause(table).qb),
      usingPart = usingPart,
      options = options
    )
  }

  val qb: CQLQuery = (usingPart merge wherePart merge casPart) build init

  override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens)
}


trait DeleteImplicits {
  implicit def columnUpdateClauseToDeleteCondition(clause: MapKeyUpdateClause[_, _]): DeleteClause.Default = {
    new DeleteClause.Condition(QueryBuilder.Collections.mapColumnType(clause.column, clause.keyName))
  }

  implicit def columnClauseToDeleteCondition(col: AbstractColumn[_]): DeleteClause.Default = {
    new DeleteClause.Condition(CQLQuery(col.name))
  }
}

object DeleteQuery {

  type Default[T <: CassandraTable[T, _], R] = DeleteQuery[T, R, Unlimited, Unordered, Unspecified, Unchainned, HNil]
  type Prepared[T <: CassandraTable[T, _], R, PS <: HList] = DeleteQuery[T, R, Unlimited, Unordered, Unspecified, Unchainned, PS]

  def apply[T <: CassandraTable[T, _], R](table: T)(implicit keySpace: KeySpace): DeleteQuery.Default[T, R] = {
    new DeleteQuery(table, QueryBuilder.Delete.delete(QueryBuilder.keyspace(keySpace.name, table.tableName).queryString))
  }

  def apply[T <: CassandraTable[T, _], R](table: T, conds: CQLQuery*)(implicit keySpace: KeySpace): DeleteQuery.Default[T, R] = {
    new DeleteQuery(
      table,
      QueryBuilder.Delete.delete(
        QueryBuilder.keyspace(keySpace.name, table.tableName).queryString,
        conds
      )
    )
  }


  def prepared[
    T <: CassandraTable[T, _],
    R,
    PS <: HList
  ](table: T, conds: CQLQuery)(implicit keySpace: KeySpace): DeleteQuery.Prepared[T, R, PS] = {
    new DeleteQuery(
      table,
      QueryBuilder.Delete.delete(
        QueryBuilder.keyspace(keySpace.name, table.tableName).queryString,
        conds
      )
    )
  }
}

sealed case class ConditionalDeleteQuery[
  Table <: CassandraTable[Table, _],
  Record,
  Limit <: LimitBound,
  Order <: OrderBound,
  Status <: ConsistencyBound,
  Chain <: WhereBound,
  PS <: HList
](table: Table,
  init: CQLQuery,
  tokens: List[TokenizerKey],
  wherePart : WherePart = WherePart.empty,
  casPart : CompareAndSetPart = CompareAndSetPart.empty,
  usingPart: UsingPart = UsingPart.empty,
  options: QueryOptions
 ) extends RootQuery[Table, Record, Status] with Batchable {

  val qb: CQLQuery = (usingPart merge wherePart merge casPart) build init

  final def and(
    clause: Table => CompareAndSetClause.Condition
  ): ConditionalDeleteQuery[Table, Record, Limit, Order, Status, Chain, PS] = {
    copy(
      casPart = casPart append QueryBuilder.Update.and(clause(table).qb)
    )
  }

  override def executableQuery: ExecutableCqlQuery = ExecutableCqlQuery(qb, options, tokens)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy