dm-fluiddb-adapter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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