lotus-model 0.0.0 → 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.
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