vorpal 0.0.6 → 0.0.7.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +9 -17
- data/lib/vorpal/aggregate_repository.rb +6 -0
- data/lib/vorpal/config_builder.rb +40 -19
- data/lib/vorpal/configs.rb +7 -7
- data/lib/vorpal/configuration.rb +3 -3
- data/lib/vorpal/db_driver.rb +9 -0
- data/lib/vorpal/version.rb +1 -1
- data/lib/vorpal.rb +3 -3
- data/spec/vorpal/acceptance/aggregate_repository_spec.rb +25 -34
- data/spec/vorpal/{acceptance → performance}/performance_spec.rb +4 -4
- data/spec/vorpal/unit/config_builder_spec.rb +67 -0
- data/spec/vorpal/unit/db_loader_spec.rb +103 -0
- metadata +32 -30
- data/spec/vorpal/unit/class_config_builder_spec.rb +0 -13
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YTQ0OGZiZGIwOTdmMjcyYmRjZTVmOWRjZGI0ODgzOWRkZTI5OWUxNQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce7c3ca0efe5dbcd1f9aa75bcbf4465a0ffa9c8b
|
4
|
+
data.tar.gz: 01a2dad313199961079b71ac522f441d9e68e79b
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ZWVmY2M1YjBiY2NhY2IyZmEyOThkMjA5MGI5YzUzZGJkMTU3Mzg0NWU4NGY5
|
11
|
-
Zjc3OGVhMmE1ZTExMzg1YWI1MjhlMjU2NjI2MTdjNzQzZGY1MzU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NTNlMTA1NjRiYzc1ODVhNGU5MGNlODIyYTNmOGY0YTQxNTBiMTYzN2UwMzdm
|
14
|
-
YTk0MTIyNTAxZmNhMzY3MTk5YjEyM2M1ZmIzNTIzMzU2M2FlZWQ2YjM4OGZj
|
15
|
-
MTU4YjU5ZTlkZmIzZTMzMjAzMWMxNWQ2OGY5YTI5MGZiZTQ3Y2Q=
|
6
|
+
metadata.gz: c54780e9bfdaab538b32c2f7a545c1f2182cca2a7ae4f23dce23fb5aeee97947e430961d56d8007c902b7833f38c5057590f4eb78e4613f100d9978602c89f7c
|
7
|
+
data.tar.gz: 16db095201901d03d70a7c75120195a529e9b1548ce1bccf059d86f2544a9c495b5ed52d76f9d27f2e3755d8f12c45498bae0107a1c67a030609f812d8c2cef8
|
data/README.md
CHANGED
@@ -74,7 +74,7 @@ end
|
|
74
74
|
|
75
75
|
In this aggregate, the Tree is the root and the Branches are inside the aggregate boundary. The Gardener is not technically part of the aggregate but is required for the aggregate to make sense so we say that it is on the aggregate boundary. Only objects that are inside the aggregate boundary will be saved, updated, or destroyed by Vorpal.
|
76
76
|
|
77
|
-
POROs must have setters and getters for all
|
77
|
+
POROs must have setters and getters for all attributes and associations that are to be persisted. They must also provide a no argument constructor.
|
78
78
|
|
79
79
|
Along with a relational model (in PostgreSQL):
|
80
80
|
|
@@ -109,25 +109,17 @@ require 'vorpal'
|
|
109
109
|
module TreeRepository
|
110
110
|
extend self
|
111
111
|
|
112
|
-
class TreeDB < ActiveRecord::Base
|
113
|
-
self.table_name = 'trees'
|
114
|
-
end
|
115
|
-
|
116
|
-
class BranchDB < ActiveRecord::Base
|
117
|
-
self.table_name = 'branches'
|
118
|
-
end
|
119
|
-
|
120
112
|
@repository = Vorpal.define do
|
121
|
-
map Tree
|
122
|
-
|
113
|
+
map Tree do
|
114
|
+
attributes :name
|
123
115
|
belongs_to :gardener, owned: false
|
124
116
|
has_many :branches
|
125
117
|
end
|
126
118
|
|
127
119
|
map Gardener, to: Gardener
|
128
120
|
|
129
|
-
map Branch
|
130
|
-
|
121
|
+
map Branch do
|
122
|
+
attributes :length, :diameter
|
131
123
|
belongs_to :tree
|
132
124
|
end
|
133
125
|
end
|
@@ -183,10 +175,10 @@ It also does not do some things that you might expect from other ORMs:
|
|
183
175
|
1. No support for validations. Validations are not a persistence concern.
|
184
176
|
1. No AR-style callbacks. Use Infrastructure, Application, or Domain [services](http://martinfowler.com/bliki/EvansClassification.html) instead.
|
185
177
|
1. No has-many-through associations. Use two has-many associations to a join entity instead.
|
186
|
-
1. The `id`
|
178
|
+
1. The `id` attribute is reserved for database primary keys. If you have a natural key/id on your domain model, name it something that makes sense for your domain. It is the strong opinion of the authors that using natural keys as foreign keys is a bad idea. This mixes domain and persistence concerns.
|
187
179
|
|
188
180
|
## Constraints
|
189
|
-
1. Persisted entities must have getters and setters for all persisted
|
181
|
+
1. Persisted entities must have getters and setters for all persisted attributes and associations. They do not need to be public.
|
190
182
|
1. Only supports PostgreSQL.
|
191
183
|
|
192
184
|
## Future Enhancements
|
@@ -196,7 +188,7 @@ It also does not do some things that you might expect from other ORMs:
|
|
196
188
|
* Value objects.
|
197
189
|
* Remove dependency on ActiveRecord (optimistic locking? updated_at, created_at support? Data type conversions? TimeZone support?)
|
198
190
|
* More efficient updates (use fewer queries.)
|
199
|
-
* Nicer DSL for specifying
|
191
|
+
* Nicer DSL for specifying attributes that have different names in the domain model than in the DB.
|
200
192
|
|
201
193
|
## FAQ
|
202
194
|
|
@@ -216,7 +208,7 @@ For example:
|
|
216
208
|
|
217
209
|
```ruby
|
218
210
|
def find_all
|
219
|
-
ids =
|
211
|
+
ids = @repository.db_class(Tree).pluck(:id) # use an AR query to determine the aggregate ids
|
220
212
|
@repository.load_all(ids, Tree) # use the repository to load all the aggregates
|
221
213
|
end
|
222
214
|
```
|
@@ -134,6 +134,12 @@ module Vorpal
|
|
134
134
|
ids
|
135
135
|
end
|
136
136
|
|
137
|
+
# Returns the DB Class (e.g. ActiveRecord::Base class) that is responsible
|
138
|
+
# for accessing the associated data in the DB.
|
139
|
+
def db_class(domain_class)
|
140
|
+
@configs.config_for(domain_class).db_class
|
141
|
+
end
|
142
|
+
|
137
143
|
private
|
138
144
|
|
139
145
|
def all_owned_objects(roots)
|
@@ -2,29 +2,31 @@ require 'simple_serializer/serializer'
|
|
2
2
|
require 'simple_serializer/deserializer'
|
3
3
|
require 'vorpal/configs'
|
4
4
|
require 'active_support/inflector/methods'
|
5
|
+
require 'active_support/core_ext/module/introspection'
|
5
6
|
|
6
7
|
module Vorpal
|
7
8
|
class ConfigBuilder
|
8
9
|
|
9
10
|
# @private
|
10
|
-
def initialize(clazz, options)
|
11
|
+
def initialize(clazz, options, db_driver)
|
11
12
|
@domain_class = clazz
|
12
13
|
@class_options = options
|
14
|
+
@db_driver = db_driver
|
13
15
|
@has_manys = []
|
14
16
|
@has_ones = []
|
15
17
|
@belongs_tos = []
|
16
|
-
@
|
18
|
+
@attributes = []
|
17
19
|
end
|
18
20
|
|
19
|
-
# Maps the given
|
21
|
+
# Maps the given attributes to and from the domain object and the DB. Not needed
|
20
22
|
# if a serializer and deserializer were provided.
|
21
|
-
def
|
22
|
-
@
|
23
|
+
def attributes(*attributes)
|
24
|
+
@attributes.concat(attributes)
|
23
25
|
end
|
24
26
|
|
25
27
|
# Defines a one-to-many association with a list of objects of the same type.
|
26
28
|
#
|
27
|
-
# @param name [String] Name of the
|
29
|
+
# @param name [String] Name of the attribute that will refer to the other object.
|
28
30
|
# @param options [Hash]
|
29
31
|
# @option options [Boolean] :owned
|
30
32
|
# @option options [String] :fk
|
@@ -37,7 +39,7 @@ module Vorpal
|
|
37
39
|
# Defines a one-to-one association with another object where the foreign key
|
38
40
|
# is stored on the other object.
|
39
41
|
#
|
40
|
-
# @param name [String] Name of the
|
42
|
+
# @param name [String] Name of the attribute that will refer to the other object.
|
41
43
|
# @param options [Hash]
|
42
44
|
# @option options [Boolean] :owned
|
43
45
|
# @option options [String] :fk
|
@@ -52,7 +54,7 @@ module Vorpal
|
|
52
54
|
#
|
53
55
|
# This association can be polymorphic. i.e.
|
54
56
|
#
|
55
|
-
# @param name [String] Name of the
|
57
|
+
# @param name [String] Name of the attribute that will refer to the other object.
|
56
58
|
# @param options [Hash]
|
57
59
|
# @option options [Boolean] :owned
|
58
60
|
# @option options [String] :fk
|
@@ -73,25 +75,44 @@ module Vorpal
|
|
73
75
|
class_config
|
74
76
|
end
|
75
77
|
|
78
|
+
# @private
|
79
|
+
def attributes_with_id
|
80
|
+
[:id].concat @attributes
|
81
|
+
end
|
82
|
+
|
83
|
+
# @private
|
84
|
+
def table_name
|
85
|
+
@class_options[:table_name] || ActiveSupport::Inflector.tableize(@domain_class.name)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @private
|
89
|
+
def build_db_class
|
90
|
+
# Module#parent comes from 'active_support/core_ext/module/introspection'
|
91
|
+
parent_module = @domain_class.parent
|
92
|
+
|
93
|
+
return parent_module.const_get(db_class_name) if parent_module.const_defined?(db_class_name)
|
94
|
+
|
95
|
+
db_class = @db_driver.build_db_class(table_name)
|
96
|
+
parent_module.const_set(db_class_name, db_class)
|
97
|
+
|
98
|
+
db_class
|
99
|
+
end
|
100
|
+
|
76
101
|
private
|
77
102
|
|
103
|
+
def db_class_name
|
104
|
+
@domain_class.name.split('::').last + 'DB'
|
105
|
+
end
|
106
|
+
|
78
107
|
def build_class_config
|
79
108
|
Vorpal::ClassConfig.new(
|
80
109
|
domain_class: @domain_class,
|
81
|
-
db_class: @class_options[:to] ||
|
82
|
-
serializer: @class_options[:serializer] || serializer(
|
83
|
-
deserializer: @class_options[:deserializer] || deserializer(
|
110
|
+
db_class: @class_options[:to] || build_db_class,
|
111
|
+
serializer: @class_options[:serializer] || serializer(attributes_with_id),
|
112
|
+
deserializer: @class_options[:deserializer] || deserializer(attributes_with_id),
|
84
113
|
)
|
85
114
|
end
|
86
115
|
|
87
|
-
def db_class
|
88
|
-
ActiveSupport::Inflector.constantize("#{@domain_class.name}DB")
|
89
|
-
end
|
90
|
-
|
91
|
-
def fields_with_id
|
92
|
-
[:id].concat @fields
|
93
|
-
end
|
94
|
-
|
95
116
|
def build_has_manys
|
96
117
|
@has_manys.map { |options| build_has_many(options) }
|
97
118
|
end
|
data/lib/vorpal/configs.rb
CHANGED
@@ -73,7 +73,7 @@ module Vorpal
|
|
73
73
|
|
74
74
|
attr_reader :local_class_config, :remote_class_configs, :fk
|
75
75
|
|
76
|
-
# Only one of these two
|
76
|
+
# Only one of these two attributes needs to be specified
|
77
77
|
# If one is specified, then the association is uni-directional.
|
78
78
|
# If both are specified, then the association is bi-directional.
|
79
79
|
attr_accessor :local_end_config, :remote_end_config
|
@@ -114,8 +114,8 @@ module Vorpal
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def set_foreign_key(local_db_object, remote_object)
|
117
|
-
local_class_config.
|
118
|
-
local_class_config.
|
117
|
+
local_class_config.set_attribute(local_db_object, @fk, remote_object.try(:id))
|
118
|
+
local_class_config.set_attribute(local_db_object, @fk_type, remote_object.class.name) if polymorphic?
|
119
119
|
end
|
120
120
|
|
121
121
|
def foreign_key_info(remote_class_config)
|
@@ -165,12 +165,12 @@ module Vorpal
|
|
165
165
|
serialization_required? ? deserializer.deserialize(domain_class.new, attributes) : db_object
|
166
166
|
end
|
167
167
|
|
168
|
-
def
|
169
|
-
db_object.send("#{
|
168
|
+
def set_attribute(db_object, attribute, value)
|
169
|
+
db_object.send("#{attribute}=", value)
|
170
170
|
end
|
171
171
|
|
172
|
-
def
|
173
|
-
db_object.send(
|
172
|
+
def get_attribute(db_object, attribute)
|
173
|
+
db_object.send(attribute)
|
174
174
|
end
|
175
175
|
|
176
176
|
private
|
data/lib/vorpal/configuration.rb
CHANGED
@@ -23,11 +23,11 @@ module Vorpal
|
|
23
23
|
# @param options [Hash] Configure how to map the domain model
|
24
24
|
# @option options [String] :to (Class with the same name as the domain class with a 'DB' appended.)
|
25
25
|
# Class of the ActiveRecord object that will map this domain class to the DB.
|
26
|
-
# @option options [Object] :serializer (map the {ConfigBuilder#
|
26
|
+
# @option options [Object] :serializer (map the {ConfigBuilder#attributes} directly)
|
27
27
|
# Object that will convert the domain objects into a hash.
|
28
28
|
#
|
29
29
|
# Must have a `(Hash) serialize(Object)` method.
|
30
|
-
# @option options [Object] :deserializer (map the {ConfigBuilder#
|
30
|
+
# @option options [Object] :deserializer (map the {ConfigBuilder#attributes} directly)
|
31
31
|
# Object that will set a hash of attribute_names->values onto a new domain
|
32
32
|
# object.
|
33
33
|
#
|
@@ -38,7 +38,7 @@ module Vorpal
|
|
38
38
|
|
39
39
|
# @private
|
40
40
|
def build_class_config(domain_class, options={}, &block)
|
41
|
-
builder = ConfigBuilder.new(domain_class, options)
|
41
|
+
builder = ConfigBuilder.new(domain_class, options, DbDriver.new)
|
42
42
|
builder.instance_exec(&block) if block_given?
|
43
43
|
builder.build
|
44
44
|
end
|
data/lib/vorpal/db_driver.rb
CHANGED
@@ -51,6 +51,15 @@ module Vorpal
|
|
51
51
|
result.rows.map(&:first).map(&:to_i)
|
52
52
|
end
|
53
53
|
|
54
|
+
# Builds an ORM Class for accessing data in the given DB table.
|
55
|
+
#
|
56
|
+
# @return [Class] ActiveRecord::Base Class
|
57
|
+
def build_db_class(table_name)
|
58
|
+
db_class = Class.new(ActiveRecord::Base)
|
59
|
+
db_class.table_name = table_name
|
60
|
+
db_class
|
61
|
+
end
|
62
|
+
|
54
63
|
private
|
55
64
|
|
56
65
|
def sequence_name(class_config)
|
data/lib/vorpal/version.rb
CHANGED
data/lib/vorpal.rb
CHANGED
@@ -7,18 +7,18 @@ require "vorpal/configuration"
|
|
7
7
|
# ```ruby
|
8
8
|
# repository = Vorpal.define do
|
9
9
|
# map Tree do
|
10
|
-
#
|
10
|
+
# attributes :name
|
11
11
|
# belongs_to :trunk
|
12
12
|
# has_many :branches
|
13
13
|
# end
|
14
14
|
#
|
15
15
|
# map Trunk do
|
16
|
-
#
|
16
|
+
# attributes :length
|
17
17
|
# has_one :tree
|
18
18
|
# end
|
19
19
|
#
|
20
20
|
# map Branch do
|
21
|
-
#
|
21
|
+
# attributes :length
|
22
22
|
# belongs_to :tree
|
23
23
|
# end
|
24
24
|
# end
|
@@ -51,19 +51,10 @@ describe 'Aggregate Repository' do
|
|
51
51
|
|
52
52
|
before(:all) do
|
53
53
|
define_table('branches', {length: :decimal, tree_id: :integer, branch_id: :integer}, false)
|
54
|
-
BranchDB = defineAr('branches')
|
55
|
-
|
56
54
|
define_table('bugs', {name: :text, lives_on_id: :integer, lives_on_type: :string}, false)
|
57
|
-
BugDB = defineAr('bugs')
|
58
|
-
|
59
55
|
define_table('fissures', {length: :decimal, tree_id: :integer}, false)
|
60
|
-
|
61
56
|
define_table('trees', {name: :text, trunk_id: :integer, environment_id: :integer, environment_type: :string}, false)
|
62
|
-
TreeDB = defineAr('trees')
|
63
|
-
|
64
57
|
define_table('trunks', {length: :decimal}, false)
|
65
|
-
TrunkDB = defineAr('trunks')
|
66
|
-
|
67
58
|
define_table('swamps', {}, false)
|
68
59
|
end
|
69
60
|
|
@@ -717,23 +708,23 @@ private
|
|
717
708
|
def configure_polymorphic_has_many
|
718
709
|
Vorpal.define do
|
719
710
|
map Tree do
|
720
|
-
|
711
|
+
attributes :name
|
721
712
|
has_many :branches
|
722
713
|
belongs_to :trunk
|
723
714
|
end
|
724
715
|
|
725
716
|
map Trunk do
|
726
|
-
|
717
|
+
attributes :length
|
727
718
|
has_many :bugs, fk: :lives_on_id, fk_type: :lives_on_type
|
728
719
|
end
|
729
720
|
|
730
721
|
map Branch do
|
731
|
-
|
722
|
+
attributes :length
|
732
723
|
has_many :bugs, fk: :lives_on_id, fk_type: :lives_on_type
|
733
724
|
end
|
734
725
|
|
735
726
|
map Bug do
|
736
|
-
|
727
|
+
attributes :name
|
737
728
|
end
|
738
729
|
end
|
739
730
|
end
|
@@ -741,16 +732,16 @@ private
|
|
741
732
|
def configure_polymorphic_belongs_to
|
742
733
|
Vorpal.define do
|
743
734
|
map Bug do
|
744
|
-
|
735
|
+
attributes :name
|
745
736
|
belongs_to :lives_on, fk: :lives_on_id, fk_type: :lives_on_type, child_classes: [Trunk, Branch]
|
746
737
|
end
|
747
738
|
|
748
739
|
map Trunk do
|
749
|
-
|
740
|
+
attributes :length
|
750
741
|
end
|
751
742
|
|
752
743
|
map Branch do
|
753
|
-
|
744
|
+
attributes :length
|
754
745
|
end
|
755
746
|
end
|
756
747
|
end
|
@@ -758,7 +749,7 @@ private
|
|
758
749
|
def configure_ar_polymorphic_belongs_to
|
759
750
|
Vorpal.define do
|
760
751
|
map Tree do
|
761
|
-
|
752
|
+
attributes :name
|
762
753
|
belongs_to :environment, owned: false, fk: :environment_id, fk_type: :environment_type, child_class: Swamp
|
763
754
|
end
|
764
755
|
|
@@ -769,16 +760,16 @@ private
|
|
769
760
|
def configure_unowned_polymorphic_belongs_to
|
770
761
|
Vorpal.define do
|
771
762
|
map Bug do
|
772
|
-
|
763
|
+
attributes :name
|
773
764
|
belongs_to :lives_on, owned: false, fk: :lives_on_id, fk_type: :lives_on_type, child_classes: [Trunk, Branch]
|
774
765
|
end
|
775
766
|
|
776
767
|
map Trunk do
|
777
|
-
|
768
|
+
attributes :length
|
778
769
|
end
|
779
770
|
|
780
771
|
map Branch do
|
781
|
-
|
772
|
+
attributes :length
|
782
773
|
end
|
783
774
|
end
|
784
775
|
end
|
@@ -786,17 +777,17 @@ private
|
|
786
777
|
def configure_unowned
|
787
778
|
Vorpal.define do
|
788
779
|
map Tree do
|
789
|
-
|
780
|
+
attributes :name
|
790
781
|
has_many :branches, owned: false
|
791
782
|
belongs_to :trunk, owned: false
|
792
783
|
end
|
793
784
|
|
794
785
|
map Trunk do
|
795
|
-
|
786
|
+
attributes :length
|
796
787
|
end
|
797
788
|
|
798
789
|
map Branch do
|
799
|
-
|
790
|
+
attributes :length
|
800
791
|
end
|
801
792
|
end
|
802
793
|
end
|
@@ -804,12 +795,12 @@ private
|
|
804
795
|
def configure_recursive
|
805
796
|
Vorpal.define do
|
806
797
|
map Branch do
|
807
|
-
|
798
|
+
attributes :length
|
808
799
|
has_many :branches
|
809
800
|
end
|
810
801
|
|
811
802
|
map Tree do
|
812
|
-
|
803
|
+
attributes :name
|
813
804
|
has_many :branches
|
814
805
|
end
|
815
806
|
end
|
@@ -818,12 +809,12 @@ private
|
|
818
809
|
def configure_with_cycle
|
819
810
|
Vorpal.define do
|
820
811
|
map Branch do
|
821
|
-
|
812
|
+
attributes :length
|
822
813
|
belongs_to :tree
|
823
814
|
end
|
824
815
|
|
825
816
|
map Tree do
|
826
|
-
|
817
|
+
attributes :name
|
827
818
|
has_many :branches
|
828
819
|
end
|
829
820
|
end
|
@@ -832,18 +823,18 @@ private
|
|
832
823
|
def configure(options={})
|
833
824
|
Vorpal.define(options) do
|
834
825
|
map Tree do
|
835
|
-
|
826
|
+
attributes :name
|
836
827
|
belongs_to :trunk
|
837
828
|
has_many :fissures
|
838
829
|
has_many :branches
|
839
830
|
end
|
840
831
|
|
841
832
|
map Trunk do
|
842
|
-
|
833
|
+
attributes :length
|
843
834
|
end
|
844
835
|
|
845
836
|
map Branch do
|
846
|
-
|
837
|
+
attributes :length
|
847
838
|
end
|
848
839
|
|
849
840
|
map Fissure, to: Fissure
|
@@ -853,12 +844,12 @@ private
|
|
853
844
|
def configure_has_one
|
854
845
|
Vorpal.define do
|
855
846
|
map Trunk do
|
856
|
-
|
847
|
+
attributes :length
|
857
848
|
has_one :tree
|
858
849
|
end
|
859
850
|
|
860
851
|
map Tree do
|
861
|
-
|
852
|
+
attributes :name
|
862
853
|
end
|
863
854
|
end
|
864
855
|
end
|
@@ -866,12 +857,12 @@ private
|
|
866
857
|
def configure_unowned_has_one
|
867
858
|
Vorpal.define do
|
868
859
|
map Trunk do
|
869
|
-
|
860
|
+
attributes :length
|
870
861
|
has_one :tree, owned: false
|
871
862
|
end
|
872
863
|
|
873
864
|
map Tree do
|
874
|
-
|
865
|
+
attributes :name
|
875
866
|
end
|
876
867
|
end
|
877
868
|
end
|
@@ -165,26 +165,26 @@ describe 'performance' do
|
|
165
165
|
def build_repository
|
166
166
|
Vorpal.define do
|
167
167
|
map Tree do
|
168
|
-
|
168
|
+
attributes :name
|
169
169
|
belongs_to :trunk
|
170
170
|
has_many :branches
|
171
171
|
end
|
172
172
|
|
173
173
|
map Trunk do
|
174
|
-
|
174
|
+
attributes :length
|
175
175
|
has_one :tree
|
176
176
|
has_many :bugs, fk: :lives_on_id, fk_type: :lives_on_type
|
177
177
|
end
|
178
178
|
|
179
179
|
map Branch do
|
180
|
-
|
180
|
+
attributes :length
|
181
181
|
belongs_to :tree
|
182
182
|
has_many :bugs, fk: :lives_on_id, fk_type: :lives_on_type
|
183
183
|
has_many :branches
|
184
184
|
end
|
185
185
|
|
186
186
|
map Bug do
|
187
|
-
|
187
|
+
attributes :name
|
188
188
|
belongs_to :lives_on, fk: :lives_on_id, fk_type: :lives_on_type, child_classes: [Trunk, Branch]
|
189
189
|
end
|
190
190
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'unit_spec_helper'
|
2
|
+
|
3
|
+
require 'vorpal/config_builder'
|
4
|
+
|
5
|
+
describe Vorpal::ConfigBuilder do
|
6
|
+
class Tester; end
|
7
|
+
|
8
|
+
let(:builder) { Vorpal::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
|
+
|
19
|
+
describe 'table name' do
|
20
|
+
it 'is derived from the domain class name' do
|
21
|
+
builder = Vorpal::ConfigBuilder.new(A::B::C::Test, {}, nil)
|
22
|
+
expect(builder.table_name).to eq('a/b/c/tests')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can be manually specified' do
|
26
|
+
builder = Vorpal::ConfigBuilder.new(Tester, {table_name: 'testing123'}, nil)
|
27
|
+
expect(builder.table_name).to eq('testing123')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'build_db_class' do
|
32
|
+
it 'sets the class name' do
|
33
|
+
driver = instance_double(Vorpal::DbDriver)
|
34
|
+
new_class = Class.new
|
35
|
+
expect(driver).to receive(:build_db_class).and_return(new_class)
|
36
|
+
|
37
|
+
builder = Vorpal::ConfigBuilder.new(A::B::C::Test, {}, driver)
|
38
|
+
|
39
|
+
builder.build_db_class
|
40
|
+
|
41
|
+
expect(A::B::C::TestDB).to eq(new_class)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not redefine constants' do
|
45
|
+
stub_const('A::B::C::TestDB', 1)
|
46
|
+
|
47
|
+
builder = Vorpal::ConfigBuilder.new(A::B::C::Test, {}, nil)
|
48
|
+
|
49
|
+
db_class = builder.build_db_class
|
50
|
+
|
51
|
+
expect(A::B::C::TestDB).to eq(1)
|
52
|
+
expect(db_class).to eq(1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
module A
|
59
|
+
module B
|
60
|
+
module C
|
61
|
+
class Test
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,103 @@
|
|
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::DbDriver.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::AggregateRepository.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::DbDriver")
|
94
|
+
expect(driver).to receive(:load_by_id).with(post_config, [post_db.id]).and_return([post_db])
|
95
|
+
expect(driver).to receive(:load_by_id).with(comment_config, [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
|
metadata
CHANGED
@@ -1,139 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vorpal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Kirby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simple_serializer
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: equalizer
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activesupport
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '10.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - ~>
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 3.0.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 3.0.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: activerecord
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 3.2.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 3.2.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: pg
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - ~>
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: 0.17.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - ~>
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 0.17.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: virtus
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - ~>
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '1.0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - ~>
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '1.0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: activerecord-import
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - ~>
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
131
|
version: 0.3.1
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - ~>
|
136
|
+
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.3.1
|
139
139
|
description: An ORM framelet that fits on top of ActiveRecord to give you 'Data Mapper'
|
@@ -144,8 +144,8 @@ executables: []
|
|
144
144
|
extensions: []
|
145
145
|
extra_rdoc_files: []
|
146
146
|
files:
|
147
|
-
- .gitignore
|
148
|
-
- .yardopts
|
147
|
+
- ".gitignore"
|
148
|
+
- ".yardopts"
|
149
149
|
- Gemfile
|
150
150
|
- LICENSE.txt
|
151
151
|
- README.md
|
@@ -168,9 +168,10 @@ files:
|
|
168
168
|
- spec/integration_spec_helper.rb
|
169
169
|
- spec/unit_spec_helper.rb
|
170
170
|
- spec/vorpal/acceptance/aggregate_repository_spec.rb
|
171
|
-
- spec/vorpal/
|
172
|
-
- spec/vorpal/unit/
|
171
|
+
- spec/vorpal/performance/performance_spec.rb
|
172
|
+
- spec/vorpal/unit/config_builder_spec.rb
|
173
173
|
- spec/vorpal/unit/configs_spec.rb
|
174
|
+
- spec/vorpal/unit/db_loader_spec.rb
|
174
175
|
- spec/vorpal/unit/identity_map_spec.rb
|
175
176
|
- spec/vorpal/unit/loaded_objects_spec.rb
|
176
177
|
- vorpal.gemspec
|
@@ -184,17 +185,17 @@ require_paths:
|
|
184
185
|
- lib
|
185
186
|
required_ruby_version: !ruby/object:Gem::Requirement
|
186
187
|
requirements:
|
187
|
-
- -
|
188
|
+
- - ">="
|
188
189
|
- !ruby/object:Gem::Version
|
189
190
|
version: '0'
|
190
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
192
|
requirements:
|
192
|
-
- -
|
193
|
+
- - ">"
|
193
194
|
- !ruby/object:Gem::Version
|
194
|
-
version:
|
195
|
+
version: 1.3.1
|
195
196
|
requirements: []
|
196
197
|
rubyforge_project:
|
197
|
-
rubygems_version: 2.4.
|
198
|
+
rubygems_version: 2.4.8
|
198
199
|
signing_key:
|
199
200
|
specification_version: 4
|
200
201
|
summary: Separate your domain model from your persistence mechanism.
|
@@ -203,8 +204,9 @@ test_files:
|
|
203
204
|
- spec/integration_spec_helper.rb
|
204
205
|
- spec/unit_spec_helper.rb
|
205
206
|
- spec/vorpal/acceptance/aggregate_repository_spec.rb
|
206
|
-
- spec/vorpal/
|
207
|
-
- spec/vorpal/unit/
|
207
|
+
- spec/vorpal/performance/performance_spec.rb
|
208
|
+
- spec/vorpal/unit/config_builder_spec.rb
|
208
209
|
- spec/vorpal/unit/configs_spec.rb
|
210
|
+
- spec/vorpal/unit/db_loader_spec.rb
|
209
211
|
- spec/vorpal/unit/identity_map_spec.rb
|
210
212
|
- spec/vorpal/unit/loaded_objects_spec.rb
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'unit_spec_helper'
|
2
|
-
|
3
|
-
require 'vorpal/config_builder'
|
4
|
-
|
5
|
-
describe Vorpal::ConfigBuilder do
|
6
|
-
class Tester; end
|
7
|
-
|
8
|
-
it 'includes the primary key in the list of fields' do
|
9
|
-
# builder = Vorpal::ConfigBuilder.new(Tester, {})
|
10
|
-
# config = builder.build
|
11
|
-
# config.field
|
12
|
-
end
|
13
|
-
end
|