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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +62 -0
  9. data/Rakefile +1 -0
  10. data/active_mapper.gemspec +26 -0
  11. data/lib/active_mapper/adapter/active_record/order/attribute.rb +34 -0
  12. data/lib/active_mapper/adapter/active_record/order.rb +30 -0
  13. data/lib/active_mapper/adapter/active_record/query/attribute.rb +63 -0
  14. data/lib/active_mapper/adapter/active_record/query/expression.rb +63 -0
  15. data/lib/active_mapper/adapter/active_record/query.rb +23 -0
  16. data/lib/active_mapper/adapter/active_record.rb +96 -0
  17. data/lib/active_mapper/adapter/memory/order/attribute.rb +40 -0
  18. data/lib/active_mapper/adapter/memory/order.rb +31 -0
  19. data/lib/active_mapper/adapter/memory/query/attribute.rb +61 -0
  20. data/lib/active_mapper/adapter/memory/query/expression.rb +81 -0
  21. data/lib/active_mapper/adapter/memory/query.rb +22 -0
  22. data/lib/active_mapper/adapter/memory.rb +80 -0
  23. data/lib/active_mapper/adapter.rb +7 -0
  24. data/lib/active_mapper/mapper.rb +107 -0
  25. data/lib/active_mapper/relation.rb +133 -0
  26. data/lib/active_mapper/version.rb +3 -0
  27. data/lib/active_mapper.rb +24 -0
  28. data/spec/active_mapper/adapter/active_record/order_spec.rb +11 -0
  29. data/spec/active_mapper/adapter/active_record_spec.rb +164 -0
  30. data/spec/active_mapper/adapter/memory_spec.rb +158 -0
  31. data/spec/active_mapper/mapper_spec.rb +195 -0
  32. data/spec/active_mapper/relation_spec.rb +190 -0
  33. data/spec/active_mapper_spec.rb +25 -0
  34. data/spec/features/active_record_spec.rb +7 -0
  35. data/spec/features/memory_spec.rb +5 -0
  36. data/spec/spec_helper.rb +30 -0
  37. data/spec/support/models/user.rb +20 -0
  38. data/spec/support/shared/active_mapper_integration.rb +129 -0
  39. metadata +162 -0
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+ describe ActiveMapper::Mapper do
3
+ let(:adapter) { ActiveMapper::Adapter::Memory.new }
4
+ let(:mapper) { ActiveMapper::Mapper.new(User, adapter) }
5
+ let(:user) { User.new(name: 'user', age: 28) }
6
+ let(:other_user) { User.new(name: 'other', age: 35) }
7
+
8
+ before do
9
+ mapper.save(user)
10
+ mapper.save(other_user)
11
+ end
12
+
13
+ describe '#all?' do
14
+ it 'is true when all objects match' do
15
+ expect(mapper.all? { |user| user.age > 18 }).to be_true
16
+ end
17
+
18
+ it 'is false when all objects do not match' do
19
+ expect(mapper.all? { |user| user.age > 28 }).to be_false
20
+ end
21
+ end
22
+
23
+ describe '#any?' do
24
+ it 'is true when any objects match' do
25
+ expect(mapper.any? { |user| user.age == 28 }).to be_true
26
+ end
27
+
28
+ it 'is false when no objects match' do
29
+ expect(mapper.any? { |user| user.age > 35 }).to be_false
30
+ end
31
+ end
32
+
33
+ describe '#none?' do
34
+ it 'is true when no objects match' do
35
+ expect(mapper.none? { |user| user.age == 18 }).to be_true
36
+ end
37
+
38
+ it 'is false when any objects match' do
39
+ expect(mapper.none? { |user| user.age == 28 }).to be_false
40
+ end
41
+ end
42
+
43
+ describe '#one?' do
44
+ it 'is true when one object matches' do
45
+ expect(mapper.one? { |user| user.age == 28 }).to be_true
46
+ end
47
+
48
+ it 'is false when no objects match' do
49
+ expect(mapper.one? { |user| user.age > 35 }).to be_false
50
+ end
51
+
52
+ it 'is false when more than one object matches' do
53
+ expect(mapper.one? { |user| user.age > 18 }).to be_false
54
+ end
55
+ end
56
+
57
+ describe '#count' do
58
+ it 'counts the all objects' do
59
+ expect(mapper.count).to eq(2)
60
+ end
61
+
62
+ it 'counts matching objects' do
63
+ expect(mapper.count { |user| user.age < 35 }).to eq(1)
64
+ end
65
+ end
66
+
67
+ describe '#min' do
68
+ it 'finds the minimum value' do
69
+ expect(mapper.min(:age)).to eq(28)
70
+ end
71
+ end
72
+
73
+ describe '#max' do
74
+ it 'finds the maximum value' do
75
+ expect(mapper.max(:age)).to eq(35)
76
+ end
77
+ end
78
+
79
+ describe '#minmax' do
80
+ it 'finds the minium and maximum values' do
81
+ expect(mapper.minmax(:age)).to eq([28, 35])
82
+ end
83
+ end
84
+
85
+ describe '#average' do
86
+ it 'finds the average value' do
87
+ expect(mapper.avg(:age)).to eq(31.5)
88
+ end
89
+ end
90
+
91
+ describe '#sum' do
92
+ it 'finds the total value' do
93
+ expect(mapper.sum(:age)).to eq(63)
94
+ end
95
+ end
96
+
97
+ describe '#find' do
98
+ it 'finds the object with the matching id' do
99
+ expect(mapper.find(user.id)).to eq(user)
100
+ end
101
+
102
+ it 'finds the first matching object' do
103
+ expect(mapper.find { |user| user.age > 21 }).to eq(user)
104
+ end
105
+ end
106
+
107
+ describe '#find_all' do
108
+ it 'finds all objects' do
109
+ expect(mapper.find_all.to_a).to eq([user, other_user])
110
+ end
111
+
112
+ it 'finds all matching objects' do
113
+ expect(mapper.find_all { |user| user.age < 30 }.to_a).to eq([user])
114
+ end
115
+ end
116
+
117
+ describe '#last' do
118
+ it 'finds the last matching object' do
119
+ expect(mapper.last { |user| user.age > 18 }).to eq(other_user)
120
+ end
121
+ end
122
+
123
+ describe '#select' do
124
+ it 'finds all matching objects' do
125
+ expect(mapper.select { |user| user.age < 30 }.to_a).to eq([user])
126
+ end
127
+ end
128
+
129
+ describe '#reject' do
130
+ it 'finds all non matching objects' do
131
+ expect(mapper.reject { |user| user.age == 28 }.to_a).to eq([other_user])
132
+ end
133
+ end
134
+
135
+ describe '#delete' do
136
+ it 'deletes the object' do
137
+ mapper.delete(user)
138
+
139
+ expect(mapper.find(user.id)).to be_nil
140
+ end
141
+ end
142
+
143
+ describe '#delete_if' do
144
+ it 'deletes all matching objects' do
145
+ mapper.delete_if { |user| user.age == 28 }
146
+
147
+ expect(mapper.find(user.id)).to be_nil
148
+ expect(mapper.find(other_user.id)).to eq(other_user)
149
+ end
150
+ end
151
+
152
+ describe '#clear' do
153
+ it 'deletes all objects' do
154
+ mapper.clear
155
+
156
+ expect(mapper.count).to eq(0)
157
+ end
158
+ end
159
+
160
+ describe '#keep_if' do
161
+ it 'deletes all non matching objects' do
162
+ mapper.keep_if { |user| user.age == 28 }
163
+
164
+ expect(mapper.find(user.id)).to eq(user)
165
+ expect(mapper.find(other_user.id)).to be_nil
166
+ end
167
+ end
168
+
169
+ describe '#save' do
170
+ before { mapper.clear }
171
+
172
+ it 'does not save invalid objects' do
173
+ user.stub(valid?: false)
174
+ expect(adapter).to_not receive(:insert)
175
+
176
+ expect(mapper.save(user)).to be_false
177
+ end
178
+
179
+ it 'creates unpersisted objects that are valid' do
180
+ user.stub(valid?: true)
181
+ user.id = nil
182
+
183
+ expect(adapter).to receive(:insert).with(User, user).and_return(1)
184
+ expect { mapper.save(user) }.to change(user, :id)
185
+ end
186
+
187
+ it 'updates persisted objects that are valid' do
188
+ user.stub(valid?: true)
189
+ mapper.save(user)
190
+
191
+ expect(adapter).to receive(:update).with(User, user)
192
+ expect { mapper.save(user) }.to_not change(user, :id)
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,190 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveMapper::Relation do
4
+ let(:adapter) { ActiveMapper::Adapter::Memory.new }
5
+ let(:user) { User.new(name: 'user', age: 28) }
6
+ let(:other_user) { User.new(name: 'other', age: 35) }
7
+
8
+ before do
9
+ user.id = adapter.insert(User, user)
10
+ other_user.id = adapter.insert(User, other_user)
11
+ end
12
+
13
+ def create_relation(&block)
14
+ ActiveMapper::Relation.new(User, adapter, &block)
15
+ end
16
+
17
+ describe '#any?' do
18
+ it 'is true when there are matching objects' do
19
+ relation = create_relation { |user| user.age == 28 }
20
+ expect(relation.any?).to be_true
21
+ end
22
+
23
+ it 'is false when there are no matching objects' do
24
+ relation = create_relation { |user| user.age == 18 }
25
+ expect(relation.any?).to be_false
26
+ end
27
+ end
28
+
29
+ describe '#none?' do
30
+ it 'is true when there are no matching objects' do
31
+ relation = create_relation { |user| user.age < 18 }
32
+
33
+ expect(relation.none?).to be_true
34
+ expect(relation.empty?).to be_true
35
+ end
36
+
37
+ it 'is false when there are matching objects' do
38
+ relation = create_relation { |user| user.age == 28 }
39
+
40
+ expect(relation.none?).to be_false
41
+ expect(relation.empty?).to be_false
42
+ end
43
+ end
44
+
45
+ describe '#one?' do
46
+ it 'is true when there is one matching object' do
47
+ relation = create_relation { |user| user.age == 28 }
48
+
49
+ expect(relation.one?).to be_true
50
+ end
51
+
52
+ it 'is false when there are no matching objects' do
53
+ relation = create_relation { |user| user.age < 18 }
54
+
55
+ expect(relation.one?).to be_false
56
+ end
57
+
58
+ it 'is false when there are is more than one matching object' do
59
+ relation = create_relation { |user| user.age > 18 }
60
+
61
+ expect(relation.one?).to be_false
62
+ end
63
+ end
64
+
65
+ describe '#count' do
66
+ it 'counts the number of matching objects' do
67
+ relation = create_relation { |user| user.age == 28 }
68
+
69
+ expect(relation.count).to eq(1)
70
+ expect(relation.length).to eq(1)
71
+ expect(relation.size).to eq(1)
72
+ end
73
+ end
74
+
75
+ describe '#min' do
76
+ it 'calculates the minimum value' do
77
+ expect(create_relation.min(:age)).to eql(28)
78
+ end
79
+ end
80
+
81
+ describe '#max' do
82
+ it 'calculates the maximum value' do
83
+ expect(create_relation.max(:age)).to eq(35)
84
+ end
85
+ end
86
+
87
+ describe '#minmax' do
88
+ it 'calculates the minimum and maximum values' do
89
+ expect(create_relation.minmax(:age)).to eq([28, 35])
90
+ end
91
+ end
92
+
93
+ describe '#avg' do
94
+ it 'calculates the average value' do
95
+ expect(create_relation.avg(:age)).to eq(31.5)
96
+ end
97
+ end
98
+
99
+ describe '#sum' do
100
+ it 'calculates the total value' do
101
+ expect(create_relation.sum(:age)).to eq(63)
102
+ end
103
+ end
104
+
105
+ describe '#drop' do
106
+ it 'offsets by the number of objects' do
107
+ expect(create_relation.drop(1).to_a).to eq([other_user])
108
+ end
109
+ end
110
+
111
+ describe '#select' do
112
+ it 'returns matching objects' do
113
+ relation = create_relation { |user| user.name == 'user' }.select { |user| user.age == 28 }.to_a
114
+
115
+ expect(relation).to include(user)
116
+ expect(relation).to_not include(other_user)
117
+ end
118
+ end
119
+
120
+ describe '#reject' do
121
+ it 'returns non matching objects' do
122
+ relation = create_relation { |user| user.age > 18 }.reject { |user| user.name == 'user' }.to_a
123
+
124
+ expect(relation).to include(other_user)
125
+ expect(relation).to_not include(user)
126
+ end
127
+ end
128
+
129
+ describe '#first' do
130
+ it 'returns the first matching object' do
131
+ expect(create_relation.first).to eq(user)
132
+ end
133
+
134
+ it 'returns the first number of matching objects' do
135
+ expect(create_relation.first(2)).to eq([user, other_user])
136
+ end
137
+ end
138
+
139
+ describe '#last' do
140
+ it 'returns the last matching object' do
141
+ expect(create_relation.last).to eq(other_user)
142
+ end
143
+
144
+ it 'returns the last number of matching objects' do
145
+ expect(create_relation.last(2)).to eq([other_user, user])
146
+ end
147
+ end
148
+
149
+ describe '#take' do
150
+ it 'limits the number of records returned' do
151
+ expect(create_relation.take(1).to_a).to eq([user])
152
+ end
153
+ end
154
+
155
+ describe '#to_a' do
156
+ it 'finds all matching objects' do
157
+ expect(create_relation { |user| user.age == 28 }.to_a).to eq([user])
158
+ end
159
+ end
160
+
161
+ describe '#map' do
162
+ it 'maps the objects' do
163
+ expect(create_relation.map(&:name)).to eq(['user', 'other'])
164
+ end
165
+ end
166
+
167
+ describe '#each' do
168
+ it 'iterates through the objects' do
169
+ create_relation { |user| user.age == 18 }.each { |u| expect(u).to eq(user) }
170
+ end
171
+ end
172
+
173
+ describe '#sort_by' do
174
+ it 'sorts the objects by attribute' do
175
+ relation = create_relation.sort_by(&:name).to_a
176
+
177
+ expect(relation.first).to eq(other_user)
178
+ expect(relation.last).to eq(user)
179
+ end
180
+ end
181
+
182
+ describe '#reverse' do
183
+ it 'sets the opposite direction to order by' do
184
+ relation = create_relation.sort_by(&:age).reverse.to_a
185
+
186
+ expect(relation.first).to eq(other_user)
187
+ expect(relation.last).to eq(user)
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveMapper do
4
+ describe '.[]' do
5
+ it 'returns the stored mapper' do
6
+ expect(ActiveMapper[User].mapped_class).to eql(User)
7
+ end
8
+ end
9
+
10
+ describe '.adapter' do
11
+ let(:adapter) { double('Adapter') }
12
+
13
+ it 'returns the adapter that has been set' do
14
+ ActiveMapper.adapter = adapter
15
+
16
+ expect(ActiveMapper.adapter).to eq(adapter)
17
+ end
18
+
19
+ it 'defaults to the memory store' do
20
+ ActiveMapper.adapter = nil
21
+
22
+ expect(ActiveMapper.adapter).to be_a(ActiveMapper::Adapter::Memory)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActiveMapper with ActiveRecord adapter' do
4
+ setup_active_record('active_record_integration')
5
+
6
+ it_should_behave_like 'ActiveMapper Integration', ActiveMapper::Adapter::ActiveRecord.new
7
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActiveMapper with Memory adapter' do
4
+ it_should_behave_like 'ActiveMapper Integration', ActiveMapper::Adapter::Memory.new
5
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_record'
2
+ require 'active_mapper'
3
+
4
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
5
+
6
+ # stop deprecation message
7
+ I18n.enforce_available_locales = false
8
+
9
+ class CreateUsers < ActiveRecord::Migration
10
+ def up
11
+ create_table :users do |t|
12
+ t.string :name
13
+ t.integer :age
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
18
+
19
+ def setup_active_record(name)
20
+ db = "./spec/support/db/#{name}.sqlite3"
21
+
22
+ before(:all) do
23
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: db)
24
+ CreateUsers.new.migrate(:up)
25
+ end
26
+
27
+ after(:all) do
28
+ File.delete(db)
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ class User
2
+ include ActiveModel::Model
3
+
4
+ attr_accessor :id, :name, :age, :created_at, :updated_at
5
+
6
+ validates :name, presence: true
7
+ validates :age, presence: true, numericality: { only_integer: true }
8
+
9
+ def persisted?
10
+ id
11
+ end
12
+
13
+ def ==(other)
14
+ if id
15
+ id == other.id
16
+ else
17
+ object_id == other.object_id
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,129 @@
1
+ shared_examples_for 'ActiveMapper Integration' do |adapter|
2
+ let(:mapper) { ActiveMapper::Mapper.new(User, adapter) }
3
+ let(:user) { User.new(name: 'user', age: 28) }
4
+ let(:other_user) { User.new(name: 'other', age: 35) }
5
+
6
+ after { mapper.clear }
7
+
8
+ it 'can create and modify records' do
9
+ mapper.save(user)
10
+ user.name = 'Changed'
11
+ user.age = 18
12
+ mapper.save(user)
13
+
14
+ record = mapper.find(user.id)
15
+
16
+ expect(record.name).to eq('Changed')
17
+ expect(record.age).to eq(18)
18
+ end
19
+
20
+ it 'can delete records' do
21
+ mapper.save(user)
22
+ mapper.delete(user)
23
+
24
+ expect(mapper.find(user.id)).to be_nil
25
+
26
+ user.id = nil
27
+
28
+ mapper.save(user)
29
+ mapper.save(other_user)
30
+ mapper.clear
31
+
32
+ expect(mapper.count).to eq(0)
33
+
34
+ user.id = nil
35
+ other_user.id = nil
36
+
37
+ mapper.save(user)
38
+ mapper.save(other_user)
39
+ mapper.delete_if { |user| user.age < 35 }
40
+
41
+ expect(mapper.find(other_user.id)).to eq(other_user)
42
+ expect(mapper.find(user.id)).to be_nil
43
+
44
+ user.id = nil
45
+ other_user.id = nil
46
+
47
+ mapper.save(user)
48
+ mapper.save(other_user)
49
+ mapper.keep_if { |user| user.age < 35 }
50
+
51
+ expect(mapper.find(user.id)).to eq(user)
52
+ expect(mapper.find(other_user.id)).to be_nil
53
+ end
54
+
55
+ it 'can retrieve the first, last and all records' do
56
+ mapper.save(user)
57
+ mapper.save(other_user)
58
+
59
+ expect(mapper.first).to eq(user)
60
+ expect(mapper.last).to eq(other_user)
61
+
62
+ records = mapper.find_all.to_a
63
+
64
+ expect(records).to include(user)
65
+ expect(records).to include(other_user)
66
+ end
67
+
68
+ it 'can count records' do
69
+ mapper.save(user)
70
+ mapper.save(other_user)
71
+
72
+ expect(mapper.count).to eq(2)
73
+ expect(mapper.count { |user| user.age < 35 }).to eq(1)
74
+ end
75
+
76
+ it 'can query for records' do
77
+ mapper.save(user)
78
+ mapper.save(other_user)
79
+
80
+ expect(mapper.reject { |user| user.name == 'user' }.to_a).to eq([other_user])
81
+ expect(mapper.first { |user| user.name.in 'user' }).to eq(user)
82
+ expect(mapper.first { |user| user.name.not_in 'user' }).to eq(other_user)
83
+ expect(mapper.first { |user| user.name.starts_with 'us' }).to eq(user)
84
+ expect(mapper.first { |user| user.name.contains 'th' }).to eq(other_user)
85
+ expect(mapper.first { |user| user.name.ends_with 'er' }).to eq(user)
86
+ expect(mapper.first { |user| user.name == 'user' }).to eq(user)
87
+ expect(mapper.first { |user| user.name != 'user' }).to eq(other_user)
88
+ expect(mapper.first { |user| user.age > 30 }).to eq(other_user)
89
+ expect(mapper.first { |user| user.age >= 35 }).to eq(other_user)
90
+ expect(mapper.first { |user| user.age < 35 }).to eq(user)
91
+ expect(mapper.first { |user| user.age <= 28 }).to eq(user)
92
+ expect(mapper.first { |user| !(user.age == 28) }).to eq(other_user)
93
+ expect(mapper.first { |user| (user.name == 'user') & (user.age > 18) }).to eq(user)
94
+ expect(mapper.first { |user| (user.name == 'other') | (user.age == 35) }).to eq(other_user)
95
+ end
96
+
97
+ it 'can aggregate data' do
98
+ mapper.save(user)
99
+ mapper.save(other_user)
100
+
101
+ expect(mapper.max(:age)).to eq(35)
102
+ expect(mapper.min(:age)).to eq(28)
103
+ expect(mapper.minmax(:age)).to eq([28, 35])
104
+ expect(mapper.avg(:age)).to eq(31.5)
105
+ expect(mapper.sum(:age)).to eq(63)
106
+ end
107
+
108
+ it 'can sort records' do
109
+ other_user.age = user.age
110
+
111
+ mapper.save(user)
112
+ mapper.save(other_user)
113
+
114
+ records = mapper.find_all.sort_by { |user| [user.name, user.age] }.to_a
115
+
116
+ expect(records.first).to eq(other_user)
117
+ expect(records.last).to eq(user)
118
+
119
+ records = mapper.find_all.sort_by { |user| [user.age, -user.name] }.to_a
120
+
121
+ expect(records.first).to eq(user)
122
+ expect(records.last).to eq(other_user)
123
+
124
+ records = mapper.find_all.sort_by { |user| [user.age, -user.name] }.reverse.to_a
125
+
126
+ expect(records.first).to eq(other_user)
127
+ expect(records.last).to eq(user)
128
+ end
129
+ end