active_mapper 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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +1 -0
- data/active_mapper.gemspec +26 -0
- data/lib/active_mapper/adapter/active_record/order/attribute.rb +34 -0
- data/lib/active_mapper/adapter/active_record/order.rb +30 -0
- data/lib/active_mapper/adapter/active_record/query/attribute.rb +63 -0
- data/lib/active_mapper/adapter/active_record/query/expression.rb +63 -0
- data/lib/active_mapper/adapter/active_record/query.rb +23 -0
- data/lib/active_mapper/adapter/active_record.rb +96 -0
- data/lib/active_mapper/adapter/memory/order/attribute.rb +40 -0
- data/lib/active_mapper/adapter/memory/order.rb +31 -0
- data/lib/active_mapper/adapter/memory/query/attribute.rb +61 -0
- data/lib/active_mapper/adapter/memory/query/expression.rb +81 -0
- data/lib/active_mapper/adapter/memory/query.rb +22 -0
- data/lib/active_mapper/adapter/memory.rb +80 -0
- data/lib/active_mapper/adapter.rb +7 -0
- data/lib/active_mapper/mapper.rb +107 -0
- data/lib/active_mapper/relation.rb +133 -0
- data/lib/active_mapper/version.rb +3 -0
- data/lib/active_mapper.rb +24 -0
- data/spec/active_mapper/adapter/active_record/order_spec.rb +11 -0
- data/spec/active_mapper/adapter/active_record_spec.rb +164 -0
- data/spec/active_mapper/adapter/memory_spec.rb +158 -0
- data/spec/active_mapper/mapper_spec.rb +195 -0
- data/spec/active_mapper/relation_spec.rb +190 -0
- data/spec/active_mapper_spec.rb +25 -0
- data/spec/features/active_record_spec.rb +7 -0
- data/spec/features/memory_spec.rb +5 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/models/user.rb +20 -0
- data/spec/support/shared/active_mapper_integration.rb +129 -0
- metadata +162 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_mapper/adapter/memory/query/attribute'
|
2
|
+
require 'active_mapper/adapter/memory/query/expression'
|
3
|
+
|
4
|
+
module ActiveMapper
|
5
|
+
module Adapter
|
6
|
+
class Memory
|
7
|
+
class Query
|
8
|
+
def initialize(&block)
|
9
|
+
@block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_proc
|
13
|
+
@block ? @block.call(self).to_proc : proc { true }
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args, &block)
|
17
|
+
Attribute.new(name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'active_mapper/adapter/memory/query'
|
2
|
+
require 'active_mapper/adapter/memory/order'
|
3
|
+
|
4
|
+
module ActiveMapper
|
5
|
+
module Adapter
|
6
|
+
class Memory
|
7
|
+
def initialize
|
8
|
+
@collection = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def find(klass, id)
|
12
|
+
collection(klass)[id]
|
13
|
+
end
|
14
|
+
|
15
|
+
def where(klass, options = {}, &block)
|
16
|
+
query = Query.new(&block)
|
17
|
+
order = Order.new(&options[:order])
|
18
|
+
|
19
|
+
records = collection(klass).values.select(&query.to_proc)
|
20
|
+
records = records.sort(&order.to_proc)
|
21
|
+
records = records.drop(options[:offset]) if options[:offset]
|
22
|
+
records = records.take(options[:limit]) if options[:limit]
|
23
|
+
|
24
|
+
records
|
25
|
+
end
|
26
|
+
|
27
|
+
def count(klass, &block)
|
28
|
+
where(klass, &block).count
|
29
|
+
end
|
30
|
+
|
31
|
+
def minimum(klass, attribute, &block)
|
32
|
+
where(klass, order: proc { |object| [object.send(attribute)] }, &block).first.send(attribute)
|
33
|
+
end
|
34
|
+
|
35
|
+
def maximum(klass, attribute, &block)
|
36
|
+
where(klass, order: proc { |object| [-object.send(attribute)] }, &block).first.send(attribute)
|
37
|
+
end
|
38
|
+
|
39
|
+
def average(klass, attribute, &block)
|
40
|
+
sum(klass, attribute, &block).to_f / count(klass, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def sum(klass, attribute, &block)
|
44
|
+
where(klass, &block).sum(&:"#{attribute}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def insert(klass, object)
|
48
|
+
object = object.dup
|
49
|
+
object.id = (collection(klass).keys.last || 0) + 1
|
50
|
+
|
51
|
+
collection(klass)[object.id] = object
|
52
|
+
object.id
|
53
|
+
end
|
54
|
+
|
55
|
+
def update(klass, object)
|
56
|
+
collection(klass)[object.id] = object.dup
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete(klass, object)
|
60
|
+
collection(klass).delete(object.id)
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete_all(klass, &block)
|
64
|
+
where(klass, &block).each do |object|
|
65
|
+
delete(klass, object)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def unserialize(klass, object)
|
70
|
+
object
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def collection(klass)
|
76
|
+
@collection[klass] ||= {}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module ActiveMapper
|
2
|
+
class Mapper
|
3
|
+
attr_reader :mapped_class, :adapter
|
4
|
+
|
5
|
+
def initialize(mapped_class, adapter)
|
6
|
+
@mapped_class = mapped_class
|
7
|
+
@adapter = adapter
|
8
|
+
end
|
9
|
+
|
10
|
+
def all?(&block)
|
11
|
+
count == count(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def any?(&block)
|
15
|
+
select(&block).any?
|
16
|
+
end
|
17
|
+
|
18
|
+
def none?(&block)
|
19
|
+
select(&block).none?
|
20
|
+
end
|
21
|
+
|
22
|
+
def one?(&block)
|
23
|
+
select(&block).one?
|
24
|
+
end
|
25
|
+
|
26
|
+
def count(&block)
|
27
|
+
select(&block).count
|
28
|
+
end
|
29
|
+
|
30
|
+
def min(attribute)
|
31
|
+
find_all.min(attribute)
|
32
|
+
end
|
33
|
+
alias :min_by :min
|
34
|
+
alias :minimum :min
|
35
|
+
|
36
|
+
def max(attribute)
|
37
|
+
find_all.max(attribute)
|
38
|
+
end
|
39
|
+
alias :max_by :max
|
40
|
+
alias :maximum :max
|
41
|
+
|
42
|
+
def minmax(attribute)
|
43
|
+
find_all.minmax(attribute)
|
44
|
+
end
|
45
|
+
alias :minmax_by :minmax
|
46
|
+
|
47
|
+
def avg(attribute)
|
48
|
+
find_all.avg(attribute)
|
49
|
+
end
|
50
|
+
alias :average :avg
|
51
|
+
|
52
|
+
def sum(attribute)
|
53
|
+
find_all.sum(attribute)
|
54
|
+
end
|
55
|
+
|
56
|
+
def find(id = nil, &block)
|
57
|
+
id ? first { |object| object.id == id } : first(&block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def first(&block)
|
61
|
+
select(&block).first
|
62
|
+
end
|
63
|
+
alias :detect :first
|
64
|
+
|
65
|
+
def last(&block)
|
66
|
+
select(&block).last
|
67
|
+
end
|
68
|
+
|
69
|
+
def select(&block)
|
70
|
+
Relation.new(mapped_class, adapter, &block)
|
71
|
+
end
|
72
|
+
alias :find_all :select
|
73
|
+
|
74
|
+
def reject(&block)
|
75
|
+
select { |object| !block.call(object) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def save(object)
|
79
|
+
return false unless object.valid?
|
80
|
+
|
81
|
+
if object.id
|
82
|
+
adapter.update(mapped_class, object)
|
83
|
+
else
|
84
|
+
object.id = adapter.insert(mapped_class, object)
|
85
|
+
end
|
86
|
+
|
87
|
+
object
|
88
|
+
end
|
89
|
+
|
90
|
+
def delete(object)
|
91
|
+
adapter.delete(mapped_class, object)
|
92
|
+
end
|
93
|
+
|
94
|
+
def delete_if(&block)
|
95
|
+
adapter.delete_all(mapped_class, &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def keep_if(&block)
|
99
|
+
delete_if { |object| !block.call(object) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def clear
|
103
|
+
adapter.delete_all(mapped_class)
|
104
|
+
end
|
105
|
+
alias :delete_all :clear
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module ActiveMapper
|
4
|
+
class Relation
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :to_a, :each, :map
|
8
|
+
|
9
|
+
def initialize(mapped_class, adapter, &block)
|
10
|
+
@mapped_class = mapped_class
|
11
|
+
@adapter = adapter
|
12
|
+
@block = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize_copy(other)
|
16
|
+
super
|
17
|
+
@to_a = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def any?
|
21
|
+
count > 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def none?
|
25
|
+
!any?
|
26
|
+
end
|
27
|
+
alias :empty? :none?
|
28
|
+
|
29
|
+
def one?
|
30
|
+
count == 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def count
|
34
|
+
@count ||= @adapter.count(@mapped_class, &@block)
|
35
|
+
end
|
36
|
+
alias :length :count
|
37
|
+
alias :size :count
|
38
|
+
|
39
|
+
def min(attribute)
|
40
|
+
@min ||= @adapter.minimum(@mapped_class, attribute, &@block)
|
41
|
+
end
|
42
|
+
alias :minimum :min
|
43
|
+
|
44
|
+
def max(attribute)
|
45
|
+
@max ||= @adapter.maximum(@mapped_class, attribute, &@block)
|
46
|
+
end
|
47
|
+
alias :maximum :max
|
48
|
+
|
49
|
+
def minmax(attribute)
|
50
|
+
[min(attribute), max(attribute)]
|
51
|
+
end
|
52
|
+
|
53
|
+
def avg(attribute)
|
54
|
+
@avg ||= @adapter.average(@mapped_class, attribute, &@block)
|
55
|
+
end
|
56
|
+
alias :average :avg
|
57
|
+
|
58
|
+
def sum(attribute)
|
59
|
+
@sum ||= @adapter.sum(@mapped_class, attribute, &@block)
|
60
|
+
end
|
61
|
+
|
62
|
+
def drop(number)
|
63
|
+
@offset = number
|
64
|
+
dup
|
65
|
+
end
|
66
|
+
|
67
|
+
def take(number)
|
68
|
+
@limit = number
|
69
|
+
dup
|
70
|
+
end
|
71
|
+
|
72
|
+
def select(&block)
|
73
|
+
if @block
|
74
|
+
query = @block.dup
|
75
|
+
|
76
|
+
@block = proc { |object| (query.call(object)) & block.call(object) }
|
77
|
+
else
|
78
|
+
@block = block
|
79
|
+
end
|
80
|
+
|
81
|
+
dup
|
82
|
+
end
|
83
|
+
|
84
|
+
def reject(&block)
|
85
|
+
select { |object| !block.call(object) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def first(number = 1)
|
89
|
+
objects = drop(0).take(number).to_a
|
90
|
+
|
91
|
+
if number == 1
|
92
|
+
objects.first
|
93
|
+
else
|
94
|
+
objects
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def last(number = 1)
|
99
|
+
objects = drop(0).take(number).reverse.to_a
|
100
|
+
|
101
|
+
if number == 1
|
102
|
+
objects.first
|
103
|
+
else
|
104
|
+
objects
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def sort_by(&block)
|
109
|
+
@order = block
|
110
|
+
dup
|
111
|
+
end
|
112
|
+
|
113
|
+
def reverse
|
114
|
+
if @order
|
115
|
+
block = @order.dup
|
116
|
+
|
117
|
+
sort_by { |object| [block.call(object)].flatten.map(&:reverse) }
|
118
|
+
else
|
119
|
+
sort_by { |object| -object.id }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_a
|
124
|
+
@to_a ||= @adapter.where(@mapped_class, options, &@block).map { |record| @adapter.unserialize(@mapped_class, record) }
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def options
|
130
|
+
{ offset: @offset, limit: @limit, order: @order }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'active_mapper/mapper'
|
2
|
+
require 'active_mapper/relation'
|
3
|
+
require 'active_mapper/adapter'
|
4
|
+
require 'active_mapper/version'
|
5
|
+
|
6
|
+
module ActiveMapper
|
7
|
+
def self.[](klass)
|
8
|
+
mappers[klass] ||= Class.new(ActiveMapper::Mapper).new(klass, adapter)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.adapter
|
12
|
+
@adapter ||= ActiveMapper::Adapter::Memory.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.adapter=(adapter)
|
16
|
+
@adapter = adapter
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.mappers
|
22
|
+
@mappers ||= {}
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveMapper::Adapter::ActiveRecord::Order do
|
4
|
+
let(:order) { described_class.new { |object| [object.name, -object.age] } }
|
5
|
+
|
6
|
+
describe '#to_sql' do
|
7
|
+
it 'converts attributes to hash' do
|
8
|
+
expect(order.to_sql).to eq({ name: :asc, age: :desc })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveMapper::Adapter::ActiveRecord do
|
4
|
+
let(:user) { User.new(name: 'user', age: 28) }
|
5
|
+
let(:other_user) { User.new(name: 'other', age: 35) }
|
6
|
+
let(:adapter) { ActiveMapper::Adapter::ActiveRecord.new }
|
7
|
+
|
8
|
+
setup_active_record('active_record')
|
9
|
+
|
10
|
+
before do
|
11
|
+
user.id = adapter.insert(User, user)
|
12
|
+
other_user.id = adapter.insert(User, other_user)
|
13
|
+
end
|
14
|
+
|
15
|
+
after { adapter.delete_all(User) }
|
16
|
+
|
17
|
+
describe '#find' do
|
18
|
+
it 'finds the record with the matching id' do
|
19
|
+
record = adapter.find(User, user.id)
|
20
|
+
|
21
|
+
expect(record.id).to eq(user.id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#where' do
|
26
|
+
it 'finds the matching records' do
|
27
|
+
ids = adapter.where(User) { |u| u.age < 35 }.load.map(&:id)
|
28
|
+
|
29
|
+
expect(ids).to include(user.id)
|
30
|
+
expect(ids).to_not include(other_user.id)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'finds and sorts the matching records in ascending order' do
|
34
|
+
records = adapter.where(User, order: proc { |object| [object.name] })
|
35
|
+
|
36
|
+
expect(records.first.id).to eq(other_user.id)
|
37
|
+
expect(records.last.id).to eq(user.id)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'finds and sorts the matching records in descending order' do
|
41
|
+
records = adapter.where(User, order: proc { |object| [-object.age] })
|
42
|
+
|
43
|
+
expect(records.first.id).to eq(other_user.id)
|
44
|
+
expect(records.last.id).to eq(user.id)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'limits the number of matching records' do
|
48
|
+
records = adapter.where(User, limit: 1)
|
49
|
+
|
50
|
+
expect(records.count).to eq(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'offsets the matching records' do
|
54
|
+
ids = adapter.where(User, offset: 1).load.map(&:id)
|
55
|
+
|
56
|
+
expect(ids).to include(other_user.id)
|
57
|
+
expect(ids).to_not include(user.id)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#count' do
|
62
|
+
it 'counts the number of total records' do
|
63
|
+
expect(adapter.count(User)).to eq(2)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'counts the number of matching records' do
|
67
|
+
expect(adapter.count(User) { |u| u.age < 35 }).to eq(1)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#minimum' do
|
72
|
+
it 'calculates the minimum value' do
|
73
|
+
expect(adapter.minimum(User, :age)).to eq(28)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'calculates the minimum value of a subset of records' do
|
77
|
+
expect(adapter.minimum(User, :age) { |user| user.age > 30 }).to eq(35)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#maximum' do
|
82
|
+
it 'calculates the maximum value' do
|
83
|
+
expect(adapter.maximum(User, :age)).to eq(35)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'calculates the maximum value of a subset of records' do
|
87
|
+
expect(adapter.maximum(User, :age) { |user| user.age < 30 }).to eq(28)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#average' do
|
92
|
+
it 'calculates the average value' do
|
93
|
+
expect(adapter.average(User, :age)).to eq(31.5)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'calculates the avarage value of a subset of records' do
|
97
|
+
expect(adapter.average(User, :age) { |user| user.age < 35 }).to eq(28)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#sum' do
|
102
|
+
it 'calculates the total value' do
|
103
|
+
expect(adapter.sum(User, :age)).to eq(63)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'calculates the total value of a subset of records' do
|
107
|
+
expect(adapter.sum(User, :age) { |user| user.age < 35 }).to eq(28)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#insert' do
|
112
|
+
it 'inserts the record into the database' do
|
113
|
+
user = User.new(name: 'test', age: 18)
|
114
|
+
id = adapter.insert(User, user)
|
115
|
+
record = adapter.find(User, id)
|
116
|
+
|
117
|
+
expect(record.id).to eq(id)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#update' do
|
122
|
+
it 'updates the record in the database' do
|
123
|
+
user.name = 'Changed'
|
124
|
+
user.age = 18
|
125
|
+
adapter.update(User, user)
|
126
|
+
record = adapter.find(User, user.id)
|
127
|
+
|
128
|
+
expect(record.name).to eq('Changed')
|
129
|
+
expect(record.age).to eq(18)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '#delete' do
|
134
|
+
it 'deletes the record from the database' do
|
135
|
+
adapter.delete(User, user)
|
136
|
+
|
137
|
+
expect(adapter.find(User, user.id)).to be_nil
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#delete_all' do
|
142
|
+
it 'deletes all the records' do
|
143
|
+
adapter.delete_all(User)
|
144
|
+
|
145
|
+
expect(adapter.count(User)).to eq(0)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'deletes the matching records' do
|
149
|
+
adapter.delete_all(User) { |u| u.name == 'user' }
|
150
|
+
|
151
|
+
expect(adapter.find(User, user.id)).to be_nil
|
152
|
+
expect(adapter.find(User, other_user.id)).to_not be_nil
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#unserialize' do
|
157
|
+
it 'unserializes the object' do
|
158
|
+
record = adapter.find(User, user.id)
|
159
|
+
unserialized = adapter.unserialize(User, record)
|
160
|
+
|
161
|
+
expect(unserialized).to eq(user)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveMapper::Adapter::Memory do
|
4
|
+
let(:user) { User.new(name: 'user', age: 28) }
|
5
|
+
let(:other_user) { User.new(name: 'other', age: 35) }
|
6
|
+
let(:adapter) { ActiveMapper::Adapter::Memory.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
user.id = adapter.insert(User, user)
|
10
|
+
other_user.id = adapter.insert(User, other_user)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#find' do
|
14
|
+
it 'finds the record with the matching id' do
|
15
|
+
expect(adapter.find(User, user.id)).to eq(user)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#where' do
|
20
|
+
it 'finds the matching records' do
|
21
|
+
records = adapter.where(User) { |u| u.age < 35 }
|
22
|
+
|
23
|
+
expect(records).to include(user)
|
24
|
+
expect(records).to_not include(other_user)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'finds and sorts the matching records in ascending order' do
|
28
|
+
records = adapter.where(User, order: proc { |object| [object.name] })
|
29
|
+
|
30
|
+
expect(records.first).to eq(other_user)
|
31
|
+
expect(records.last).to eq(user)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'finds and sorts the matching records in descending order' do
|
35
|
+
records = adapter.where(User, order: proc { |object| [-object.age] })
|
36
|
+
|
37
|
+
expect(records.first).to eq(other_user)
|
38
|
+
expect(records.last).to eq(user)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'limits the number of matching records' do
|
42
|
+
records = adapter.where(User, limit: 1)
|
43
|
+
|
44
|
+
expect(records.count).to eq(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'offsets the matching records' do
|
48
|
+
records = adapter.where(User, offset: 1)
|
49
|
+
|
50
|
+
expect(records).to include(other_user)
|
51
|
+
expect(records).to_not include(user)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#count' do
|
56
|
+
it 'counts the number of total records' do
|
57
|
+
expect(adapter.count(User)).to eq(2)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'counts the number of matching records' do
|
61
|
+
expect(adapter.count(User) { |u| u.age < 35 }).to eq(1)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#minimum' do
|
66
|
+
it 'calculates the minimum value' do
|
67
|
+
expect(adapter.minimum(User, :age)).to eq(28)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'calculates the minimum value of a subset of records' do
|
71
|
+
expect(adapter.minimum(User, :age) { |user| user.age > 30 }).to eq(35)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#maximum' do
|
76
|
+
it 'calculates the maximum value' do
|
77
|
+
expect(adapter.maximum(User, :age)).to eq(35)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'calculates the maximum value of a subset of records' do
|
81
|
+
expect(adapter.maximum(User, :age) { |user| user.age < 30 }).to eq(28)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#average' do
|
86
|
+
it 'calculates the average value' do
|
87
|
+
expect(adapter.average(User, :age)).to eq(31.5)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'calculates the average value of a subset of records' do
|
91
|
+
expect(adapter.average(User, :age) { |user| user.age < 35 }).to eq(28)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#sum' do
|
96
|
+
it 'calculates the total value' do
|
97
|
+
expect(adapter.sum(User, :age)).to eq(63)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'calculates the total value of a subset of records' do
|
101
|
+
expect(adapter.sum(User, :age) { |user| user.age < 35 }).to eq(28)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#insert' do
|
106
|
+
it 'inserts the record into the collection' do
|
107
|
+
user = User.new(name: 'test', age: 18)
|
108
|
+
id = adapter.insert(User, user)
|
109
|
+
record = adapter.find(User, id)
|
110
|
+
|
111
|
+
expect(record.id).to eq(id)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#update' do
|
116
|
+
it 'updates the record in the collection' do
|
117
|
+
user.name = 'Changed'
|
118
|
+
user.age = 18
|
119
|
+
adapter.update(User, user)
|
120
|
+
record = adapter.find(User, user.id)
|
121
|
+
|
122
|
+
expect(record.name).to eq('Changed')
|
123
|
+
expect(record.age).to eq(18)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#delete' do
|
128
|
+
it 'deletes the record from the collection' do
|
129
|
+
adapter.delete(User, user)
|
130
|
+
|
131
|
+
expect(adapter.find(User, user.id)).to be_nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#delete_all' do
|
136
|
+
it 'deletes all the records' do
|
137
|
+
adapter.delete_all(User)
|
138
|
+
|
139
|
+
expect(adapter.count(User)).to eq(0)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'deletes the matching records' do
|
143
|
+
adapter.delete_all(User) { |u| u.name == 'user' }
|
144
|
+
|
145
|
+
expect(adapter.find(User, user.id)).to be_nil
|
146
|
+
expect(adapter.find(User, other_user.id)).to eq(other_user)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#unserialize' do
|
151
|
+
it 'unserializes the object' do
|
152
|
+
record = adapter.find(User, user.id)
|
153
|
+
unserialized = adapter.unserialize(User, record)
|
154
|
+
|
155
|
+
expect(unserialized).to eq(user)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|