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

com.dslplatform.api.client.CubeBuilder.scala Maven / Gradle / Ivy

package com.dslplatform.api.client

import scala.reflect.ClassTag
import scala.concurrent.ExecutionContext
import scala.concurrent.duration.Duration
import scala.concurrent.Await
import scala.collection.mutable.Buffer
import com.dslplatform.api.patterns.Cube
import com.dslplatform.api.patterns.Searchable
import com.dslplatform.api.patterns.ServiceLocator
import com.dslplatform.api.patterns.Specification

/**
 * Utility class for building olap cube analysis.
 */
class CubeBuilder[TCube <: Cube[TSource]: ClassTag, TSource <: Searchable: ClassTag](
    cube: Cube[TSource]) {

  private var specification: Option[Specification[TSource]] = None
  private val dimensions: Buffer[String] = Buffer.empty
  private val facts: Buffer[String] = Buffer.empty
  private var limit: Option[Int] = None
  private var offset: Option[Int] = None
  private val order: Buffer[(String, Boolean)] = Buffer.empty

  /**
   * Restrict analysis on data subset
   *
   * @param specification use provided specification to filter data used for analysis
   * @return              self
   */
  def where(specification: Specification[TSource]) = filter(specification)
  /**
   * Restrict analysis on data subset
   *
   * @param specification use provided specification to filter data used for analysis
   * @return              self
   */
  def filter(specification: Specification[TSource]) = {
    this.specification = Option(specification)
    this
  }
  /**
   * Add dimension or fact to the result
   *
   * @param dimensionOrFact dimension or fact which will be shown in result
   * @return                self
   */
  def use(dimensionOrFact: String) = {
    require(dimensionOrFact ne null, "null value provided for dimension or fact")
    require(dimensionOrFact.length != 0, "empty value provided for dimension or fact")

    if (cube.dimensions.contains(dimensionOrFact)) {
      dimensions += dimensionOrFact
    } else if (cube.facts.contains(dimensionOrFact)) {
      facts += dimensionOrFact
    } else {
      throw new IllegalArgumentException("Unknown dimension or fact: " + dimensionOrFact)
    }
    this
  }

  private def orderBy(property: String, ascending: Boolean) = {
    if (property == null || property == "")
      throw new IllegalArgumentException("property can't be empty");
    order += property -> ascending
    this
  }

  /**
   * Order result ascending using a provided property or path
   *
   * @param property name of domain objects property or path
   * @return         self
   */
  def ascending(property: String) = orderBy(property, true)

  /**
   * Order result descending using a provided property or path
   *
   * @param property name of domain objects property or path
   * @return         self
   */
  def descending(property: String) = orderBy(property, false)

  /**
   * Limit total number of results to provided value
   *
   * @param limit maximum number of results
   * @return      self
   */
  def limit(limit: Int) = take(limit)
  /**
   * Limit total number of results to provided value
   *
   * @param limit maximum number of results
   * @return      self
   */
  def take(limit: Int): this.type = {
    this.limit = Some(limit)
    this
  }
  /**
   * Skip specified number of initial results
   *
   * @param offset number of results to skip
   * @return       self
   */
  def offset(offset: Int) = skip(offset)
  /**
   * Skip specified number of initial results
   *
   * @param offset number of results to skip
   * @return       self
   */
  def skip(offset: Int): this.type = {
    this.offset = Some(offset)
    this
  }

  /**
   * Runs the analysis using provided configuration.
   * Result will be deserialized to TResult
   *
   * @return  sequence of specified data types
   */
  def analyze[TResult: ClassTag](
    implicit locator: ServiceLocator,
    ec: ExecutionContext,
    duration: Duration): Seq[TResult] = {

    require(locator ne null, "locator not provided")
    require(ec ne null, "execution context not provided")
    require(duration ne null, "duration not provided")

    val proxy = locator.resolve[StandardProxy]
    Await.result(
      proxy.olapCube[TCube, TSource, TResult](
        specification,
        dimensions,
        facts,
        limit,
        offset,
        order.toMap),
      duration)
  }

  /**
   * Runs the analysis using provided configuration.
   * Result will be deserialized into sequence of Map[String, Any]
   *
   * @return  analysis result
   */
  def analyzeMap(
    implicit locator: ServiceLocator,
    ec: ExecutionContext,
    duration: Duration): Seq[Map[String, Any]] = {

    require(locator ne null, "locator not provided")
    require(ec ne null, "execution context not provided")
    require(duration ne null, "duration not provided")

    val proxy = locator.resolve[StandardProxy]
    Await.result(
      proxy.olapCube[TCube, TSource, Map[String, Any]](
        specification,
        dimensions,
        facts,
        limit,
        offset,
        order.toMap),
      duration)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy