vorpal 1.0.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -26
  3. data/lib/vorpal/aggregate_mapper.rb +13 -2
  4. data/lib/vorpal/aggregate_traversal.rb +9 -8
  5. data/lib/vorpal/config/association_config.rb +84 -0
  6. data/lib/vorpal/config/belongs_to_config.rb +35 -0
  7. data/lib/vorpal/config/class_config.rb +71 -0
  8. data/lib/vorpal/config/configs.rb +54 -0
  9. data/lib/vorpal/config/foreign_key_info.rb +23 -0
  10. data/lib/vorpal/config/has_many_config.rb +38 -0
  11. data/lib/vorpal/config/has_one_config.rb +35 -0
  12. data/lib/vorpal/config/main_config.rb +68 -0
  13. data/lib/vorpal/db_loader.rb +25 -22
  14. data/lib/vorpal/driver/postgresql.rb +42 -6
  15. data/lib/vorpal/dsl/config_builder.rb +26 -73
  16. data/lib/vorpal/dsl/configuration.rb +139 -42
  17. data/lib/vorpal/dsl/defaults_generator.rb +1 -1
  18. data/lib/vorpal/engine.rb +27 -13
  19. data/lib/vorpal/exceptions.rb +4 -0
  20. data/lib/vorpal/identity_map.rb +7 -2
  21. data/lib/vorpal/loaded_objects.rb +57 -14
  22. data/lib/vorpal/util/array_hash.rb +22 -8
  23. data/lib/vorpal/util/hash_initialization.rb +1 -1
  24. data/lib/vorpal/version.rb +1 -1
  25. data/vorpal.gemspec +4 -5
  26. metadata +18 -78
  27. data/.editorconfig +0 -13
  28. data/.envrc +0 -4
  29. data/.gitignore +0 -16
  30. data/.rspec +0 -1
  31. data/.ruby-version +0 -1
  32. data/.travis.yml +0 -18
  33. data/.yardopts +0 -1
  34. data/Appraisals +0 -18
  35. data/Gemfile +0 -4
  36. data/Rakefile +0 -39
  37. data/bin/appraisal +0 -29
  38. data/bin/rake +0 -29
  39. data/bin/rspec +0 -29
  40. data/docker-compose.yml +0 -19
  41. data/gemfiles/rails_5_1.gemfile +0 -11
  42. data/gemfiles/rails_5_1.gemfile.lock +0 -101
  43. data/gemfiles/rails_5_2.gemfile +0 -11
  44. data/gemfiles/rails_5_2.gemfile.lock +0 -101
  45. data/gemfiles/rails_6_0.gemfile +0 -9
  46. data/gemfiles/rails_6_0.gemfile.lock +0 -101
  47. data/lib/vorpal/configs.rb +0 -296
  48. data/spec/acceptance/vorpal/aggregate_mapper_spec.rb +0 -910
  49. data/spec/helpers/codecov_helper.rb +0 -7
  50. data/spec/helpers/db_helpers.rb +0 -69
  51. data/spec/helpers/profile_helpers.rb +0 -26
  52. data/spec/integration/vorpal/driver/postgresql_spec.rb +0 -42
  53. data/spec/integration_spec_helper.rb +0 -29
  54. data/spec/performance/vorpal/performance_spec.rb +0 -305
  55. data/spec/unit/vorpal/configs_spec.rb +0 -117
  56. data/spec/unit/vorpal/db_loader_spec.rb +0 -103
  57. data/spec/unit/vorpal/dsl/config_builder_spec.rb +0 -18
  58. data/spec/unit/vorpal/dsl/defaults_generator_spec.rb +0 -75
  59. data/spec/unit/vorpal/identity_map_spec.rb +0 -62
  60. data/spec/unit/vorpal/loaded_objects_spec.rb +0 -22
  61. data/spec/unit/vorpal/util/string_utils_spec.rb +0 -25
  62. data/spec/unit_spec_helper.rb +0 -1
@@ -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
@@ -1,18 +0,0 @@
1
- require 'unit_spec_helper'
2
-
3
- require 'vorpal/dsl/config_builder'
4
-
5
- describe Vorpal::Dsl::ConfigBuilder do
6
- class Tester; end
7
-
8
- let(:builder) { Vorpal::Dsl::ConfigBuilder.new(Tester, {}, nil) }
9
-
10
- describe 'mapping attributes' do
11
- it 'allows the \'attributes\' method to be called multiple times' do
12
- builder.attributes :first
13
- builder.attributes :second
14
-
15
- expect(builder.attributes_with_id).to eq([:id, :first, :second])
16
- end
17
- end
18
- end
@@ -1,75 +0,0 @@
1
- require 'unit_spec_helper'
2
-
3
- require 'vorpal/dsl/defaults_generator'
4
- require 'vorpal/driver/postgresql'
5
-
6
- describe Vorpal::Dsl::DefaultsGenerator do
7
- class Tester; end
8
- class Author; end
9
- module Namespace
10
- class Tester; end
11
- class Author; end
12
- end
13
-
14
- let(:db_driver) { instance_double(Vorpal::Driver::Postgresql)}
15
-
16
- describe '#build_db_class' do
17
- it 'derives the table_name from the domain class name' do
18
- generator = build_generator(Tester)
19
- expect(db_driver).to receive(:build_db_class).with(Tester, "testers")
20
-
21
- generator.build_db_class(nil)
22
- end
23
-
24
- it 'specifies the table_name manually' do
25
- generator = build_generator(Tester)
26
- expect(db_driver).to receive(:build_db_class).with(Tester, "override")
27
-
28
- generator.build_db_class("override")
29
- end
30
- end
31
-
32
- describe '#table_name' do
33
- it 'namespaces the table name' do
34
- generator = build_generator(Namespace::Tester)
35
-
36
- expect(generator.table_name).to eq("namespace/testers")
37
- end
38
- end
39
-
40
- describe '#child_class' do
41
- it 'resolves the associated class' do
42
- generator = build_generator(Tester)
43
- clazz = generator.child_class("author")
44
-
45
- expect(clazz.name).to eq("Author")
46
- end
47
-
48
- it 'resolves the associated class in the same namespace as the owning class' do
49
- generator = build_generator(Namespace::Tester)
50
- clazz = generator.child_class("author")
51
-
52
- expect(clazz.name).to eq("Namespace::Author")
53
- end
54
- end
55
-
56
- describe '#foreign_key' do
57
- it 'generates a foreign key from an association name' do
58
- generator = build_generator(Tester)
59
- fk_name = generator.foreign_key("author")
60
-
61
- expect(fk_name).to eq("author_id")
62
- end
63
-
64
- it 'generates a foreign key from an association name regardless of the namespace of the owning class' do
65
- generator = build_generator(Namespace::Tester)
66
- fk_name = generator.foreign_key("author")
67
-
68
- expect(fk_name).to eq("author_id")
69
- end
70
- end
71
-
72
- def build_generator(domain_clazz)
73
- Vorpal::Dsl::DefaultsGenerator.new(domain_clazz, db_driver)
74
- end
75
- end
@@ -1,62 +0,0 @@
1
- require 'unit_spec_helper'
2
-
3
- require 'vorpal/identity_map'
4
-
5
- describe Vorpal::IdentityMap do
6
- let(:map) { Vorpal::IdentityMap.new }
7
-
8
- it "does not rely on the key object's implementation of hash and eql?" do
9
- funny1 = build_funny_entity(1)
10
- map.set(funny1, 'funny 1')
11
-
12
- funny2 = build_funny_entity(2)
13
- map.set(funny2, 'funny 2')
14
-
15
- expect(map.get(funny1)).to eq('funny 1')
16
- end
17
-
18
- it "raises an exception when the key object does not have an id set" do
19
- entity = build_entity(nil)
20
-
21
- expect { map.set(entity, 'something') }.to raise_error(/Cannot map a DB row/)
22
- end
23
-
24
- it 'raises an exception when the key object extends a class with no name (such as anonymous classes)' do
25
- anonymous_class = Class.new do
26
- attr_accessor :id
27
- end
28
-
29
- entity = anonymous_class.new
30
- entity.id = 1
31
-
32
- expect { map.set(entity, 'something') }.to raise_error(/Cannot map a DB row/)
33
- end
34
-
35
- def build_entity(id)
36
- entity = Entity.new
37
- entity.id = id
38
- entity
39
- end
40
-
41
- class Entity
42
- attr_accessor :id
43
- end
44
-
45
- def build_funny_entity(id)
46
- funny1 = Funny.new
47
- funny1.id = id
48
- funny1
49
- end
50
-
51
- class Funny
52
- attr_accessor :id
53
-
54
- def hash
55
- 1
56
- end
57
-
58
- def eql?(other)
59
- true
60
- end
61
- end
62
- end
@@ -1,22 +0,0 @@
1
- require 'unit_spec_helper'
2
-
3
- require 'virtus'
4
- require 'vorpal/loaded_objects'
5
- require 'vorpal/configs'
6
-
7
- describe Vorpal::LoadedObjects do
8
- class TestObject
9
- include Virtus.model
10
- attribute :id, Integer
11
- end
12
-
13
- it 'does not accept duplicate objects' do
14
- object = TestObject.new(id: 22)
15
- config = Vorpal::ClassConfig.new({domain_class: Object})
16
-
17
- subject.add(config, [object, object])
18
- subject.add(config, [object])
19
-
20
- expect(subject.objects.values.flatten).to contain_exactly(object)
21
- end
22
- end
@@ -1,25 +0,0 @@
1
- require 'unit_spec_helper'
2
- require 'vorpal/util/string_utils'
3
-
4
- describe Vorpal::Util::StringUtils do
5
-
6
- describe '.escape_class_name' do
7
- it 'does nothing when there are no :: in the class name' do
8
- expect(escape_class_name("Foo")).to eq("Foo")
9
- end
10
-
11
- it 'converts :: into __' do
12
- expect(escape_class_name("Foo::Bar")).to eq("Foo__Bar")
13
- end
14
-
15
- it 'converts multiple :: into __' do
16
- expect(escape_class_name("Foo::Bar::Baz")).to eq("Foo__Bar__Baz")
17
- end
18
- end
19
-
20
- private
21
-
22
- def escape_class_name(class_name)
23
- Vorpal::Util::StringUtils.escape_class_name(class_name)
24
- end
25
- end
@@ -1 +0,0 @@
1
- require 'helpers/codecov_helper'