Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 173 lines (153 sloc) 7.034 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

class Cassandra
  # A bunch of crap, mostly related to introspecting on column types
  module Columns #:nodoc:
    private

    def is_super(column_family)
      @is_super[column_family] ||= column_family_property(column_family, 'column_type') == "Super"
    end

    def column_name_class(column_family)
      @column_name_class[column_family] ||= column_name_class_for_key(column_family, "comparator_type")
    end

    def sub_column_name_class(column_family)
      @sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "subcomparator_type")
    end

    def column_name_maker(column_family)
      @column_name_maker[column_family] ||=
        begin
          klass = column_name_class(column_family)
          if klass == Composite || klass == DynamicComposite
            lambda {|name| klass.new_from_packed(name) }
          else
            lambda {|name| klass.new(name) }
          end
        end
    end

    def sub_column_name_maker(column_family)
      @sub_column_name_maker[column_family] ||=
        begin
          klass = sub_column_name_class(column_family)
          if klass == Composite || klass == DynamicComposite
            lambda {|name| klass.new_from_packed(name) }
          else
            lambda {|name| klass.new(name) }
          end
        end
    end

    def column_name_class_for_key(column_family, comparator_key)
      property = column_family_property(column_family, comparator_key)
      property =~ /[^(]*\.(.*?)$/
      case $1
      when "LongType" then Long
      when "LexicalUUIDType", "TimeUUIDType" then SimpleUUID::UUID
      when /^DynamicCompositeType\(/ then DynamicComposite
      when /^CompositeType\(/ then Composite
      else
        String # UTF8, Ascii, Bytes, anything else
      end
    end

    def column_family_property(column_family, key)
      cfdef = schema.cf_defs.find {|cfdef| cfdef.name == column_family }
      unless cfdef
        raise AccessError, "Invalid column family \"#{column_family}\""
      end
      cfdef.send(key)
    end

    def multi_key_slices_to_hash(column_family, array, return_empty_rows = false)
      ret = OrderedHash.new
      array.each do |value|
        next if return_empty_rows == false && value.columns.length == 0
        ret[value.key] = columns_to_hash(column_family, value.columns)
      end
      ret
    end

    def multi_column_to_hash!(hash)
      hash.each do |key, column_or_supercolumn|
        hash[key] = (column_or_supercolumn.column.value if column_or_supercolumn.column)
      end
    end

    def multi_columns_to_hash!(column_family, hash)
      hash.each do |key, columns|
        hash[key] = columns_to_hash(column_family, columns)
      end
    end

    def multi_sub_columns_to_hash!(column_family, hash)
      hash.each do |key, sub_columns|
        hash[key] = sub_columns_to_hash(column_family, sub_columns)
      end
    end

    def columns_to_hash(column_family, columns)
      columns_to_hash_for_classes(columns, column_name_maker(column_family), sub_column_name_maker(column_family))
    end

    def sub_columns_to_hash(column_family, columns)
      columns_to_hash_for_classes(columns, sub_column_name_maker(column_family))
    end

    def columns_to_hash_for_classes(columns, column_name_maker, sub_column_name_maker = nil)
      hash = OrderedHash.new
      Array(columns).each do |c|
        c = c.super_column || c.column || c.counter_column || c.counter_super_column if c.is_a?(CassandraThrift::ColumnOrSuperColumn)
        case c
        when CassandraThrift::SuperColumn
          hash.[]=(column_name_maker.call(c.name), columns_to_hash_for_classes(c.columns, sub_column_name_maker)) # Pop the class stack, and recurse
        when CassandraThrift::Column
          hash.[]=(column_name_maker.call(c.name), c.value, c.timestamp)
        when CassandraThrift::CounterColumn
          hash.[]=(column_name_maker.call(c.name), c.value, 0)
        when CassandraThrift::CounterSuperColumn
          hash.[]=(column_name_maker.call(c.name), columns_to_hash_for_classes(c.columns, sub_column_name_maker)) # Pop the class stack, and recurse
        end
      end
      hash
    end

    def _standard_insert_mutation(column_family, column_name, value, timestamp, ttl = nil)
      CassandraThrift::Mutation.new(
        :column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
          :column => CassandraThrift::Column.new(
            :name => column_name_class(column_family).new(column_name).to_s,
            :value => value,
            :timestamp => timestamp,
            :ttl => ttl
          )
        )
      )
    end

    def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, ttl = nil)
      CassandraThrift::Mutation.new(:column_or_supercolumn =>
        CassandraThrift::ColumnOrSuperColumn.new(
          :super_column => CassandraThrift::SuperColumn.new(
            :name => column_name_class(column_family).new(super_column_name).to_s,
            :columns => sub_columns.collect { |sub_column_name, sub_column_value|
              CassandraThrift::Column.new(
                :name => sub_column_name_class(column_family).new(sub_column_name).to_s,
                :value => sub_column_value.to_s,
                :timestamp => timestamp,
                :ttl => ttl
              )
            }
          )
        )
      )
    end

    # General info about a deletion object within a mutation
    # timestamp - required. If this is the only param, it will cause deletion of the whole key at that TS
    # supercolumn - opt. If passed, the deletes will only occur within that supercolumn (only subcolumns
    # will be deleted). Otherwise the normal columns will be deleted.
    # predicate - opt. Defines how to match the columns to delete. if supercolumn passed, the slice will
    # be scoped to subcolumns of that supercolumn.

    # Deletes a single column from the containing key/CF (and possibly supercolumn), at a given timestamp.
    # Although mutations (as opposed to 'remove' calls) support deleting slices and lists of columns in one shot, this is not implemented here.
    # The main reason being that the batch function takes removes, but removes don't have that capability...so we'd need to change the remove
    # methods to use delete mutation calls...although that might have performance implications. We'll leave that refactoring for later.
    def _delete_mutation(cf, column, subcolumn, timestamp, options={})
      deletion_hash = {:timestamp => timestamp}
      if is_super(cf)
        deletion_hash[:super_column] = column if column
        deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [subcolumn]) if subcolumn
      else
        deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [column]) if column
      end
      CassandraThrift::Mutation.new(
        :deletion => CassandraThrift::Deletion.new(deletion_hash)
      )
    end
  end
end
Something went wrong with that request. Please try again.