dm-fluiddb-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.
@@ -0,0 +1,27 @@
1
+ require 'logger'
2
+
3
+ module Loggable
4
+ def self.logger=(global)
5
+ @logger = global
6
+ end
7
+
8
+ def self.logger
9
+ @logger ||= Logger.new(STDERR)
10
+ end
11
+
12
+ def self.included(base)
13
+ base.class_eval do
14
+ def logger=(l)
15
+ @logger = l
16
+ end
17
+
18
+ def logger
19
+ @logger ||= Loggable.logger
20
+ end
21
+ end
22
+ end
23
+
24
+ def logger
25
+ self.class.logger
26
+ end
27
+ end
@@ -0,0 +1,189 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe DataMapper::Adapters::FluidDBAdapter do
4
+ before :all do
5
+ @adapter = DataMapper.setup(:default, DATABASE_URL)
6
+ @repository = DataMapper.repository(:default)
7
+
8
+ @http = mock('http client')
9
+ @adapter.instance_variable_set("@http", @http)
10
+
11
+ @cache = mock('memcache client')
12
+ DataMapper::Adapters::FluidDBAdapter.cache = @cache
13
+
14
+ class Flinstone
15
+ include DataMapper::Resource
16
+
17
+ property :id, String, :key => true
18
+ property :name, String
19
+ property :age, Integer
20
+ end
21
+ end
22
+
23
+ def tag(name)
24
+ prefix = @adapter.send(:tag_prefix) + '/flinstones'
25
+ name.nil? ? prefix : (prefix + '/' + name)
26
+ end
27
+
28
+ after :all do
29
+ DataMapper::Adapters::FluidDBAdapter.cache = CACHE
30
+ end
31
+
32
+ describe :create do
33
+
34
+ end
35
+
36
+ describe :read do
37
+
38
+ end
39
+
40
+ describe :delete do
41
+
42
+ end
43
+
44
+ describe :check_tag do
45
+
46
+ end
47
+
48
+ describe :check_namespace do
49
+
50
+ end
51
+
52
+ describe :paged_query do
53
+
54
+ end
55
+
56
+ describe :update do
57
+
58
+ end
59
+
60
+ describe :conditions_statement do
61
+ def test(c)
62
+ @adapter.send(:conditions_statement, c)
63
+ end
64
+
65
+ before(:all) do
66
+ @id = Flinstone.properties[:id]
67
+ @name = Flinstone.properties[:name]
68
+ @age = Flinstone.properties[:age]
69
+ end
70
+
71
+ it 'should extract ids' do
72
+ cond = DataMapper::Query::Conditions::EqualToComparison.new(@id, 'wilma')
73
+ test(cond).should == '|id:wilma|'
74
+ end
75
+
76
+ it 'should handle inclusion comparisons' do
77
+ andc = DataMapper::Query::Conditions::AndOperation.new
78
+ andc << DataMapper::Query::Conditions::InclusionComparison.new(@name, 1...6)
79
+
80
+ test(andc).should == "(#{tag('name')} >= 1 and #{tag('name')} < 6)"
81
+ end
82
+
83
+ it 'should handle negative operators' do
84
+ notc = DataMapper::Query::Conditions::NotOperation.new
85
+ notc << DataMapper::Query::Conditions::EqualToComparison.new(@age, 78)
86
+ andc = DataMapper::Query::Conditions::AndOperation.new
87
+ andc << "has #{tag(nil)}"
88
+ andc << notc
89
+
90
+ test(andc).should == "has #{tag(nil)} except #{tag('age')} = 78"
91
+ end
92
+ end
93
+
94
+ describe :query_ids do
95
+ it 'should parse extracted ids' do
96
+ #@adapter.stub(:blocking_request)
97
+
98
+ q = DataMapper::Query.new(@repository, Flinstone, :id => 'wilma')
99
+ @adapter.send(:query_ids, q, false).should == [ 'wilma' ]
100
+ end
101
+
102
+ it 'should add the identity query' do
103
+ @adapter.should_receive(:fluiddb_query).with("has #{tag(nil)}").and_yield(['list', 'of', 'ids'])
104
+
105
+ q = DataMapper::Query.new(@repository, Flinstone)
106
+ @adapter.send(:query_ids, q).should == [ 'list', 'of', 'ids' ]
107
+ end
108
+ end
109
+
110
+ describe :fetch_fields do
111
+ def mock_multi_get(keys, values=nil)
112
+ result = keys.map_hash do |k|
113
+ value =values.nil? ? nil : values[keys.index(k)]
114
+ [ k, value ]
115
+ end
116
+
117
+ @cache.should_receive(:get) {|args|
118
+ args.sort.should == keys.sort
119
+ result
120
+ }
121
+ end
122
+
123
+ before(:each) do
124
+ @ids = [ 'id1', 'id2' ]
125
+ @fields = [ 'description', 'path' ]
126
+ @tags = @fields.map_hash {|f| [ f, 'fluiddb/tags/'+f] }
127
+ @cached = @ids.map_hash do |id|
128
+ [ @adapter.send(:object_cache_key, id, @tags.values),
129
+ @fields.map_hash.merge("id"=>id) ]
130
+ end
131
+
132
+ @http.should_receive(:parallel).and_yield
133
+ end
134
+
135
+ describe 'when objects are cached' do
136
+ it 'should not fetch any fields' do
137
+ mock_multi_get(@cached.keys, @cached.values)
138
+ @adapter.send(:fetch_fields, @ids, @tags)
139
+ end
140
+ end
141
+
142
+ describe 'when objects are not cached' do
143
+ before(:each) do
144
+ mock_multi_get(@cached.keys)
145
+
146
+ @ids.each do |id|
147
+ key = @adapter.send(:object_cache_key, id, @tags.values)
148
+ @cache.should_receive(:set).with(key, @fields.map_hash.merge("id"=>id), 600)
149
+ end
150
+ end
151
+
152
+ it 'should fetch fields when not cached' do
153
+ @ids.each do |id|
154
+ mock_multi_get @fields.map {|f| id+'/fluiddb/tags/'+f }
155
+
156
+ @fields.each do |field|
157
+ resp = mock(:code => 200, :body => field)
158
+ @http.should_receive(:get).with("/objects/#{id}/fluiddb/tags/#{field}").and_yield(resp)
159
+ @cache.should_receive(:set).with("#{id}/fluiddb/tags/#{field}", field, 600)
160
+ end
161
+ end
162
+
163
+ @adapter.send(:fetch_fields, @ids, @tags)
164
+ end
165
+
166
+ it 'should not fetch fields when cached' do
167
+ @ids.each do |id|
168
+ values = @fields.map_hash {|f| [ id+'/fluiddb/tags/'+f, f ] }
169
+ mock_multi_get(values.keys, values.values)
170
+ end
171
+
172
+ @adapter.send(:fetch_fields, @ids, @tags)
173
+ end
174
+ end
175
+ end
176
+
177
+ describe :save do
178
+
179
+ end
180
+
181
+ describe :serialize do
182
+
183
+ end
184
+
185
+ describe :tags do
186
+
187
+ end
188
+
189
+ end
@@ -0,0 +1,302 @@
1
+ # This had to be copied from the db-core source because this adapter
2
+ # doesn't support serial keys which the spec previously relied upon
3
+ require 'spec/spec_helper'
4
+
5
+ describe DataMapper::Adapters::FluidDBAdapter do
6
+ before :all do
7
+ @adapter = DataMapper.setup(:default, DATABASE_URL)
8
+ @repository = DataMapper.repository(:default)
9
+
10
+ class ::Heffalump
11
+ include DataMapper::Resource
12
+
13
+ property :id, String, :key => true
14
+ property :color, String
15
+ property :num_spots, Integer
16
+ property :striped, Boolean
17
+ end
18
+
19
+ # create all tables and constraints before each spec
20
+ if @repository.respond_to?(:auto_migrate!)
21
+ Heffalump.auto_migrate!
22
+ end
23
+ end
24
+
25
+ after :all do
26
+ Heffalump.repository.delete(Heffalump.all)
27
+ end
28
+
29
+ def self.adapter_supports?(*methods)
30
+ methods.all? do |method|
31
+ # TODO: figure out a way to see if the instance method is only inherited
32
+ # from the Abstract Adapter, and not defined in it's class. If that is
33
+ # the case return false
34
+
35
+ # CRUD methods can be inherited from parent class
36
+ described_type.instance_methods.any? { |instance_method| method.to_s == instance_method.to_s }
37
+ end
38
+ end
39
+
40
+ if adapter_supports?(:create)
41
+ describe '#create' do
42
+ it 'should not raise any errors' do
43
+ lambda {
44
+ Heffalump.create(:color => 'peach')
45
+ }.should_not raise_error
46
+ end
47
+
48
+ it 'should set the identity field for the resource' do
49
+ heffalump = Heffalump.new(:color => 'peach')
50
+ heffalump.id.should be_nil
51
+ heffalump.save
52
+ heffalump.id.should_not be_nil
53
+ end
54
+ end
55
+ else
56
+ it 'needs to support #create'
57
+ end
58
+
59
+ if adapter_supports?(:read)
60
+ describe '#read' do
61
+ before :all do
62
+ @heffalump = Heffalump.create(:color => 'brownish hue')
63
+ #just going to borrow this, so I can check the return values
64
+ @query = Heffalump.all.query
65
+ end
66
+
67
+ it 'should not raise any errors' do
68
+ lambda {
69
+ Heffalump.all()
70
+ }.should_not raise_error
71
+ end
72
+
73
+ it 'should return stuff' do
74
+ Heffalump.all.should be_include(@heffalump)
75
+ end
76
+ end
77
+ else
78
+ it 'needs to support #read'
79
+ end
80
+
81
+ if adapter_supports?(:update)
82
+ describe '#update' do
83
+ before do
84
+ @heffalump = Heffalump.create(:color => 'indigo')
85
+ end
86
+
87
+ it 'should not raise any errors' do
88
+ lambda {
89
+ @heffalump.color = 'violet'
90
+ @heffalump.save
91
+ }.should_not raise_error
92
+ end
93
+
94
+ it 'should not alter the identity field' do
95
+ id = @heffalump.id
96
+ @heffalump.color = 'violet'
97
+ @heffalump.save
98
+ @heffalump.id.should == id
99
+ end
100
+
101
+ it 'should update altered fields' do
102
+ @heffalump.color = 'violet'
103
+ @heffalump.save
104
+ Heffalump.get(*@heffalump.key).color.should == 'violet'
105
+ end
106
+
107
+ it 'should not alter other fields' do
108
+ color = @heffalump.color
109
+ @heffalump.num_spots = 3
110
+ @heffalump.save
111
+ Heffalump.get(*@heffalump.key).color.should == color
112
+ end
113
+ end
114
+ else
115
+ it 'needs to support #update'
116
+ end
117
+
118
+ if adapter_supports?(:delete)
119
+ describe '#delete' do
120
+ before do
121
+ @heffalump = Heffalump.create(:color => 'forest green')
122
+ end
123
+
124
+ it 'should not raise any errors' do
125
+ lambda {
126
+ @heffalump.destroy
127
+ }.should_not raise_error
128
+ end
129
+
130
+ it 'should delete the requested resource' do
131
+ id = @heffalump.id
132
+ @heffalump.destroy
133
+ Heffalump.get(id).should be_nil
134
+ end
135
+ end
136
+ else
137
+ it 'needs to support #delete'
138
+ end
139
+
140
+ if adapter_supports?(:read, :create)
141
+ describe 'query matching' do
142
+ before :all do
143
+ @red = Heffalump.create(:color => 'red')
144
+ @two = Heffalump.create(:num_spots => 2)
145
+ @five = Heffalump.create(:num_spots => 5)
146
+ end
147
+
148
+ describe 'conditions' do
149
+ describe 'eql' do
150
+ it 'should be able to search for objects included in an inclusive range of values' do
151
+ Heffalump.all(:num_spots => 1..5).should be_include(@five)
152
+ end
153
+
154
+ it 'should be able to search for objects included in an exclusive range of values' do
155
+ Heffalump.all(:num_spots => 1...6).should be_include(@five)
156
+ end
157
+
158
+ it 'should not be able to search for values not included in an inclusive range of values' do
159
+ Heffalump.all(:num_spots => 1..4).should_not be_include(@five)
160
+ end
161
+
162
+ it 'should not be able to search for values not included in an exclusive range of values' do
163
+ Heffalump.all(:num_spots => 1...5).should_not be_include(@five)
164
+ end
165
+ end
166
+
167
+ describe 'not' do
168
+ it 'should be able to search for objects with not equal value' do
169
+ Heffalump.all(:color.not => 'red').should_not be_include(@red)
170
+ end
171
+
172
+ it 'should include objects that are not like the value' do
173
+ Heffalump.all(:color.not => 'black').should be_include(@red)
174
+ end
175
+
176
+ it 'should be able to search for objects with not nil value' do
177
+ Heffalump.all(:color.not => nil).should be_include(@red)
178
+ end
179
+
180
+ it 'should not include objects with a nil value' do
181
+ Heffalump.all(:color.not => nil).should_not be_include(@two)
182
+ end
183
+
184
+ it 'should be able to search for objects not included in an array of values' do
185
+ Heffalump.all(:num_spots.not => [ 1, 3, 5, 7 ]).should be_include(@two)
186
+ end
187
+
188
+ it 'should be able to search for objects not included in an array of values' do
189
+ Heffalump.all(:num_spots.not => [ 1, 3, 5, 7 ]).should_not be_include(@five)
190
+ end
191
+
192
+ it 'should be able to search for objects not included in an inclusive range of values' do
193
+ Heffalump.all(:num_spots.not => 1..4).should be_include(@five)
194
+ end
195
+
196
+ it 'should be able to search for objects not included in an exclusive range of values' do
197
+ Heffalump.all(:num_spots.not => 1...5).should be_include(@five)
198
+ end
199
+
200
+ it 'should not be able to search for values not included in an inclusive range of values' do
201
+ Heffalump.all(:num_spots.not => 1..5).should_not be_include(@five)
202
+ end
203
+
204
+ it 'should not be able to search for values not included in an exclusive range of values' do
205
+ Heffalump.all(:num_spots.not => 1...6).should_not be_include(@five)
206
+ end
207
+ end
208
+
209
+ describe 'like' do
210
+ it 'should be able to search for objects that match value' do
211
+ Heffalump.all(:color.like => '%ed').should be_include(@red)
212
+ end
213
+
214
+ it 'should not search for objects that do not match the value' do
215
+ Heffalump.all(:color.like => '%blak%').should_not be_include(@red)
216
+ end
217
+ end
218
+
219
+ describe 'regexp' do
220
+ before do
221
+ if defined?(DataMapper::Adapters::Sqlite3Adapter) && @adapter.kind_of?(DataMapper::Adapters::Sqlite3Adapter)
222
+ pending 'delegate regexp matches to same system that the InMemory and YAML adapters use'
223
+ end
224
+ end
225
+
226
+ it 'should be able to search for objects that match value' do
227
+ Heffalump.all(:color => /ed/).should be_include(@red)
228
+ end
229
+
230
+ it 'should not be able to search for objects that do not match the value' do
231
+ Heffalump.all(:color => /blak/).should_not be_include(@red)
232
+ end
233
+
234
+ it 'should be able to do a negated search for objects that match value' do
235
+ Heffalump.all(:color.not => /blak/).should be_include(@red)
236
+ end
237
+
238
+ it 'should not be able to do a negated search for objects that do not match value' do
239
+ Heffalump.all(:color.not => /ed/).should_not be_include(@red)
240
+ end
241
+
242
+ end
243
+
244
+ describe 'gt' do
245
+ it 'should be able to search for objects with value greater than' do
246
+ Heffalump.all(:num_spots.gt => 1).should be_include(@two)
247
+ end
248
+
249
+ it 'should not find objects with a value less than' do
250
+ Heffalump.all(:num_spots.gt => 3).should_not be_include(@two)
251
+ end
252
+ end
253
+
254
+ describe 'gte' do
255
+ it 'should be able to search for objects with value greater than' do
256
+ Heffalump.all(:num_spots.gte => 1).should be_include(@two)
257
+ end
258
+
259
+ it 'should be able to search for objects with values equal to' do
260
+ Heffalump.all(:num_spots.gte => 2).should be_include(@two)
261
+ end
262
+
263
+ it 'should not find objects with a value less than' do
264
+ Heffalump.all(:num_spots.gte => 3).should_not be_include(@two)
265
+ end
266
+ end
267
+
268
+ describe 'lt' do
269
+ it 'should be able to search for objects with value less than' do
270
+ Heffalump.all(:num_spots.lt => 3).should be_include(@two)
271
+ end
272
+
273
+ it 'should not find objects with a value less than' do
274
+ Heffalump.all(:num_spots.gt => 2).should_not be_include(@two)
275
+ end
276
+ end
277
+
278
+ describe 'lte' do
279
+ it 'should be able to search for objects with value less than' do
280
+ Heffalump.all(:num_spots.lte => 3).should be_include(@two)
281
+ end
282
+
283
+ it 'should be able to search for objects with values equal to' do
284
+ Heffalump.all(:num_spots.lte => 2).should be_include(@two)
285
+ end
286
+
287
+ it 'should not find objects with a value less than' do
288
+ Heffalump.all(:num_spots.lte => 1).should_not be_include(@two)
289
+ end
290
+ end
291
+ end
292
+
293
+ describe 'limits' do
294
+ it 'should be able to limit the objects' do
295
+ Heffalump.all(:limit => 2).length.should == 2
296
+ end
297
+ end
298
+ end
299
+ else
300
+ it 'needs to support #read and #create to test query matching'
301
+ end
302
+ end