vorpal 1.0.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.
|
1
|
+
# Vorpal [![Build Status](https://travis-ci.com/nulogy/vorpal.svg?branch=main)](https://travis-ci.com/nulogy/vorpal) [![Code Climate](https://codeclimate.com/github/nulogy/vorpal/badges/gpa.svg)](https://codeclimate.com/github/nulogy/vorpal) [![Code Coverage](https://codecov.io/gh/nulogy/vorpal/branch/main/graph/badge.svg)](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
|