Class: ODBA::IndexCommon

Inherits:
Object show all
Includes:
Persistable
Defined in:
lib/odba/index.rb

Overview

Indices in ODBA are defined by origin and target (which may be identical) Any time a Persistable of class target_klass or origin_klass is stored, all corresponding indices are updated. To make this possible, we have to tell Index, how to navigate from origin to target and vice versa. This entails the Limitation that these paths must not change without origin and/or target being stored. Further, search_term must be resolved in relation to origin.

Direct Known Subclasses

ConditionIndex, FulltextIndex, Index

Constant Summary

Constants included from Persistable

Persistable::Exact, Persistable::Find, Persistable::ODBA_EXCLUDE_VARS, Persistable::ODBA_INDEXABLE, Persistable::ODBA_PREDEFINE_EXCLUDE_VARS, Persistable::ODBA_PREDEFINE_SERIALIZABLE, Persistable::ODBA_PREFETCH, Persistable::ODBA_SERIALIZABLE

Instance Attribute Summary collapse

Attributes included from Persistable

#odba_id, #odba_name, #odba_persistent, #odba_prefetch

Instance Method Summary collapse

Methods included from Persistable

#==, append_features, #dup, #eql?, #odba_add_observer, #odba_collection, #odba_cut_connection, #odba_delete, #odba_delete_observer, #odba_delete_observers, #odba_dup, #odba_exclude_vars, #odba_indexable?, #odba_isolated_dump, #odba_isolated_store, #odba_isolated_stub, #odba_isolated_twin, #odba_notify_observers, #odba_observers, #odba_potentials, #odba_prefetch?, #odba_replace!, #odba_replace_persistables, #odba_replace_stubs, #odba_restore, #odba_serializables, #odba_snapshot, #odba_store, #odba_store_unsaved, #odba_stubize, #odba_take_snapshot, #odba_target_ids, #odba_unsaved?, #odba_unsaved_neighbors, sanitize

Constructor Details

#initialize(index_definition, origin_module) ⇒ IndexCommon

Returns a new instance of IndexCommon.



22
23
24
25
26
27
28
29
30
# File 'lib/odba/index.rb', line 22

def initialize(index_definition, origin_module)
  @origin_klass = origin_module.instance_eval(index_definition.origin_klass.to_s)
  @target_klass = origin_module.instance_eval(index_definition.target_klass.to_s)
  @resolve_origin = index_definition.resolve_origin
  @resolve_target = index_definition.resolve_target
  @index_name = index_definition.index_name
  @resolve_search_term = index_definition.resolve_search_term
  @class_filter = index_definition.class_filter
end

Instance Attribute Details

#class_filterObject

Returns the value of attribute class_filter.



20
21
22
# File 'lib/odba/index.rb', line 20

def class_filter
  @class_filter
end

#index_nameObject

Returns the value of attribute index_name.



20
21
22
# File 'lib/odba/index.rb', line 20

def index_name
  @index_name
end

#origin_klassObject

Returns the value of attribute origin_klass.



20
21
22
# File 'lib/odba/index.rb', line 20

def origin_klass
  @origin_klass
end

#resolve_originObject

Returns the value of attribute resolve_origin.



20
21
22
# File 'lib/odba/index.rb', line 20

def resolve_origin
  @resolve_origin
end

#resolve_search_termObject

Returns the value of attribute resolve_search_term.



20
21
22
# File 'lib/odba/index.rb', line 20

def resolve_search_term
  @resolve_search_term
end

#resolve_targetObject

Returns the value of attribute resolve_target.



20
21
22
# File 'lib/odba/index.rb', line 20

def resolve_target
  @resolve_target
end

#target_klassObject

Returns the value of attribute target_klass.



20
21
22
# File 'lib/odba/index.rb', line 20

def target_klass
  @target_klass
end

Instance Method Details

#current_origin_ids(target_id) ⇒ Object

:nodoc:



32
33
34
# File 'lib/odba/index.rb', line 32

def current_origin_ids(target_id) # :nodoc:
  ODBA.storage.index_origin_ids(@index_name, target_id)
end

#current_target_ids(origin_id) ⇒ Object

:nodoc:



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

def current_target_ids(origin_id) # :nodoc:
  ODBA.storage.index_target_ids(@index_name, origin_id)
end

#delete(object) ⇒ Object

:nodoc:



40
41
42
43
44
45
46
47
48
49
# File 'lib/odba/index.rb', line 40

def delete(object) # :nodoc:
  if object.is_a?(@origin_klass)
    ODBA.storage.delete_index_element(@index_name, object.odba_id,
      "origin_id")
  end
  if object.is_a?(@target_klass)
    ODBA.storage.delete_index_element(@index_name, object.odba_id,
      "target_id")
  end
end

#delete_origin(origin_id, term) ⇒ Object

:nodoc:



51
52
53
# File 'lib/odba/index.rb', line 51

def delete_origin(origin_id, term) # :nodoc:
  ODBA.storage.index_delete_origin(@index_name, origin_id, term)
end

#delete_target(origin_id, old_term, target_id) ⇒ Object

:nodoc:



55
56
57
58
# File 'lib/odba/index.rb', line 55

def delete_target(origin_id, old_term, target_id) # :nodoc:
  ODBA.storage.index_delete_target(@index_name, origin_id,
    old_term, target_id)
end

#do_update_index(origin_id, term, target_id = nil) ⇒ Object

:nodoc:



60
61
62
# File 'lib/odba/index.rb', line 60

def do_update_index(origin_id, term, target_id = nil) # :nodoc:
  ODBA.storage.update_index(@index_name, origin_id, term, target_id)
end

#fill(targets) ⇒ Object



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

def fill(targets)
  @proc_origin = nil
  targets.flatten.each { |target|
    target_id = target.odba_id
    origins = proc_instance_origin.call(target)
    origins.each { |origin|
      search_terms(origin).each { |term|
        do_update_index(origin.odba_id, term, target_id)
      }
    }
  }
end

#keys(length = nil) ⇒ Object



77
78
79
80
81
# File 'lib/odba/index.rb', line 77

def keys(length = nil)
  ODBA.storage.index_fetch_keys(@index_name, length).delete_if { |k|
    k.empty?
  }
end

#matches(substring, limit = nil, offset = 0) ⇒ Object



83
84
85
# File 'lib/odba/index.rb', line 83

def matches(substring, limit = nil, offset = 0)
  ODBA.storage.index_matches @index_name, substring, limit, offset
end

#origin_class?(klass) ⇒ Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/odba/index.rb', line 87

def origin_class?(klass)
  (@origin_klass == klass)
end

#proc_instance_originObject

:nodoc:



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/odba/index.rb', line 91

def proc_instance_origin # :nodoc:
  if @proc_origin.nil?
    if @resolve_origin.to_s.empty?
      @proc_origin = proc { |odba_item| [odba_item] }
    else
      src = <<-EOS
		Proc.new { |odba_item| 
			res = [odba_item.#{@resolve_origin}]
			res.flatten!
			res.compact!
			res
		}
      EOS
      @proc_origin = eval(src)
    end
  end
  @proc_origin
end

#proc_instance_targetObject

:nodoc:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/odba/index.rb', line 110

def proc_instance_target # :nodoc:
  if @proc_target.nil?
    if @resolve_target.to_s.empty?
      @proc_target = proc { |odba_item| [odba_item] }
    # elsif(@resolve_target == :odba_skip)
    #  @proc_target = Proc.new { [] }
    else
      src = <<-EOS
        Proc.new { |odba_item| 
          res = [odba_item.#{@resolve_target}]
          res.flatten!
          res.compact!
          res
        }
      EOS
      @proc_target = eval(src)
    end
  end
  @proc_target
end

#proc_resolve_search_termObject

:nodoc:



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/odba/index.rb', line 131

def proc_resolve_search_term # :nodoc:
  if @proc_resolve_search_term.nil?
    if @resolve_search_term.to_s.empty?
      @proc_resolve_search_term = proc { |origin|
        origin.to_s.downcase
      }
    else
      src = <<-EOS
		Proc.new { |origin| 
			begin
				origin.#{@resolve_search_term}
			rescue NameError => e
				nil
			end
		}
      EOS
      @proc_resolve_search_term = eval(src)
    end
  end
  @proc_resolve_search_term
end

#search_term(origin) ⇒ Object

:nodoc:



153
154
155
# File 'lib/odba/index.rb', line 153

def search_term(origin) # :nodoc:
  proc_resolve_search_term.call(origin)
end

#search_terms(origin) ⇒ Object



157
158
159
# File 'lib/odba/index.rb', line 157

def search_terms(origin)
  [search_term(origin)].flatten.compact.uniq
end

#set_relevance(meta, rows) ⇒ Object

:nodoc:



161
162
163
164
165
166
167
# File 'lib/odba/index.rb', line 161

def set_relevance(meta, rows) # :nodoc:
  if meta.respond_to?(:set_relevance)
    rows.each { |row|
      meta.set_relevance(row.at(0), row.at(1))
    }
  end
end

#update(object) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/odba/index.rb', line 169

def update(object)
  @class_filter ||= :is_a?
  if object.send(@class_filter, @target_klass)
    update_target(object)
  elsif object.send(@class_filter, @origin_klass)
    update_origin(object)
  end
rescue => err
  warn <<~EOS
    #{err.class}: #{err.message} when updating index '#{@index_name}' with a #{object.class}
    #{err.backtrace[0, 4]}
    [...]
  EOS
end

#update_origin(object) ⇒ Object

:nodoc:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/odba/index.rb', line 184

def update_origin(object) # :nodoc:
  origin_id = object.odba_id
  search_terms = search_terms(object)
  current = current_target_ids(origin_id)
  target_ids = []
  current_terms = []
  current.each { |row|
    target_ids.push(row[0])
    current_terms.push(row[1])
  }
  current_terms.uniq!
  target_ids.uniq!
  (current_terms - search_terms).each { |term|
    delete_origin(origin_id, term)
  }
  new_terms = search_terms - current_terms
  unless new_terms.empty?
    target_ids.each { |target_id|
      new_terms.each { |term|
        do_update_index(origin_id, term, target_id)
      }
    }
  end
end

#update_target(target) ⇒ Object

:nodoc:



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/odba/index.rb', line 209

def update_target(target) # :nodoc:
  target_id = target.odba_id
  current = current_origin_ids(target_id)
  old_terms = current.collect { |row|
    [row[0], row[1]]
  }
  origins = proc_instance_origin.call(target)
  new_terms = []
  origins.each { |origin|
    origin_id = origin.odba_id
    search_terms(origin).each { |term|
      new_terms.push([origin_id, term])
    }
  }
  (old_terms - new_terms).each { |origin_id, terms|
    delete_target(origin_id, terms, target_id)
  }
  (new_terms - old_terms).each { |origin_id, terms|
    do_update_index(origin_id, terms, target_id)
  }
end