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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -1
  3. data/lib/rom/association_set.rb +3 -0
  4. data/lib/rom/associations/abstract.rb +72 -1
  5. data/lib/rom/associations/definitions/abstract.rb +22 -6
  6. data/lib/rom/associations/definitions/many_to_many.rb +3 -0
  7. data/lib/rom/associations/definitions/many_to_one.rb +1 -0
  8. data/lib/rom/associations/definitions/one_to_many.rb +1 -0
  9. data/lib/rom/associations/definitions/one_to_one.rb +1 -0
  10. data/lib/rom/associations/definitions/one_to_one_through.rb +1 -0
  11. data/lib/rom/associations/many_to_many.rb +44 -0
  12. data/lib/rom/associations/many_to_one.rb +26 -0
  13. data/lib/rom/associations/one_to_many.rb +26 -0
  14. data/lib/rom/associations/one_to_one.rb +3 -0
  15. data/lib/rom/associations/one_to_one_through.rb +3 -0
  16. data/lib/rom/attribute.rb +2 -2
  17. data/lib/rom/auto_curry.rb +11 -0
  18. data/lib/rom/cache.rb +29 -0
  19. data/lib/rom/command_compiler.rb +4 -4
  20. data/lib/rom/command_registry.rb +9 -5
  21. data/lib/rom/commands/class_interface.rb +7 -7
  22. data/lib/rom/commands/graph/input_evaluator.rb +33 -3
  23. data/lib/rom/commands/lazy.rb +4 -0
  24. data/lib/rom/commands/lazy/create.rb +10 -0
  25. data/lib/rom/commands/lazy/delete.rb +10 -0
  26. data/lib/rom/commands/lazy/update.rb +10 -0
  27. data/lib/rom/configuration.rb +34 -14
  28. data/lib/rom/configuration_dsl.rb +0 -2
  29. data/lib/rom/constants.rb +10 -0
  30. data/lib/rom/container.rb +16 -0
  31. data/lib/rom/create_container.rb +7 -0
  32. data/lib/rom/environment.rb +3 -2
  33. data/lib/rom/gateway.rb +16 -1
  34. data/lib/rom/global.rb +1 -1
  35. data/lib/rom/global/plugin_dsl.rb +3 -1
  36. data/lib/rom/initializer.rb +25 -13
  37. data/lib/rom/mapper_registry.rb +4 -1
  38. data/lib/rom/memory/dataset.rb +29 -2
  39. data/lib/rom/memory/schema.rb +7 -0
  40. data/lib/rom/plugin_base.rb +1 -1
  41. data/lib/rom/plugin_registry.rb +2 -2
  42. data/lib/rom/plugins/command/schema.rb +7 -0
  43. data/lib/rom/plugins/relation/instrumentation.rb +10 -0
  44. data/lib/rom/plugins/relation/registry_reader.rb +0 -3
  45. data/lib/rom/registry.rb +15 -3
  46. data/lib/rom/relation.rb +38 -23
  47. data/lib/rom/relation/class_interface.rb +15 -6
  48. data/lib/rom/relation/combined.rb +7 -2
  49. data/lib/rom/relation/curried.rb +23 -0
  50. data/lib/rom/relation/graph.rb +25 -14
  51. data/lib/rom/relation/loaded.rb +7 -4
  52. data/lib/rom/relation/materializable.rb +2 -2
  53. data/lib/rom/relation/view_dsl.rb +2 -1
  54. data/lib/rom/relation/wrap.rb +14 -0
  55. data/lib/rom/relation_registry.rb +2 -0
  56. data/lib/rom/schema.rb +25 -4
  57. data/lib/rom/schema/associations_dsl.rb +9 -0
  58. data/lib/rom/schema/dsl.rb +27 -4
  59. data/lib/rom/setup.rb +20 -7
  60. data/lib/rom/setup/auto_registration.rb +27 -0
  61. data/lib/rom/setup/auto_registration_strategies/base.rb +7 -2
  62. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +17 -0
  63. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +11 -0
  64. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +9 -0
  65. data/lib/rom/setup/finalize/finalize_mappers.rb +4 -2
  66. data/lib/rom/setup/finalize/finalize_relations.rb +1 -1
  67. data/lib/rom/support/configurable.rb +19 -0
  68. data/lib/rom/support/notifications.rb +29 -2
  69. data/lib/rom/types.rb +53 -8
  70. data/lib/rom/version.rb +1 -1
  71. metadata +7 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8a152a49542a83c5195f02e61f08823c7207f23
4
- data.tar.gz: d4513f31be747f8f01e7c581084782afc3662a6a
3
+ metadata.gz: dd842da91b8eff4e935f9bc0064b7225fbc41d6a
4
+ data.tar.gz: b949c0798bbddfb9bb49b52b0e4137759accc1f7
5
5
  SHA512:
6
- metadata.gz: 652ebe10f678636a8dfe0dd78e1f31fbba58499a9e65eaf1589e46c3abc87e730ee773fdf60435146725e73ca7596e519bc3888dd5498a3d81a90783740a7b40
7
- data.tar.gz: 95f2e25a3eac0195a6d9d35697b619b52364255b7fefcbfd1c68a647f9aefecc21a489f9a945346f6834d2936d81235b447451c9131d2b86be40a5c834144e00
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)
@@ -1,6 +1,9 @@
1
1
  require 'rom/registry'
2
2
 
3
3
  module ROM
4
+ # Association set contains a registry with associations defined
5
+ # in schema DSL
6
+ #
4
7
  # @api public
5
8
  class AssociationSet < ROM::Registry
6
9
  # @api private
@@ -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] options The option hash
63
- # @option options [Symbol] :as The name of the association (defaults to target)
64
- # @option options [Symbol] :relation The name of the target relation (defaults to target)
65
- # @option options [Symbol] :foreign_key The name of a custom foreign key
66
- # @option options [Symbol] :view The name of a custom relation view on the target's relation side
67
- # @option options [TrueClass,FalseClass] :override Whether provided :view should override association's default view
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,6 +3,7 @@ require 'rom/associations/definitions/abstract'
3
3
  module ROM
4
4
  module Associations
5
5
  module Definitions
6
+ # @api private
6
7
  class ManyToOne < Abstract
7
8
  result :one
8
9
  end
@@ -3,6 +3,7 @@ require 'rom/associations/definitions/abstract'
3
3
  module ROM
4
4
  module Associations
5
5
  module Definitions
6
+ # @api private
6
7
  class OneToMany < Abstract
7
8
  result :many
8
9
  end
@@ -3,6 +3,7 @@ require 'rom/associations/definitions/abstract'
3
3
  module ROM
4
4
  module Associations
5
5
  module Definitions
6
+ # @api private
6
7
  class OneToOne < Abstract
7
8
  result :one
8
9
  end
@@ -3,6 +3,7 @@ require 'rom/associations/definitions/abstract'
3
3
  module ROM
4
4
  module Associations
5
5
  module Definitions
6
+ # @api private
6
7
  class OneToOneThrough < ManyToMany
7
8
  result :one
8
9
  end
@@ -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