lotus-model 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +6 -0
  4. data/.yardopts +5 -0
  5. data/EXAMPLE.md +217 -0
  6. data/Gemfile +14 -2
  7. data/README.md +303 -3
  8. data/Rakefile +17 -1
  9. data/lib/lotus-model.rb +1 -0
  10. data/lib/lotus/entity.rb +157 -0
  11. data/lib/lotus/model.rb +23 -2
  12. data/lib/lotus/model/adapters/abstract.rb +167 -0
  13. data/lib/lotus/model/adapters/implementation.rb +111 -0
  14. data/lib/lotus/model/adapters/memory/collection.rb +132 -0
  15. data/lib/lotus/model/adapters/memory/command.rb +90 -0
  16. data/lib/lotus/model/adapters/memory/query.rb +457 -0
  17. data/lib/lotus/model/adapters/memory_adapter.rb +149 -0
  18. data/lib/lotus/model/adapters/sql/collection.rb +209 -0
  19. data/lib/lotus/model/adapters/sql/command.rb +67 -0
  20. data/lib/lotus/model/adapters/sql/query.rb +615 -0
  21. data/lib/lotus/model/adapters/sql_adapter.rb +154 -0
  22. data/lib/lotus/model/mapper.rb +101 -0
  23. data/lib/lotus/model/mapping.rb +23 -0
  24. data/lib/lotus/model/mapping/coercer.rb +80 -0
  25. data/lib/lotus/model/mapping/collection.rb +336 -0
  26. data/lib/lotus/model/version.rb +4 -1
  27. data/lib/lotus/repository.rb +620 -0
  28. data/lotus-model.gemspec +15 -11
  29. data/test/entity_test.rb +126 -0
  30. data/test/fixtures.rb +81 -0
  31. data/test/model/adapters/abstract_test.rb +75 -0
  32. data/test/model/adapters/implementation_test.rb +22 -0
  33. data/test/model/adapters/memory/query_test.rb +91 -0
  34. data/test/model/adapters/memory_adapter_test.rb +1044 -0
  35. data/test/model/adapters/sql/query_test.rb +121 -0
  36. data/test/model/adapters/sql_adapter_test.rb +1078 -0
  37. data/test/model/mapper_test.rb +94 -0
  38. data/test/model/mapping/coercer_test.rb +27 -0
  39. data/test/model/mapping/collection_test.rb +82 -0
  40. data/test/repository_test.rb +283 -0
  41. data/test/test_helper.rb +30 -0
  42. data/test/version_test.rb +7 -0
  43. metadata +109 -11
@@ -0,0 +1,121 @@
1
+ require 'test_helper'
2
+
3
+ describe Lotus::Model::Adapters::Sql::Query do
4
+ before do
5
+ @query = Lotus::Model::Adapters::Sql::Query.new(collection)
6
+ end
7
+
8
+ let(:collection) { [] }
9
+
10
+ describe '#negate!' do
11
+ describe 'where' do
12
+ before do
13
+ @query.where(id: 1)
14
+ end
15
+
16
+ it 'negates with exclude' do
17
+ @query.negate!
18
+ operator, condition = *@query.conditions.first
19
+
20
+ operator.must_equal :exclude
21
+ condition.must_equal({id: 1})
22
+ end
23
+ end
24
+
25
+ describe 'multipe where conditions' do
26
+ before do
27
+ @query.where(id: 1).and(name: 'L')
28
+ end
29
+
30
+ it 'negates with exclude' do
31
+ @query.negate!
32
+ operator, condition = *@query.conditions.last
33
+
34
+ operator.must_equal :exclude
35
+ condition.must_equal({name: 'L'})
36
+ end
37
+ end
38
+
39
+ describe 'exclude' do
40
+ before do
41
+ @query.exclude(published: false)
42
+ end
43
+
44
+ it 'negates with where' do
45
+ @query.negate!
46
+ operator, condition = *@query.conditions.first
47
+
48
+ operator.must_equal :where
49
+ condition.must_equal({published: false})
50
+ end
51
+ end
52
+
53
+ describe 'multiple exclude conditions' do
54
+ before do
55
+ @query.exclude(published: false).not(comments_count: 0)
56
+ end
57
+
58
+ it 'negates with where' do
59
+ @query.negate!
60
+ operator, condition = *@query.conditions.last
61
+
62
+ operator.must_equal :where
63
+ condition.must_equal({comments_count: 0})
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#to_s' do
69
+ let(:collection) { [1, 2, 3] }
70
+
71
+ it 'delegates to the wrapped collection' do
72
+ @query.to_s.must_equal collection.to_s
73
+ end
74
+ end
75
+
76
+ describe '#empty?' do
77
+ describe "when it's empty" do
78
+ it 'returns true' do
79
+ @query.must_be_empty
80
+ end
81
+ end
82
+
83
+ describe "when it's filled with elements" do
84
+ let(:collection) { [1, 2, 3] }
85
+
86
+ it 'returns false' do
87
+ @query.wont_be_empty
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#any?' do
93
+ describe "when it's empty" do
94
+ it 'returns false' do
95
+ assert !@query.any?
96
+ end
97
+ end
98
+
99
+ describe "when it's filled with elements" do
100
+ let(:collection) { [1, 2, 3] }
101
+
102
+ it 'returns true' do
103
+ assert @query.any?
104
+ end
105
+
106
+ describe "when a block is passed" do
107
+ describe "and it doesn't match elements" do
108
+ it 'returns false' do
109
+ assert !@query.any? {|e| e > 100 }
110
+ end
111
+ end
112
+
113
+ describe "and it matches elements" do
114
+ it 'returns true' do
115
+ assert @query.any? {|e| e % 2 == 0 }
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,1078 @@
1
+ require 'test_helper'
2
+
3
+ describe Lotus::Model::Adapters::SqlAdapter do
4
+ before do
5
+ TestUser = Struct.new(:id, :name, :age) do
6
+ include Lotus::Entity
7
+ end
8
+
9
+ TestDevice = Struct.new(:id) do
10
+ include Lotus::Entity
11
+ end
12
+
13
+ @mapper = Lotus::Model::Mapper.new do
14
+ collection :users do
15
+ entity TestUser
16
+
17
+ attribute :id, Integer
18
+ attribute :name, String
19
+ attribute :age, Integer
20
+ end
21
+
22
+ collection :devices do
23
+ entity TestDevice
24
+
25
+ attribute :id, Integer
26
+ end
27
+ end.load!
28
+
29
+ @adapter = Lotus::Model::Adapters::SqlAdapter.new(@mapper, SQLITE_CONNECTION_STRING)
30
+ end
31
+
32
+ after do
33
+ Object.send(:remove_const, :TestUser)
34
+ Object.send(:remove_const, :TestDevice)
35
+ end
36
+
37
+ let(:collection) { :users }
38
+
39
+ describe 'multiple collections' do
40
+ it 'create records' do
41
+ user = TestUser.new
42
+ device = TestDevice.new
43
+
44
+ @adapter.create(:users, user)
45
+ @adapter.create(:devices, device)
46
+
47
+ @adapter.all(:users).must_equal [user]
48
+ @adapter.all(:devices).must_equal [device]
49
+ end
50
+ end
51
+
52
+ describe '#initialize' do
53
+ it 'raises an error when the given URI refers to a non registered database adapter' do
54
+ -> {
55
+ Lotus::Model::Adapters::SqlAdapter.new(@mapper, 'postgres://host')
56
+ }.must_raise(Lotus::Model::Adapters::DatabaseAdapterNotFound)
57
+ end
58
+
59
+ it 'raises an error when the given URI refers to an unknown database adapter' do
60
+ -> {
61
+ Lotus::Model::Adapters::SqlAdapter.new(@mapper, 'unknown://host')
62
+ }.must_raise(Lotus::Model::Adapters::DatabaseAdapterNotFound)
63
+ end
64
+
65
+ it 'raises an error when the given URI is malformed' do
66
+ -> {
67
+ Lotus::Model::Adapters::SqlAdapter.new(@mapper, 'unknown_db:host')
68
+ }.must_raise(URI::InvalidURIError)
69
+ end
70
+ end
71
+
72
+ describe '#persist' do
73
+ describe 'when the given entity is not persisted' do
74
+ let(:entity) { TestUser.new }
75
+
76
+ it 'stores the record and assigns an id' do
77
+ @adapter.persist(collection, entity)
78
+
79
+ entity.id.wont_be_nil
80
+ @adapter.find(collection, entity.id).must_equal entity
81
+ end
82
+ end
83
+
84
+ describe 'when the given entity is persisted' do
85
+ before do
86
+ @adapter.create(collection, entity)
87
+ end
88
+
89
+ let(:entity) { TestUser.new }
90
+
91
+ it 'updates the record and leaves untouched the id' do
92
+ id = entity.id
93
+ id.wont_be_nil
94
+
95
+ entity.name = 'L'
96
+ @adapter.persist(collection, entity)
97
+
98
+ entity.id.must_equal(id)
99
+ @adapter.find(collection, entity.id).must_equal entity
100
+ end
101
+ end
102
+ end
103
+
104
+ describe '#create' do
105
+ let(:entity) { TestUser.new }
106
+
107
+ it 'stores the record and assigns an id' do
108
+ @adapter.create(collection, entity)
109
+
110
+ entity.id.wont_be_nil
111
+ @adapter.find(collection, entity.id).must_equal entity
112
+ end
113
+ end
114
+
115
+ describe '#update' do
116
+ before do
117
+ @adapter.create(collection, entity)
118
+ end
119
+
120
+ let(:entity) { TestUser.new(id: nil, name: 'L') }
121
+
122
+ it 'stores the changes and leave the id untouched' do
123
+ id = entity.id
124
+
125
+ entity.name = 'MG'
126
+ @adapter.update(collection, entity)
127
+
128
+ entity.id.must_equal id
129
+ @adapter.find(collection, entity.id).must_equal entity
130
+ end
131
+ end
132
+
133
+ describe '#delete' do
134
+ before do
135
+ @adapter.create(collection, entity)
136
+ end
137
+
138
+ let(:entity) { TestUser.new }
139
+
140
+ it 'removes the given identity' do
141
+ @adapter.delete(collection, entity)
142
+ @adapter.find(collection, entity.id).must_be_nil
143
+ end
144
+ end
145
+
146
+ describe '#all' do
147
+ describe 'when no records are persisted' do
148
+ before do
149
+ @adapter.clear(collection)
150
+ end
151
+
152
+ it 'returns an empty collection' do
153
+ @adapter.all(collection).must_be_empty
154
+ end
155
+ end
156
+
157
+ describe 'when some records are persisted' do
158
+ before do
159
+ @adapter.create(collection, entity)
160
+ end
161
+
162
+ let(:entity) { TestUser.new }
163
+
164
+ it 'returns all of them' do
165
+ @adapter.all(collection).must_equal [entity]
166
+ end
167
+ end
168
+ end
169
+
170
+ describe '#find' do
171
+ before do
172
+ @adapter.create(collection, entity)
173
+ end
174
+
175
+ let(:entity) { TestUser.new }
176
+
177
+ it 'returns the record by id' do
178
+ @adapter.find(collection, entity.id).must_equal entity
179
+ end
180
+
181
+ it 'returns nil when the record cannot be found' do
182
+ @adapter.find(collection, 1_000_000).must_be_nil
183
+ end
184
+
185
+ it 'returns nil when the given id is nil' do
186
+ @adapter.find(collection, nil).must_be_nil
187
+ end
188
+ end
189
+
190
+ describe '#first' do
191
+ describe 'when no records are peristed' do
192
+ before do
193
+ @adapter.clear(collection)
194
+ end
195
+
196
+ it 'returns nil' do
197
+ @adapter.first(collection).must_be_nil
198
+ end
199
+ end
200
+
201
+ describe 'when some records are persisted' do
202
+ before do
203
+ @adapter.create(collection, entity1)
204
+ @adapter.create(collection, entity2)
205
+ end
206
+
207
+ let(:entity1) { TestUser.new }
208
+ let(:entity2) { TestUser.new }
209
+
210
+ it 'returns the first record' do
211
+ @adapter.first(collection).must_equal entity1
212
+ end
213
+ end
214
+ end
215
+
216
+ describe '#last' do
217
+ describe 'when no records are peristed' do
218
+ before do
219
+ @adapter.clear(collection)
220
+ end
221
+
222
+ it 'returns nil' do
223
+ @adapter.last(collection).must_be_nil
224
+ end
225
+ end
226
+
227
+ describe 'when some records are persisted' do
228
+ before do
229
+ @adapter.create(collection, entity1)
230
+ @adapter.create(collection, entity2)
231
+ end
232
+
233
+ let(:entity1) { TestUser.new }
234
+ let(:entity2) { TestUser.new }
235
+
236
+ it 'returns the last record' do
237
+ @adapter.last(collection).must_equal entity2
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#clear' do
243
+ before do
244
+ @adapter.create(collection, entity)
245
+ end
246
+
247
+ let(:entity) { TestUser.new }
248
+
249
+ it 'removes all the records' do
250
+ @adapter.clear(collection)
251
+ @adapter.all(collection).must_be_empty
252
+ end
253
+ end
254
+
255
+ describe '#query' do
256
+ before do
257
+ @adapter.clear(collection)
258
+ end
259
+
260
+ let(:user1) { TestUser.new(name: 'L', age: '32') }
261
+ let(:user2) { TestUser.new(name: 'MG', age: 31) }
262
+
263
+ describe 'where' do
264
+ describe 'with an empty collection' do
265
+ it 'returns an empty result set' do
266
+ result = @adapter.query(collection) do
267
+ where(id: 23)
268
+ end.all
269
+
270
+ result.must_be_empty
271
+ end
272
+ end
273
+
274
+ describe 'with a filled collection' do
275
+ before do
276
+ @adapter.create(collection, user1)
277
+ @adapter.create(collection, user2)
278
+ end
279
+
280
+ it 'returns selected records' do
281
+ id = user1.id
282
+
283
+ query = Proc.new {
284
+ where(id: id)
285
+ }
286
+
287
+ result = @adapter.query(collection, &query).all
288
+ result.must_equal [user1]
289
+ end
290
+
291
+ it 'can use multiple where conditions' do
292
+ id = user1.id
293
+ name = user1.name
294
+
295
+ query = Proc.new {
296
+ where(id: id).where(name: name)
297
+ }
298
+
299
+ result = @adapter.query(collection, &query).all
300
+ result.must_equal [user1]
301
+ end
302
+
303
+ it 'can use multiple where conditions with "and" alias' do
304
+ id = user1.id
305
+ name = user1.name
306
+
307
+ query = Proc.new {
308
+ where(id: id).and(name: name)
309
+ }
310
+
311
+ result = @adapter.query(collection, &query).all
312
+ result.must_equal [user1]
313
+ end
314
+ end
315
+ end
316
+
317
+ describe 'exclude' do
318
+ describe 'with an empty collection' do
319
+ it 'returns an empty result set' do
320
+ result = @adapter.query(collection) do
321
+ exclude(id: 23)
322
+ end.all
323
+
324
+ result.must_be_empty
325
+ end
326
+ end
327
+
328
+ describe 'with a filled collection' do
329
+ before do
330
+ @adapter.create(collection, user1)
331
+ @adapter.create(collection, user2)
332
+ @adapter.create(collection, user3)
333
+ end
334
+
335
+ let(:user3) { TestUser.new(name: 'S', age: 2) }
336
+
337
+ it 'returns selected records' do
338
+ id = user1.id
339
+
340
+ query = Proc.new {
341
+ exclude(id: id)
342
+ }
343
+
344
+ result = @adapter.query(collection, &query).all
345
+ result.must_equal [user2, user3]
346
+ end
347
+
348
+ it 'can use multiple exclude conditions' do
349
+ id = user1.id
350
+ name = user2.name
351
+
352
+ query = Proc.new {
353
+ exclude(id: id).exclude(name: name)
354
+ }
355
+
356
+ result = @adapter.query(collection, &query).all
357
+ result.must_equal [user3]
358
+ end
359
+
360
+ it 'can use multiple exclude conditions with "not" alias' do
361
+ id = user1.id
362
+ name = user2.name
363
+
364
+ query = Proc.new {
365
+ self.not(id: id).not(name: name)
366
+ }
367
+
368
+ result = @adapter.query(collection, &query).all
369
+ result.must_equal [user3]
370
+ end
371
+ end
372
+ end
373
+
374
+ describe 'or' do
375
+ describe 'with an empty collection' do
376
+ it 'returns an empty result set' do
377
+ result = @adapter.query(collection) do
378
+ where(name: 'L').or(name: 'MG')
379
+ end.all
380
+
381
+ result.must_be_empty
382
+ end
383
+ end
384
+
385
+ describe 'with a filled collection' do
386
+ before do
387
+ @adapter.create(collection, user1)
388
+ @adapter.create(collection, user2)
389
+ end
390
+
391
+ it 'returns selected records' do
392
+ name1 = user1.name
393
+ name2 = user2.name
394
+
395
+ query = Proc.new {
396
+ where(name: name1).or(name: name2)
397
+ }
398
+
399
+ result = @adapter.query(collection, &query).all
400
+ result.must_equal [user1, user2]
401
+ end
402
+ end
403
+ end
404
+
405
+ describe 'select' do
406
+ describe 'with an empty collection' do
407
+ it 'returns an empty result' do
408
+ result = @adapter.query(collection) do
409
+ select(:age)
410
+ end.all
411
+
412
+ result.must_be_empty
413
+ end
414
+ end
415
+
416
+ describe 'with a filled collection' do
417
+ before do
418
+ @adapter.create(collection, user1)
419
+ @adapter.create(collection, user2)
420
+ @adapter.create(collection, user3)
421
+ end
422
+
423
+ let(:user1) { TestUser.new(name: 'L', age: 32) }
424
+ let(:user3) { TestUser.new(name: 'S') }
425
+ let(:users) { [user1, user2, user3] }
426
+
427
+ it 'returns the selected columnts from all the records' do
428
+ query = Proc.new {
429
+ select(:age)
430
+ }
431
+
432
+ result = @adapter.query(collection, &query).all
433
+
434
+ users.each do |user|
435
+ record = result.find {|r| r.age == user.age }
436
+ record.wont_be_nil
437
+ record.name.must_be_nil
438
+ end
439
+ end
440
+
441
+ it 'returns only the select of requested records' do
442
+ name = user2.name
443
+
444
+ query = Proc.new {
445
+ where(name: name).select(:age)
446
+ }
447
+
448
+ result = @adapter.query(collection, &query).all
449
+
450
+ record = result.first
451
+ record.age.must_equal(user2.age)
452
+ record.name.must_be_nil
453
+ end
454
+
455
+ it 'returns only the multiple select of requested records' do
456
+ name = user2.name
457
+
458
+ query = Proc.new {
459
+ where(name: name).select(:name, :age)
460
+ }
461
+
462
+ result = @adapter.query(collection, &query).all
463
+
464
+ record = result.first
465
+ record.name.must_equal(user2.name)
466
+ record.age.must_equal(user2.age)
467
+ record.id.must_be_nil
468
+ end
469
+ end
470
+ end
471
+
472
+ describe 'order' do
473
+ describe 'with an empty collection' do
474
+ it 'returns an empty result set' do
475
+ result = @adapter.query(collection) do
476
+ order(:id)
477
+ end.all
478
+
479
+ result.must_be_empty
480
+ end
481
+ end
482
+
483
+ describe 'with a filled collection' do
484
+ before do
485
+ @adapter.create(collection, user1)
486
+ @adapter.create(collection, user2)
487
+ end
488
+
489
+ it 'returns sorted records' do
490
+ query = Proc.new {
491
+ order(:id)
492
+ }
493
+
494
+ result = @adapter.query(collection, &query).all
495
+ result.must_equal [user1, user2]
496
+ end
497
+
498
+ it 'returns sorted records, using multiple columns' do
499
+ query = Proc.new {
500
+ order(:age, :id)
501
+ }
502
+
503
+ result = @adapter.query(collection, &query).all
504
+ result.must_equal [user2, user1]
505
+ end
506
+
507
+ it 'returns sorted records, using multiple invokations' do
508
+ query = Proc.new {
509
+ order(:age).order(:id)
510
+ }
511
+
512
+ result = @adapter.query(collection, &query).all
513
+ result.must_equal [user2, user1]
514
+ end
515
+ end
516
+ end
517
+
518
+ describe 'asc' do
519
+ describe 'with an empty collection' do
520
+ it 'returns an empty result set' do
521
+ result = @adapter.query(collection) do
522
+ asc(:id)
523
+ end.all
524
+
525
+ result.must_be_empty
526
+ end
527
+ end
528
+
529
+ describe 'with a filled collection' do
530
+ before do
531
+ @adapter.create(collection, user1)
532
+ @adapter.create(collection, user2)
533
+ end
534
+
535
+ it 'returns sorted records' do
536
+ query = Proc.new {
537
+ asc(:id)
538
+ }
539
+
540
+ result = @adapter.query(collection, &query).all
541
+ result.must_equal [user1, user2]
542
+ end
543
+ end
544
+ end
545
+
546
+ describe 'desc' do
547
+ describe 'with an empty collection' do
548
+ it 'returns an empty result set' do
549
+ result = @adapter.query(collection) do
550
+ desc(:id)
551
+ end.all
552
+
553
+ result.must_be_empty
554
+ end
555
+ end
556
+
557
+ describe 'with a filled collection' do
558
+ before do
559
+ @adapter.create(collection, user1)
560
+ @adapter.create(collection, user2)
561
+ end
562
+
563
+ it 'returns reverse sorted records' do
564
+ query = Proc.new {
565
+ desc(:id)
566
+ }
567
+
568
+ result = @adapter.query(collection, &query).all
569
+ result.must_equal [user2, user1]
570
+ end
571
+
572
+ it 'returns sorted records, using multiple columns' do
573
+ query = Proc.new {
574
+ desc(:age, :id)
575
+ }
576
+
577
+ result = @adapter.query(collection, &query).all
578
+ result.must_equal [user1, user2]
579
+ end
580
+
581
+ it 'returns sorted records, using multiple invokations' do
582
+ query = Proc.new {
583
+ desc(:age).desc(:id)
584
+ }
585
+
586
+ result = @adapter.query(collection, &query).all
587
+ result.must_equal [user1, user2]
588
+ end
589
+ end
590
+ end
591
+
592
+ describe 'limit' do
593
+ describe 'with an empty collection' do
594
+ it 'returns an empty result set' do
595
+ result = @adapter.query(collection) do
596
+ limit(1)
597
+ end.all
598
+
599
+ result.must_be_empty
600
+ end
601
+ end
602
+
603
+ describe 'with a filled collection' do
604
+ before do
605
+ @adapter.create(collection, user1)
606
+ @adapter.create(collection, user2)
607
+ @adapter.create(collection, TestUser.new(name: user2.name))
608
+ end
609
+
610
+ it 'returns only the number of requested records' do
611
+ name = user2.name
612
+
613
+ query = Proc.new {
614
+ where(name: name).limit(1)
615
+ }
616
+
617
+ result = @adapter.query(collection, &query).all
618
+ result.must_equal [user2]
619
+ end
620
+ end
621
+ end
622
+
623
+ describe 'offset' do
624
+ describe 'with an empty collection' do
625
+ it 'returns an empty result set' do
626
+ result = @adapter.query(collection) do
627
+ limit(1).offset(1)
628
+ end.all
629
+
630
+ result.must_be_empty
631
+ end
632
+ end
633
+
634
+ describe 'with a filled collection' do
635
+ before do
636
+ @adapter.create(collection, user1)
637
+ @adapter.create(collection, user2)
638
+ @adapter.create(collection, user3)
639
+ end
640
+
641
+ let(:user3) { TestUser.new(name: user2.name) }
642
+
643
+ it 'returns only the number of requested records' do
644
+ name = user2.name
645
+
646
+ query = Proc.new {
647
+ where(name: name).limit(1).offset(1)
648
+ }
649
+
650
+ result = @adapter.query(collection, &query).all
651
+ result.must_equal [user3]
652
+ end
653
+ end
654
+ end
655
+
656
+ describe 'exist?' do
657
+ describe 'with an empty collection' do
658
+ it 'returns false' do
659
+ result = @adapter.query(collection) do
660
+ where(id: 23)
661
+ end.exist?
662
+
663
+ result.must_equal false
664
+ end
665
+ end
666
+
667
+ describe 'with a filled collection' do
668
+ before do
669
+ @adapter.create(collection, user1)
670
+ @adapter.create(collection, user2)
671
+ end
672
+
673
+ it 'returns true when there are matched records' do
674
+ id = user1.id
675
+
676
+ query = Proc.new {
677
+ where(id: id)
678
+ }
679
+
680
+ result = @adapter.query(collection, &query).exist?
681
+ result.must_equal true
682
+ end
683
+
684
+ it 'returns false when there are matched records' do
685
+ query = Proc.new {
686
+ where(id: 'unknown')
687
+ }
688
+
689
+ result = @adapter.query(collection, &query).exist?
690
+ result.must_equal false
691
+ end
692
+ end
693
+ end
694
+
695
+ describe 'count' do
696
+ describe 'with an empty collection' do
697
+ it 'returns 0' do
698
+ result = @adapter.query(collection) do
699
+ all
700
+ end.count
701
+
702
+ result.must_equal 0
703
+ end
704
+ end
705
+
706
+ describe 'with a filled collection' do
707
+ before do
708
+ @adapter.create(collection, user1)
709
+ @adapter.create(collection, user2)
710
+ end
711
+
712
+ it 'returns the count of all the records' do
713
+ query = Proc.new {
714
+ all
715
+ }
716
+
717
+ result = @adapter.query(collection, &query).count
718
+ result.must_equal 2
719
+ end
720
+
721
+ it 'returns the count from an empty query block' do
722
+ query = Proc.new {
723
+ }
724
+
725
+ result = @adapter.query(collection, &query).count
726
+ result.must_equal 2
727
+ end
728
+
729
+ it 'returns only the count of requested records' do
730
+ name = user2.name
731
+
732
+ query = Proc.new {
733
+ where(name: name)
734
+ }
735
+
736
+ result = @adapter.query(collection, &query).count
737
+ result.must_equal 1
738
+ end
739
+ end
740
+ end
741
+
742
+ describe 'sum' do
743
+ describe 'with an empty collection' do
744
+ it 'returns nil' do
745
+ result = @adapter.query(collection) do
746
+ all
747
+ end.sum(:age)
748
+
749
+ result.must_be_nil
750
+ end
751
+ end
752
+
753
+ describe 'with a filled collection' do
754
+ before do
755
+ @adapter.create(collection, user1)
756
+ @adapter.create(collection, user2)
757
+ @adapter.create(collection, TestUser.new(name: 'S'))
758
+ end
759
+
760
+ it 'returns the sum of all the records' do
761
+ query = Proc.new {
762
+ all
763
+ }
764
+
765
+ result = @adapter.query(collection, &query).sum(:age)
766
+ result.must_equal 63
767
+ end
768
+
769
+ it 'returns the sum from an empty query block' do
770
+ query = Proc.new {
771
+ }
772
+
773
+ result = @adapter.query(collection, &query).sum(:age)
774
+ result.must_equal 63
775
+ end
776
+
777
+ it 'returns only the sum of requested records' do
778
+ name = user2.name
779
+
780
+ query = Proc.new {
781
+ where(name: name)
782
+ }
783
+
784
+ result = @adapter.query(collection, &query).sum(:age)
785
+ result.must_equal 31
786
+ end
787
+ end
788
+ end
789
+
790
+ describe 'average' do
791
+ describe 'with an empty collection' do
792
+ it 'returns nil' do
793
+ result = @adapter.query(collection) do
794
+ all
795
+ end.average(:age)
796
+
797
+ result.must_be_nil
798
+ end
799
+ end
800
+
801
+ describe 'with a filled collection' do
802
+ before do
803
+ @adapter.create(collection, user1)
804
+ @adapter.create(collection, user2)
805
+ @adapter.create(collection, TestUser.new(name: 'S'))
806
+ end
807
+
808
+ it 'returns the average of all the records' do
809
+ query = Proc.new {
810
+ all
811
+ }
812
+
813
+ result = @adapter.query(collection, &query).average(:age)
814
+ result.must_equal 31.5
815
+ end
816
+
817
+ it 'returns the average from an empty query block' do
818
+ query = Proc.new {
819
+ }
820
+
821
+ result = @adapter.query(collection, &query).average(:age)
822
+ result.must_equal 31.5
823
+ end
824
+
825
+ it 'returns only the average of requested records' do
826
+ name = user2.name
827
+
828
+ query = Proc.new {
829
+ where(name: name)
830
+ }
831
+
832
+ result = @adapter.query(collection, &query).average(:age)
833
+ result.must_equal 31
834
+ end
835
+ end
836
+ end
837
+
838
+ describe 'avg' do
839
+ describe 'with an empty collection' do
840
+ it 'returns nil' do
841
+ result = @adapter.query(collection) do
842
+ all
843
+ end.avg(:age)
844
+
845
+ result.must_be_nil
846
+ end
847
+ end
848
+
849
+ describe 'with a filled collection' do
850
+ before do
851
+ @adapter.create(collection, user1)
852
+ @adapter.create(collection, user2)
853
+ @adapter.create(collection, TestUser.new(name: 'S'))
854
+ end
855
+
856
+ it 'returns the average of all the records' do
857
+ query = Proc.new {
858
+ all
859
+ }
860
+
861
+ result = @adapter.query(collection, &query).avg(:age)
862
+ result.must_equal 31.5
863
+ end
864
+
865
+ it 'returns the average from an empty query block' do
866
+ query = Proc.new {
867
+ }
868
+
869
+ result = @adapter.query(collection, &query).avg(:age)
870
+ result.must_equal 31.5
871
+ end
872
+
873
+ it 'returns only the average of requested records' do
874
+ name = user2.name
875
+
876
+ query = Proc.new {
877
+ where(name: name)
878
+ }
879
+
880
+ result = @adapter.query(collection, &query).avg(:age)
881
+ result.must_equal 31
882
+ end
883
+ end
884
+ end
885
+
886
+ describe 'max' do
887
+ describe 'with an empty collection' do
888
+ it 'returns nil' do
889
+ result = @adapter.query(collection) do
890
+ all
891
+ end.max(:age)
892
+
893
+ result.must_be_nil
894
+ end
895
+ end
896
+
897
+ describe 'with a filled collection' do
898
+ before do
899
+ @adapter.create(collection, user1)
900
+ @adapter.create(collection, user2)
901
+ @adapter.create(collection, TestUser.new(name: 'S'))
902
+ end
903
+
904
+ it 'returns the maximum of all the records' do
905
+ query = Proc.new {
906
+ all
907
+ }
908
+
909
+ result = @adapter.query(collection, &query).max(:age)
910
+ result.must_equal 32
911
+ end
912
+
913
+ it 'returns the maximum from an empty query block' do
914
+ query = Proc.new {
915
+ }
916
+
917
+ result = @adapter.query(collection, &query).max(:age)
918
+ result.must_equal 32
919
+ end
920
+
921
+ it 'returns only the maximum of requested records' do
922
+ name = user2.name
923
+
924
+ query = Proc.new {
925
+ where(name: name)
926
+ }
927
+
928
+ result = @adapter.query(collection, &query).max(:age)
929
+ result.must_equal 31
930
+ end
931
+ end
932
+ end
933
+
934
+ describe 'min' do
935
+ describe 'with an empty collection' do
936
+ it 'returns nil' do
937
+ result = @adapter.query(collection) do
938
+ all
939
+ end.min(:age)
940
+
941
+ result.must_be_nil
942
+ end
943
+ end
944
+
945
+ describe 'with a filled collection' do
946
+ before do
947
+ @adapter.create(collection, user1)
948
+ @adapter.create(collection, user2)
949
+ @adapter.create(collection, TestUser.new(name: 'S'))
950
+ end
951
+
952
+ it 'returns the minimum of all the records' do
953
+ query = Proc.new {
954
+ all
955
+ }
956
+
957
+ result = @adapter.query(collection, &query).min(:age)
958
+ result.must_equal 31
959
+ end
960
+
961
+ it 'returns the minimum from an empty query block' do
962
+ query = Proc.new {
963
+ }
964
+
965
+ result = @adapter.query(collection, &query).min(:age)
966
+ result.must_equal 31
967
+ end
968
+
969
+ it 'returns only the minimum of requested records' do
970
+ name = user1.name
971
+
972
+ query = Proc.new {
973
+ where(name: name)
974
+ }
975
+
976
+ result = @adapter.query(collection, &query).min(:age)
977
+ result.must_equal 32
978
+ end
979
+ end
980
+ end
981
+
982
+ describe 'interval' do
983
+ describe 'with an empty collection' do
984
+ it 'returns nil' do
985
+ result = @adapter.query(collection) do
986
+ all
987
+ end.interval(:age)
988
+
989
+ result.must_be_nil
990
+ end
991
+ end
992
+
993
+ describe 'with a filled collection' do
994
+ before do
995
+ @adapter.create(collection, user1)
996
+ @adapter.create(collection, user2)
997
+ @adapter.create(collection, TestUser.new(name: 'S'))
998
+ end
999
+
1000
+ it 'returns the interval of all the records' do
1001
+ query = Proc.new {
1002
+ all
1003
+ }
1004
+
1005
+ result = @adapter.query(collection, &query).interval(:age)
1006
+ result.must_equal 1
1007
+ end
1008
+
1009
+ it 'returns the interval from an empty query block' do
1010
+ query = Proc.new {
1011
+ }
1012
+
1013
+ result = @adapter.query(collection, &query).interval(:age)
1014
+ result.must_equal 1
1015
+ end
1016
+
1017
+ it 'returns only the interval of requested records' do
1018
+ name = user1.name
1019
+
1020
+ query = Proc.new {
1021
+ where(name: name)
1022
+ }
1023
+
1024
+ result = @adapter.query(collection, &query).interval(:age)
1025
+ result.must_equal 0
1026
+ end
1027
+ end
1028
+ end
1029
+
1030
+ describe 'range' do
1031
+ describe 'with an empty collection' do
1032
+ it 'returns nil' do
1033
+ result = @adapter.query(collection) do
1034
+ all
1035
+ end.range(:age)
1036
+
1037
+ result.must_equal nil..nil
1038
+ end
1039
+ end
1040
+
1041
+ describe 'with a filled collection' do
1042
+ before do
1043
+ @adapter.create(collection, user1)
1044
+ @adapter.create(collection, user2)
1045
+ @adapter.create(collection, TestUser.new(name: 'S'))
1046
+ end
1047
+
1048
+ it 'returns the range of all the records' do
1049
+ query = Proc.new {
1050
+ all
1051
+ }
1052
+
1053
+ result = @adapter.query(collection, &query).range(:age)
1054
+ result.must_equal 31..32
1055
+ end
1056
+
1057
+ it 'returns the range from an empty query block' do
1058
+ query = Proc.new {
1059
+ }
1060
+
1061
+ result = @adapter.query(collection, &query).range(:age)
1062
+ result.must_equal 31..32
1063
+ end
1064
+
1065
+ it 'returns only the range of requested records' do
1066
+ name = user2.name
1067
+
1068
+ query = Proc.new {
1069
+ where(name: name)
1070
+ }
1071
+
1072
+ result = @adapter.query(collection, &query).range(:age)
1073
+ result.must_equal 31..31
1074
+ end
1075
+ end
1076
+ end
1077
+ end
1078
+ end