dm-rinda-adapter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest +16 -0
- data/Rakefile +47 -0
- data/dm-rinda-adapter.gemspec +29 -0
- data/lib/rinda-patch.rb +25 -0
- data/lib/rinda_adapter.rb +448 -0
- data/spec/legacy/README +6 -0
- data/spec/legacy/adapter_shared_spec.rb +331 -0
- data/spec/legacy/spec_helper.rb +3 -0
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +46 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
- data/spec/rcov.opts +6 -0
- data/spec/rinda-adapter_spec.rb +168 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +110 -0
- metadata +88 -0
data/Manifest
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Manifest
|
2
|
+
Rakefile
|
3
|
+
lib/rinda-patch.rb
|
4
|
+
lib/rinda_adapter.rb
|
5
|
+
spec/legacy/README
|
6
|
+
spec/legacy/adapter_shared_spec.rb
|
7
|
+
spec/legacy/spec_helper.rb
|
8
|
+
spec/lib/adapter_helpers.rb
|
9
|
+
spec/lib/collection_helpers.rb
|
10
|
+
spec/lib/counter_adapter.rb
|
11
|
+
spec/lib/pending_helpers.rb
|
12
|
+
spec/lib/rspec_immediate_feedback_formatter.rb
|
13
|
+
spec/rcov.opts
|
14
|
+
spec/rinda-adapter_spec.rb
|
15
|
+
spec/spec.opts
|
16
|
+
spec/spec_helper.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
def with_gem(gemname, &blk)
|
6
|
+
begin
|
7
|
+
require gemname
|
8
|
+
blk.call
|
9
|
+
rescue LoadError => e
|
10
|
+
puts "Failed to load gem #{gemname} because #{e}."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Echoe.new('dm-rinda-adapter', '0.1.0') do |p|
|
15
|
+
p.description = "A datamapper adapter to connect to a rinda tuplespace"
|
16
|
+
p.url = "http://github.com/sfeu/dm-rinda-adapter"
|
17
|
+
p.author = "Sebastian Feuerstack"
|
18
|
+
p.email = "sebastian @nospam@ feuerstack.de"
|
19
|
+
p.ignore_pattern = ["tmp/*", "script/*","#*.*#"]
|
20
|
+
p.development_dependencies = []
|
21
|
+
p.need_tar_gz = false
|
22
|
+
p.need_tgz = false
|
23
|
+
end
|
24
|
+
|
25
|
+
with_gem 'spec/rake/spectask' do
|
26
|
+
|
27
|
+
desc 'Run all specs'
|
28
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
29
|
+
t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.spec_files = FileList['spec/**_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Default: Run Specs'
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
desc 'Run all tests'
|
38
|
+
task :test => :spec
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
with_gem 'yard' do
|
43
|
+
desc "Generate Yardoc"
|
44
|
+
YARD::Rake::YardocTask.new do |t|
|
45
|
+
t.files = ['lib/**/*.rb', 'README.markdown']
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{dm-rinda-adapter}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = [%q{Sebastian Feuerstack}]
|
9
|
+
s.date = %q{2011-06-30}
|
10
|
+
s.description = %q{A datamapper adapter to connect to a rinda tuplespace}
|
11
|
+
s.email = %q{sebastian @nospam@ feuerstack.de}
|
12
|
+
s.extra_rdoc_files = [%q{lib/rinda-patch.rb}, %q{lib/rinda_adapter.rb}]
|
13
|
+
s.files = [%q{Manifest}, %q{Rakefile}, %q{lib/rinda-patch.rb}, %q{lib/rinda_adapter.rb}, %q{spec/legacy/README}, %q{spec/legacy/adapter_shared_spec.rb}, %q{spec/legacy/spec_helper.rb}, %q{spec/lib/adapter_helpers.rb}, %q{spec/lib/collection_helpers.rb}, %q{spec/lib/counter_adapter.rb}, %q{spec/lib/pending_helpers.rb}, %q{spec/lib/rspec_immediate_feedback_formatter.rb}, %q{spec/rcov.opts}, %q{spec/rinda-adapter_spec.rb}, %q{spec/spec.opts}, %q{spec/spec_helper.rb}, %q{dm-rinda-adapter.gemspec}]
|
14
|
+
s.homepage = %q{http://github.com/sfeu/dm-rinda-adapter}
|
15
|
+
s.rdoc_options = [%q{--line-numbers}, %q{--inline-source}, %q{--title}, %q{Dm-rinda-adapter}, %q{--main}, %q{README.rdoc}]
|
16
|
+
s.require_paths = [%q{lib}]
|
17
|
+
s.rubyforge_project = %q{dm-rinda-adapter}
|
18
|
+
s.rubygems_version = %q{1.8.5}
|
19
|
+
s.summary = %q{A datamapper adapter to connect to a rinda tuplespace}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
s.specification_version = 3
|
23
|
+
|
24
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
|
+
else
|
26
|
+
end
|
27
|
+
else
|
28
|
+
end
|
29
|
+
end
|
data/lib/rinda-patch.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rinda # dirty monkey patching to retrieve unique running ID, primitiv einc beacuse touble nested tuplebag storage with symbols.
|
2
|
+
class TupleSpace
|
3
|
+
|
4
|
+
def initialize(period=60)
|
5
|
+
super()
|
6
|
+
@bag = TupleBag.new
|
7
|
+
@read_waiter = TupleBag.new
|
8
|
+
@take_waiter = TupleBag.new
|
9
|
+
@notify_waiter = TupleBag.new
|
10
|
+
@period = period
|
11
|
+
@keeper = nil
|
12
|
+
@id = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def writeID(tuple,sec=nil)
|
17
|
+
synchronize do
|
18
|
+
@id =@id+1
|
19
|
+
tuple["id"] = @id
|
20
|
+
write(tuple,sec)
|
21
|
+
@id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,448 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
gem 'dm-core', '>=0.10.0'
|
3
|
+
require "rinda/tuplespace"
|
4
|
+
require 'monitor'
|
5
|
+
require 'rinda-patch'
|
6
|
+
|
7
|
+
module DataMapper
|
8
|
+
|
9
|
+
class Repository
|
10
|
+
def notify(action,query,callback,model,dm_query,time)
|
11
|
+
adapter.notify(action,query,callback,model,dm_query,time)
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait(action,query,callback,model,dm_query,time)
|
15
|
+
adapter.notify(action,query,callback,model,dm_query,time)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Model
|
20
|
+
def notify(action,query,callback,time = nil)
|
21
|
+
q = scoped_query(query)
|
22
|
+
q.repository.notify(action,query,callback,self,q,time)
|
23
|
+
end
|
24
|
+
def wait(action,query,callback,time = nil)
|
25
|
+
q = scoped_query(query)
|
26
|
+
q.repository.notify(action,query,callback,self,q, time)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Adapters
|
31
|
+
|
32
|
+
#monkey patching new notification methods
|
33
|
+
class AbstractAdapter
|
34
|
+
def notify(action,query,callback,model,dm_query,time)
|
35
|
+
raise NotImplementedError, "#{self.class}#notify not implemented"
|
36
|
+
end
|
37
|
+
def wait(action,query,callback,model,dm_query,time)
|
38
|
+
raise NotImplementedError, "#{self.class}#wait not implemented"
|
39
|
+
end
|
40
|
+
|
41
|
+
end # class AbstractAdapter
|
42
|
+
|
43
|
+
# This is probably the simplest functional adapter possible. It simply
|
44
|
+
# stores and queries from a hash containing the model classes as keys,
|
45
|
+
# and an array of hashes. It is not persistent whatsoever; when the Ruby
|
46
|
+
# process finishes, everything that was stored it lost. However, it doesn't
|
47
|
+
# require any other external libraries, such as data_objects, so it is ideal
|
48
|
+
# for writing specs against. It also serves as an excellent example for
|
49
|
+
# budding adapter developers, so it is critical that it remains well documented
|
50
|
+
# and up to date.
|
51
|
+
class RindaAdapter < AbstractAdapter
|
52
|
+
#include MonitorMixin
|
53
|
+
|
54
|
+
# Used by DataMapper to put records into a data-store: "INSERT" in SQL-speak.
|
55
|
+
# It takes an array of the resources (model instances) to be saved. Resources
|
56
|
+
# each have a key that can be used to quickly look them up later without
|
57
|
+
# searching, if the adapter supports it.
|
58
|
+
#
|
59
|
+
# @param [Enumerable(Resource)] resources
|
60
|
+
# The set of resources (model instances)
|
61
|
+
#
|
62
|
+
# @api semipublic
|
63
|
+
def create(resources)
|
64
|
+
name = self.name
|
65
|
+
# DataMapper.logger << "create #{resources.first.model}"
|
66
|
+
|
67
|
+
resources.each do |resource|
|
68
|
+
model = resource.model
|
69
|
+
serial = model.serial(name)
|
70
|
+
|
71
|
+
# DataMapper.logger << "res #{resource.inspect}"
|
72
|
+
#initialize_serial(resource, rand(2**32))
|
73
|
+
#DataMapper.logger << "att #{resource.attributes(:field).inspect}"
|
74
|
+
|
75
|
+
saveblock = { }
|
76
|
+
|
77
|
+
resource.attributes.each do |key, value|
|
78
|
+
# DataMapper.logger << "before convert #{resource.model.properties[key].type}"
|
79
|
+
saveblock[key.to_s]=convert_to_ts(resource.model.properties[key].type, value)
|
80
|
+
end
|
81
|
+
# model = resource.model
|
82
|
+
# attributes = resource.dirty_attributes
|
83
|
+
|
84
|
+
# model.properties_with_subclasses(name).each do |property|
|
85
|
+
# next unless attributes.key?(property)
|
86
|
+
|
87
|
+
# value = attributes[property]
|
88
|
+
# saveblock[property.field.to_s]=convert_to_ts(property.type, value)
|
89
|
+
#end
|
90
|
+
# add model name to be included into tuple
|
91
|
+
saveblock["_model_"]=resources.first.model.storage_name(name).to_s
|
92
|
+
|
93
|
+
DataMapper.logger << "write #{saveblock.inspect}"
|
94
|
+
@monitor.synchronize do
|
95
|
+
if serial
|
96
|
+
id = @ts.writeID saveblock
|
97
|
+
serial.set!(resource, id)
|
98
|
+
else
|
99
|
+
@ts.write saveblock
|
100
|
+
end
|
101
|
+
|
102
|
+
# @ts.write saveblock
|
103
|
+
#initialize_serial(resource,id)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Looks up one record or a collection of records from the data-store:
|
110
|
+
# "SELECT" in SQL.
|
111
|
+
#
|
112
|
+
# @param [Query] query
|
113
|
+
# The query to be used to seach for the resources
|
114
|
+
#
|
115
|
+
# @return [Array]
|
116
|
+
# An Array of Hashes containing the key-value pairs for
|
117
|
+
# each record
|
118
|
+
#
|
119
|
+
# @api semipublic
|
120
|
+
def read(query)
|
121
|
+
|
122
|
+
|
123
|
+
# DataMapper.logger << "query #{query.model.to_s}"
|
124
|
+
# DataMapper.logger << "query #{query.fields.inspect}"
|
125
|
+
queryblock = generate_query_with_conditions(query)
|
126
|
+
DataMapper.logger << "ts query #{queryblock.inspect}"
|
127
|
+
result=@ts.read_all(queryblock)
|
128
|
+
|
129
|
+
DataMapper.logger << "result #{result.inspect}"
|
130
|
+
#Kernel.const_get(s)
|
131
|
+
|
132
|
+
query.fields.each do |property|
|
133
|
+
if (property.type == DataMapper::Types::Discriminator)
|
134
|
+
|
135
|
+
key = property.name.to_s
|
136
|
+
result.each do |entry|
|
137
|
+
entry[key]=eval(entry[key].to_s)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
# DataMapper.logger << "result after transformation of discriminators #{result.inspect}"
|
142
|
+
|
143
|
+
query.filter_records(result)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Used by DataMapper to update the attributes on existing records in a
|
147
|
+
# data-store: "UPDATE" in SQL-speak. It takes a hash of the attributes
|
148
|
+
# to update with, as well as a collection object that specifies which resources
|
149
|
+
# should be updated.
|
150
|
+
#
|
151
|
+
# @param [Hash] attributes
|
152
|
+
# A set of key-value pairs of the attributes to update the resources with.
|
153
|
+
# @param [DataMapper::Collection] resources
|
154
|
+
# The collection of resources to update.
|
155
|
+
#
|
156
|
+
# @api semipublic
|
157
|
+
def update(attributes, collection)
|
158
|
+
DataMapper.logger << "update attributes: #{attributes.inspect} collection: #{collection.inspect}"
|
159
|
+
query = collection.query
|
160
|
+
|
161
|
+
query = generate_query_with_conditions(query)
|
162
|
+
# generate_query(collection.model)
|
163
|
+
|
164
|
+
records_to_delete=[]
|
165
|
+
@monitor.synchronize do
|
166
|
+
result=@ts.read_all(query)
|
167
|
+
|
168
|
+
records_to_delete = collection.query.filter_records(result)
|
169
|
+
|
170
|
+
records_to_delete.each do |record|
|
171
|
+
result=@ts.take(record)
|
172
|
+
saveblock ={ }
|
173
|
+
attributes.each do |key, value|
|
174
|
+
# DataMapper.logger << "key: #{key.name} value: #{value}"
|
175
|
+
saveblock[key.name.to_s]=convert_to_ts(key.name, value)
|
176
|
+
end
|
177
|
+
new = result.merge saveblock
|
178
|
+
@ts.write(new)
|
179
|
+
|
180
|
+
DataMapper.logger << "replaced: #{result.inspect} with: #{new.inspect}"
|
181
|
+
end
|
182
|
+
end # class synchronize
|
183
|
+
|
184
|
+
return records_to_delete.size
|
185
|
+
#end # class mutex synchronize
|
186
|
+
end
|
187
|
+
|
188
|
+
# Destroys all the records matching the given query. "DELETE" in SQL.
|
189
|
+
#
|
190
|
+
# @param [DataMapper::Collection] resources
|
191
|
+
# The collection of resources to delete.
|
192
|
+
#
|
193
|
+
# @return [Integer]
|
194
|
+
# The number of records that were deleted.
|
195
|
+
#
|
196
|
+
# @api semipublic
|
197
|
+
def delete(collection)
|
198
|
+
#DataMapper.logger << "delete #{collection.model.to_s}"
|
199
|
+
query = generate_query(collection.model)
|
200
|
+
# @mutex.synchronize do
|
201
|
+
|
202
|
+
result=@ts.read_all(query)
|
203
|
+
|
204
|
+
records_to_delete = collection.query.filter_records(result)
|
205
|
+
#DataMapper.logger << "entries to delete #{records_to_delete.inspect}"
|
206
|
+
|
207
|
+
records_to_delete.each do |record|
|
208
|
+
result=@ts.take(record)
|
209
|
+
end
|
210
|
+
records_to_delete.size
|
211
|
+
#end # class mutex synchronize
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
def wait(action,query,callback,model,dm_query,time = 10000)
|
216
|
+
|
217
|
+
query = generate_query(model).merge create_conditions(dm_query)
|
218
|
+
|
219
|
+
x = Thread.start do
|
220
|
+
begin
|
221
|
+
t = @ts.read query,(time/1000)
|
222
|
+
end until t and check_descendents(model,t) # quick patch that belongs into tuplespace
|
223
|
+
|
224
|
+
repository = dm_query.repository
|
225
|
+
model = dm_query.model
|
226
|
+
identity_fields = model.key(repository.name).map &:name
|
227
|
+
|
228
|
+
retrieve = identity_fields.map do |x| t[x.to_s] end
|
229
|
+
|
230
|
+
resource = model.get(*retrieve)
|
231
|
+
callback.call resource
|
232
|
+
end
|
233
|
+
x
|
234
|
+
end
|
235
|
+
|
236
|
+
def notify(action,query,callback,model,dm_query,time = nil)
|
237
|
+
x = Thread.start do
|
238
|
+
observer = notifyInternal(model, action, query,time)
|
239
|
+
DataMapper.logger << "waiting on #{model.to_s} model new #{action} changes with a state change to #{query.inspect}"
|
240
|
+
|
241
|
+
observer.each do |e,t|
|
242
|
+
@monitor.synchronize {
|
243
|
+
DataMapper.logger << "TRIGGERED on #{model.to_s} model new #{action} changes with a state change to #{query.inspect}"
|
244
|
+
|
245
|
+
if check_descendents(model,t) # quick patch that belongs into tuplespace
|
246
|
+
DataMapper.logger << "#{e} change detected for #{t.inspect}"
|
247
|
+
resource = nil
|
248
|
+
|
249
|
+
repository = dm_query.repository
|
250
|
+
model = dm_query.model
|
251
|
+
identity_fields = model.key(repository.name).map &:name
|
252
|
+
|
253
|
+
DataMapper.logger << "rep: #{repository.name} model:#{model} identifier key: #{identity_fields.inspect}"
|
254
|
+
|
255
|
+
retrieve = identity_fields.map do |x| t[x.to_s] end
|
256
|
+
|
257
|
+
resource = model.get(*retrieve)
|
258
|
+
DataMapper.logger << "found resource #{resource.inspect}"
|
259
|
+
|
260
|
+
callback.call resource
|
261
|
+
end
|
262
|
+
}
|
263
|
+
end
|
264
|
+
end
|
265
|
+
return x
|
266
|
+
end
|
267
|
+
|
268
|
+
private
|
269
|
+
def create_conditions(conditions)
|
270
|
+
newconditions={}
|
271
|
+
#newconditions["classtype"]=resource.attributes[:classtype].to_s
|
272
|
+
conditions.each do |key, value|
|
273
|
+
if value.is_a? Regexp
|
274
|
+
newconditions[key.to_s]=value
|
275
|
+
else
|
276
|
+
newconditions[key.to_s]=value.to_s
|
277
|
+
end
|
278
|
+
end
|
279
|
+
newconditions
|
280
|
+
end
|
281
|
+
|
282
|
+
# Returns a tupleSpace Observer that waits for an {action} bason on a hash of
|
283
|
+
# {conditions}
|
284
|
+
def notifyInternal(model,action,conditions,time = nil)
|
285
|
+
query = generate_query(model)
|
286
|
+
DataMapper.logger << "notify query generated #{query.inspect}"
|
287
|
+
# DataMapper.logger << "notify query generated11111 #{resource.attributes.inspect}"
|
288
|
+
|
289
|
+
# ressource.attributes.key?("classtype")
|
290
|
+
|
291
|
+
# value = attributes[property]
|
292
|
+
|
293
|
+
newconditions = create_conditions(conditions)
|
294
|
+
|
295
|
+
query = query.merge newconditions
|
296
|
+
DataMapper.logger << "notify query after merge of conditions #{query.inspect}"
|
297
|
+
|
298
|
+
if (time)
|
299
|
+
@ts.notify action,query,(time/1000)
|
300
|
+
else
|
301
|
+
@ts.notify action,query
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
def check_descendents (model,result)
|
307
|
+
if (result["classtype"].nil?) # in case there is no inheritanence relationship
|
308
|
+
return true
|
309
|
+
end
|
310
|
+
descendents = model.descendants.to_ary
|
311
|
+
|
312
|
+
# transform array to hash for quicker lookup
|
313
|
+
desc_lookup = Hash[*descendents.collect { |v|
|
314
|
+
[v.to_s, v.to_s]
|
315
|
+
}.flatten]
|
316
|
+
# p " identified following descendents #{desc_lookup.inspect}"
|
317
|
+
#result = {"classtype" => nil }
|
318
|
+
return desc_lookup[result["classtype"]]
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
def generate_query(model)
|
323
|
+
queryblock={ }
|
324
|
+
queryblock["_model_"]=model.storage_name(name).to_s
|
325
|
+
model.properties.each do |property|
|
326
|
+
queryblock[property.name.to_s]=nil
|
327
|
+
end
|
328
|
+
queryblock
|
329
|
+
end
|
330
|
+
|
331
|
+
def generate_query_with_conditions(query)
|
332
|
+
model = query.model
|
333
|
+
|
334
|
+
queryblock={ }
|
335
|
+
queryblock["_model_"]=model.storage_name(name).to_s
|
336
|
+
|
337
|
+
# properties = model.properties
|
338
|
+
# properties.each do |property|
|
339
|
+
query.fields.each do |property|
|
340
|
+
queryblock[property.field.to_s]=nil
|
341
|
+
end
|
342
|
+
|
343
|
+
# DataMapper.logger << "Conditions #{query.conditions.inspect}"
|
344
|
+
|
345
|
+
conditions_statement(query.conditions, queryblock )
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
def comparison_statement(comparison,queryblock,negate=false)
|
350
|
+
|
351
|
+
value = comparison.value
|
352
|
+
|
353
|
+
if comparison.slug == :eql and not comparison.relationship?
|
354
|
+
# DataMapper.logger << "comparison with eql #{comparison.inspect}"
|
355
|
+
|
356
|
+
if not negate
|
357
|
+
subject = comparison.subject
|
358
|
+
column_name = subject.field
|
359
|
+
queryblock[column_name]=value
|
360
|
+
end
|
361
|
+
|
362
|
+
# elsif comparison.relationship?
|
363
|
+
# DataMapper.logger << "comparison with relationship #{comparison.inspect}"
|
364
|
+
|
365
|
+
# if value.respond_to?(:query) && value.respond_to?(:loaded?) && !value.loaded?
|
366
|
+
# return subquery(value.query, subject, qualify)
|
367
|
+
# else
|
368
|
+
# return conditions_statement(comparison.foreign_key_mapping, queryblock)
|
369
|
+
# end
|
370
|
+
end
|
371
|
+
return queryblock
|
372
|
+
end
|
373
|
+
|
374
|
+
def conditions_statement(conditions,queryblock, negate = false)
|
375
|
+
case conditions
|
376
|
+
when Query::Conditions::NotOperation then negate_operation(conditions.operand, queryblock,negate)
|
377
|
+
when Query::Conditions::AbstractOperation then operation_statement(conditions,queryblock,negate)
|
378
|
+
when Query::Conditions::AbstractComparison then comparison_statement(conditions,queryblock,negate)
|
379
|
+
when Array
|
380
|
+
statement, bind_values = conditions # handle raw conditions
|
381
|
+
[ "(#{statement})", bind_values ].compact
|
382
|
+
|
383
|
+
else
|
384
|
+
return queryblock
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# @api private
|
389
|
+
def operation_statement(operation,queryblock,negate=false)
|
390
|
+
operation.each do |operand|
|
391
|
+
# DataMapper.logger << "operation #{operand.inspect}"
|
392
|
+
queryblock = conditions_statement(operand,queryblock,negate)
|
393
|
+
end
|
394
|
+
return queryblock
|
395
|
+
end
|
396
|
+
|
397
|
+
# @api private
|
398
|
+
def negate_operation(operand, queryblock,negate)
|
399
|
+
if negate
|
400
|
+
return conditions_statement(operand, queryblock,false)
|
401
|
+
else
|
402
|
+
return conditions_statement(operand, queryblock,true)
|
403
|
+
end
|
404
|
+
|
405
|
+
#statement = "NOT(#{statement})" unless statement.nil?
|
406
|
+
# [ statement, bind_values ]
|
407
|
+
# return queryblick
|
408
|
+
end
|
409
|
+
|
410
|
+
# Make a new instance of the adapter. The @records ivar is the 'data-store'
|
411
|
+
# for this adapter. It is not shared amongst multiple incarnations of this
|
412
|
+
# adapter, eg DataMapper.setup(:default, :adapter => :in_memory);
|
413
|
+
# DataMapper.setup(:alternate, :adapter => :in_memory) do not share the
|
414
|
+
# data-store between them.
|
415
|
+
#
|
416
|
+
# @param [String, Symbol] name
|
417
|
+
# The name of the Repository using this adapter.
|
418
|
+
# @param [String, Hash] uri_or_options
|
419
|
+
# The connection uri string, or a hash of options to set up
|
420
|
+
# the adapter
|
421
|
+
#
|
422
|
+
# @api semipublic
|
423
|
+
def initialize(name, options = {})
|
424
|
+
super
|
425
|
+
@records = {}
|
426
|
+
if (@options[:local])
|
427
|
+
@ts = @options[:local]
|
428
|
+
else
|
429
|
+
@ts = DRbObject.new_with_uri("druby://#{@options[:host]}:#{@options[:port]}")
|
430
|
+
end
|
431
|
+
@monitor = Monitor.new
|
432
|
+
end
|
433
|
+
|
434
|
+
def convert_to_ts(key,value)
|
435
|
+
# DataMapper.logger << "key1 #{key.inspect} convert #{value.inspect} class #{value.class}"
|
436
|
+
|
437
|
+
if (key== DataMapper::Types::Discriminator)
|
438
|
+
return value.to_s
|
439
|
+
else
|
440
|
+
return value
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
end # class InMemoryAdapter
|
445
|
+
|
446
|
+
const_added(:RindaAdapter)
|
447
|
+
end # module Adapters
|
448
|
+
end # module DataMapper
|
data/spec/legacy/README
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
This directory contains the old specs, written for 0.1.0. They are retained
|
2
|
+
here while the specs are separated into spec/{public,semipublic}.
|
3
|
+
|
4
|
+
Examples marked as @done indicate those for which there are equivalents in
|
5
|
+
spec/{public,semipublic}. Once all specs are moved (or rewritten, as
|
6
|
+
appropriate), the legacy specs will be removed.
|