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