class Cequel::Metal::DataSet

Encapsulates a data set, specified as a table and optionally various query elements.

@example Data set representing entire contents of a table

data_set = database[:posts]

@example Data set limiting rows returned

data_set = database[:posts].limit(10)

@example Data set targeting only one partition

data_set = database[:posts].where(blog_subdomain: 'cassandra')

@see cassandra.apache.org/doc/cql3/CQL.html#selectStmt

CQL documentation for SELECT

Attributes

allow_filtering[RW]
keyspace[R]

@return [Keyspace] keyspace that this data set's table resides in

query_consistency[RW]

@return [Symbol] what consistency level queries from this data set will

use

@since 1.1.0

query_page_size[RW]
query_paging_state[RW]
row_limit[RW]

@return [Integer] maximum number of rows to return, `nil` if no limit

row_specifications[R]

@return [Array<RowSpecification>] row specifications limiting the

result rows returned by this data set
select_columns[R]

@return [Array<Symbol>] columns that this data set restricts result

rows to; empty if none
sort_order[R]

@return [Hash<Symbol,Symbol>] map of column names to sort directions

table_name[R]

@return [Symbol] name of the table that this data set retrieves data

from
ttl_columns[R]

@return [Array<Symbol>] columns that this data set will select the TTLs

of
writetime_columns[R]

@return [Array<Symbol>] columns that this data set will select the

writetimes of

Public Class Methods

new(table_name, keyspace) click to toggle source

@param table_name [Symbol] column family for this data set @param keyspace [Keyspace] keyspace this data set's table lives in

@see Keyspace#[] @api private

# File lib/cequel/metal/data_set.rb, line 63
def initialize(table_name, keyspace)
  @table_name, @keyspace = table_name, keyspace
  @select_columns, @ttl_columns, @writetime_columns, @row_specifications,
    @sort_order = [], [], [], [], {}
end

Public Instance Methods

==(other) click to toggle source

@return [Boolean]

# File lib/cequel/metal/data_set.rb, line 672
def ==(other)
  cql == other.cql
end
allow_filtering!() click to toggle source

@see RecordSet#allow_filtering!

# File lib/cequel/metal/data_set.rb, line 581
def allow_filtering!
  clone.tap do |data_set|
    data_set.allow_filtering = true
  end
end
allow_filtering_cql() click to toggle source

@private

# File lib/cequel/metal/data_set.rb, line 691
def allow_filtering_cql
  if allow_filtering
    ' ALLOW FILTERING'
  else ''
  end
end
consistency(consistency) click to toggle source

Change the consistency for queries performed by this data set

@param consistency [Symbol] a consistency level @return [DataSet] new data set tuned to the given consistency

@see www.datastax.com/documentation/cassandra/2.0/cassandra/dml/dml_config_consistency_c.html @since 1.1.0

# File lib/cequel/metal/data_set.rb, line 566
def consistency(consistency)
  clone.tap do |data_set|
    data_set.query_consistency = consistency
  end
end
count() click to toggle source

@raise [DangerousQueryError] to prevent loading the entire record set

to be counted
# File lib/cequel/metal/data_set.rb, line 643
def count
  raise Cequel::Record::DangerousQueryError.new
end
Also aliased as: length, size
cql() click to toggle source

@return [Statement] CQL `SELECT` statement encoding this data set's scope.

# File lib/cequel/metal/data_set.rb, line 652
def cql
  statement = Statement.new
    .append(select_cql)
    .append(" FROM #{table_name}")
    .append(*row_specifications_cql)
    .append(sort_order_cql)
    .append(limit_cql)
    .append(allow_filtering_cql)
end
decr(deltas, options = {})
Alias for: decrement
decrement(deltas, options = {}) click to toggle source

Decrement one or more counter columns

@param deltas [Hash<Symbol,Integer>] map of counter column names to

amount by which to decrement each column

@return [void]

@see increment @see cassandra.apache.org/doc/cql3/CQL.html#counters

CQL documentation for counter columns

@since 0.5.0

# File lib/cequel/metal/data_set.rb, line 174
def decrement(deltas, options = {})
  incrementer { decrement(deltas) }.execute(options)
end
Also aliased as: decr
delete(*columns, &block) click to toggle source

@overload delete(options = {})

Delete one or more rows from the table

@param options [Options] options for persistence
@option (See Writer#initialize)

@example
  posts.where(blog_subdomain: 'cassandra', permalink: 'cequel').
    delete

@overload delete(*columns, options = {})

Delete data from given columns in the specified rows. This is
equivalent to setting columns to `NULL` in an SQL database.

@param columns [Symbol] columns to remove
@param options [Options] options for persistence
@option (see Writer#initialize)

@example
  posts.where(blog_subdomain: 'cassandra', permalink: 'cequel').
    delete(:body)

@overload delete(options = {}, &block)

Construct a `DELETE` statement with multiple operations (column
deletions, collection element removals, etc.)

@param options [Options] options for persistence
@option (see Writer#initialize)
@yield DSL context for construction delete statement

@example
  posts.where(blog_subdomain: 'bigdata', permalink: 'cql').delete do
    delete_columns :body
    list_remove_at :categories, 2
  end

@see Deleter

@return [void]

@note If enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see cassandra.apache.org/doc/cql3/CQL.html#deleteStmt

CQL documentation for DELETE
# File lib/cequel/metal/data_set.rb, line 428
def delete(*columns, &block)
  options = columns.extract_options!
  if block
    deleter(&block).execute(options)
  elsif columns.empty?
    deleter { delete_row }.execute(options)
  else
    deleter { delete_columns(*columns) }.execute(options)
  end
end
deleter(&block) click to toggle source
# File lib/cequel/metal/data_set.rb, line 724
def deleter(&block)
  Deleter.new(self, &block)
end
each() { |from_result_row| ... } click to toggle source

Enumerate over rows in this data set. Along with each, all other Enumerable methods are implemented.

@overload each

@return [Enumerator] enumerator for rows, if no block given

@overload each(&block)

@yield [Hash] result rows
@return [void]

@return [Enumerator,void]

# File lib/cequel/metal/data_set.rb, line 628
def each
  return enum_for(:each) unless block_given?
  results.each { |row| yield Row.from_result_row(row) }
end
execute_cql(cql_stmt) click to toggle source
# File lib/cequel/metal/data_set.rb, line 704
def execute_cql(cql_stmt)
  keyspace.execute_with_options(cql_stmt,
                                consistency: query_consistency,
                                page_size: query_page_size,
                                paging_state: query_paging_state
                               )
end
first() click to toggle source

@return [Hash] the first row in this data set

# File lib/cequel/metal/data_set.rb, line 636
def first
  row = execute_cql(*limit(1).cql).first
  Row.from_result_row(row)
end
incr(deltas, options = {})
Alias for: increment
increment(deltas, options = {}) click to toggle source

Increment one or more counter columns

@param deltas [Hash<Symbol,Integer>] map of counter column names to

amount by which to increment each column

@return [void]

@example

post_analytics.
  where(blog_subdomain: 'cassandra', permalink: 'cequel').
  increment(pageviews: 10, tweets: 2)

@note This can only be used on counter tables @since 0.5.0 @see decrement @see cassandra.apache.org/doc/cql3/CQL.html#counters

CQL documentation for counter columns
# File lib/cequel/metal/data_set.rb, line 157
def increment(deltas, options = {})
  incrementer { increment(deltas) }.execute(options)
end
Also aliased as: incr
incrementer(&block) click to toggle source
# File lib/cequel/metal/data_set.rb, line 716
def incrementer(&block)
  Incrementer.new(self, &block)
end
insert(data, options = {}) click to toggle source

Insert a row into the column family.

@param data [Hash] column-value pairs @param options [Options] options for persisting the row @option (see Writer#initialize) @return [void]

@note `INSERT` statements will succeed even if a row at the specified

primary key already exists. In this case, column values specified in
the insert will overwrite the existing row.

@note If a enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see cassandra.apache.org/doc/cql3/CQL.html#insertStmt

CQL documentation for INSERT
# File lib/cequel/metal/data_set.rb, line 85
def insert(data, options = {})
  inserter { insert(data) }.execute(options)
end
inserter(&block) click to toggle source
# File lib/cequel/metal/data_set.rb, line 712
def inserter(&block)
  Inserter.new(self, &block)
end
inspect() click to toggle source

@return [String]

# File lib/cequel/metal/data_set.rb, line 665
def inspect
  "#<#{self.class.name}: #{cql.inspect}>"
end
last_page?() click to toggle source

@return [Boolean] Returns whether no more pages are available

@see docs.datastax.com/en/developer/ruby-driver/3.0/api/cassandra/result/#last_page?-instance_method

# File lib/cequel/metal/data_set.rb, line 609
def last_page?
  results.last_page?
end
length()
Alias for: count
limit(limit) click to toggle source

Limit the number of rows returned by this data set

@param limit [Integer] maximum number of rows to return @return [DataSet] new data set scoped with given limit

# File lib/cequel/metal/data_set.rb, line 536
def limit(limit)
  clone.tap { |data_set| data_set.row_limit = limit }
end
list_append(column, elements, options = {}) click to toggle source

Append element(s) to a list in the row(s) matched by this data set.

@param column [Symbol] name of list column to append to @param elements [Object,Array] one element or an array of elements to

append

@param options [Options] options for persisting the column data @option (see Writer#initialize) @return [void]

@example

posts.list_append(:categories, ['CQL', 'ORMs'])

@note If a enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see list_append @see update @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 222
def list_append(column, elements, options = {})
  updater { list_append(column, elements) }.execute(options)
end
list_prepend(column, elements, options = {}) click to toggle source

Prepend element(s) to a list in the row(s) matched by this data set.

@param column [Symbol] name of list column to prepend to @param elements [Object,Array] one element or an array of elements to

prepend

@param options [Options] options for persisting the column data @option (see Writer#initialize) @return [void]

@example

posts.list_prepend(:categories, ['CQL', 'ORMs'])

@note A bug (CASSANDRA-8733) exists in Cassandra versions 0.3.0-2.0.12 and 2.1.0-2.1.2 which

will make elements appear in REVERSE ORDER in the list.

@note If a enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see list_append @see update

# File lib/cequel/metal/data_set.rb, line 199
def list_prepend(column, elements, options = {})
  updater { list_prepend(column, elements) }.execute(options)
end
list_remove(column, value, options = {}) click to toggle source

Remove all occurrences of a given value from a list column

@param column [Symbol] name of list column @param value [Object] value to remove @param options [Options] options for persisting the data @option (see Writer#initialize) @return [void]

@example

posts.list_remove(:categories, 'CQL3')

@note If enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see list_remove_at @see update @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 266
def list_remove(column, value, options = {})
  updater { list_remove(column, value) }.execute(options)
end
list_remove_at(column, *positions) click to toggle source

@overload list_remove_at(column, *positions, options = {})

Remove the value from a given position or positions in a list column

@param column [Symbol] name of list column
@param positions [Integer] position(s) in list to remove value from
@param options [Options] options for persisting the data
@option (see Writer#initialize)
@return [void]

@example
  posts.list_remove_at(:categories, 2)

@note If enclosed in a Keyspace#batch block, this method will be
  executed as part of the batch.
@see #list_remove
@see #update
@since 1.0.0
# File lib/cequel/metal/data_set.rb, line 289
def list_remove_at(column, *positions)
  options = positions.extract_options!
  sorted_positions = positions.sort.reverse

  deleter { list_remove_at(column, *sorted_positions) }.execute(options)
end
list_replace(column, index, value, options = {}) click to toggle source

Replace a list element at a specified index with a new value

@param column [Symbol] name of list column @param index [Integer] which element to replace @param value [Object] new value at this index @param options [Options] options for persisting the data @option (see Writer#initialize) @return [void]

@example

posts.list_replace(:categories, 2, 'Object-Relational Mapper')

@note if a enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see update @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 244
def list_replace(column, index, value, options = {})
  updater { list_replace(column, index, value) }.execute(options)
end
map_remove(column, *keys) click to toggle source

@overload map_remove(column, *keys, options = {})

Remove a given key from a map column

@param column [Symbol] name of map column
@param keys [Object] map key to remove
@param options [Options] options for persisting the data
@option (see Writer#initialize)
@return [void]

@example
  posts.map_remove(:credits, 'editor')

@note If enclosed in a Keyspace#batch block, this method will be
  executed as part of the batch.
@see #update
@since 1.0.0
# File lib/cequel/metal/data_set.rb, line 314
def map_remove(column, *keys)
  options = keys.extract_options!
  deleter { map_remove(column, *keys) }.execute(options)
end
map_update(column, updates, options = {}) click to toggle source

Update one or more keys in a map column

@param column [Symbol] name of set column @param updates [Hash] map of map keys to new values @param options [Options] options for persisting the data @option (see Writer#initialize) @return [void]

@example

posts.map_update(:credits, 'editor' => 34)

@note If enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see update @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 378
def map_update(column, updates, options = {})
  updater { map_update(column, updates) }.execute(options)
end
next_paging_state() click to toggle source

Exposes current paging state for stateless pagination

@return [String] or nil

@see docs.datastax.com/en/developer/ruby-driver/3.0/api/cassandra/result/#paging_state-instance_method

# File lib/cequel/metal/data_set.rb, line 600
def next_paging_state
  results.paging_state
end
order(pairs) click to toggle source

Control how the result rows are sorted

@param pairs [Hash] Map of column name to sort direction @return [DataSet] new data set with the specified ordering

@note The only valid ordering column is the first clustering column @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 549
def order(pairs)
  clone.tap do |data_set|
    data_set.sort_order.merge!(pairs.symbolize_keys)
  end
end
page_size(page_size) click to toggle source
# File lib/cequel/metal/data_set.rb, line 572
def page_size(page_size)
  clone.tap do |data_set|
    data_set.query_page_size = page_size
  end
end
paging_state(paging_state) click to toggle source
# File lib/cequel/metal/data_set.rb, line 587
def paging_state(paging_state)
  clone.tap do |data_set|
    data_set.query_paging_state = paging_state
  end
end
results() click to toggle source
# File lib/cequel/metal/data_set.rb, line 700
def results
  @results ||= execute_cql(cql)
end
row_specifications_cql() click to toggle source

@private

# File lib/cequel/metal/data_set.rb, line 677
def row_specifications_cql
  if row_specifications.any?
    cql_fragments, bind_vars = [], []
    row_specifications.each do |spec|
      cql_with_vars = spec.cql
      cql_fragments << cql_with_vars.shift
      bind_vars.concat(cql_with_vars)
    end
    [" WHERE #{cql_fragments.join(' AND ')}", *bind_vars]
  else ['']
  end
end
select(*columns) click to toggle source

Select specified columns from this data set.

@param columns [Symbol] columns columns to select @return [DataSet] new data set scoped to specified columns

# File lib/cequel/metal/data_set.rb, line 445
def select(*columns)
  clone.tap do |data_set|
    data_set.select_columns.concat(columns.flatten)
  end
end
select!(*columns) click to toggle source

Select specified columns from this data set, overriding chained scope.

@param columns [Symbol,Array] columns to select @return [DataSet] new data set scoped to specified columns

# File lib/cequel/metal/data_set.rb, line 486
def select!(*columns)
  clone.tap do |data_set|
    data_set.select_columns.replace(columns.flatten)
  end
end
select_timestamp(*columns)
Alias for: select_writetime
select_ttl(*columns) click to toggle source

Return the remaining TTL for the specified columns from this data set.

@param columns [Symbol] columns to select @return [DataSet] new data set scoped to specified columns

@since 1.0.0

# File lib/cequel/metal/data_set.rb, line 459
def select_ttl(*columns)
  clone.tap do |data_set|
    data_set.ttl_columns.concat(columns.flatten)
  end
end
select_writetime(*columns) click to toggle source

Return the write time for the specified columns in the data set

@param columns [Symbol] columns to select @return [DataSet] new data set scoped to specified columns

@since 1.0.0

# File lib/cequel/metal/data_set.rb, line 473
def select_writetime(*columns)
  clone.tap do |data_set|
    data_set.writetime_columns.concat(columns.flatten)
  end
end
Also aliased as: select_timestamp
set_add(column, values, options = {}) click to toggle source

Add one or more elements to a set column

@param column [Symbol] name of set column @param values [Object,Set] value or values to add @param options [Options] options for persisting the data @option (see Writer#initialize) @return [void]

@example

posts.set_add(:tags, 'cql3')

@note If enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see update @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 336
def set_add(column, values, options = {})
  updater { set_add(column, values) }.execute(options)
end
set_remove(column, value, options = {}) click to toggle source

Remove an element from a set

@param column [Symbol] name of set column @param value [Object] value to remove @param options [Options] options for persisting the data @option (see Writer#initialize) @return [void]

@example

posts.set_remove(:tags, 'cql3')

@note If enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see update @since 1.0.0

# File lib/cequel/metal/data_set.rb, line 357
def set_remove(column, value, options = {})
  updater { set_remove(column, value) }.execute(options)
end
size()
Alias for: count
update(*args, &block) click to toggle source

Upsert data into one or more rows

@overload update(column_values, options = {})

Update the rows specified in the data set with new values

@param column_values [Hash] map of column names to new values
@param options [Options] options for persisting the column data
@option (see #generate_upsert_options)

@example
  posts.where(blog_subdomain: 'cassandra', permalink: 'cequel').
    update(title: 'Announcing Cequel 1.0')

@overload update(options = {}, &block)

Construct an update statement consisting of multiple operations

@param options [Options] options for persisting the data
@option (see #generate_upsert_options)
@yield DSL context for adding write operations

@see Updater
@since 1.0.0

@example
  posts.where(blog_subdomain: 'bigdata', permalink: 'cql').update do
    set(title: 'Announcing Cequel 1.0')
    list_append(categories: 'ORMs')
  end

@return [void]

@note `UPDATE` statements will succeed even if targeting a row that

does not exist. In this case a new row will be created.

@note This statement will fail unless one or more rows are fully

specified by primary key using `where`

@note If a enclosed in a Keyspace#batch block, this method will be

executed as part of the batch.

@see cassandra.apache.org/doc/cql3/CQL.html#updateStmt

CQL documentation for UPDATE
# File lib/cequel/metal/data_set.rb, line 130
def update(*args, &block)
  if block
    updater(&block).execute(args.extract_options!)
  else
    data = args.shift
    updater { set(data) }.execute(args.extract_options!)
  end
end
updater(&block) click to toggle source
# File lib/cequel/metal/data_set.rb, line 720
def updater(&block)
  Updater.new(self, &block)
end
where(row_specification, *bind_vars) click to toggle source

Filter this data set with a row specification

@overload where(column_values)

@param column_values [Hash] Map of column name to values to match

@example
  database[:posts].where(title: 'Hey')

@overload where(cql, *bind_vars)

@param cql [String] CQL fragment representing `WHERE` statement
@param bind_vars [Object] Bind variables for the CQL fragment

@example
  DB[:posts].where('title = ?', 'Hey')

@return [DataSet] New data set scoped to the row specification

# File lib/cequel/metal/data_set.rb, line 510
def where(row_specification, *bind_vars)
  clone.tap do |data_set|
    data_set.row_specifications
      .concat(build_row_specifications(row_specification, bind_vars))
  end
end
where!(row_specification, *bind_vars) click to toggle source

Replace existing row specifications

@see where @return [DataSet] New data set with only row specifications given

# File lib/cequel/metal/data_set.rb, line 523
def where!(row_specification, *bind_vars)
  clone.tap do |data_set|
    data_set.row_specifications
      .replace(build_row_specifications(row_specification, bind_vars))
  end
end

Private Instance Methods

build_row_specifications(row_specification, bind_vars) click to toggle source
# File lib/cequel/metal/data_set.rb, line 764
def build_row_specifications(row_specification, bind_vars)
  case row_specification
  when Hash
    RowSpecification.build(row_specification)
  when String
    CqlRowSpecification.build(row_specification, bind_vars)
  else
    fail ArgumentError,
         "Invalid argument #{row_specification.inspect}; " \
         "expected Hash or String"
  end
end
initialize_copy(source) click to toggle source
Calls superclass method
# File lib/cequel/metal/data_set.rb, line 730
def initialize_copy(source)
  super
  @select_columns = source.select_columns.clone
  @ttl_columns = source.ttl_columns.clone
  @writetime_columns = source.writetime_columns.clone
  @row_specifications = source.row_specifications.clone
  @sort_order = source.sort_order.clone
end
limit_cql() click to toggle source
# File lib/cequel/metal/data_set.rb, line 751
def limit_cql
  row_limit ? " LIMIT #{row_limit}" : ''
end
select_cql() click to toggle source
# File lib/cequel/metal/data_set.rb, line 739
def select_cql
  all_columns = select_columns +
    ttl_columns.map { |column| "TTL(#{column})" } +
    writetime_columns.map { |column| "WRITETIME(#{column})" }

  if all_columns.any?
    "SELECT #{all_columns.join(',')}"
  else
    'SELECT *'
  end
end
sort_order_cql() click to toggle source
# File lib/cequel/metal/data_set.rb, line 755
def sort_order_cql
  if sort_order.any?
    order = sort_order
      .map { |column, direction| "#{column} #{direction.to_s.upcase}" }
      .join(', ')
    " ORDER BY #{order}"
  end
end