Module: Risky::Indexes

Defined in:
lib/risky/indexes.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

Provides indexes on an attribute. Mostly.



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
# File 'lib/risky/indexes.rb', line 4

def self.included(base)
  base.instance_eval do
    @indexes = {}

    def indexes
      @indexes
    end

    # Options:
    # :proc => Anything responding to #[record]. Returns the key used for the index.
    # :unique => Perform a unique check to ensure this index does not
    #            conflict with another record.
    def index(attribute, opts = {})
      opts[:bucket] ||= "#{@bucket_name}_by_#{attribute}"
      @indexes[attribute] = opts

      class_eval %{
        def self.by_#{attribute}(value)
          return nil unless value

          begin
            from_riak_object(
              Riak::RObject.new(
                riak[#{opts[:bucket].inspect}],
                value.to_s
              ).walk(:bucket => #{@bucket_name.inspect}).first.first
            )
          rescue Riak::FailedRequest => e
            raise e unless e.not_found?
            nil
          end
        end
      }
    end
  end
end

Instance Method Details

#after_loadObject



47
48
49
50
51
52
53
# File 'lib/risky/indexes.rb', line 47

def after_load
  super

  self.class.indexes.each do |attr, opts|
    @old_indexed_values[attr] = opts[:proc][self] rescue self[attr.to_s]
  end
end

#after_saveObject



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
# File 'lib/risky/indexes.rb', line 55

def after_save
  super

  self.class.indexes.each do |attr, opts|
    current = opts[:proc][self] rescue self[attr.to_s]
    old = @old_indexed_values[attr]
    @old_indexed_values[attr] = current

    unless old == current
      # Remove old index
      if old
        self.class.riak[opts[:bucket]].delete(old) rescue nil
      end

      # Create new index
      unless current.nil?
        index = Riak::RObject.new(self.class.riak[opts[:bucket]], current.to_s)
        index.content_type = 'text/plain'
        index.data = ''
        index.links = Set.new([@riak_object.to_link('value')])
        index.store
      end
    end
  end
end

#before_deleteObject



81
82
83
84
85
86
87
88
89
# File 'lib/risky/indexes.rb', line 81

def before_delete
  super

  self.class.indexes.each do |attr, opts|
    if key = @old_indexed_values[attr]
      self.class.riak[opts[:bucket]].delete(key) rescue nil
    end
  end
end

#initialize(*a) ⇒ Object



41
42
43
44
45
# File 'lib/risky/indexes.rb', line 41

def initialize(*a)
  @old_indexed_values = {}

  super *a
end

#validateObject



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
# File 'lib/risky/indexes.rb', line 91

def validate
  super

  # Validate unique indexes
  self.class.indexes.each do |attr, opts|
    next unless opts[:unique]

    current = opts[:proc][self] rescue self[attr.to_s]
    old = @old_indexed_values[attr]

    next if current.nil?
    next if current == old

    # Validate that the record belongs to us.
    begin
      existing = self.class.riak[opts[:bucket]][current]
      existing_key = existing.links.find { |l| l.tag == 'value' }.key
    rescue
      # Any failure here means no current index exists exists.
      next
    end

    if existing_key and (new? or key != existing_key)
      # Conflicts!
      errors[attr.to_sym] = 'taken'
    end
  end
end