class NoSE::Backend::CassandraBackend::IndexLookupStatementStep

A query step to look up data from a particular column family

Public Class Methods

new(client, select, conditions, step, next_step, prev_step) click to toggle source

rubocop:disable Metrics/ParameterLists

# File lib/nose/backend/cassandra.rb, line 273
def initialize(client, select, conditions, step, next_step, prev_step)
  super

  @logger = Logging.logger['nose::backend::cassandra::indexlookupstep']

  # TODO: Check if we can apply the next filter via ALLOW FILTERING
  @prepared = client.prepare select_cql(select, conditions)
end

Public Instance Methods

process(conditions, results) click to toggle source

Perform a column family lookup in Cassandra

# File lib/nose/backend/cassandra.rb, line 284
def process(conditions, results)
  results = initial_results(conditions) if results.nil?
  condition_list = result_conditions conditions, results
  new_result = fetch_all_queries condition_list, results

  # Limit the size of the results in case we fetched multiple keys
  new_result[0..(@step.limit.nil? ? -1 : @step.limit)]
end

Private Instance Methods

cql_order_by() click to toggle source

Produce the CQL ORDER BY clause for this step @return [String]

# File lib/nose/backend/cassandra.rb, line 325
def cql_order_by
  # TODO: CQL3 requires all clustered columns before the one actually
  #       ordered on also be specified
  #
  #       Example:
  #
  #         SELECT * FROM cf WHERE id=? AND col1=? ORDER by col1, col2
  return '' if @step.order_by.empty?
  ' ORDER BY ' + @step.order_by.map { |f| "\"#{f.id}\"" }.join(', ')
end
cql_where_clause(conditions) click to toggle source

Produce a CQL where clause using the given conditions @return [String]

# File lib/nose/backend/cassandra.rb, line 311
def cql_where_clause(conditions)
  where = @eq_fields.map do |field|
    "\"#{field.id}\" = ?"
  end.join ' AND '
  unless @range_field.nil?
    condition = conditions.each_value.find(&:range?)
    where << " AND \"#{condition.field.id}\" #{condition.operator} ?"
  end

  where
end
fetch_all_queries(condition_list, results) click to toggle source

Lookup values from an index selecting the given fields and filtering on the given conditions

# File lib/nose/backend/cassandra.rb, line 338
def fetch_all_queries(condition_list, results)
  new_result = []
  @logger.debug { "  #{@prepared.cql} * #{condition_list.size}" }

  # TODO: Chain enumerables of results instead
  # Limit the total number of queries as well as the query limit
  condition_list.zip(results).each do |condition_set, result|
    # Loop over all pages to fetch results
    values = lookup_values condition_set
    fetch_query_pages values, new_result, result

    # Don't continue with further queries
    break if !@step.limit.nil? && new_result.length >= @step.limit
  end
  @logger.debug "Total result size = #{new_result.size}"

  new_result
end
fetch_query_pages(values, new_result, result) click to toggle source

Get the necessary pages of results for a given list of values

# File lib/nose/backend/cassandra.rb, line 358
def fetch_query_pages(values, new_result, result)
  new_results = @client.execute(@prepared, arguments: values)
  loop do
    # Add the previous results to each row
    rows = new_results.map { |row| result.merge row }

    # XXX Ignore null values in results for now
    # fail if rows.any? { |row| row.values.any?(&:nil?) }

    new_result.concat rows
    break if new_results.last_page? ||
             (!@step.limit.nil? && result.length >= @step.limit)
    new_results = new_results.next_page
    @logger.debug "Fetched #{result.length} results"
  end
end
lookup_values(condition_set) click to toggle source

Produce the values used for lookup on a given set of conditions

# File lib/nose/backend/cassandra.rb, line 376
def lookup_values(condition_set)
  condition_set.map do |condition|
    value = condition.value ||
            conditions[condition.field.id].value
    fail if value.nil?

    if condition.field.is_a?(Fields::IDField)
      Cassandra::Uuid.new(value.to_i)
    else
      value
    end
  end
end
select_cql(select, conditions) click to toggle source

Produce the select CQL statement for a provided set of fields @return [String]

# File lib/nose/backend/cassandra.rb, line 297
def select_cql(select, conditions)
  select = expand_selected_fields select
  cql = "SELECT #{select.map { |f| "\"#{f.id}\"" }.join ', '} FROM " \
        "\"#{@step.index.key}\" WHERE #{cql_where_clause conditions}"
  cql += cql_order_by

  # Add an optional limit
  cql << " LIMIT #{@step.limit}" unless @step.limit.nil?

  cql
end