Class: Dynamoid::Indexes::Index

Inherits:
Object
  • Object
show all
Defined in:
lib/dynamoid/indexes/index.rb

Overview

The class contains all the information an index contains, including its keys and which attributes it covers.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, name, options = {}) ⇒ Index

Create a new index. Pass either :range => true or :range => :column_name to create a ranged index on that column.

Parameters:

  • source (Class)

    the source class for the index

  • name (Symbol)

    the name of the index

Raises:

Since:

  • 0.2.0



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/dynamoid/indexes/index.rb', line 16

def initialize(source, name, options = {})
  @source = source
  
  if options.delete(:range)
    @range_keys = sort(name)
  elsif options[:range_key]
    @range_keys = sort(options[:range_key])
  end
  @hash_keys = sort(name)
  @name = sort([hash_keys, range_keys])
  
  raise Dynamoid::Errors::InvalidField, 'A key specified for an index is not a field' unless keys.all?{|n| source.attributes.include?(n)}
end

Instance Attribute Details

#hash_keysObject

Returns the value of attribute hash_keys.



7
8
9
# File 'lib/dynamoid/indexes/index.rb', line 7

def hash_keys
  @hash_keys
end

#nameObject

Returns the value of attribute name.



7
8
9
# File 'lib/dynamoid/indexes/index.rb', line 7

def name
  @name
end

#range_keysObject Also known as: range_key?

Returns the value of attribute range_keys.



7
8
9
# File 'lib/dynamoid/indexes/index.rb', line 7

def range_keys
  @range_keys
end

#sourceObject

Returns the value of attribute source.



7
8
9
# File 'lib/dynamoid/indexes/index.rb', line 7

def source
  @source
end

Instance Method Details

#delete(obj, changed_attributes = false) ⇒ Object

Delete an object from this index, preserving existing ids if there are any, and failing gracefully if for some reason the index doesn’t already have this object in it.

Since:

  • 0.2.0



93
94
95
96
97
98
99
# File 'lib/dynamoid/indexes/index.rb', line 93

def delete(obj, changed_attributes = false)
  values = values(obj, changed_attributes)
  return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
  existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], { :range_key => values[:range_value]})
  return true unless existing && existing[:ids] && existing[:ids].include?(obj.id)
  Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => (existing[:ids] - Set[obj.id]), :range => values[:range_value]})
end

#keysObject

Return the array of keys this index uses for its table.

Since:

  • 0.2.0



43
44
45
# File 'lib/dynamoid/indexes/index.rb', line 43

def keys
  [Array(hash_keys) + Array(range_keys)].flatten.uniq
end

#save(obj) ⇒ Object

Save an object to this index, merging it with existing ids if there’s already something present at this index location. First, though, delete this object from its old indexes (so the object isn’t listed in an erroneous index).

Since:

  • 0.2.0



80
81
82
83
84
85
86
87
# File 'lib/dynamoid/indexes/index.rb', line 80

def save(obj)
  self.delete(obj, true)
  values = values(obj)
  return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
  existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], { :range_key => values[:range_value] })
  ids = ((existing and existing[:ids]) or Set.new)
  Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => ids.merge([obj.id]), :range => values[:range_value]})
end

#sort(objs) ⇒ Object

Sort objects into alphabetical strings, used for composing index names correctly (since we always assume they’re alphabetical).

Examples:

find all users by first and last name

sort([:gamma, :alpha, :beta, :omega]) # => [:alpha, :beta, :gamma, :omega]

Since:

  • 0.2.0



36
37
38
# File 'lib/dynamoid/indexes/index.rb', line 36

def sort(objs)
  Array(objs).flatten.compact.uniq.collect(&:to_s).sort.collect(&:to_sym)
end

#table_nameObject

Return the table name for this index.

Since:

  • 0.2.0



50
51
52
# File 'lib/dynamoid/indexes/index.rb', line 50

def table_name
  "#{Dynamoid::Config.namespace}_index_" + source.table_name.sub("#{Dynamoid::Config.namespace}_", '').singularize + "_#{name.collect(&:to_s).collect(&:pluralize).join('_and_')}"
end

#values(attrs, changed_attributes = false) ⇒ Hash

Given either an object or a list of attributes, generate a hash key and a range key for the index. Optionally pass in true to changed_attributes for a list of all the object’s dirty attributes in convenient index form (for deleting stale information from the indexes).

Parameters:

  • attrs (Object)

    either an object that responds to :attributes, or a hash of attributes

Returns:

  • (Hash)

    a hash with the keys :hash_value and :range_value

Since:

  • 0.2.0



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/dynamoid/indexes/index.rb', line 63

def values(attrs, changed_attributes = false)
  if changed_attributes
    hash = {}
    attrs.changes.each {|k, v| hash[k.to_sym] = (v.first || v.last)}
    attrs = hash
  end
  attrs = attrs.send(:attributes) if attrs.respond_to?(:attributes)
  {}.tap do |hash|
    hash[:hash_value] = hash_keys.collect{|key| attrs[key]}.join('.')
    hash[:range_value] = range_keys.inject(0.0) {|sum, key| sum + attrs[key].to_f} if self.range_key?
  end
end