active_repository 0.0.1
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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/Rakefile +2 -0
- data/active_repository.gemspec +23 -0
- data/lib/active_repository/associations.rb +102 -0
- data/lib/active_repository/base.rb +266 -0
- data/lib/active_repository/sql_query_executor.rb +123 -0
- data/lib/active_repository/uniqueness.rb +196 -0
- data/lib/active_repository/version.rb +3 -0
- data/lib/active_repository/write_support.rb +76 -0
- data/lib/active_repository.rb +15 -0
- data/spec/active_repository/base_spec.rb +123 -0
- data/spec/active_repository/sql_query_executor_spec.rb +84 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/shared_examples.rb +582 -0
- data/spec/support/sql_query_shared_examples.rb +317 -0
- metadata +164 -0
@@ -0,0 +1,582 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
shared_examples ".update_attributes" do
|
4
|
+
it "updates records" do
|
5
|
+
country = Country.find(1)
|
6
|
+
country.update_attributes(:name => "Italy")
|
7
|
+
|
8
|
+
Country.first.name.should == "Italy"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "must not update id" do
|
12
|
+
country = Country.find(1)
|
13
|
+
|
14
|
+
country.update_attributes(:id => 45, :name => "Russia")
|
15
|
+
|
16
|
+
Country.first.name.should == "Russia"
|
17
|
+
Country.first.id.should_not == 45
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
shared_examples ".all" do
|
22
|
+
it "returns an empty array if data is nil" do
|
23
|
+
Country.delete_all
|
24
|
+
Country.all.should be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns all data as repository objects" do
|
28
|
+
Country.all.all? { |country| country.should be_kind_of(Country) }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "populates the data correctly" do
|
32
|
+
records = Country.all
|
33
|
+
records.first.id.should == 1
|
34
|
+
records.first.name.should == "US"
|
35
|
+
records.last.id.should == 5
|
36
|
+
records.last.name.should == "Brazil"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
shared_examples ".where" do
|
41
|
+
it "raises ArgumentError if no conditions are provided" do
|
42
|
+
lambda{
|
43
|
+
Country.where
|
44
|
+
}.should raise_error(ArgumentError)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns all data as inflated objects" do
|
48
|
+
Country.where(:language => 'English', :name => 'US').all? { |country| country.should be_kind_of(Country) }
|
49
|
+
end
|
50
|
+
|
51
|
+
it "populates the data correctly" do
|
52
|
+
records = Country.where(:language => 'English')
|
53
|
+
records.first.id.should == 1
|
54
|
+
records.first.name.should == "US"
|
55
|
+
records.last.id.should == 4
|
56
|
+
records.last.name.should == "UK"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "filters the records from a AR-like conditions hash" do
|
60
|
+
record = Country.where(:name => 'US')
|
61
|
+
record.count.should == 1
|
62
|
+
record.first.id.should == 1
|
63
|
+
record.first.name.should == 'US'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "if id exists, use auto increment id" do
|
67
|
+
country = Country.create(:id => 1, :name => "Russia", :language => 'Russian')
|
68
|
+
|
69
|
+
country.id.should_not == 1
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
shared_examples ".exists?" do
|
74
|
+
it "checks if a record exists" do
|
75
|
+
id = Country.last.id + 1
|
76
|
+
|
77
|
+
Country.delete_all
|
78
|
+
Country.exists?(id).should be_false
|
79
|
+
|
80
|
+
country = Country.create(:id => id, :name => "France")
|
81
|
+
|
82
|
+
Country.exists?(id).should be_true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
shared_examples ".count" do
|
87
|
+
it "returns the number of elements in the array" do
|
88
|
+
Country.count.should == 5
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
shared_examples ".first" do
|
93
|
+
it "returns the first object" do
|
94
|
+
Country.first.should == Country.find(1)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
shared_examples ".last" do
|
99
|
+
it "returns the last object" do
|
100
|
+
Country.last.should == Country.find(5)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
shared_examples ".find" do
|
105
|
+
context "with an id" do
|
106
|
+
it "finds the record with the specified id" do
|
107
|
+
Country.find(2).id.should == 2
|
108
|
+
end
|
109
|
+
|
110
|
+
it "finds the record with the specified id as a string" do
|
111
|
+
Country.find("2").id.should == 2
|
112
|
+
end
|
113
|
+
|
114
|
+
it "raises ActiveHash::RecordNotFound when id not found" do
|
115
|
+
proc do
|
116
|
+
Country.find(0)
|
117
|
+
end.should raise_error(ActiveHash::RecordNotFound, /Couldn't find Country with ID=0/)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "with :all" do
|
122
|
+
it "returns all records" do
|
123
|
+
Country.find(:all).should == [Country.find(1), Country.find(2), Country.find(3), Country.find(4), Country.find(5)]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "with an array of ids" do
|
128
|
+
it "returns all matching ids" do
|
129
|
+
Country.find([1, 3]).should == [Country.find(1), Country.find(3)]
|
130
|
+
end
|
131
|
+
|
132
|
+
it "raises ActiveHash::RecordNotFound when id not found" do
|
133
|
+
proc do
|
134
|
+
Country.find([0, 3])
|
135
|
+
end.should raise_error(ActiveHash::RecordNotFound, "Couldn't find all Country objects with IDs (0, 3)")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
shared_examples ".find_by_id" do
|
141
|
+
context "with an id" do
|
142
|
+
it "finds the record with the specified id" do
|
143
|
+
Country.find_by_id(2).id.should == 2
|
144
|
+
end
|
145
|
+
|
146
|
+
it "finds the record with the specified id as a string" do
|
147
|
+
Country.find_by_id("2").id.should == 2
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "with nil" do
|
152
|
+
it "returns nil" do
|
153
|
+
Country.find_by_id(nil).should be_nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "with an id not present" do
|
158
|
+
it "returns nil" do
|
159
|
+
Country.find_by_id(4567).should be_nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
shared_examples "custom finders" do
|
165
|
+
describe "find_by_<field_name>" do
|
166
|
+
describe "with a match" do
|
167
|
+
context "for a non-nil argument" do
|
168
|
+
it "returns the first matching record" do
|
169
|
+
Country.find_by_name("US").id.should == 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "for a nil argument" do
|
174
|
+
it "returns the first matching record" do
|
175
|
+
Country.find_by_language(nil).id.should == 5
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "without a match" do
|
181
|
+
context "for a non-nil argument" do
|
182
|
+
it "returns nil" do
|
183
|
+
Country.find_by_name("Argentina").should be_nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "for a nil argument" do
|
188
|
+
it "returns nil" do
|
189
|
+
Country.find_by_name(nil).should be_nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "find_all_by_<field_name>" do
|
196
|
+
describe "with matches" do
|
197
|
+
it "returns all matching records" do
|
198
|
+
countries = Country.find_all_by_language("English")
|
199
|
+
countries.length.should == 3
|
200
|
+
countries.first.name.should == "US"
|
201
|
+
countries.last.name.should == "UK"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "without matches" do
|
206
|
+
it "returns an empty array" do
|
207
|
+
Country.find_all_by_name("Argentina").should be_empty
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "find_by_<field_one>_and_<field_two>" do
|
213
|
+
describe "with a match" do
|
214
|
+
it "returns the first matching record" do
|
215
|
+
Country.find_by_name_and_language("Canada", "English").id.should == 2
|
216
|
+
Country.find_by_language_and_name("English", "Canada").id.should == 2
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "with a match based on to_s" do
|
221
|
+
it "returns the first matching record" do
|
222
|
+
Country.find_by_name_and_id("Canada", "2").id.should == 2
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "without a match" do
|
227
|
+
it "returns nil" do
|
228
|
+
Country.find_by_name_and_monarch("Mexico", "The Crown of England").should be_nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "for fields the class doesn't have" do
|
233
|
+
it "raises a NoMethodError" do
|
234
|
+
lambda {
|
235
|
+
Country.find_by_name_and_shoe_size("US", 10)
|
236
|
+
}.should raise_error(NoMethodError, "undefined method `find_by_name_and_shoe_size' for Country:Class")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "find_all_by_<field_one>_and_<field_two>" do
|
242
|
+
describe "with matches" do
|
243
|
+
it "returns all matching records" do
|
244
|
+
countries = Country.find_all_by_language_and_monarch("English", "The Crown of England")
|
245
|
+
countries.length.should == 2
|
246
|
+
countries.first.name.should == "Canada"
|
247
|
+
countries.last.name.should == "UK"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe "without matches" do
|
252
|
+
it "returns an empty array" do
|
253
|
+
Country.find_all_by_monarch_and_language("Shaka Zulu", "Zulu").should be_empty
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
shared_examples "#method_missing" do
|
260
|
+
it "doesn't blow up if you call a missing dynamic finder when fields haven't been set" do
|
261
|
+
proc do
|
262
|
+
Country.find_by_size("Foo")
|
263
|
+
end.should raise_error(NoMethodError, "undefined method `find_by_size' for Country:Class")
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
shared_examples "#attributes" do
|
268
|
+
before do
|
269
|
+
Country.field :foo
|
270
|
+
end
|
271
|
+
|
272
|
+
it "returns the hash passed in the initializer" do
|
273
|
+
country = Country.new(:foo => :bar)
|
274
|
+
country.attributes.should == {:foo => :bar}
|
275
|
+
end
|
276
|
+
|
277
|
+
it "symbolizes keys" do
|
278
|
+
country = Country.new("foo" => :bar)
|
279
|
+
country.attributes.should == {:foo => :bar}
|
280
|
+
end
|
281
|
+
|
282
|
+
it "is works with #[]" do
|
283
|
+
country = Country.new(:foo => :bar)
|
284
|
+
country.foo.should == :bar
|
285
|
+
end
|
286
|
+
|
287
|
+
it "is works with #[]=" do
|
288
|
+
country = Country.new
|
289
|
+
country.foo = :bar
|
290
|
+
country.foo.should == :bar
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
shared_examples "reader_methods" do
|
295
|
+
context "for regular fields" do
|
296
|
+
before do
|
297
|
+
Country.fields :name, :iso_name
|
298
|
+
end
|
299
|
+
|
300
|
+
it "returns the given attribute when present" do
|
301
|
+
country = Country.new(:name => "Spain")
|
302
|
+
country.name.should == "Spain"
|
303
|
+
end
|
304
|
+
|
305
|
+
it "returns nil when not present" do
|
306
|
+
country = Country.new
|
307
|
+
country.name.should be_nil
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
shared_examples "interrogator methods" do
|
313
|
+
before do
|
314
|
+
Country.fields :name, :iso_name
|
315
|
+
end
|
316
|
+
|
317
|
+
it "returns true if the given attribute is non-blank" do
|
318
|
+
country = Country.new(:name => "Spain")
|
319
|
+
country.should be_name
|
320
|
+
end
|
321
|
+
|
322
|
+
it "returns false if the given attribute is blank" do
|
323
|
+
country = Country.new(:name => " ")
|
324
|
+
country.name?.should == false
|
325
|
+
end
|
326
|
+
|
327
|
+
it "returns false if the given attribute was not passed" do
|
328
|
+
country = Country.new
|
329
|
+
country.should_not be_name
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
shared_examples "#id" do
|
334
|
+
context "when not passed an id" do
|
335
|
+
it "returns nil" do
|
336
|
+
country = Country.new
|
337
|
+
country.id.should be_nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
shared_examples "#quoted_id" do
|
343
|
+
it "should return id" do
|
344
|
+
Country.new(:id => 2).quoted_id.should == 2
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
shared_examples "#to_param" do
|
349
|
+
it "should return id as a string" do
|
350
|
+
id = Country.last.id + 1
|
351
|
+
Country.create(:id => id).to_param.should == id.to_s
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
shared_examples "#persisted?" do
|
356
|
+
it "should return true if the object has been saved" do
|
357
|
+
Country.delete_all
|
358
|
+
Country.create(:id => 2).should be_persisted
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should return false if the object has not been saved" do
|
362
|
+
Country.new(:id => 12).should_not be_persisted
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
shared_examples "#eql?" do
|
367
|
+
before do
|
368
|
+
class Region < ActiveRepository::Base
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
it "should return true with the same class and id" do
|
373
|
+
Country.new(:id => 23).eql?(Country.new(:id => 23)).should be_true
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should return false with the same class and different ids" do
|
377
|
+
Country.new(:id => 24).eql?(Country.new(:id => 23)).should be_false
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should return false with the different classes and the same id" do
|
381
|
+
Country.new(:id => 23).eql?(Region.new(:id => 23)).should be_false
|
382
|
+
end
|
383
|
+
|
384
|
+
it "returns false when id is nil" do
|
385
|
+
Country.new.eql?(Country.new).should be_false
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
shared_examples "#==" do
|
390
|
+
before do
|
391
|
+
class Region < ActiveRepository::Base
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should return true with the same class and id" do
|
396
|
+
Country.new(:id => 23).should == Country.new(:id => 23)
|
397
|
+
end
|
398
|
+
|
399
|
+
it "should return false with the same class and different ids" do
|
400
|
+
Country.new(:id => 24).should_not == Country.new(:id => 23)
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should return false with the different classes and the same id" do
|
404
|
+
Country.new(:id => 23).should_not == Region.new(:id => 23)
|
405
|
+
end
|
406
|
+
|
407
|
+
it "returns false when id is nil" do
|
408
|
+
Country.new.should_not == Country.new
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
shared_examples "#hash" do
|
413
|
+
it "returns id for hash" do
|
414
|
+
Country.new(:id => 45).hash.should == 45.hash
|
415
|
+
Country.new.hash.should == nil.hash
|
416
|
+
end
|
417
|
+
|
418
|
+
it "is hashable" do
|
419
|
+
{Country.new(:id => 4) => "bar"}.should == {Country.new(:id => 4) => "bar"}
|
420
|
+
{Country.new(:id => 3) => "bar"}.should_not == {Country.new(:id => 4) => "bar"}
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
shared_examples "#readonly?" do
|
425
|
+
it "returns true" do
|
426
|
+
Country.new.should_not be_readonly
|
427
|
+
end
|
428
|
+
|
429
|
+
it "updates a record" do
|
430
|
+
country = Country.find(1)
|
431
|
+
|
432
|
+
country.name = "Germany"
|
433
|
+
|
434
|
+
country.save.should be_true
|
435
|
+
|
436
|
+
Country.all.size.should == 5
|
437
|
+
country.should be_valid
|
438
|
+
country.name.should == "Germany"
|
439
|
+
country.id.should == 1
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
shared_examples "#cache_key" do
|
444
|
+
before do
|
445
|
+
Country.delete_all
|
446
|
+
end
|
447
|
+
|
448
|
+
it 'should use the record\'s updated_at if present' do
|
449
|
+
country = Country.create(:id => 6, :name => "foo")
|
450
|
+
|
451
|
+
Country.first.cache_key.should == "countries/6-#{country.updated_at.to_s(:number)}"
|
452
|
+
end
|
453
|
+
|
454
|
+
it 'should use "new" instead of the id for a new record' do
|
455
|
+
Country.new(:id => 1).cache_key.should == 'countries/new'
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
shared_examples "#save" do
|
460
|
+
before do
|
461
|
+
Country.field :name
|
462
|
+
Country.delete_all
|
463
|
+
end
|
464
|
+
|
465
|
+
it "adds the new object to the data collection" do
|
466
|
+
Country.all.should be_empty
|
467
|
+
country = Country.new :id => 1, :name => "foo", :monarch => nil, :language => nil
|
468
|
+
country.persist.should be_true
|
469
|
+
country.reload
|
470
|
+
Country.all.should == [country]
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
shared_examples ".create" do
|
475
|
+
before do
|
476
|
+
Country.field :name
|
477
|
+
Country.delete_all
|
478
|
+
end
|
479
|
+
|
480
|
+
it "works with no args" do
|
481
|
+
Country.all.should be_empty
|
482
|
+
country = Country.create :id => 6
|
483
|
+
country.id.should == 6
|
484
|
+
end
|
485
|
+
|
486
|
+
it "adds the new object to the data collection" do
|
487
|
+
Country.all.should be_empty
|
488
|
+
country = Country.create :id => 6, :name => "foo"
|
489
|
+
country.id.should == 6
|
490
|
+
country.name.should == "foo"
|
491
|
+
Country.all.should == [country]
|
492
|
+
end
|
493
|
+
|
494
|
+
it "adds an auto-incrementing id if the id is nil" do
|
495
|
+
country1 = Country.new :name => "foo"
|
496
|
+
country1.save
|
497
|
+
country1.id.should == 1
|
498
|
+
|
499
|
+
country2 = Country.new :name => "bar", :id => 2
|
500
|
+
country2.save
|
501
|
+
country2.id.should == 2
|
502
|
+
end
|
503
|
+
|
504
|
+
it "does not add auto-incrementing id if the id is present" do
|
505
|
+
country1 = Country.new :id => 456, :name => "foo"
|
506
|
+
country1.save
|
507
|
+
country1.id.should == 456
|
508
|
+
end
|
509
|
+
|
510
|
+
it "adds the new object to the data collection" do
|
511
|
+
Country.all.should be_empty
|
512
|
+
country = Country.create :id => 6, :name => "foo"
|
513
|
+
country.id.should == 6
|
514
|
+
country.name.should == "foo"
|
515
|
+
|
516
|
+
Country.all.should == [country]
|
517
|
+
end
|
518
|
+
|
519
|
+
it "updates count" do
|
520
|
+
proc {
|
521
|
+
Country.create :name => "Russia"
|
522
|
+
}.should change { Country.count }
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
shared_examples "#valid?" do
|
527
|
+
it "should return true" do
|
528
|
+
Country.new.should be_valid
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
shared_examples "#new_record?" do
|
533
|
+
before do
|
534
|
+
Country.field :name
|
535
|
+
Country.delete_all
|
536
|
+
Country.create(:id => 1, :name => "foo")
|
537
|
+
end
|
538
|
+
|
539
|
+
it "returns true when the object is not part of the collection" do
|
540
|
+
Country.new(:id => 2).should be_new_record
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
shared_examples ".transaction" do
|
545
|
+
it "execute the block given to it" do
|
546
|
+
foo = Object.new
|
547
|
+
foo.should_receive(:bar)
|
548
|
+
Country.transaction do
|
549
|
+
foo.bar
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
it "swallows ActiveRecord::Rollback errors" do
|
554
|
+
proc do
|
555
|
+
Country.transaction do
|
556
|
+
raise ActiveRecord::Rollback
|
557
|
+
end
|
558
|
+
end.should_not raise_error
|
559
|
+
end
|
560
|
+
|
561
|
+
it "passes other errors through" do
|
562
|
+
proc do
|
563
|
+
Country.transaction do
|
564
|
+
raise "hell"
|
565
|
+
end
|
566
|
+
end.should raise_error("hell")
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
shared_examples ".delete_all" do
|
571
|
+
before do
|
572
|
+
Country.delete_all
|
573
|
+
end
|
574
|
+
|
575
|
+
it "clears out all record" do
|
576
|
+
country1 = Country.create
|
577
|
+
country2 = Country.create
|
578
|
+
Country.all.should == [country1, country2]
|
579
|
+
Country.delete_all
|
580
|
+
Country.all.should be_empty
|
581
|
+
end
|
582
|
+
end
|