rom-core 4.0.0.beta3 → 4.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -1
- data/lib/rom/association_set.rb +3 -0
- data/lib/rom/associations/abstract.rb +72 -1
- data/lib/rom/associations/definitions/abstract.rb +22 -6
- data/lib/rom/associations/definitions/many_to_many.rb +3 -0
- data/lib/rom/associations/definitions/many_to_one.rb +1 -0
- data/lib/rom/associations/definitions/one_to_many.rb +1 -0
- data/lib/rom/associations/definitions/one_to_one.rb +1 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +1 -0
- data/lib/rom/associations/many_to_many.rb +44 -0
- data/lib/rom/associations/many_to_one.rb +26 -0
- data/lib/rom/associations/one_to_many.rb +26 -0
- data/lib/rom/associations/one_to_one.rb +3 -0
- data/lib/rom/associations/one_to_one_through.rb +3 -0
- data/lib/rom/attribute.rb +2 -2
- data/lib/rom/auto_curry.rb +11 -0
- data/lib/rom/cache.rb +29 -0
- data/lib/rom/command_compiler.rb +4 -4
- data/lib/rom/command_registry.rb +9 -5
- data/lib/rom/commands/class_interface.rb +7 -7
- data/lib/rom/commands/graph/input_evaluator.rb +33 -3
- data/lib/rom/commands/lazy.rb +4 -0
- data/lib/rom/commands/lazy/create.rb +10 -0
- data/lib/rom/commands/lazy/delete.rb +10 -0
- data/lib/rom/commands/lazy/update.rb +10 -0
- data/lib/rom/configuration.rb +34 -14
- data/lib/rom/configuration_dsl.rb +0 -2
- data/lib/rom/constants.rb +10 -0
- data/lib/rom/container.rb +16 -0
- data/lib/rom/create_container.rb +7 -0
- data/lib/rom/environment.rb +3 -2
- data/lib/rom/gateway.rb +16 -1
- data/lib/rom/global.rb +1 -1
- data/lib/rom/global/plugin_dsl.rb +3 -1
- data/lib/rom/initializer.rb +25 -13
- data/lib/rom/mapper_registry.rb +4 -1
- data/lib/rom/memory/dataset.rb +29 -2
- data/lib/rom/memory/schema.rb +7 -0
- data/lib/rom/plugin_base.rb +1 -1
- data/lib/rom/plugin_registry.rb +2 -2
- data/lib/rom/plugins/command/schema.rb +7 -0
- data/lib/rom/plugins/relation/instrumentation.rb +10 -0
- data/lib/rom/plugins/relation/registry_reader.rb +0 -3
- data/lib/rom/registry.rb +15 -3
- data/lib/rom/relation.rb +38 -23
- data/lib/rom/relation/class_interface.rb +15 -6
- data/lib/rom/relation/combined.rb +7 -2
- data/lib/rom/relation/curried.rb +23 -0
- data/lib/rom/relation/graph.rb +25 -14
- data/lib/rom/relation/loaded.rb +7 -4
- data/lib/rom/relation/materializable.rb +2 -2
- data/lib/rom/relation/view_dsl.rb +2 -1
- data/lib/rom/relation/wrap.rb +14 -0
- data/lib/rom/relation_registry.rb +2 -0
- data/lib/rom/schema.rb +25 -4
- data/lib/rom/schema/associations_dsl.rb +9 -0
- data/lib/rom/schema/dsl.rb +27 -4
- data/lib/rom/setup.rb +20 -7
- data/lib/rom/setup/auto_registration.rb +27 -0
- data/lib/rom/setup/auto_registration_strategies/base.rb +7 -2
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +17 -0
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +11 -0
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +9 -0
- data/lib/rom/setup/finalize/finalize_mappers.rb +4 -2
- data/lib/rom/setup/finalize/finalize_relations.rb +1 -1
- data/lib/rom/support/configurable.rb +19 -0
- data/lib/rom/support/notifications.rb +29 -2
- data/lib/rom/types.rb +53 -8
- data/lib/rom/version.rb +1 -1
- metadata +7 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd842da91b8eff4e935f9bc0064b7225fbc41d6a
|
4
|
+
data.tar.gz: b949c0798bbddfb9bb49b52b0e4137759accc1f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c95c856d8c205db0013f905ad72e4e8bcecc243f227410d05607c8e2f1280e5d7cf8943c607cd6b45f5926e55e8febadab4e809cb847efe3e96c48e8c4873200
|
7
|
+
data.tar.gz: bf2277dae18e48950740d93a6478cf4d0d56eda97065b797edb5d88d8ab9327f871ab99d2207a909ae80663ae0a654b2495485be7ddf071ab5da6105737b9db8
|
data/CHANGELOG.md
CHANGED
@@ -12,8 +12,10 @@ Previous `rom` gem was renamed to `rom-core`
|
|
12
12
|
* `Relation#command` which automatically creates a command for a given relation, supports graphs too (solnic)
|
13
13
|
* `Relation::to_ast` which returns an AST representation of a relation. This can be used to infer other objects based on relation information (solnic)
|
14
14
|
* `Relation::Name#as` which returns an aliased relation name (solnic)
|
15
|
-
* Association DSL supports `:override` option which will use configured `:view` as the relation used by association (solnic)
|
16
15
|
* Associations are now part of core API and available to all adapters, cross-adapter associations are supported too via `:override` option (solnic)
|
16
|
+
* New settings in association DSL:
|
17
|
+
* `:override` option which will use configured `:view` as the relation used by association (solnic)
|
18
|
+
* `:combine_keys` option which overriddes default combine keys that are based on join keys (solnic)
|
17
19
|
* `Schema#primary_key_name` and `Schema#primary_key_names` are now part of core schema API (solnic)
|
18
20
|
* `Schema#to_ast` which returns an AST representation of a relation schema (flash-gordon)
|
19
21
|
* Plugin system supports schema plugins (flash-gordon)
|
data/lib/rom/association_set.rb
CHANGED
@@ -32,6 +32,11 @@ module ROM
|
|
32
32
|
# @return [ROM::SQL::Relation::Name] the target relation
|
33
33
|
option :target, reader: true
|
34
34
|
|
35
|
+
# Create an association object
|
36
|
+
#
|
37
|
+
# @param [Definition] definition The association definition object
|
38
|
+
# @param [RelationRegistry] relations The relation registry
|
39
|
+
#
|
35
40
|
# @api public
|
36
41
|
def self.new(definition, relations)
|
37
42
|
super(
|
@@ -42,62 +47,116 @@ module ROM
|
|
42
47
|
)
|
43
48
|
end
|
44
49
|
|
50
|
+
# Return if an association has an alias
|
51
|
+
#
|
52
|
+
# @return [Boolean]
|
53
|
+
#
|
45
54
|
# @api public
|
46
55
|
def aliased?
|
47
56
|
definition.aliased?
|
48
57
|
end
|
49
58
|
|
59
|
+
# Return association alias
|
60
|
+
#
|
61
|
+
# @return [Symbol]
|
62
|
+
#
|
50
63
|
# @api public
|
51
64
|
def as
|
52
65
|
definition.as
|
53
66
|
end
|
54
67
|
|
68
|
+
# Return association canonical name
|
69
|
+
#
|
70
|
+
# @return [Symbol]
|
71
|
+
#
|
55
72
|
# @api public
|
56
73
|
def name
|
57
74
|
definition.name
|
58
75
|
end
|
59
76
|
|
77
|
+
# Return the name of a custom relation view that should be use to
|
78
|
+
# extend or override default association view
|
79
|
+
#
|
80
|
+
# @return [Symbol]
|
81
|
+
#
|
60
82
|
# @api public
|
61
83
|
def view
|
62
84
|
definition.view
|
63
85
|
end
|
64
86
|
|
87
|
+
# Return association foreign key name
|
88
|
+
#
|
89
|
+
# @return [Symbol]
|
90
|
+
#
|
65
91
|
# @api public
|
66
92
|
def foreign_key
|
67
93
|
definition.foreign_key
|
68
94
|
end
|
69
95
|
|
96
|
+
# Return result type
|
97
|
+
#
|
98
|
+
# This can be either :one or :many
|
99
|
+
#
|
100
|
+
# @return [Symbol]
|
101
|
+
#
|
70
102
|
# @api public
|
71
103
|
def result
|
72
104
|
definition.result
|
73
105
|
end
|
74
106
|
|
107
|
+
# Return if a custom view should override default association view
|
108
|
+
#
|
109
|
+
# @return [Boolean]
|
110
|
+
#
|
75
111
|
# @api public
|
76
112
|
def override?
|
77
113
|
definition.override
|
78
114
|
end
|
79
115
|
|
116
|
+
# Return the name of a key in tuples under which loaded association data are returned
|
117
|
+
#
|
118
|
+
# @return [Symbol]
|
119
|
+
#
|
80
120
|
# @api public
|
81
121
|
def key
|
82
122
|
as || name
|
83
123
|
end
|
84
124
|
|
125
|
+
# Applies custom view to the default association view
|
126
|
+
#
|
127
|
+
# @return [Relation]
|
128
|
+
#
|
85
129
|
# @api protected
|
86
130
|
def apply_view(schema, relation)
|
87
131
|
view_rel = relation.public_send(view)
|
88
132
|
schema.merge(view_rel.schema).uniq(&:key).(view_rel)
|
89
133
|
end
|
90
134
|
|
135
|
+
# Return combine keys hash
|
136
|
+
#
|
137
|
+
# Combine keys are used for merging associated data together, typically these
|
138
|
+
# are the same as fk<=>pk mapping
|
139
|
+
#
|
140
|
+
# @return [Hash<Symbol=>Symbol>]
|
141
|
+
#
|
91
142
|
# @api public
|
92
143
|
def combine_keys
|
93
|
-
{ source_key => target_key }
|
144
|
+
definition.combine_keys || { source_key => target_key }
|
94
145
|
end
|
95
146
|
|
147
|
+
# Return names of source PKs and target FKs
|
148
|
+
#
|
149
|
+
# @return [Array<Symbol>]
|
150
|
+
#
|
96
151
|
# @api private
|
97
152
|
def join_key_map
|
98
153
|
join_keys.to_a.flatten(1).map(&:key)
|
99
154
|
end
|
100
155
|
|
156
|
+
# Return target relation configured as a combine node
|
157
|
+
#
|
158
|
+
# @return [Relation]
|
159
|
+
#
|
101
160
|
# @api private
|
102
161
|
def node
|
103
162
|
target.with(
|
@@ -106,6 +165,10 @@ module ROM
|
|
106
165
|
)
|
107
166
|
end
|
108
167
|
|
168
|
+
# Return target relation as a wrap node
|
169
|
+
#
|
170
|
+
# @return [Relation]
|
171
|
+
#
|
109
172
|
# @api private
|
110
173
|
def wrap
|
111
174
|
target.with(
|
@@ -115,6 +178,10 @@ module ROM
|
|
115
178
|
)
|
116
179
|
end
|
117
180
|
|
181
|
+
# Prepare association's target relation for composition
|
182
|
+
#
|
183
|
+
# @return [Relation]
|
184
|
+
#
|
118
185
|
# @api private
|
119
186
|
def prepare(target)
|
120
187
|
if override?
|
@@ -124,6 +191,10 @@ module ROM
|
|
124
191
|
end
|
125
192
|
end
|
126
193
|
|
194
|
+
# Return if this association's source relation is the same as the target
|
195
|
+
#
|
196
|
+
# @return [Boolean]
|
197
|
+
#
|
127
198
|
# @api private
|
128
199
|
def self_ref?
|
129
200
|
source.name.dataset == target.name.dataset
|
@@ -55,16 +55,20 @@ module ROM
|
|
55
55
|
# @return [TrueClass,FalseClass] Whether custom view should override default one or not
|
56
56
|
option :override, optional: true, default: -> { false }
|
57
57
|
|
58
|
+
# @!attribute [r] combine_keys
|
59
|
+
# @return [Hash<Symbol=>Symbol>] Override inferred combine keys
|
60
|
+
option :combine_keys, optional: true
|
61
|
+
|
58
62
|
# Instantiate a new association definition
|
59
63
|
#
|
60
64
|
# @param [Symbol] source The name of the source dataset
|
61
65
|
# @param [Symbol] target The name of the target dataset
|
62
|
-
# @param [Hash]
|
63
|
-
# @option
|
64
|
-
# @option
|
65
|
-
# @option
|
66
|
-
# @option
|
67
|
-
# @option
|
66
|
+
# @param [Hash] opts The option hash
|
67
|
+
# @option opts [Symbol] :as The name of the association (defaults to target)
|
68
|
+
# @option opts [Symbol] :relation The name of the target relation (defaults to target)
|
69
|
+
# @option opts [Symbol] :foreign_key The name of a custom foreign key
|
70
|
+
# @option opts [Symbol] :view The name of a custom relation view on the target's relation side
|
71
|
+
# @option opts [TrueClass,FalseClass] :override Whether provided :view should override association's default view
|
68
72
|
#
|
69
73
|
# @api public
|
70
74
|
def self.new(source, target, opts = EMPTY_HASH)
|
@@ -96,16 +100,28 @@ module ROM
|
|
96
100
|
options
|
97
101
|
end
|
98
102
|
|
103
|
+
# Return true if association's default relation view should be overridden by a custom one
|
104
|
+
#
|
105
|
+
# @return [Boolean]
|
106
|
+
#
|
99
107
|
# @api public
|
100
108
|
def override?
|
101
109
|
options[:override].equal?(true)
|
102
110
|
end
|
103
111
|
|
112
|
+
# Return true if association is aliased
|
113
|
+
#
|
114
|
+
# @return [Boolean]
|
115
|
+
#
|
104
116
|
# @api public
|
105
117
|
def aliased?
|
106
118
|
options.key?(:as)
|
107
119
|
end
|
108
120
|
|
121
|
+
# Return association class for a given definition object
|
122
|
+
#
|
123
|
+
# @return [Class]
|
124
|
+
#
|
109
125
|
# @api public
|
110
126
|
def type
|
111
127
|
Dry::Core::Inflector.demodulize(self.class.name).to_sym
|
@@ -4,9 +4,12 @@ require 'rom/associations/definitions/abstract'
|
|
4
4
|
module ROM
|
5
5
|
module Associations
|
6
6
|
module Definitions
|
7
|
+
# @api private
|
7
8
|
class ManyToMany < Abstract
|
8
9
|
result :many
|
9
10
|
|
11
|
+
# @!attribute [r] through
|
12
|
+
# @return [ThroughIdentifier] The name of the "through" relation
|
10
13
|
option :through, reader: true
|
11
14
|
|
12
15
|
# @api private
|
@@ -3,7 +3,12 @@ require 'rom/associations/abstract'
|
|
3
3
|
|
4
4
|
module ROM
|
5
5
|
module Associations
|
6
|
+
# Abstract many-to-many association type
|
7
|
+
#
|
8
|
+
# @api public
|
6
9
|
class ManyToMany < Abstract
|
10
|
+
# @!attribute [r] join_relation
|
11
|
+
# @return [Relation] Intermediate join relation
|
7
12
|
attr_reader :join_relation
|
8
13
|
|
9
14
|
# @api private
|
@@ -12,26 +17,49 @@ module ROM
|
|
12
17
|
@join_relation = relations[through]
|
13
18
|
end
|
14
19
|
|
20
|
+
# Adapters should implement this method
|
21
|
+
#
|
22
|
+
# @abstract
|
23
|
+
#
|
15
24
|
# @api public
|
16
25
|
def call(*)
|
17
26
|
raise NotImplementedError
|
18
27
|
end
|
19
28
|
|
29
|
+
# Return configured or inferred FK name
|
30
|
+
#
|
31
|
+
# @return [Symbol]
|
32
|
+
#
|
20
33
|
# @api public
|
21
34
|
def foreign_key
|
22
35
|
definition.foreign_key || join_relation.foreign_key(source.name)
|
23
36
|
end
|
24
37
|
|
38
|
+
# Return join-relation name
|
39
|
+
#
|
40
|
+
# @return [Symbol]
|
41
|
+
#
|
25
42
|
# @api public
|
26
43
|
def through
|
27
44
|
definition.through
|
28
45
|
end
|
29
46
|
|
47
|
+
# Return parent's relation combine keys
|
48
|
+
#
|
49
|
+
# @return [Hash<Symbol=>Symbol>]
|
50
|
+
#
|
30
51
|
# @api private
|
31
52
|
def parent_combine_keys
|
32
53
|
target.associations[source.name].combine_keys.to_a.flatten(1)
|
33
54
|
end
|
34
55
|
|
56
|
+
# Associate child tuples with the provided parent
|
57
|
+
#
|
58
|
+
# @param [Array<Hash>] children An array with child tuples
|
59
|
+
# @param [Array,Hash] parent An array with parent tuples or a single tuple
|
60
|
+
#
|
61
|
+
# @return [Array<Hash>]
|
62
|
+
#
|
35
63
|
# @api private
|
36
64
|
def associate(children, parent)
|
37
65
|
((spk, sfk), (tfk, tpk)) = join_key_map
|
@@ -48,16 +76,28 @@ module ROM
|
|
48
76
|
|
49
77
|
protected
|
50
78
|
|
79
|
+
# Primary key name on the source side
|
80
|
+
#
|
81
|
+
# @return [Symbol]
|
82
|
+
#
|
51
83
|
# @api protected
|
52
84
|
def source_key
|
53
85
|
source.primary_key
|
54
86
|
end
|
55
87
|
|
88
|
+
# Foreign key name on the target side
|
89
|
+
#
|
90
|
+
# @return [Symbol]
|
91
|
+
#
|
56
92
|
# @api protected
|
57
93
|
def target_key
|
58
94
|
foreign_key
|
59
95
|
end
|
60
96
|
|
97
|
+
# Return association for many-to-many-through
|
98
|
+
#
|
99
|
+
# @return [Association]
|
100
|
+
#
|
61
101
|
# @api protected
|
62
102
|
def join_assoc
|
63
103
|
if join_relation.associations.key?(through.assoc_name)
|
@@ -67,6 +107,10 @@ module ROM
|
|
67
107
|
end
|
68
108
|
end
|
69
109
|
|
110
|
+
# Return a [pk, fk] mapping for source/target relations
|
111
|
+
#
|
112
|
+
# @return [Array<Symbol>]
|
113
|
+
#
|
70
114
|
# @api protected
|
71
115
|
def join_key_map
|
72
116
|
left = super
|
@@ -2,17 +2,35 @@ require 'rom/associations/abstract'
|
|
2
2
|
|
3
3
|
module ROM
|
4
4
|
module Associations
|
5
|
+
# Abstract many-to-one association type
|
6
|
+
#
|
7
|
+
# @api public
|
5
8
|
class ManyToOne < Abstract
|
9
|
+
# Adapters must implement this method
|
10
|
+
#
|
11
|
+
# @abstract
|
12
|
+
#
|
6
13
|
# @api public
|
7
14
|
def call(*)
|
8
15
|
raise NotImplementedError
|
9
16
|
end
|
10
17
|
|
18
|
+
# Return configured or inferred FK name
|
19
|
+
#
|
20
|
+
# @return [Symbol]
|
21
|
+
#
|
11
22
|
# @api public
|
12
23
|
def foreign_key
|
13
24
|
definition.foreign_key || source.foreign_key(target.name)
|
14
25
|
end
|
15
26
|
|
27
|
+
# Associate child with a parent
|
28
|
+
#
|
29
|
+
# @param [Hash] child The child tuple
|
30
|
+
# @param [Hash] parent The parent tuple
|
31
|
+
#
|
32
|
+
# @return [Hash]
|
33
|
+
#
|
16
34
|
# @api private
|
17
35
|
def associate(child, parent)
|
18
36
|
fk, pk = join_key_map
|
@@ -21,11 +39,19 @@ module ROM
|
|
21
39
|
|
22
40
|
protected
|
23
41
|
|
42
|
+
# Return foreign key on the source side
|
43
|
+
#
|
44
|
+
# @return [Symbol]
|
45
|
+
#
|
24
46
|
# @api protected
|
25
47
|
def source_key
|
26
48
|
foreign_key
|
27
49
|
end
|
28
50
|
|
51
|
+
# Return primary key on the target side
|
52
|
+
#
|
53
|
+
# @return [Symbol]
|
54
|
+
#
|
29
55
|
# @api protected
|
30
56
|
def target_key
|
31
57
|
target.schema.primary_key_name
|