vorpal 1.0.1 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +72 -56
  3. data/lib/vorpal/aggregate_mapper.rb +11 -0
  4. data/lib/vorpal/config/class_config.rb +71 -0
  5. data/lib/vorpal/configs.rb +9 -66
  6. data/lib/vorpal/driver/postgresql.rb +39 -3
  7. data/lib/vorpal/dsl/config_builder.rb +12 -50
  8. data/lib/vorpal/dsl/configuration.rb +131 -42
  9. data/lib/vorpal/dsl/defaults_generator.rb +14 -4
  10. data/lib/vorpal/engine.rb +18 -5
  11. data/lib/vorpal/identity_map.rb +15 -14
  12. data/lib/vorpal/version.rb +1 -1
  13. data/vorpal.gemspec +9 -9
  14. metadata +36 -88
  15. data/.editorconfig +0 -13
  16. data/.envrc +0 -4
  17. data/.gitignore +0 -16
  18. data/.rspec +0 -1
  19. data/.yardopts +0 -1
  20. data/Appraisals +0 -34
  21. data/Gemfile +0 -4
  22. data/Rakefile +0 -10
  23. data/bin/appraisal +0 -29
  24. data/bin/rake +0 -29
  25. data/bin/rspec +0 -29
  26. data/gemfiles/rails_4_1.gemfile +0 -11
  27. data/gemfiles/rails_4_1.gemfile.lock +0 -92
  28. data/gemfiles/rails_4_2.gemfile +0 -11
  29. data/gemfiles/rails_4_2.gemfile.lock +0 -90
  30. data/gemfiles/rails_5_0.gemfile +0 -11
  31. data/gemfiles/rails_5_0.gemfile.lock +0 -88
  32. data/gemfiles/rails_5_1.gemfile +0 -11
  33. data/gemfiles/rails_5_1.gemfile.lock +0 -88
  34. data/gemfiles/rails_5_2.gemfile +0 -11
  35. data/gemfiles/rails_5_2.gemfile.lock +0 -88
  36. data/spec/helpers/db_helpers.rb +0 -66
  37. data/spec/helpers/profile_helpers.rb +0 -26
  38. data/spec/integration_spec_helper.rb +0 -36
  39. data/spec/unit_spec_helper.rb +0 -0
  40. data/spec/vorpal/acceptance/aggregate_mapper_spec.rb +0 -911
  41. data/spec/vorpal/integration/driver/postgresql_spec.rb +0 -42
  42. data/spec/vorpal/performance/performance_spec.rb +0 -235
  43. data/spec/vorpal/unit/configs_spec.rb +0 -117
  44. data/spec/vorpal/unit/db_loader_spec.rb +0 -103
  45. data/spec/vorpal/unit/dsl/config_builder_spec.rb +0 -18
  46. data/spec/vorpal/unit/dsl/defaults_generator_spec.rb +0 -75
  47. data/spec/vorpal/unit/identity_map_spec.rb +0 -62
  48. data/spec/vorpal/unit/loaded_objects_spec.rb +0 -22
  49. data/spec/vorpal/unit/util/string_utils_spec.rb +0 -25
@@ -1,42 +0,0 @@
1
- require 'integration_spec_helper'
2
- require 'vorpal'
3
-
4
- describe Vorpal::Driver::Postgresql do
5
- describe '#build_db_class' do
6
- let(:db_class) { subject.build_db_class(PostgresDriverSpec::Foo, 'example') }
7
-
8
- it 'generates a valid class name so that rails auto-reloading works' do
9
- expect { Vorpal.const_defined?(db_class.name) }.to_not raise_error
10
- end
11
-
12
- it 'does not let the user access the generated class' do
13
- expect { Vorpal.const_get(db_class.name) }.to raise_error(NameError)
14
- end
15
-
16
- it 'isolates two POROs that map to the same db table' do
17
- db_class1 = build_db_class(PostgresDriverSpec::Foo)
18
- db_class2 = build_db_class(PostgresDriverSpec::Bar)
19
-
20
- expect(db_class1).to_not eq(db_class2)
21
- expect(db_class1.name).to_not eq(db_class2.name)
22
- end
23
-
24
- it 'uses the model class name to make the generated AR::Base class name unique' do
25
- db_class = build_db_class(PostgresDriverSpec::Foo)
26
-
27
- expect(db_class.name).to match("PostgresDriverSpec__Foo")
28
- end
29
- end
30
-
31
- private
32
-
33
- module PostgresDriverSpec
34
- class Foo; end
35
- class Bar; end
36
- end
37
-
38
- def build_db_class(clazz)
39
- db_driver = Vorpal::Driver::Postgresql.new
40
- db_driver.build_db_class(clazz, 'example')
41
- end
42
- end
@@ -1,235 +0,0 @@
1
- require 'integration_spec_helper'
2
- require 'vorpal'
3
- require 'virtus'
4
- require 'activerecord-import/base'
5
-
6
- module Performance
7
- describe 'performance' do
8
-
9
- class Bug
10
- include Virtus.model
11
-
12
- attribute :id, Integer
13
- attribute :name, String
14
- attribute :lives_on, Object
15
- end
16
-
17
- class Tree; end
18
-
19
- class Trunk
20
- include Virtus.model
21
-
22
- attribute :id, Integer
23
- attribute :length, Decimal
24
- attribute :bugs, Array[Bug]
25
- attribute :tree, Tree
26
- end
27
-
28
- class Branch
29
- include Virtus.model
30
-
31
- attribute :id, Integer
32
- attribute :length, Decimal
33
- attribute :tree, Tree
34
- attribute :branches, Array[Branch]
35
- attribute :bugs, Array[Bug]
36
-
37
- def add_branch(branch_options)
38
- branch = Branch.new(branch_options.merge(branch: self))
39
- branches << branch
40
- branch
41
- end
42
- end
43
-
44
- class Tree
45
- include Virtus.model
46
-
47
- attribute :id, Integer
48
- attribute :name, String
49
- attribute :trunk, Trunk
50
- attribute :branches, Array[Branch]
51
-
52
- def set_trunk(trunk)
53
- trunk.tree = self
54
- self.trunk = trunk
55
- end
56
-
57
- def add_branch(branch_options)
58
- branch = Branch.new(branch_options.merge(tree: self))
59
- branches << branch
60
- branch
61
- end
62
- end
63
-
64
- before(:all) do
65
- define_table('branches_perf', {length: :decimal, tree_id: :integer, branch_id: :integer}, false)
66
- define_table('bugs_perf', {name: :text, lives_on_id: :integer, lives_on_type: :string}, false)
67
- define_table('trees_perf', {name: :text, trunk_id: :integer}, false)
68
- define_table('trunks_perf', {length: :decimal}, false)
69
- end
70
-
71
- let(:tree_mapper) { build_mapper }
72
-
73
- # Vorpal 0.0.5:
74
- # user system total real
75
- # create 4.160000 0.440000 4.600000 ( 6.071752)
76
- # update 7.990000 0.730000 8.720000 ( 15.281017)
77
- # load 10.120000 0.730000 10.850000 ( 21.087785)
78
- # destroy 6.090000 0.620000 6.710000 ( 12.541420)
79
- #
80
- # Vorpal 0.0.6:
81
- # user system total real
82
- # create 0.990000 0.100000 1.090000 ( 1.415715)
83
- # update 2.240000 0.180000 2.420000 ( 2.745321)
84
- # load 2.130000 0.020000 2.150000 ( 2.223182)
85
- # destroy 0.930000 0.010000 0.940000 ( 1.038624)
86
- #
87
- # Vorpal 0.1.0:
88
- # user system total real
89
- # create 0.870000 0.100000 0.970000 ( 1.320534)
90
- # update 1.820000 0.210000 2.030000 ( 2.351518)
91
- # load 1.310000 0.010000 1.320000 ( 1.394192)
92
- # destroy 0.930000 0.010000 0.940000 ( 1.030910)
93
- #
94
- # Vorpal 1.0.0, Ruby 2.1.6, ActiveRecord 4.1.16, AR:Import 0.10.0
95
- # user system total real
96
- # create 0.980000 0.140000 1.120000 ( 1.671115)
97
- # update 2.030000 0.250000 2.280000 ( 2.748697)
98
- # load 1.230000 0.010000 1.240000 ( 1.395219)
99
- # destroy 0.830000 0.010000 0.840000 ( 1.042960)
100
- #
101
- # Vorpal 1.0.0, Ruby 2.3.3, ActiveRecord 4.1.16, AR:Import 0.10.0
102
- # user system total real
103
- # create 0.940000 0.120000 1.060000 ( 1.579334)
104
- # update 1.880000 0.250000 2.130000 ( 2.601979)
105
- # load 1.130000 0.010000 1.140000 ( 1.292817)
106
- # destroy 0.730000 0.000000 0.730000 ( 0.930980)
107
- #
108
- # Vorpal 1.0.0, Ruby 2.3.3, ActiveRecord 4.2.10, AR:Import 0.10.0
109
- # user system total real
110
- # create 1.230000 0.130000 1.360000 ( 1.864400)
111
- # update 2.660000 0.260000 2.920000 ( 3.416604)
112
- # load 1.310000 0.010000 1.320000 ( 1.479030)
113
- # destroy 0.840000 0.010000 0.850000 ( 1.037512)
114
- #
115
- # Vorpal 1.0.0, Ruby 2.3.3, ActiveRecord 5.0.7, AR:Import 0.13.0
116
- # user system total real
117
- # create 0.960000 0.120000 1.080000 ( 1.631415)
118
- # update 2.810000 0.270000 3.080000 ( 3.633569)
119
- # load 1.340000 0.010000 1.350000 ( 1.510898)
120
- # destroy 0.900000 0.010000 0.910000 ( 1.085288)
121
- #
122
- # Vorpal 1.0.0, Ruby 2.3.3, ActiveRecord 5.1.6, AR:Import 0.13.0
123
- # create 0.960000 0.120000 1.080000 ( 1.588142)
124
- # update 3.030000 0.290000 3.320000 ( 3.839557)
125
- # load 1.340000 0.010000 1.350000 ( 1.509182)
126
- # destroy 0.950000 0.010000 0.960000 ( 1.155866)
127
- #
128
- # Vorpal 1.0.0, Ruby 2.3.3, ActiveRecord 5.1.6, AR:Import 0.13.0
129
- # create 0.920000 0.120000 1.040000 ( 1.534410)
130
- # update 3.010000 0.290000 3.300000 ( 3.850101)
131
- # load 1.380000 0.010000 1.390000 ( 1.561047)
132
- # destroy 1.050000 0.010000 1.060000 ( 1.260379)
133
- it 'benchmarks all operations' do
134
- trees = build_trees(1000)
135
- Benchmark.bm(7) do |x|
136
- x.report('create') { tree_mapper.persist(trees) }
137
- x.report('update') { tree_mapper.persist(trees) }
138
- x.report('load') { tree_mapper.query.where(id: trees.map(&:id)).load_many }
139
- x.report('destroy') { tree_mapper.destroy(trees) }
140
- end
141
- end
142
-
143
- # it 'creates aggregates quickly' do
144
- # trees = build_trees(1000)
145
- #
146
- # puts 'starting persistence benchmark'
147
- # puts Benchmark.measure {
148
- # tree_mapper.persist(trees)
149
- # }
150
- # end
151
- #
152
- # it 'updates aggregates quickly' do
153
- # trees = build_trees(1000)
154
- #
155
- # tree_mapper.persist(trees)
156
- #
157
- # puts 'starting update benchmark'
158
- # puts Benchmark.measure {
159
- # tree_mapper.persist(trees)
160
- # }
161
- # end
162
- #
163
- # it 'loads aggregates quickly' do
164
- # trees = build_trees(1000)
165
- # tree_mapper.persist(trees)
166
- # ids = trees.map(&:id)
167
- #
168
- # puts 'starting loading benchmark'
169
- # puts Benchmark.measure {
170
- # tree_mapper.query.where(id: ids).load_many
171
- # }
172
- # end
173
- #
174
- # it 'destroys aggregates quickly' do
175
- # trees = build_trees(1000)
176
- # tree_mapper.persist(trees)
177
- #
178
- # puts 'starting destruction benchmark'
179
- # puts Benchmark.measure {
180
- # tree_mapper.destroy(trees)
181
- # }
182
- # end
183
-
184
- def build_trees(count)
185
- (1..count).map do |i|
186
- tree = Tree.new
187
- trunk = Trunk.new(length: i)
188
- tree.set_trunk(trunk)
189
-
190
- branch1 = tree.add_branch(length: i * 10)
191
- branch2 = tree.add_branch(length: i * 20)
192
- branch2.add_branch(length: i * 30)
193
-
194
- build_bug(trunk)
195
- build_bug(branch1)
196
-
197
- tree
198
- end
199
- end
200
-
201
- def build_bug(bug_home)
202
- bug = Bug.new(lives_on: bug_home)
203
- bug_home.bugs = [bug]
204
- end
205
-
206
- def build_mapper
207
- engine = Vorpal.define do
208
- map Tree, table_name: "trees_perf" do
209
- attributes :name
210
- belongs_to :trunk
211
- has_many :branches
212
- end
213
-
214
- map Trunk, table_name: "trunks_perf" do
215
- attributes :length
216
- has_one :tree
217
- has_many :bugs, fk: :lives_on_id, fk_type: :lives_on_type
218
- end
219
-
220
- map Branch, table_name: "branches_perf" do
221
- attributes :length
222
- belongs_to :tree
223
- has_many :bugs, fk: :lives_on_id, fk_type: :lives_on_type
224
- has_many :branches
225
- end
226
-
227
- map Bug, table_name: "bugs_perf" do
228
- attributes :name
229
- belongs_to :lives_on, fk: :lives_on_id, fk_type: :lives_on_type, child_classes: [Trunk, Branch]
230
- end
231
- end
232
- engine.mapper_for(Tree)
233
- end
234
- end
235
- end
@@ -1,117 +0,0 @@
1
- require 'unit_spec_helper'
2
- require 'vorpal/configs'
3
-
4
- describe Vorpal::MasterConfig do
5
- class Post
6
- attr_accessor :comments
7
- attr_accessor :best_comment
8
- end
9
-
10
- class Comment
11
- attr_accessor :post
12
- end
13
-
14
- let(:post_config) { Vorpal::ClassConfig.new(domain_class: Post) }
15
- let(:comment_config) { Vorpal::ClassConfig.new(domain_class: Comment) }
16
- let(:post_has_many_comments_config) { Vorpal::HasManyConfig.new(name: 'comments', fk: 'post_id', child_class: Comment) }
17
- let(:post_has_one_comment_config) { Vorpal::HasOneConfig.new(name: 'best_comment', fk: 'post_id', child_class: Comment) }
18
- let(:comment_belongs_to_post_config) { Vorpal::BelongsToConfig.new(name: 'post', fk: 'post_id', child_classes: [Post]) }
19
-
20
- describe 'local_association_configs' do
21
- it 'builds an association_config for a belongs_to' do
22
- comment_config.belongs_tos << comment_belongs_to_post_config
23
-
24
- Vorpal::MasterConfig.new([post_config, comment_config])
25
-
26
- expect(comment_config.local_association_configs.size).to eq(1)
27
- expect(post_config.local_association_configs.size).to eq(0)
28
- end
29
-
30
- it 'sets the association end configs' do
31
- comment_config.belongs_tos << comment_belongs_to_post_config
32
- post_config.has_manys << post_has_many_comments_config
33
-
34
- Vorpal::MasterConfig.new([post_config, comment_config])
35
-
36
- association_config = comment_config.local_association_configs.first
37
-
38
- expect(association_config.remote_end_config).to eq(post_has_many_comments_config)
39
- expect(association_config.local_end_config).to eq(comment_belongs_to_post_config)
40
- end
41
-
42
- it 'builds an association_config for a has_many' do
43
- post_config.has_manys << post_has_many_comments_config
44
-
45
- Vorpal::MasterConfig.new([post_config, comment_config])
46
-
47
- expect(comment_config.local_association_configs.size).to eq(1)
48
- expect(post_config.local_association_configs.size).to eq(0)
49
- end
50
- end
51
-
52
- describe 'nice user feedback' do
53
- it 'lets the user know what the problem is when a configuration is missing' do
54
- master_config = Vorpal::MasterConfig.new([])
55
-
56
- expect {
57
- master_config.config_for(String)
58
- }.to raise_error(Vorpal::ConfigurationNotFound, "No configuration found for String")
59
- end
60
- end
61
-
62
- describe Vorpal::AssociationConfig do
63
- describe 'associate' do
64
- let(:post) { Post.new }
65
- let(:comment) { Comment.new }
66
-
67
- it 'sets both ends of a one-to-one association' do
68
- config = Vorpal::AssociationConfig.new(comment_config, 'post_id', nil)
69
- config.add_remote_class_config(post_config)
70
-
71
- config.local_end_config = comment_belongs_to_post_config
72
- config.remote_end_config = post_has_one_comment_config
73
-
74
- config.associate(comment, post)
75
-
76
- expect(comment.post).to eq(post)
77
- expect(post.best_comment).to eq(comment)
78
- end
79
-
80
- it 'sets both ends of a one-to-many association' do
81
- config = Vorpal::AssociationConfig.new(comment_config, 'post_id', nil)
82
- config.add_remote_class_config(post_config)
83
-
84
- config.local_end_config = comment_belongs_to_post_config
85
- config.remote_end_config = post_has_many_comments_config
86
-
87
- config.associate(comment, post)
88
-
89
- expect(comment.post).to eq(post)
90
- expect(post.comments).to eq([comment])
91
- end
92
- end
93
-
94
- describe 'remote_class_config' do
95
- it 'works with non-polymorphic associations' do
96
- config = Vorpal::AssociationConfig.new(comment_config, 'post_id', nil)
97
- config.add_remote_class_config(post_config)
98
-
99
- post = Post.new
100
- class_config = config.remote_class_config(post)
101
-
102
- expect(class_config).to eq(post_config)
103
- end
104
-
105
- it 'works with polymorphic associations' do
106
- config = Vorpal::AssociationConfig.new(comment_config, 'commented_upon_id', 'commented_upon_type')
107
- config.add_remote_class_config(post_config)
108
- config.add_remote_class_config(comment_config)
109
-
110
- comment = double('comment', commented_upon_type: 'Comment')
111
- class_config = config.remote_class_config(comment)
112
-
113
- expect(class_config).to eq(comment_config)
114
- end
115
- end
116
- end
117
- end
@@ -1,103 +0,0 @@
1
- require 'unit_spec_helper'
2
- require 'vorpal'
3
- require 'virtus'
4
-
5
- describe Vorpal::DbLoader do
6
-
7
- class Post; end
8
-
9
- class Comment
10
- include Virtus.model
11
-
12
- attribute :id, Integer
13
- attribute :post, Post
14
- end
15
-
16
- class Post
17
- include Virtus.model
18
-
19
- attribute :id, Integer
20
- attribute :best_comment, Comment
21
- attribute :comments, Array[Comment]
22
- end
23
-
24
- class PostDB
25
- include Virtus.model
26
- attribute :id, Integer
27
- attribute :best_comment_id, Integer
28
- end
29
-
30
- class CommentDB
31
- include Virtus.model
32
- attribute :id, Integer
33
- attribute :post_id, Integer
34
- end
35
-
36
- before(:all) do
37
- # define_table('comments', {post_id: :integer}, false)
38
- # CommentDB = defineAr('comments')
39
-
40
- # define_table('posts', {best_comment_id: :integer}, false)
41
- # PostDB = defineAr('posts')
42
- end
43
-
44
- # it 'loads an object once even when referred to by different associations of different types2' do
45
- # post_config = Vorpal.build_class_config(Post) do
46
- # attributes :name
47
- # belongs_to :best_comment, child_class: Comment
48
- # has_many :comments
49
- # end
50
- #
51
- # comment_config = Vorpal.build_class_config(Comment) do
52
- # attributes :length
53
- # end
54
- #
55
- # master_config = Vorpal::MasterConfig.new([post_config, comment_config])
56
- #
57
- # driver = Vorpal::Postgresql.new
58
- #
59
- # best_comment_db = CommentDB.create!
60
- # post_db = PostDB.create!(best_comment_id: best_comment_db.id)
61
- # best_comment_db.update_attributes!(post_id: post_db.id)
62
- #
63
- # loader = Vorpal::DbLoader.new(false, driver)
64
- # loaded_objects = loader.load_from_db([post_db.id], master_config.config_for(Post))
65
- # p loaded_objects.all_objects
66
- # # expect(loaded_objects.all_objects.size).to eq(2)
67
- #
68
- # repo = Vorpal::AggregateMapper.new(driver, master_config)
69
- # post = repo.load(post_db.id, Post)
70
- # p post
71
- # expect(post.comments.size).to eq(1)
72
- # end
73
-
74
- it 'loads an object once even when referred to by different associations of different types with stubs' do
75
- post_config = Vorpal.build_class_config(Post, to: PostDB) do
76
- attributes :name
77
- belongs_to :best_comment, child_class: Comment
78
- has_many :comments
79
- end
80
-
81
- comment_config = Vorpal.build_class_config(Comment, to: CommentDB) do
82
- attributes :length
83
- end
84
-
85
- Vorpal::MasterConfig.new([post_config, comment_config])
86
-
87
- best_comment_db = CommentDB.new
88
- best_comment_db.id = 99
89
- post_db = PostDB.new(best_comment_id: best_comment_db.id)
90
- post_db.id = 100
91
- best_comment_db.post_id = post_db.id
92
-
93
- driver = instance_double("Vorpal::Driver::Postgresql")
94
- expect(driver).to receive(:load_by_id).with(PostDB, [post_db.id]).and_return([post_db])
95
- expect(driver).to receive(:load_by_id).with(CommentDB, [best_comment_db.id]).and_return([best_comment_db])
96
- expect(driver).to receive(:load_by_foreign_key).and_return([best_comment_db])
97
-
98
- loader = Vorpal::DbLoader.new(false, driver)
99
- loaded_objects = loader.load_from_db([post_db.id], post_config)
100
-
101
- expect(loaded_objects.all_objects).to contain_exactly(post_db, best_comment_db)
102
- end
103
- end