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

com.exasol.spark.ExasolQueryEnricher.scala Maven / Gradle / Ivy

package com.exasol.spark

import org.apache.spark.sql.sources.Filter

import com.exasol.spark.util.Filters
import com.exasol.sql.StatementFactory
import com.exasol.sql.dql.select.Select
import com.exasol.sql.dql.select.rendering.SelectRenderer
import com.exasol.sql.expression.BooleanTerm.and
import com.exasol.sql.expression.ExpressionTerm.stringLiteral
import com.exasol.sql.expression.function.exasol.ExasolAggregateFunction.COUNT
import com.exasol.sql.rendering.StringRendererConfig

/**
 * Improves the original user query with column pruning and predicate
 * pushdown.
 *
 * @param userQuery A user provided initial query
 */
final case class ExasolQueryEnricher(userQuery: String) {

  private[this] val PLACEHOLDER_TABLE_NAME = ""

  /**
   * Enriches user query with column pruning and where clause using the
   * provided column names and filters.
   *
   * Additionally, if no column names are provided it creates a {@code
   * COUNT('*')} query.
   *
   * @param columns A list of column names
   * @param filters A list of Spark [[org.apache.spark.sql.sources.Filter]]-s
   * @return An enriched query with column selection and predicate pushdown
   */
  def enrichQuery(columns: Array[String], filters: Array[Filter]): String = {
    val select = StatementFactory.getInstance().select()
    val _ = select.from().table(PLACEHOLDER_TABLE_NAME)
    addColumns(columns, select)
    addFilters(filters, select)
    renderSelectQuery(PLACEHOLDER_TABLE_NAME, select)
  }

  private[this] def addColumns(columns: Array[String], select: Select): Unit = {
    if (columns.isEmpty) {
      val _ = select.function(COUNT, stringLiteral("*"))
    } else {
      columns.foreach(column => select.field(column))
    }
    ()
  }

  private[this] def addFilters(filters: Array[Filter], select: Select): Unit = {
    val booleanExpressions = Filters.booleanExpressionFromFilters(filters.toSeq)
    if (!booleanExpressions.isEmpty) {
      val _ = select.where(and(booleanExpressions: _*))
    }
    ()
  }

  private[this] def renderSelectQuery(subSelectPlaceholder: String, select: Select): String = {
    val rendererConfig = StringRendererConfig.builder().quoteIdentifiers(true).build()
    val renderer = new SelectRenderer(rendererConfig)
    select.accept(renderer)
    renderer.render().replace(s""""$subSelectPlaceholder"""", s"($userQuery) A")
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy