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

com.outworkers.phantom.builder.batch.BatchQuery.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.batch

import com.datastax.driver.core.{BatchStatement, ConsistencyLevel, Session, Statement}
import com.outworkers.phantom.builder.query.{Batchable, _}
import com.outworkers.phantom.builder.syntax.CQLSyntax
import com.outworkers.phantom.builder.{ConsistencyBound, QueryBuilder, Specified, Unspecified}
import com.outworkers.phantom.connectors.SessionAugmenterImplicits
import org.joda.time.DateTime

import scala.annotation.implicitNotFound
import scala.collection.compat._

case class BatchWithQuery(
  statement: Statement,
  queries: String,
  batchType: BatchType
) {
  val debugString = s"BEGIN BATCH ${batchType.batch} ($queries) APPLY BATCH;"
}

class BatchType(val batch: String)

object BatchType {
  case object Logged extends BatchType(CQLSyntax.Batch.Logged)
  case object Unlogged extends BatchType(CQLSyntax.Batch.Unlogged)
  case object Counter extends BatchType(CQLSyntax.Batch.Counter)
}

sealed case class BatchQuery[Status <: ConsistencyBound](
  iterator: Iterator[Batchable],
  batchType: BatchType,
  usingPart: UsingPart = UsingPart.empty,
  options: QueryOptions
) extends SessionAugmenterImplicits {

  def initBatch(): BatchStatement = batchType match {
    case BatchType.Logged => new BatchStatement(BatchStatement.Type.LOGGED)
    case BatchType.Unlogged => new BatchStatement(BatchStatement.Type.UNLOGGED)
    case BatchType.Counter => new BatchStatement(BatchStatement.Type.COUNTER)
  }

  def makeBatch()(implicit session: Session): BatchWithQuery = {
    val batch = initBatch()

    val builder = List.newBuilder[String]

    for (st <- iterator) {
      builder += st.executableQuery.qb.queryString
      batch.add(st.executableQuery.statement())
    }

    val strings = builder.result()
    BatchWithQuery(batch, strings.mkString("\n"), batchType)
  }

  def queryString()(implicit session: Session): String = makeBatch().debugString

  @implicitNotFound("A ConsistencyLevel was already specified for this query.")
  final def consistencyLevel_=(level: ConsistencyLevel)(
    implicit ev: Status =:= Unspecified,
    session: Session
  ): BatchQuery[Specified] = {
    if (session.protocolConsistency) {
      copy(options = options.consistencyLevel_=(level))
    } else {
      copy(usingPart = usingPart append QueryBuilder.consistencyLevel(level.toString))
    }
  }

  def add(queries: Batchable*): BatchQuery[Status] = {
    copy(iterator = iterator ++ queries.iterator)
  }

  def add(query: Option[Batchable]): BatchQuery[Status] = {
    query match {
      case Some(value) => copy(iterator = iterator ++ Iterator(value))
      case None => this
    }
  }

  def add[M[X] <: IterableOnce[X], Y <: Batchable](queries: M[Y])(
    implicit cbf: Factory[Batchable, Iterator[Batchable]]
  ): BatchQuery[Status] = {
    val builder = cbf.newBuilder
    queries.iterator.foreach(builder +=)
    copy(iterator = iterator ++ builder.result())
  }

  /**
    * Adds the statement of another query to the statements of this batch query.
    * @param batch A batch query.
    * @return A batch query with the same consistencyLevel as the original query.
    */
  def add(batch: BatchQuery[_]): BatchQuery[Status] = {
    copy(this.iterator ++ batch.iterator)
  }

  def timestamp(time: DateTime): BatchQuery[Status] = {
    timestamp(time.getMillis)
  }

  def timestamp(stamp: Long): BatchQuery[Status] = {
    copy(usingPart = usingPart append QueryBuilder.microstamp(stamp * 1000))
  }
}

private[phantom] trait Batcher {

  def apply(batchType: BatchType = BatchType.Logged): BatchQuery[Unspecified] = {
    BatchQuery(Iterator.empty, batchType, UsingPart.empty, QueryOptions.empty)
  }

  def logged: BatchQuery[Unspecified] = {
    BatchQuery(Iterator.empty, BatchType.Logged, UsingPart.empty, QueryOptions.empty)
  }

  def timestamp(stamp: Long): BatchQuery[Unspecified] = {
    apply().timestamp(stamp)
  }

  def unlogged: BatchQuery[Unspecified] = {
    BatchQuery(Iterator.empty, BatchType.Unlogged, UsingPart.empty, QueryOptions.empty)
  }

  def counter: BatchQuery[Unspecified] = {
    BatchQuery(Iterator.empty, BatchType.Counter, UsingPart.empty, QueryOptions.empty)
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy