class CassandraMigrations::Migration::TableDefinition

Used to define a table in a migration of table creation or to add columns to an existing table.

An instance of this class is passed to the block of the method create_table, available on every migration.

This class is also internally used in the method add_column.

Constants

PASSTHROUGH_TYPES
PRECISION_MAP
SPECIAL_OPTIONS_MAP
TYPES_MAP

Public Class Methods

new() click to toggle source

C* Data Types. See www.datastax.com/documentation/cql/3.0/cql/cql_reference/cql_data_types_c.html


Migration | CQL Type | Ruby | Description Type | | Class |


string | varchar | String | UTF-8 encoded string text | text | String | UTF-8 encoded string ascii | ascii | String | US-ASCII character string


integer(4) | int | Integer | 32-bit signed integer integer(8) | bigint | Fixnum | 64-bit signed long varint | varint | Bignum | Arbitrary-precision integer


decimal | decimal | BigDecimal | Variable-precision decimal float(4) | float | | 32-bit IEEE-754 floating point double | double | | Float 64-bit IEEE-754 floating point float(8) | double | |


boolean | boolean | TrueClass | true or false

|           | FalseClass    |

uuid | uuid | Cql::Uuid | A UUID in standard UUID format timeuuid | timeuuid | Cql::TimeUuid | Type 1 UUID only (CQL 3)


inet | inet | IPAddr | IP address string in IPv4 or

|           |               | IPv6 format*

timestamp | timestamp | Time | Date plus time, encoded as 8

|           |               | bytes since epoch

datetime | timestamp | |


list | list | Array | A collection of one or more

|           |               | ordered elements

map | map | Hash | A JSON-style array of literals:

|           |               | { literal : literal, ... }

set | set | Set | A collection of one or more

|           |               | elements

binary | blob | | Arbitrary bytes (no validation),

|           |               | expressed as hexadecimal
      | counter   |               | Distributed counter value
|           |               | (64-bit long)

# File lib/cassandra_migrations/migration/table_definition.rb, line 60
def initialize()
  @columns_name_type_hash = {}
  @primary_keys = []
  @partition_keys = []
end

Public Instance Methods

ascii(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 128
def ascii(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:ascii, options)
  define_primary_keys(column_name) if options[:primary_key]
end
binary(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 153
def binary(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:binary, options)
  define_primary_keys(column_name) if options[:primary_key]
end
boolean(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 92
def boolean(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:boolean, options)
  define_primary_keys(column_name) if options[:primary_key]
end
counter(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 158
def counter(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:counter, options)
  if options[:primary_key]
    raise Errors::MigrationDefinitionError, 'Counter columns cannot be primary keys'
  end
end
datetime(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 133
def datetime(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:datetime, options)
  define_primary_keys(column_name) if options[:primary_key]
end
decimal(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 102
def decimal(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:decimal, options)
  define_primary_keys(column_name) if options[:primary_key]
end
define_options(hash) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 205
def define_options(hash)
  @options = hash
end
define_partition_keys(*keys) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 197
def define_partition_keys(*keys)
  if !@partition_keys.empty?
    raise Errors::MigrationDefinitionError, 'Partition key defined twice for the same table.'
  end

  @partition_keys = keys.flatten
end
define_primary_keys(*keys) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 189
def define_primary_keys(*keys)
  if !@primary_keys.empty?
    raise Errors::MigrationDefinitionError, 'Primary key defined twice for the same table.'
  end

  @primary_keys = keys.flatten
end
double(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 112
def double(column_name, options={})
  options[:limit] = 8
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:float, options)
  define_primary_keys(column_name) if options[:primary_key]
end
float(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 107
def float(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:float, options)
  define_primary_keys(column_name) if options[:primary_key]
end
integer(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 97
def integer(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:integer, options)
  define_primary_keys(column_name) if options[:primary_key]
end
list(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 165
def list(column_name, options={})
  list_or_set(:list, column_name, options)
end
map(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 173
def map(column_name, options={})
  key_type, value_type = options[:key_type], options[:value_type]
  [key_type, value_type].each_with_index do |type, index|
    if type.nil?
      raise Errors::MigrationDefinitionError, "A map must define a #{index = 0 ? 'key' : 'value'} type."
    elsif !self.respond_to?(type)
      raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
    end
  end

  if options[:primary_key]
    raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
  end
  @columns_name_type_hash[column_name.to_sym] = :"map<#{column_type_for(key_type)},#{column_type_for(value_type)}>"
end
options() click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 88
def options
  @options ? " WITH %s" % (@options.map {|option| build_option(option)}.join(" AND ")) : ''
end
set(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 169
def set(column_name, options={})
  list_or_set(:set, column_name, options)
end
string(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 118
def string(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:string, options)
  define_primary_keys(column_name) if options[:primary_key]
end
text(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 123
def text(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:text, options)
  define_primary_keys(column_name) if options[:primary_key]
end
timestamp(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 138
def timestamp(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:timestamp, options)
  define_primary_keys(column_name) if options[:primary_key]
end
timeuuid(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 148
def timeuuid(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:timeuuid, options)
  define_primary_keys(column_name) if options[:primary_key]
end
to_add_column_cql() click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 74
def to_add_column_cql
  cql = ""

  if @columns_name_type_hash.size == 1
    cql = "#{@columns_name_type_hash.keys.first} #{@columns_name_type_hash.values.first}"
  elsif @columns_name_type_hash.empty?
    raise Errors::MigrationDefinitionError, 'No column to add.'
  else
    raise Errors::MigrationDefinitionError, 'Only one column can be added at once.'
  end

  cql
end
to_create_cql() click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 66
def to_create_cql
  cql = []
  build_name_type_cql(cql)
  check_for_non_key_fields_in_counter_table
  build_pk_clause(cql)
  cql.join(', ')
end
uuid(column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 143
def uuid(column_name, options={})
  @columns_name_type_hash[column_name.to_sym] = column_type_for(:uuid, options)
  define_primary_keys(column_name) if options[:primary_key]
end

Private Instance Methods

build_name_type_cql(cql) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 258
def build_name_type_cql(cql)
  if !@columns_name_type_hash.empty?
    @columns_name_type_hash.each do |column_name, type|
      cql << "#{column_name} #{type}"
    end
  else
    raise Errors::MigrationDefinitionError, 'No columns defined for table.'
  end
end
build_option(option) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 241
def build_option(option)
  name, value = option
  cql_name = SPECIAL_OPTIONS_MAP.fetch(name, name.to_s)
  case name
    when :clustering_order
      "#{cql_name} BY (#{value})"
    when :compact_storage
      cql_name
    else
      #if complex option with nested hash, convert keys and values to proper string value
      if value.is_a?(Hash)
        value = "{#{value.map {|k, v| "'#{k}':'#{v}'"}.join(',')}}"
      end
      "#{cql_name} = #{value}"
  end
end
build_pk_clause(cql) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 278
def build_pk_clause(cql)
  key_info = (@primary_keys - @partition_keys)
  key_info = ["(#{@partition_keys.join(', ')})", *key_info] if @partition_keys.any?

  if key_info.any?
    cql << "PRIMARY KEY(#{key_info.join(', ')})"
  else
    raise Errors::MigrationDefinitionError, 'No primary key defined.'
  end
end
check_for_non_key_fields_in_counter_table() click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 268
def check_for_non_key_fields_in_counter_table
  if (@columns_name_type_hash.values.include? :counter)
    non_key_columns = @columns_name_type_hash.keys - @primary_keys
    counter_columns = @columns_name_type_hash.select { |name, type| type == :counter }.keys
    if (non_key_columns - counter_columns).present?
      raise Errors::MigrationDefinitionError, 'Non key fields not allowed in tables with counter'
    end
  end
end
column_type_for(type, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 228
def column_type_for(type, options={})
  cql_type = type if PASSTHROUGH_TYPES.include?(type)
  cql_type ||= TYPES_MAP[type]
  if PRECISION_MAP.keys.include?(type)
    limit = options[:limit]
    unless PRECISION_MAP[type].keys.include?(limit)
      raise Errors::MigrationDefinitionError, ":limit option should be #{PRECISION_MAP[type].keys.compact.join(' or ')} for #{type}."
    end
    cql_type ||= PRECISION_MAP[type][limit]
  end
  cql_type
end
list_or_set(collection_type, column_name, options={}) click to toggle source
# File lib/cassandra_migrations/migration/table_definition.rb, line 289
def list_or_set(collection_type, column_name, options={})
  type = options[:type]
  if type.nil?
    raise Errors::MigrationDefinitionError, "A #{collection_type} must define a collection type."
  elsif !self.respond_to?(type)
    raise Errors::MigrationDefinitionError, "Type '#{type}' is not valid for cassandra migration."
  end
  if options[:primary_key]
    raise Errors::MigrationDefinitionError, 'A collection cannot be used as a primary key.'
  end
  @columns_name_type_hash[column_name.to_sym] = :"#{collection_type}<#{column_type_for(type)}>"
end