vorpal 1.0.2 → 1.3.0
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.
- checksums.yaml +4 -4
- data/README.md +73 -26
- data/lib/vorpal/aggregate_mapper.rb +13 -2
- data/lib/vorpal/aggregate_traversal.rb +9 -8
- data/lib/vorpal/config/association_config.rb +84 -0
- data/lib/vorpal/config/belongs_to_config.rb +35 -0
- data/lib/vorpal/config/class_config.rb +71 -0
- data/lib/vorpal/config/configs.rb +54 -0
- data/lib/vorpal/config/foreign_key_info.rb +23 -0
- data/lib/vorpal/config/has_many_config.rb +38 -0
- data/lib/vorpal/config/has_one_config.rb +35 -0
- data/lib/vorpal/config/main_config.rb +68 -0
- data/lib/vorpal/db_loader.rb +25 -22
- data/lib/vorpal/driver/postgresql.rb +42 -6
- data/lib/vorpal/dsl/config_builder.rb +26 -73
- data/lib/vorpal/dsl/configuration.rb +139 -42
- data/lib/vorpal/dsl/defaults_generator.rb +1 -1
- data/lib/vorpal/engine.rb +27 -13
- data/lib/vorpal/exceptions.rb +4 -0
- data/lib/vorpal/identity_map.rb +7 -2
- data/lib/vorpal/loaded_objects.rb +57 -14
- data/lib/vorpal/util/array_hash.rb +22 -8
- data/lib/vorpal/util/hash_initialization.rb +1 -1
- data/lib/vorpal/version.rb +1 -1
- data/vorpal.gemspec +4 -5
- metadata +18 -78
- data/.editorconfig +0 -13
- data/.envrc +0 -4
- data/.gitignore +0 -16
- data/.rspec +0 -1
- data/.ruby-version +0 -1
- data/.travis.yml +0 -18
- data/.yardopts +0 -1
- data/Appraisals +0 -18
- data/Gemfile +0 -4
- data/Rakefile +0 -39
- data/bin/appraisal +0 -29
- data/bin/rake +0 -29
- data/bin/rspec +0 -29
- data/docker-compose.yml +0 -19
- data/gemfiles/rails_5_1.gemfile +0 -11
- data/gemfiles/rails_5_1.gemfile.lock +0 -101
- data/gemfiles/rails_5_2.gemfile +0 -11
- data/gemfiles/rails_5_2.gemfile.lock +0 -101
- data/gemfiles/rails_6_0.gemfile +0 -9
- data/gemfiles/rails_6_0.gemfile.lock +0 -101
- data/lib/vorpal/configs.rb +0 -296
- data/spec/acceptance/vorpal/aggregate_mapper_spec.rb +0 -910
- data/spec/helpers/codecov_helper.rb +0 -7
- data/spec/helpers/db_helpers.rb +0 -69
- data/spec/helpers/profile_helpers.rb +0 -26
- data/spec/integration/vorpal/driver/postgresql_spec.rb +0 -42
- data/spec/integration_spec_helper.rb +0 -29
- data/spec/performance/vorpal/performance_spec.rb +0 -305
- data/spec/unit/vorpal/configs_spec.rb +0 -117
- data/spec/unit/vorpal/db_loader_spec.rb +0 -103
- data/spec/unit/vorpal/dsl/config_builder_spec.rb +0 -18
- data/spec/unit/vorpal/dsl/defaults_generator_spec.rb +0 -75
- data/spec/unit/vorpal/identity_map_spec.rb +0 -62
- data/spec/unit/vorpal/loaded_objects_spec.rb +0 -22
- data/spec/unit/vorpal/util/string_utils_spec.rb +0 -25
- data/spec/unit_spec_helper.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c236d5dee0ca27224473d24e59680317a5b30fae7e400a13738298d27e6f1e74
|
4
|
+
data.tar.gz: ffe4922245341adc4ef2e4ed25751dee28a03232c2bb5b19699120f07d7fd3d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6ba4c4ab43cc66a776be399be185130665ea4951a18a34e664b45d851801b37260ce4eee343f81511910e739f7451b3b30ead059c24712e9ee577c579fdeffa
|
7
|
+
data.tar.gz: e134e15a04d0e7037fbbedf83f5e381e281e72f8bae51e43b0f9b488877477d7d6dfb7350c037e9bfb06279ac78d74024b1e592725cd8673348bf6ad4d6f61c7
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Vorpal [](https://travis-ci.com/nulogy/vorpal) [](https://codeclimate.com/github/nulogy/vorpal) [](https://codecov.io/gh/nulogy/vorpal/branch/main)
|
2
2
|
|
3
3
|
Separate your domain model from your persistence mechanism. Some problems call for a really sharp tool.
|
4
4
|
|
@@ -45,27 +45,21 @@ Or install it yourself as:
|
|
45
45
|
Start with a domain model of POROs and AR::Base objects that form an aggregate:
|
46
46
|
|
47
47
|
```ruby
|
48
|
-
class Tree; end
|
49
|
-
|
50
48
|
class Branch
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
attribute :diameter, Decimal
|
56
|
-
attribute :tree, Tree
|
49
|
+
attr_accessor :id
|
50
|
+
attr_accessor :length
|
51
|
+
attr_accessor :diameter
|
52
|
+
attr_accessor :tree
|
57
53
|
end
|
58
54
|
|
59
|
-
class Gardener
|
55
|
+
class Gardener
|
60
56
|
end
|
61
57
|
|
62
58
|
class Tree
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
attribute :gardener, Gardener
|
68
|
-
attribute :branches, Array[Branch]
|
59
|
+
attr_accessor :id
|
60
|
+
attr_accessor :name
|
61
|
+
attr_accessor :gardener
|
62
|
+
attr_accessor :branches
|
69
63
|
end
|
70
64
|
```
|
71
65
|
|
@@ -162,9 +156,33 @@ TreeRepository.destroy(dead_tree)
|
|
162
156
|
TreeRepository.destroy_by_id(dead_tree_id)
|
163
157
|
```
|
164
158
|
|
159
|
+
### Ids
|
160
|
+
|
161
|
+
Vorpal by default will use auto-incrementing Integers from a DB sequence for ids. However, UUID v4 ids are also
|
162
|
+
supported:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
Vorpal.define do
|
166
|
+
# UUID v4 id!
|
167
|
+
map Tree, primary_key_type: :uuid do
|
168
|
+
# ..
|
169
|
+
end
|
170
|
+
|
171
|
+
# Also a UUID v4 id, the Rails Way!
|
172
|
+
map Trunk, id: :uuid do
|
173
|
+
# ..
|
174
|
+
end
|
175
|
+
|
176
|
+
# If you feel the need to specify an auto-incrementing integer id.
|
177
|
+
map Branch, primary_key_type: :serial do
|
178
|
+
# ..
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
165
183
|
## API Documentation
|
166
184
|
|
167
|
-
http://rubydoc.info/github/nulogy/vorpal
|
185
|
+
http://rubydoc.info/github/nulogy/vorpal
|
168
186
|
|
169
187
|
## Caveats
|
170
188
|
It also does not do some things that you might expect from other ORMs:
|
@@ -181,13 +199,11 @@ It also does not do some things that you might expect from other ORMs:
|
|
181
199
|
1. Only supports PostgreSQL.
|
182
200
|
|
183
201
|
## Future Enhancements
|
184
|
-
*
|
185
|
-
* Support for
|
186
|
-
* Support for other ORMs.
|
187
|
-
* Value objects.
|
188
|
-
* Remove dependency on ActiveRecord (optimistic locking? updated_at, created_at support? Data type conversions? TimeZone support?)
|
189
|
-
* More efficient updates (use fewer queries.)
|
202
|
+
* Support for having foreign keys point to columns other than primary keys.
|
203
|
+
* Support for storing entity ids in a column called something other than "id".
|
190
204
|
* Nicer DSL for specifying attributes that have different names in the domain model than in the DB.
|
205
|
+
* Aggregate updated_at.
|
206
|
+
* Better support for value objects.
|
191
207
|
|
192
208
|
## FAQ
|
193
209
|
|
@@ -203,11 +219,12 @@ It also does not do some things that you might expect from other ORMs:
|
|
203
219
|
|
204
220
|
**A.** Create a method on a [Repository](http://martinfowler.com/eaaCatalog/repository.html)! They have full access to the DB/ORM so you can use [Arel](https://github.com/rails/arel) and go [crazy](http://asciicasts.com/episodes/239-activerecord-relation-walkthrough) or use direct SQL if you want.
|
205
221
|
|
206
|
-
For example:
|
222
|
+
For example, use the [#query](https://rubydoc.info/github/nulogy/vorpal/main/Vorpal/AggregateMapper#query-instance_method) method on the [AggregateMapper](https://rubydoc.info/github/nulogy/vorpal/main/Vorpal/AggregateMapper) to access the underyling [ActiveRecordRelation](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html):
|
207
223
|
|
208
224
|
```ruby
|
209
|
-
def
|
210
|
-
|
225
|
+
def find_special_ones
|
226
|
+
# use `load_all` or `load_one` to convert from ActiveRecord objects to domain POROs.
|
227
|
+
@mapper.query.where(special: true).load_all
|
211
228
|
end
|
212
229
|
```
|
213
230
|
|
@@ -229,6 +246,28 @@ For example:
|
|
229
246
|
|
230
247
|
**A.** You can use [ActiveModel::Serialization](http://api.rubyonrails.org/classes/ActiveModel/Serialization.html) or [ActiveModel::Serializers](https://github.com/rails-api/active_model_serializers) but they are not heartily recommended. The former is too coupled to the model and the latter is too coupled to Rails controllers. Vorpal uses [SimpleSerializer](https://github.com/nulogy/simple_serializer) for this purpose.
|
231
248
|
|
249
|
+
**Q.** Are `updated_at` and `created_at` supported?
|
250
|
+
|
251
|
+
**A.** Yes. If they exist on your database tables, they will behave exactly as if you were using vanilla ActiveRecord.
|
252
|
+
|
253
|
+
**Q.** How do I tell ActiveRecord to ignore certain columns so that I can rename/remove them using zero-downtime deploys?
|
254
|
+
|
255
|
+
**A.** You will want to use ActiveRecord's [`ignored_columns=`](https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-ignored_columns) method like this:
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
engine = Vorpal.define do
|
259
|
+
map Product do
|
260
|
+
attributes(
|
261
|
+
:name,
|
262
|
+
:description,
|
263
|
+
# :column_to_remove
|
264
|
+
)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
product_ar_class = engine.mapper_for(Product).db_class
|
268
|
+
product_ar_class.ignored_columns = [:column_to_remove]
|
269
|
+
```
|
270
|
+
|
232
271
|
## Contributing
|
233
272
|
|
234
273
|
1. Fork it ( https://github.com/nulogy/vorpal/fork )
|
@@ -265,6 +304,14 @@ For example:
|
|
265
304
|
|
266
305
|
Please see the [Appraisal gem docs](https://github.com/thoughtbot/appraisal) for more information.
|
267
306
|
|
307
|
+
### Releasing
|
308
|
+
|
309
|
+
1. Update the version number in `lib/vorpal/version.rb`
|
310
|
+
2. Update the version of Vorpal in the Appraisal gemfiles (otherwise Travis CI will fail): `appraisal install`
|
311
|
+
3. Commit the above changes with the message: `Bump version to <X.Y.Z>`
|
312
|
+
4. Release the new version to Rubygems: `rake release`
|
313
|
+
5. Profit!
|
314
|
+
|
268
315
|
## Contributors
|
269
316
|
|
270
317
|
See who's [contributed](https://github.com/nulogy/vorpal/graphs/contributors)!
|
@@ -27,12 +27,12 @@ module Vorpal
|
|
27
27
|
# Loads an aggregate from the DB. Will eagerly load all objects in the
|
28
28
|
# aggregate and on the boundary (owned: false).
|
29
29
|
#
|
30
|
-
# @param db_root [Object] DB representation of the root of the aggregate to be
|
30
|
+
# @param db_root [Object, nil] DB representation of the root of the aggregate to be
|
31
31
|
# loaded. This can be nil.
|
32
32
|
# @param identity_map [IdentityMap] Provide your own IdentityMap instance
|
33
33
|
# if you want entity id -> unique object mapping for a greater scope than one
|
34
34
|
# operation.
|
35
|
-
# @return [Object] Aggregate root corresponding to the given DB representation.
|
35
|
+
# @return [Object, nil] Aggregate root corresponding to the given DB representation.
|
36
36
|
def load_one(db_root, identity_map=IdentityMap.new)
|
37
37
|
@engine.load_one(db_root, @domain_class, identity_map)
|
38
38
|
end
|
@@ -84,6 +84,17 @@ module Vorpal
|
|
84
84
|
@engine
|
85
85
|
end
|
86
86
|
|
87
|
+
# Returns a 'Vorpal-aware' [ActiveRecord::Relation](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html)
|
88
|
+
# for the ActiveRecord object underlying the domain entity mapped by this mapper.
|
89
|
+
#
|
90
|
+
# This method allows you to easily access the power of ActiveRecord::Relation to do more complex
|
91
|
+
# queries in your repositories.
|
92
|
+
#
|
93
|
+
# The ActiveRecord::Relation is 'Vorpal-aware' because it has the {#load_one} and {#load_many} methods
|
94
|
+
# mixed in so that you can get the POROs from your domain model instead of the ActiveRecord
|
95
|
+
# objects normally returned by ActiveRecord::Relation.
|
96
|
+
#
|
97
|
+
# @return [ActiveRecord::Relation]
|
87
98
|
def query
|
88
99
|
@engine.query(@domain_class)
|
89
100
|
end
|
@@ -19,19 +19,20 @@ module Vorpal
|
|
19
19
|
visitor.visit_object(object, config)
|
20
20
|
|
21
21
|
config.belongs_tos.each do |belongs_to_config|
|
22
|
-
|
23
|
-
accept(
|
22
|
+
associate = belongs_to_config.get_associated(object)
|
23
|
+
accept(associate, visitor, already_visited) if visitor.continue_traversal?(belongs_to_config)
|
24
24
|
end
|
25
25
|
|
26
26
|
config.has_ones.each do |has_one_config|
|
27
|
-
|
28
|
-
accept(
|
27
|
+
associate = has_one_config.get_associated(object)
|
28
|
+
accept(associate, visitor, already_visited) if visitor.continue_traversal?(has_one_config)
|
29
29
|
end
|
30
30
|
|
31
31
|
config.has_manys.each do |has_many_config|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
associates = has_many_config.get_associated(object)
|
33
|
+
raise InvariantViolated.new("#{has_many_config.pretty_name} was set to nil. Use an empty array instead.") if associates.nil?
|
34
|
+
associates.each do |associate|
|
35
|
+
accept(associate, visitor, already_visited) if visitor.continue_traversal?(has_many_config)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
@@ -47,4 +48,4 @@ module Vorpal
|
|
47
48
|
true
|
48
49
|
end
|
49
50
|
end
|
50
|
-
end
|
51
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'vorpal/config/foreign_key_info'
|
2
|
+
require 'equalizer'
|
3
|
+
|
4
|
+
module Vorpal
|
5
|
+
module Config
|
6
|
+
# @private
|
7
|
+
# Object association terminology:
|
8
|
+
# - All object associations are uni-directional
|
9
|
+
# - The end that holds the association is the 'Owner' and the end that
|
10
|
+
# is referred to is the 'Associate' or 'Associates'
|
11
|
+
#
|
12
|
+
# Relational association terminology:
|
13
|
+
# - Local end: has FK
|
14
|
+
# - Remote end: has no FK
|
15
|
+
#
|
16
|
+
class AssociationConfig
|
17
|
+
include Equalizer.new(:local_class_config, :fk)
|
18
|
+
|
19
|
+
attr_reader :local_class_config, :remote_class_configs, :fk
|
20
|
+
|
21
|
+
# Only one of these two attributes needs to be specified
|
22
|
+
# If one is specified, then the association is uni-directional.
|
23
|
+
# If both are specified, then the association is bi-directional.
|
24
|
+
attr_accessor :local_end_config, :remote_end_config
|
25
|
+
|
26
|
+
def initialize(local_class_config, fk, fk_type)
|
27
|
+
@local_class_config = local_class_config
|
28
|
+
@remote_class_configs = {}
|
29
|
+
@fk = fk
|
30
|
+
@fk_type = fk_type
|
31
|
+
end
|
32
|
+
|
33
|
+
def fk_value(local_db_object)
|
34
|
+
local_db_object.send(fk)
|
35
|
+
end
|
36
|
+
|
37
|
+
def associate(local_object, remote_object)
|
38
|
+
local_end_config.associate(local_object, remote_object) if local_end_config && local_object
|
39
|
+
remote_end_config.associate(remote_object, local_object) if remote_end_config && remote_object
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_remote_class_config(remote_class_configs)
|
43
|
+
Array(remote_class_configs).each do |remote_class_config|
|
44
|
+
@remote_class_configs[remote_class_config.domain_class.name] = remote_class_config
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def remote_class_config(local_db_object)
|
49
|
+
if polymorphic?
|
50
|
+
fk_type_value = local_db_object.send(@fk_type)
|
51
|
+
@remote_class_configs[fk_type_value]
|
52
|
+
else
|
53
|
+
@remote_class_configs.values.first
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def polymorphic?
|
58
|
+
!@fk_type.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_foreign_key(local_db_object, remote_object)
|
62
|
+
local_class_config.set_attribute(local_db_object, @fk, remote_object&.send(unique_key_name))
|
63
|
+
local_class_config.set_attribute(local_db_object, @fk_type, remote_object.class.name) if polymorphic?
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return ForeignKeyInfo
|
67
|
+
def foreign_key_info(remote_class_config)
|
68
|
+
ForeignKeyInfo.new(@fk, @fk_type, remote_class_config.domain_class.name, polymorphic?)
|
69
|
+
end
|
70
|
+
|
71
|
+
def unique_key_name
|
72
|
+
(@local_end_config || @remote_end_config).unique_key_name
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate
|
76
|
+
if @local_end_config && @remote_end_config
|
77
|
+
if @local_end_config.unique_key_name != @remote_end_config.unique_key_name
|
78
|
+
raise ConfigurationError.new("#{@local_end_config.pretty_name} and #{@remote_end_config.pretty_name} must have the same unique_key_name/primary_key")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'vorpal/config/configs'
|
2
|
+
|
3
|
+
module Vorpal
|
4
|
+
module Config
|
5
|
+
# @private
|
6
|
+
# Object association terminology:
|
7
|
+
# - All object associations are uni-directional
|
8
|
+
# - The end that holds the association is the 'Owner' and the end that
|
9
|
+
# is referred to is the 'Associate' or 'Associates'
|
10
|
+
#
|
11
|
+
# Relational association terminology:
|
12
|
+
# - Local end: has FK
|
13
|
+
# - Remote end: has no FK
|
14
|
+
#
|
15
|
+
class BelongsToConfig
|
16
|
+
include Util::HashInitialization
|
17
|
+
include LocalEndConfig
|
18
|
+
|
19
|
+
attr_reader :name, :owned, :fk, :fk_type, :associated_classes, :unique_key_name
|
20
|
+
attr_accessor :association_config
|
21
|
+
|
22
|
+
def get_associated(owner)
|
23
|
+
owner.send(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def associate(owner, associate)
|
27
|
+
owner.send("#{name}=", associate)
|
28
|
+
end
|
29
|
+
|
30
|
+
def pretty_name
|
31
|
+
"#{association_config.local_class_config.domain_class.name} belongs_to :#{name}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'equalizer'
|
2
|
+
|
3
|
+
module Vorpal
|
4
|
+
module Config
|
5
|
+
# @private
|
6
|
+
class ClassConfig
|
7
|
+
include Equalizer.new(:domain_class, :db_class)
|
8
|
+
attr_reader :serializer, :deserializer, :domain_class, :db_class, :primary_key_type, :local_association_configs
|
9
|
+
attr_accessor :has_manys, :belongs_tos, :has_ones
|
10
|
+
|
11
|
+
ALLOWED_PRIMARY_KEY_TYPE_OPTIONS = [:serial, :uuid]
|
12
|
+
|
13
|
+
def initialize(attrs)
|
14
|
+
@has_manys = []
|
15
|
+
@belongs_tos = []
|
16
|
+
@has_ones = []
|
17
|
+
@local_association_configs = []
|
18
|
+
|
19
|
+
@serializer = attrs[:serializer]
|
20
|
+
@deserializer = attrs[:deserializer]
|
21
|
+
@domain_class = attrs[:domain_class]
|
22
|
+
@db_class = attrs[:db_class]
|
23
|
+
@primary_key_type = attrs[:primary_key_type]
|
24
|
+
raise "Invalid primary_key_type: '#{@primary_key_type}'" unless ALLOWED_PRIMARY_KEY_TYPE_OPTIONS.include?(@primary_key_type)
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_db_object(attributes)
|
28
|
+
db_class.new(attributes)
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_db_object_attributes(db_object, attributes)
|
32
|
+
db_object.attributes = attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_db_object_attributes(db_object)
|
36
|
+
symbolize_keys(db_object.attributes)
|
37
|
+
end
|
38
|
+
|
39
|
+
def serialization_required?
|
40
|
+
domain_class.superclass.name != 'ActiveRecord::Base'
|
41
|
+
end
|
42
|
+
|
43
|
+
def serialize(object)
|
44
|
+
serializer.serialize(object)
|
45
|
+
end
|
46
|
+
|
47
|
+
def deserialize(db_object)
|
48
|
+
attributes = get_db_object_attributes(db_object)
|
49
|
+
serialization_required? ? deserializer.deserialize(domain_class.new, attributes) : db_object
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_attribute(db_object, attribute, value)
|
53
|
+
db_object.send("#{attribute}=", value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_attribute(db_object, attribute)
|
57
|
+
db_object.send(attribute)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def symbolize_keys(hash)
|
63
|
+
result = {}
|
64
|
+
hash.each_key do |key|
|
65
|
+
result[key.to_sym] = hash[key]
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'vorpal/util/hash_initialization'
|
2
|
+
require 'vorpal/exceptions'
|
3
|
+
require 'equalizer'
|
4
|
+
|
5
|
+
module Vorpal
|
6
|
+
module Config
|
7
|
+
# @private
|
8
|
+
# Object association terminology:
|
9
|
+
# - All object associations are uni-directional
|
10
|
+
# - The end that holds the association is the 'Owner' and the end that
|
11
|
+
# is referred to is the 'Associate' or 'Associates'
|
12
|
+
#
|
13
|
+
# Relational association terminology:
|
14
|
+
# - Local end: has FK
|
15
|
+
# - Remote end: has no FK
|
16
|
+
#
|
17
|
+
module RemoteEndConfig
|
18
|
+
def associated_class_config
|
19
|
+
association_config.local_class_config
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_foreign_key(db_associate, owner)
|
23
|
+
association_config.set_foreign_key(db_associate, owner)
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_class_config(class_config)
|
27
|
+
@class_config = class_config
|
28
|
+
end
|
29
|
+
|
30
|
+
def foreign_key_info
|
31
|
+
association_config.foreign_key_info(@class_config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_unique_key_value(db_owner)
|
35
|
+
db_owner.send(unique_key_name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @private
|
40
|
+
module LocalEndConfig
|
41
|
+
def associated_class_config(db_owner)
|
42
|
+
association_config.remote_class_config(db_owner)
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_foreign_key(db_owner, associate)
|
46
|
+
association_config.set_foreign_key(db_owner, associate)
|
47
|
+
end
|
48
|
+
|
49
|
+
def fk_value(db_owner)
|
50
|
+
db_owner.send(fk)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|