odba 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ #-- CacheEntry -- odba -- 29.04.2004 -- hwyss@ywesee.com mwalder@ywesee.com
3
+
4
+ module ODBA
5
+ class CacheEntry # :nodoc: all
6
+ @@id_table = {}
7
+ @@finalizer = proc { |object_id|
8
+ if(odba_id = @@id_table.delete(object_id))
9
+ ODBA.cache.invalidate odba_id
10
+ end
11
+ }
12
+ attr_accessor :last_access
13
+ attr_reader :accessed_by, :odba_id, :odba_object_id
14
+ def initialize(obj)
15
+ @odba_id = obj.odba_id
16
+ update obj
17
+ @accessed_by = {}
18
+ @odba_observers = obj.odba_observers
19
+ end
20
+ def update obj
21
+ @last_access = Time.now
22
+ @odba_object = obj
23
+ @odba_class = obj.class
24
+ @odba_id = obj.odba_id
25
+ unless @odba_object_id == obj.object_id
26
+ @@id_table.delete @odba_object_id
27
+ @odba_object_id = obj.object_id
28
+ @@id_table.store @odba_object_id, @odba_id
29
+ ObjectSpace.define_finalizer obj, @@finalizer
30
+ end
31
+ end
32
+ def object_id2ref(object_id, odba_id)
33
+ if (obj = ObjectSpace._id2ref(object_id)) \
34
+ && obj.is_a?(Persistable) && !obj.odba_unsaved? \
35
+ && obj.odba_id == odba_id
36
+ obj
37
+ end
38
+ rescue RangeError, NoMethodError => e
39
+ nil
40
+ end
41
+ def odba_id2ref(odba_id)
42
+ odba_id && ODBA.cache.include?(odba_id) && ODBA.cache.fetch(odba_id)
43
+ end
44
+ def odba_add_reference(object)
45
+ @accessed_by.store(object.object_id, object.odba_id)
46
+ object
47
+ end
48
+ def odba_cut_connections!
49
+ @accessed_by.each { |object_id, odba_id|
50
+ if((item = odba_id2ref(odba_id) || object_id2ref(object_id, odba_id)) \
51
+ && item.respond_to?(:odba_cut_connection))
52
+ item.odba_cut_connection(_odba_object)
53
+ end
54
+ }
55
+ end
56
+ def odba_notify_observers(*args)
57
+ @odba_observers.each { |obs| obs.odba_update(*args) }
58
+ end
59
+ def odba_object
60
+ @last_access = Time.now
61
+ @odba_object = _odba_object
62
+ @odba_object || ODBA.cache.fetch(@odba_id)
63
+ end
64
+ def _odba_object
65
+ @odba_object || object_id2ref(@odba_object_id, @odba_id)
66
+ end
67
+ def odba_old?(retire_horizon = Time.now - ODBA.cache.retire_age)
68
+ !_odba_object.odba_unsaved? \
69
+ && (retire_horizon > @last_access)
70
+ end
71
+ def odba_retire opts={}
72
+ # replace with stubs in accessed_by
73
+ instance = _odba_object
74
+ if opts[:force]
75
+ @accessed_by.each do |object_id, odba_id|
76
+ if item = odba_id2ref(odba_id)
77
+ item.odba_stubize instance, opts
78
+ elsif(item = object_id2ref(object_id, odba_id))
79
+ if item.is_a?(Persistable) && !item.is_a?(Stub)
80
+ item.odba_stubize instance, opts
81
+ end
82
+ end
83
+ end
84
+ @accessed_by.clear
85
+ @odba_object = nil
86
+ else
87
+ @accessed_by.delete_if { |object_id, odba_id|
88
+ if(item = odba_id2ref(odba_id))
89
+ item.odba_stubize instance
90
+ elsif(item = object_id2ref(object_id, odba_id))
91
+ case item
92
+ when Stub
93
+ true
94
+ when Array, Hash
95
+ false
96
+ when Persistable
97
+ item.odba_stubize instance
98
+ else
99
+ true
100
+ end
101
+ else
102
+ true
103
+ end
104
+ }
105
+ if @accessed_by.empty?
106
+ @odba_object = nil
107
+ end
108
+ end
109
+ end
110
+ def odba_replace!(obj)
111
+ oldhash = _odba_object.hash
112
+ _odba_object.odba_replace!(obj)
113
+ if(_odba_object.hash != oldhash)
114
+ @accessed_by.each { |object_id, odba_id|
115
+ if(item = odba_id2ref(odba_id) || object_id2ref(object_id, odba_id))
116
+ item.rehash if(item.respond_to? :rehash)
117
+ end
118
+ }
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+ #-- ConnectionPool -- ODBA -- 08.03.2005 -- hwyss@ywesee.com
3
+
4
+ require 'dbi'
5
+ require 'thread'
6
+
7
+ module ODBA
8
+ class ConnectionPool
9
+ POOL_SIZE = 5
10
+ SETUP_RETRIES = 3
11
+ attr_reader :connections
12
+ # All connections are delegated to DBI. The constructor simply records
13
+ # the DBI-arguments and reuses them to setup connections when needed.
14
+ def initialize(*dbi_args)
15
+ @dbi_args = dbi_args
16
+ @opts = @dbi_args.last.is_a?(Hash) ? @dbi_args.pop : Hash.new
17
+ @connections = []
18
+ @mutex = Mutex.new
19
+ connect
20
+ end
21
+ def next_connection # :nodoc:
22
+ conn = nil
23
+ @mutex.synchronize {
24
+ conn = @connections.shift
25
+ }
26
+ yield(conn)
27
+ ensure
28
+ @mutex.synchronize {
29
+ @connections.push(conn)
30
+ }
31
+ end
32
+ def method_missing(method, *args, &block) # :nodoc:
33
+ tries = SETUP_RETRIES
34
+ begin
35
+ next_connection { |conn|
36
+ conn.send(method, *args, &block)
37
+ }
38
+ rescue NoMethodError, DBI::Error => e
39
+ warn e
40
+ if(tries > 0 && (!e.is_a?(DBI::ProgrammingError) \
41
+ || e.message == 'no connection to the server'))
42
+ sleep(SETUP_RETRIES - tries)
43
+ tries -= 1
44
+ reconnect
45
+ retry
46
+ else
47
+ raise
48
+ end
49
+ end
50
+ end
51
+ def size
52
+ @connections.size
53
+ end
54
+ alias :pool_size :size
55
+ def connect # :nodoc:
56
+ @mutex.synchronize { _connect }
57
+ end
58
+ def _connect # :nodoc:
59
+ POOL_SIZE.times {
60
+ conn = DBI.connect(*@dbi_args)
61
+ if encoding = @opts[:client_encoding]
62
+ conn.execute "SET CLIENT_ENCODING TO '#{encoding}'"
63
+ end
64
+ @connections.push(conn)
65
+ }
66
+ end
67
+ def disconnect # :nodoc:
68
+ @mutex.synchronize { _disconnect }
69
+ end
70
+ def _disconnect # :nodoc:
71
+ while(conn = @connections.shift)
72
+ begin
73
+ conn.disconnect
74
+ rescue DBI::InterfaceError, Exception
75
+ ## we're not interested, since we are disconnecting anyway
76
+ nil
77
+ end
78
+ end
79
+ end
80
+ def reconnect # :nodoc:
81
+ @mutex.synchronize {
82
+ _disconnect
83
+ _connect
84
+ }
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+ # DRbWrapper -- ydim -- 11.01.2006 -- hwyss@ywesee.com
3
+
4
+ require 'drb'
5
+ require 'odba/persistable'
6
+ require 'odba/stub'
7
+ require 'odba/odba'
8
+ require 'drb/timeridconv'
9
+
10
+ module ODBA
11
+ class DRbWrapper
12
+ instance_methods.each { |m|
13
+ undef_method(m) unless m =~ /^(__)|(respond_to\?|object_id$)/ }
14
+ include DRb::DRbUndumped
15
+ def initialize(obj)
16
+ @obj = obj
17
+ end
18
+ def respond_to?(sym, *args)
19
+ super || @obj.respond_to?(sym, *args)
20
+ end
21
+ def method_missing(sym, *args)
22
+ if(block_given?)
23
+ res = @obj.__send__(sym, *args) { |*block_args|
24
+ yield *block_args.collect { |arg| __wrap(arg) }
25
+ }
26
+ __wrap(res)
27
+ else
28
+ res = @obj.__send__(sym, *args)
29
+ if(res.is_a?(Array))
30
+ res.collect { |item| __wrap(item) }
31
+ elsif(res.is_a?(Hash))
32
+ res.inject({}) { |memo, (key, value)|
33
+ memo.store(__wrap(key), __wrap(value))
34
+ memo
35
+ }
36
+ else
37
+ __wrap(res)
38
+ end
39
+ end
40
+ end
41
+ def __wrap(obj)
42
+ if(obj.is_a?(ODBA::Persistable))
43
+ DRbWrapper.new(obj.odba_instance)
44
+ else
45
+ obj
46
+ end
47
+ end
48
+ def __wrappee
49
+ @obj
50
+ end
51
+ end
52
+ class DRbIdConv < DRb::DRbIdConv
53
+ def initialize(*args)
54
+ super
55
+ @unsaved = {}
56
+ end
57
+ def odba_update(key, odba_id, object_id)
58
+ case key
59
+ when :store
60
+ @unsaved.store(object_id, odba_id)
61
+ when :clean, :delete
62
+ @unsaved.delete(object_id)
63
+ end
64
+ end
65
+ def to_obj(ref)
66
+ test = ref
67
+ if(test.is_a?(String) || (test = @unsaved[ref]))
68
+ DRbWrapper.new(ODBA.cache.fetch(test.to_i))
69
+ else
70
+ super
71
+ end
72
+ rescue RuntimeError => e
73
+ raise RangeError, e.message
74
+ end
75
+ def to_id(obj)
76
+ if(obj.is_a?(ODBA::Persistable))
77
+ if(obj.odba_unsaved?)
78
+ obj.odba_add_observer(self)
79
+ super
80
+ else
81
+ obj.odba_id.to_s
82
+ end
83
+ else
84
+ super
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ #-- IdServer -- odba -- 10.11.2004 -- hwyss@ywesee.com
3
+
4
+ require 'odba/persistable'
5
+ require 'thread'
6
+
7
+ module ODBA
8
+ class IdServer
9
+ include Persistable
10
+ ODBA_SERIALIZABLE = ['@ids']
11
+ ODBA_EXCLUDE_VARS = ['@mutex']
12
+ def initialize
13
+ @ids = {}
14
+ end
15
+ def next_id(key, startval=1)
16
+ @mutex ||= Mutex.new
17
+ res = nil
18
+ @mutex.synchronize {
19
+ @ids[key] ||= (startval - 1)
20
+ res = @ids[key] += 1
21
+ }
22
+ odba_store
23
+ res
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,395 @@
1
+ #!/usr/bin/env ruby
2
+ #-- Index -- odba -- 13.05.2004 -- rwaltert@ywesee.com
3
+
4
+ require 'odba/persistable'
5
+
6
+ module ODBA
7
+ # Indices in ODBA are defined by origin and target (which may be identical)
8
+ # Any time a Persistable of class _target_klass_ or _origin_klass_ is stored,
9
+ # all corresponding indices are updated. To make this possible, we have to tell
10
+ # Index, how to navigate from _origin_ to _target_ and vice versa.
11
+ # This entails the Limitation that these paths must not change without
12
+ # _origin_ and/or _target_ being stored.
13
+ # Further, _search_term_ must be resolved in relation to _origin_.
14
+ class IndexCommon # :nodoc: all
15
+ include Persistable
16
+ if RUBY_VERSION >= '1.9'
17
+ ODBA_EXCLUDE_VARS = [
18
+ :@proc_origin, :@proc_target, :@proc_resolve_search_term
19
+ ]
20
+ else
21
+ ODBA_EXCLUDE_VARS = [
22
+ '@proc_origin', '@proc_target', '@proc_resolve_search_term'
23
+ ]
24
+ end
25
+ attr_accessor :origin_klass, :target_klass, :resolve_origin, :resolve_target,
26
+ :resolve_search_term, :index_name, :dictionary, :class_filter
27
+ def initialize(index_definition, origin_module)
28
+ @origin_klass = origin_module.instance_eval(index_definition.origin_klass.to_s)
29
+ @target_klass = origin_module.instance_eval(index_definition.target_klass.to_s)
30
+ @resolve_origin = index_definition.resolve_origin
31
+ @resolve_target = index_definition.resolve_target
32
+ @index_name = index_definition.index_name
33
+ @resolve_search_term = index_definition.resolve_search_term
34
+ @dictionary = index_definition.dictionary
35
+ @class_filter = index_definition.class_filter
36
+ end
37
+ def current_origin_ids(target_id) # :nodoc:
38
+ ODBA.storage.index_origin_ids(@index_name, target_id)
39
+ end
40
+ def current_target_ids(origin_id) # :nodoc:
41
+ ODBA.storage.index_target_ids(@index_name, origin_id)
42
+ end
43
+ def delete(object) # :nodoc:
44
+ if(object.is_a?(@origin_klass))
45
+ ODBA.storage.delete_index_element(@index_name, object.odba_id,
46
+ 'origin_id')
47
+ end
48
+ if(object.is_a?(@target_klass))
49
+ ODBA.storage.delete_index_element(@index_name, object.odba_id,
50
+ 'target_id')
51
+ end
52
+ end
53
+ def delete_origin(origin_id, term) # :nodoc:
54
+ ODBA.storage.index_delete_origin(@index_name, origin_id, term)
55
+ end
56
+ def delete_target(origin_id, old_term, target_id) # :nodoc:
57
+ ODBA.storage.index_delete_target(@index_name, origin_id,
58
+ old_term, target_id)
59
+ end
60
+ def do_update_index(origin_id, term, target_id=nil) # :nodoc:
61
+ ODBA.storage.update_index(@index_name, origin_id, term, target_id)
62
+ end
63
+ def fill(targets)
64
+ @proc_origin = nil
65
+ rows = []
66
+ targets.flatten.each { |target|
67
+ target_id = target.odba_id
68
+ origins = proc_instance_origin.call(target)
69
+ origins.each { |origin|
70
+ search_terms(origin).each { |term|
71
+ do_update_index( origin.odba_id, term, target_id)
72
+ }
73
+ }
74
+ }
75
+ end
76
+ def keys(length=nil)
77
+ ODBA.storage.index_fetch_keys(@index_name, length).delete_if { |k|
78
+ k.empty? }
79
+ end
80
+ def matches(substring, limit=nil, offset=0)
81
+ ODBA.storage.index_matches @index_name, substring, limit, offset
82
+ end
83
+ def origin_class?(klass)
84
+ (@origin_klass == klass)
85
+ end
86
+ def proc_instance_origin # :nodoc:
87
+ if(@proc_origin.nil?)
88
+ if(@resolve_origin.to_s.empty?)
89
+ @proc_origin = Proc.new { |odba_item| [odba_item] }
90
+ else
91
+ src = <<-EOS
92
+ Proc.new { |odba_item|
93
+ res = [odba_item.#{@resolve_origin}]
94
+ res.flatten!
95
+ res.compact!
96
+ res
97
+ }
98
+ EOS
99
+ @proc_origin = eval(src)
100
+ end
101
+ end
102
+ @proc_origin
103
+ end
104
+ def proc_instance_target # :nodoc:
105
+ if(@proc_target.nil?)
106
+ if(@resolve_target.to_s.empty?)
107
+ @proc_target = Proc.new { |odba_item| [odba_item] }
108
+ #elsif(@resolve_target == :odba_skip)
109
+ # @proc_target = Proc.new { [] }
110
+ else
111
+ src = <<-EOS
112
+ Proc.new { |odba_item|
113
+ res = [odba_item.#{@resolve_target}]
114
+ res.flatten!
115
+ res.compact!
116
+ res
117
+ }
118
+ EOS
119
+ @proc_target = eval(src)
120
+ end
121
+ end
122
+ @proc_target
123
+ end
124
+ def proc_resolve_search_term # :nodoc:
125
+ if(@proc_resolve_search_term.nil?)
126
+ if(@resolve_search_term.to_s.empty?)
127
+ @proc_resolve_search_term = Proc.new { |origin|
128
+ origin.to_s.downcase
129
+ }
130
+ else
131
+ src = <<-EOS
132
+ Proc.new { |origin|
133
+ begin
134
+ origin.#{@resolve_search_term}
135
+ rescue NameError => e
136
+ nil
137
+ end
138
+ }
139
+ EOS
140
+ @proc_resolve_search_term = eval(src)
141
+ end
142
+ end
143
+ @proc_resolve_search_term
144
+ end
145
+ def search_term(origin) # :nodoc:
146
+ proc_resolve_search_term.call(origin)
147
+ end
148
+ def search_terms(origin)
149
+ [search_term(origin)].flatten.compact.uniq
150
+ end
151
+ def set_relevance(meta, rows) # :nodoc:
152
+ if(meta.respond_to?(:set_relevance))
153
+ rows.each { |row|
154
+ meta.set_relevance(row.at(0), row.at(1))
155
+ }
156
+ end
157
+ end
158
+ def update(object)
159
+ @class_filter ||= :is_a?
160
+ if(object.send(@class_filter, @target_klass))
161
+ update_target(object)
162
+ elsif(object.send(@class_filter, @origin_klass))
163
+ update_origin(object)
164
+ end
165
+ rescue StandardError => err
166
+ warn <<-EOS
167
+ #{err.class}: #{err.message} when updating index '#{@index_name}' with a #{object.class}
168
+ #{err.backtrace[0,4]}
169
+ [...]
170
+ EOS
171
+ end
172
+ def update_origin(object) # :nodoc:
173
+ origin_id = object.odba_id
174
+ search_terms = search_terms(object)
175
+ current = current_target_ids(origin_id)
176
+ target_ids = []
177
+ current_terms = []
178
+ current.each { |row|
179
+ target_ids.push(row[0])
180
+ current_terms.push(row[1])
181
+ }
182
+ current_terms.uniq!
183
+ target_ids.uniq!
184
+ (current_terms - search_terms).each { |term|
185
+ delete_origin(origin_id, term)
186
+ }
187
+ new_terms = search_terms - current_terms
188
+ unless(new_terms.empty?)
189
+ target_ids.each { |target_id|
190
+ new_terms.each { |term|
191
+ do_update_index(origin_id, term, target_id)
192
+ }
193
+ }
194
+ end
195
+ end
196
+ def update_target(target) # :nodoc:
197
+ target_id = target.odba_id
198
+ current = current_origin_ids(target_id)
199
+ old_terms = current.collect { |row|
200
+ [row[0], row[1]]
201
+ }
202
+ origins = proc_instance_origin.call(target)
203
+ new_terms = []
204
+ origins.each { |origin|
205
+ origin_id = origin.odba_id
206
+ search_terms(origin).each { |term|
207
+ new_terms.push([origin_id, term])
208
+ }
209
+ }
210
+ (old_terms - new_terms).each { |origin_id, terms|
211
+ delete_target(origin_id, terms, target_id)
212
+ }
213
+ (new_terms - old_terms).each { |origin_id, terms|
214
+ do_update_index(origin_id, terms, target_id)
215
+ }
216
+ end
217
+ end
218
+ # Currently there are 3 predefined Index-classes
219
+ # For Sample Code see
220
+ # http://dev.ywesee.com/wiki.php/ODBA/SimpleIndex
221
+ # http://dev.ywesee.com/wiki.php/ODBA/ConditionIndex
222
+ # http://dev.ywesee.com/wiki.php/ODBA/FulltextIndex
223
+ class Index < IndexCommon # :nodoc: all
224
+ def initialize(index_definition, origin_module) # :nodoc:
225
+ super(index_definition, origin_module)
226
+ ODBA.storage.create_index(index_definition.index_name)
227
+ end
228
+ def fetch_ids(search_term, meta=nil) # :nodoc:
229
+ exact = meta.respond_to?(:exact) && meta.exact
230
+ limit = meta.respond_to?(:limit) && meta.limit
231
+ rows = ODBA.storage.retrieve_from_index(@index_name,
232
+ search_term.to_s.downcase,
233
+ exact, limit)
234
+ set_relevance(meta, rows)
235
+ rows.collect { |row| row.at(0) }
236
+ end
237
+ def update_origin(object) # :nodoc:
238
+ # Possible changes:
239
+ # - search_terms of origin have changed
240
+ # - targets have changed, except if @resolve_target == :none
241
+ # => we need a matrix of all current [term, target_id]
242
+ # and of all new [term, target_id]
243
+ origin_id = object.odba_id
244
+ search_terms = search_terms(object)
245
+ current = current_target_ids(origin_id)
246
+ target_ids = if @resolve_target == :none
247
+ current.dup
248
+ else
249
+ proc_instance_target.call(object).collect { |obj|
250
+ obj.odba_id }
251
+ end
252
+ target_ids.compact!
253
+ target_ids.uniq!
254
+ current_ids = []
255
+ current_terms = []
256
+ current.each { |row|
257
+ current_ids.push(row[0])
258
+ current_terms.push(row[1])
259
+ }
260
+ current_ids.uniq!
261
+ current_terms.uniq!
262
+ current_combinations = current_ids.inject([]) { |memo, id|
263
+ current_terms.each { |term| memo.push [term, id] }
264
+ memo
265
+ }
266
+ combinations = target_ids.inject([]) { |memo, id|
267
+ search_terms.each { |term| memo.push [term, id] }
268
+ memo
269
+ }
270
+ (current_combinations - combinations).each { |pair|
271
+ delete_target(origin_id, *pair)
272
+ }
273
+ (combinations - current_combinations).each { |pair|
274
+ do_update_index(origin_id, *pair)
275
+ }
276
+ end
277
+ def search_terms(origin)
278
+ super.collect { |term| term.to_s.downcase }.uniq
279
+ end
280
+ end
281
+ class ConditionIndex < IndexCommon # :nodoc: all
282
+ def initialize(index_definition, origin_module) # :nodoc:
283
+ super(index_definition, origin_module)
284
+ definition = {}
285
+ @resolve_search_term = {}
286
+ index_definition.resolve_search_term.each { |name, info|
287
+ if(info.is_a?(String))
288
+ info = { 'resolve' => info }
289
+ end
290
+ if(info['type'].nil?)
291
+ info['type'] = 'text'
292
+ end
293
+ @resolve_search_term.store(name, info)
294
+ definition.store(name, info['type'])
295
+ }
296
+ ODBA.storage.create_condition_index(@index_name, definition)
297
+ end
298
+ def current_ids(rows, id_name)
299
+ rows.collect { |row|
300
+ [
301
+ row[id_name],
302
+ @resolve_search_term.keys.collect { |key|
303
+ [key.to_s, row[key]] }.sort,
304
+ ]
305
+ }
306
+ end
307
+ def current_origin_ids(target_id)
308
+ current_ids(ODBA.storage.condition_index_ids(@index_name,
309
+ target_id,
310
+ 'target_id'),
311
+ 'origin_id')
312
+ end
313
+ def current_target_ids(origin_id)
314
+ current_ids(ODBA.storage.condition_index_ids(@index_name,
315
+ origin_id,
316
+ 'origin_id'),
317
+ 'target_id')
318
+ end
319
+ def delete_origin(origin_id, search_terms)
320
+ ODBA.storage.condition_index_delete(@index_name, origin_id,
321
+ search_terms)
322
+ end
323
+ def delete_target(origin_id, search_terms, target_id)
324
+ ODBA.storage.condition_index_delete(@index_name, origin_id,
325
+ search_terms, target_id)
326
+ end
327
+ def do_update_index(origin_id, search_terms, target_id=nil) # :nodoc:
328
+ ODBA.storage.update_condition_index(@index_name, origin_id,
329
+ search_terms, target_id)
330
+ end
331
+ def fetch_ids(conditions, meta=nil) # :nodoc:
332
+ limit = meta.respond_to?(:limit) && meta.limit
333
+ rows = ODBA.storage.retrieve_from_condition_index(@index_name,
334
+ conditions,
335
+ limit)
336
+ set_relevance(meta, rows)
337
+ rows.collect { |row| row.at(0) }
338
+ end
339
+ def proc_resolve_search_term # :nodoc:
340
+ if(@proc_resolve_search_term.nil?)
341
+ src = <<-EOS
342
+ Proc.new { |origin|
343
+ values = {}
344
+ EOS
345
+ @resolve_search_term.each { |name, info|
346
+ src << <<-EOS
347
+ begin
348
+ values.store('#{name}', origin.#{info['resolve']})
349
+ rescue NameError
350
+ end
351
+ EOS
352
+ }
353
+ src << <<-EOS
354
+ values
355
+ }
356
+ EOS
357
+ @proc_resolve_search_term = eval(src)
358
+ end
359
+ @proc_resolve_search_term
360
+ end
361
+ def search_terms(origin)
362
+ super.collect { |data| data.to_a.sort }
363
+ end
364
+ end
365
+ class FulltextIndex < IndexCommon # :nodoc: all
366
+ def initialize(index_definition, origin_module) # :nodoc:
367
+ super(index_definition, origin_module)
368
+ ODBA.storage.create_fulltext_index(@index_name)
369
+ end
370
+ def current_origin_ids(target_id)
371
+ ODBA.storage.fulltext_index_delete(@index_name, target_id,
372
+ 'target_id')
373
+ []
374
+ end
375
+ def current_target_ids(origin_id)
376
+ ODBA.storage.fulltext_index_target_ids(@index_name, origin_id)
377
+ end
378
+ def delete_origin(origin_id, term)
379
+ ODBA.storage.fulltext_index_delete(@index_name, origin_id,
380
+ 'origin_id')
381
+ end
382
+ def fetch_ids(search_term, meta=nil) # :nodoc:
383
+ limit = meta.respond_to?(:limit) && meta.limit
384
+ rows = ODBA.storage.retrieve_from_fulltext_index(@index_name,
385
+ search_term, @dictionary, limit)
386
+ set_relevance(meta, rows)
387
+ rows.collect { |row| row.at(0) }
388
+ end
389
+ def do_update_index(origin_id, search_text, target_id=nil) # :nodoc:
390
+ ODBA.storage.update_fulltext_index(@index_name, origin_id,
391
+ search_text, target_id,
392
+ @dictionary)
393
+ end
394
+ end
395
+ end