rom 5.4.1 → 6.0.0.alpha1

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.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -65
  3. data/LICENSE +1 -1
  4. data/README.md +7 -6
  5. data/lib/rom/array_dataset.rb +46 -0
  6. data/lib/rom/associations/abstract.rb +217 -0
  7. data/lib/rom/associations/definitions/abstract.rb +150 -0
  8. data/lib/rom/associations/definitions/many_to_many.rb +29 -0
  9. data/lib/rom/associations/definitions/many_to_one.rb +14 -0
  10. data/lib/rom/associations/definitions/one_to_many.rb +14 -0
  11. data/lib/rom/associations/definitions/one_to_one.rb +14 -0
  12. data/lib/rom/associations/definitions/one_to_one_through.rb +14 -0
  13. data/lib/rom/associations/definitions.rb +7 -0
  14. data/lib/rom/associations/many_to_many.rb +128 -0
  15. data/lib/rom/associations/many_to_one.rb +65 -0
  16. data/lib/rom/associations/one_to_many.rb +65 -0
  17. data/lib/rom/associations/one_to_one.rb +13 -0
  18. data/lib/rom/associations/one_to_one_through.rb +13 -0
  19. data/lib/rom/associations/through_identifier.rb +41 -0
  20. data/lib/rom/attribute.rb +425 -0
  21. data/lib/rom/auto_curry.rb +70 -0
  22. data/lib/rom/cache.rb +87 -0
  23. data/lib/rom/changeset/associated.rb +110 -0
  24. data/lib/rom/changeset/create.rb +18 -0
  25. data/lib/rom/changeset/delete.rb +15 -0
  26. data/lib/rom/changeset/extensions/relation.rb +26 -0
  27. data/lib/rom/changeset/pipe.rb +81 -0
  28. data/lib/rom/changeset/pipe_registry.rb +27 -0
  29. data/lib/rom/changeset/stateful.rb +285 -0
  30. data/lib/rom/changeset/update.rb +81 -0
  31. data/lib/rom/changeset.rb +185 -0
  32. data/lib/rom/command.rb +351 -0
  33. data/lib/rom/command_compiler.rb +201 -0
  34. data/lib/rom/command_proxy.rb +36 -0
  35. data/lib/rom/commands/class_interface.rb +236 -0
  36. data/lib/rom/commands/composite.rb +55 -0
  37. data/lib/rom/commands/create.rb +15 -0
  38. data/lib/rom/commands/delete.rb +16 -0
  39. data/lib/rom/commands/graph/class_interface.rb +64 -0
  40. data/lib/rom/commands/graph/input_evaluator.rb +94 -0
  41. data/lib/rom/commands/graph.rb +88 -0
  42. data/lib/rom/commands/lazy/create.rb +35 -0
  43. data/lib/rom/commands/lazy/delete.rb +39 -0
  44. data/lib/rom/commands/lazy/update.rb +46 -0
  45. data/lib/rom/commands/lazy.rb +106 -0
  46. data/lib/rom/commands/update.rb +16 -0
  47. data/lib/rom/commands.rb +5 -0
  48. data/lib/rom/compat/auto_registration.rb +115 -0
  49. data/lib/rom/compat/auto_registration_strategies/base.rb +29 -0
  50. data/lib/rom/compat/auto_registration_strategies/custom_namespace.rb +84 -0
  51. data/lib/rom/compat/auto_registration_strategies/no_namespace.rb +33 -0
  52. data/lib/rom/compat/auto_registration_strategies/with_namespace.rb +29 -0
  53. data/lib/rom/compat/command.rb +74 -0
  54. data/lib/rom/compat/components/dsl/schema.rb +130 -0
  55. data/lib/rom/compat/components.rb +91 -0
  56. data/lib/rom/compat/global.rb +17 -0
  57. data/lib/rom/compat/mapper.rb +22 -0
  58. data/lib/rom/compat/registries.rb +47 -0
  59. data/lib/rom/compat/relation.rb +40 -0
  60. data/lib/rom/compat/schema/dsl.rb +260 -0
  61. data/lib/rom/compat/setting_proxy.rb +44 -0
  62. data/lib/rom/compat/setup.rb +151 -0
  63. data/lib/rom/compat/transformer.rb +49 -0
  64. data/lib/rom/compat.rb +22 -0
  65. data/lib/rom/components/association.rb +26 -0
  66. data/lib/rom/components/command.rb +24 -0
  67. data/lib/rom/components/core.rb +148 -0
  68. data/lib/rom/components/dataset.rb +60 -0
  69. data/lib/rom/components/dsl/association.rb +47 -0
  70. data/lib/rom/components/dsl/command.rb +60 -0
  71. data/lib/rom/components/dsl/core.rb +126 -0
  72. data/lib/rom/components/dsl/dataset.rb +33 -0
  73. data/lib/rom/components/dsl/gateway.rb +14 -0
  74. data/lib/rom/components/dsl/mapper.rb +70 -0
  75. data/lib/rom/components/dsl/relation.rb +49 -0
  76. data/lib/rom/components/dsl/schema.rb +150 -0
  77. data/lib/rom/components/dsl/view.rb +82 -0
  78. data/lib/rom/components/dsl.rb +255 -0
  79. data/lib/rom/components/gateway.rb +50 -0
  80. data/lib/rom/components/mapper.rb +29 -0
  81. data/lib/rom/components/provider.rb +160 -0
  82. data/lib/rom/components/registry.rb +154 -0
  83. data/lib/rom/components/relation.rb +41 -0
  84. data/lib/rom/components/schema.rb +61 -0
  85. data/lib/rom/components/view.rb +55 -0
  86. data/lib/rom/components.rb +55 -0
  87. data/lib/rom/configuration_dsl.rb +4 -0
  88. data/lib/rom/constants.rb +135 -0
  89. data/lib/rom/container.rb +182 -0
  90. data/lib/rom/core.rb +125 -0
  91. data/lib/rom/data_proxy.rb +97 -0
  92. data/lib/rom/enumerable_dataset.rb +70 -0
  93. data/lib/rom/gateway.rb +232 -0
  94. data/lib/rom/global.rb +56 -0
  95. data/lib/rom/header/attribute.rb +190 -0
  96. data/lib/rom/header.rb +198 -0
  97. data/lib/rom/inferrer.rb +55 -0
  98. data/lib/rom/initializer.rb +80 -0
  99. data/lib/rom/lint/enumerable_dataset.rb +56 -0
  100. data/lib/rom/lint/gateway.rb +120 -0
  101. data/lib/rom/lint/linter.rb +79 -0
  102. data/lib/rom/lint/spec.rb +22 -0
  103. data/lib/rom/lint/test.rb +98 -0
  104. data/lib/rom/loader.rb +161 -0
  105. data/lib/rom/mapper/attribute_dsl.rb +480 -0
  106. data/lib/rom/mapper/dsl.rb +107 -0
  107. data/lib/rom/mapper/model_dsl.rb +61 -0
  108. data/lib/rom/mapper.rb +99 -0
  109. data/lib/rom/mapper_compiler.rb +84 -0
  110. data/lib/rom/memory/associations/many_to_many.rb +12 -0
  111. data/lib/rom/memory/associations/many_to_one.rb +12 -0
  112. data/lib/rom/memory/associations/one_to_many.rb +12 -0
  113. data/lib/rom/memory/associations/one_to_one.rb +12 -0
  114. data/lib/rom/memory/associations.rb +6 -0
  115. data/lib/rom/memory/commands.rb +60 -0
  116. data/lib/rom/memory/dataset.rb +127 -0
  117. data/lib/rom/memory/gateway.rb +66 -0
  118. data/lib/rom/memory/mapper_compiler.rb +10 -0
  119. data/lib/rom/memory/relation.rb +91 -0
  120. data/lib/rom/memory/schema.rb +32 -0
  121. data/lib/rom/memory/storage.rb +61 -0
  122. data/lib/rom/memory/types.rb +11 -0
  123. data/lib/rom/memory.rb +7 -0
  124. data/lib/rom/model_builder.rb +103 -0
  125. data/lib/rom/open_struct.rb +112 -0
  126. data/lib/rom/pipeline.rb +111 -0
  127. data/lib/rom/plugin.rb +130 -0
  128. data/lib/rom/plugins/class_methods.rb +37 -0
  129. data/lib/rom/plugins/command/schema.rb +45 -0
  130. data/lib/rom/plugins/command/timestamps.rb +149 -0
  131. data/lib/rom/plugins/dsl.rb +53 -0
  132. data/lib/rom/plugins/relation/changeset.rb +97 -0
  133. data/lib/rom/plugins/relation/instrumentation.rb +66 -0
  134. data/lib/rom/plugins/relation/registry_reader.rb +36 -0
  135. data/lib/rom/plugins/schema/timestamps.rb +59 -0
  136. data/lib/rom/plugins.rb +100 -0
  137. data/lib/rom/processor/composer.rb +37 -0
  138. data/lib/rom/processor/transformer.rb +415 -0
  139. data/lib/rom/processor.rb +30 -0
  140. data/lib/rom/registries/associations.rb +26 -0
  141. data/lib/rom/registries/commands.rb +11 -0
  142. data/lib/rom/registries/container.rb +12 -0
  143. data/lib/rom/registries/datasets.rb +21 -0
  144. data/lib/rom/registries/gateways.rb +8 -0
  145. data/lib/rom/registries/mappers.rb +21 -0
  146. data/lib/rom/registries/nestable.rb +32 -0
  147. data/lib/rom/registries/relations.rb +8 -0
  148. data/lib/rom/registries/root.rb +203 -0
  149. data/lib/rom/registries/schemas.rb +44 -0
  150. data/lib/rom/registries/views.rb +11 -0
  151. data/lib/rom/relation/class_interface.rb +61 -0
  152. data/lib/rom/relation/combined.rb +160 -0
  153. data/lib/rom/relation/commands.rb +65 -0
  154. data/lib/rom/relation/composite.rb +53 -0
  155. data/lib/rom/relation/curried.rb +129 -0
  156. data/lib/rom/relation/graph.rb +107 -0
  157. data/lib/rom/relation/loaded.rb +136 -0
  158. data/lib/rom/relation/materializable.rb +62 -0
  159. data/lib/rom/relation/name.rb +122 -0
  160. data/lib/rom/relation/wrap.rb +64 -0
  161. data/lib/rom/relation.rb +625 -0
  162. data/lib/rom/repository/class_interface.rb +162 -0
  163. data/lib/rom/repository/relation_reader.rb +48 -0
  164. data/lib/rom/repository/root.rb +75 -0
  165. data/lib/rom/repository/session.rb +60 -0
  166. data/lib/rom/repository.rb +179 -0
  167. data/lib/rom/schema/associations_dsl.rb +222 -0
  168. data/lib/rom/schema/inferrer.rb +106 -0
  169. data/lib/rom/schema.rb +471 -0
  170. data/lib/rom/settings.rb +141 -0
  171. data/lib/rom/setup.rb +297 -0
  172. data/lib/rom/struct.rb +99 -0
  173. data/lib/rom/struct_compiler.rb +114 -0
  174. data/lib/rom/support/configurable.rb +213 -0
  175. data/lib/rom/support/inflector.rb +31 -0
  176. data/lib/rom/support/memoizable.rb +61 -0
  177. data/lib/rom/support/notifications.rb +238 -0
  178. data/lib/rom/transaction.rb +26 -0
  179. data/lib/rom/transformer.rb +46 -0
  180. data/lib/rom/types.rb +74 -0
  181. data/lib/rom/version.rb +1 -1
  182. data/lib/rom-changeset.rb +4 -0
  183. data/lib/rom-core.rb +3 -0
  184. data/lib/rom-repository.rb +4 -0
  185. data/lib/rom.rb +3 -3
  186. metadata +302 -23
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/support/inflector"
4
+
5
+ require "rom/associations/definitions"
6
+
7
+ module ROM
8
+ class Schema
9
+ # Additional schema DSL for definition SQL associations
10
+ #
11
+ # This DSL is exposed in `associations do .. end` blocks in schema defintions.
12
+ #
13
+ # @api public
14
+ class AssociationsDSL < ::BasicObject
15
+ class << self
16
+ define_method(:const_missing, ::Object.method(:const_get))
17
+ end
18
+
19
+ include Associations::Definitions
20
+
21
+ # @!attribute [r] source
22
+ # @return [Relation::Name] The source relation
23
+ attr_reader :source
24
+
25
+ # @!attribute [r] inflector
26
+ # @return [Dry::Inflector] String inflector
27
+ attr_reader :inflector
28
+
29
+ # @!attribute [r] registry
30
+ # @return [Hash]
31
+ attr_reader :registry
32
+
33
+ # @api private
34
+ def initialize(source, inflector = Inflector, &block)
35
+ @source = source
36
+ @inflector = inflector
37
+ @registry = {}
38
+ instance_exec(&block) if block
39
+ end
40
+
41
+ # Establish a one-to-many association
42
+ #
43
+ # @example using relation identifier
44
+ # has_many :tasks
45
+ #
46
+ # @example setting custom foreign key name
47
+ # has_many :tasks, foreign_key: :assignee_id
48
+ #
49
+ # @example with a :through option
50
+ # # this establishes many-to-many association
51
+ # has_many :tasks, through: :users_tasks
52
+ #
53
+ # @example using a custom view which overrides default one
54
+ # has_many :posts, view: :published, override: true
55
+ #
56
+ # @example using aliased association with a custom view
57
+ # has_many :posts, as: :published_posts, view: :published
58
+ #
59
+ # @example using custom target relation
60
+ # has_many :user_posts, relation: :posts
61
+ #
62
+ # @example using custom target relation and an alias
63
+ # has_many :user_posts, relation: :posts, as: :published, view: :published
64
+ #
65
+ # @param [Symbol] target The target relation identifier
66
+ # @param [Hash] options A hash with additional options
67
+ #
68
+ # @return [Associations::OneToMany]
69
+ #
70
+ # @see #many_to_many
71
+ #
72
+ # @api public
73
+ def one_to_many(target, **options)
74
+ if options[:through]
75
+ many_to_many(target, **options, inflector: inflector)
76
+ else
77
+ add(build(OneToMany, target, options))
78
+ end
79
+ end
80
+ alias_method :has_many, :one_to_many
81
+
82
+ # Establish a one-to-one association
83
+ #
84
+ # @example using relation identifier
85
+ # one_to_one :addresses, as: :address
86
+ #
87
+ # @example with an intermediate join relation
88
+ # one_to_one :tasks, as: :priority_task, through: :assignments
89
+ #
90
+ # @param [Symbol] target The target relation identifier
91
+ # @param [Hash] options A hash with additional options
92
+ #
93
+ # @return [Associations::OneToOne]
94
+ #
95
+ # @see #belongs_to
96
+ #
97
+ # @api public
98
+ def one_to_one(target, **options)
99
+ if options[:through]
100
+ one_to_one_through(target, **options)
101
+ else
102
+ add(build(OneToOne, target, options))
103
+ end
104
+ end
105
+
106
+ # Establish a one-to-one association with a :through option
107
+ #
108
+ # @example
109
+ # one_to_one_through :users, as: :author, through: :users_posts
110
+ #
111
+ # @return [Associations::OneToOneThrough]
112
+ #
113
+ # @api public
114
+ def one_to_one_through(target, **options)
115
+ add(build(OneToOneThrough, target, options))
116
+ end
117
+
118
+ # Establish a many-to-many association
119
+ #
120
+ # @example using relation identifier
121
+ # many_to_many :tasks, through: :users_tasks
122
+ #
123
+ # @param [Symbol] target The target relation identifier
124
+ # @param [Hash] options A hash with additional options
125
+ #
126
+ # @return [Associations::ManyToMany]
127
+ #
128
+ # @see #one_to_many
129
+ #
130
+ # @api public
131
+ def many_to_many(target, **options)
132
+ add(build(ManyToMany, target, options))
133
+ end
134
+
135
+ # Establish a many-to-one association
136
+ #
137
+ # @example using relation identifier
138
+ # many_to_one :users, as: :author
139
+ #
140
+ # @param [Symbol] target The target relation identifier
141
+ # @param [Hash] options A hash with additional options
142
+ #
143
+ # @return [Associations::ManyToOne]
144
+ #
145
+ # @see #one_to_many
146
+ #
147
+ # @api public
148
+ def many_to_one(target, **options)
149
+ add(build(ManyToOne, target, options))
150
+ end
151
+
152
+ # Shortcut for many_to_one which sets alias automatically
153
+ #
154
+ # @example with an alias (relation identifier is inferred via pluralization)
155
+ # belongs_to :user
156
+ #
157
+ # @example with an explicit alias
158
+ # belongs_to :users, as: :author
159
+ #
160
+ # @see #many_to_one
161
+ #
162
+ # @return [Associations::ManyToOne]
163
+ #
164
+ # @api public
165
+ def belongs_to(target, **options)
166
+ many_to_one(dataset_name(target), as: target, **options)
167
+ end
168
+
169
+ # Shortcut for one_to_one which sets alias automatically
170
+ #
171
+ # @example with an alias (relation identifier is inferred via pluralization)
172
+ # has_one :address
173
+ #
174
+ # @example with an explicit alias and a custom view
175
+ # has_one :posts, as: :priority_post, view: :prioritized
176
+ #
177
+ # @see #one_to_one
178
+ #
179
+ # @return [Associations::OneToOne]
180
+ #
181
+ # @api public
182
+ def has_one(target, **options)
183
+ one_to_one(dataset_name(target), as: target, **options)
184
+ end
185
+
186
+ # Return an association set for a schema
187
+ #
188
+ # @return [Array<Association::Definition]
189
+ #
190
+ # @api private
191
+ def call
192
+ registry.values
193
+ end
194
+
195
+ private
196
+
197
+ # @api private
198
+ def build(definition, target, options)
199
+ definition.new(source, target, **options, inflector: inflector)
200
+ end
201
+
202
+ # @api private
203
+ def add(association)
204
+ key = association.as || association.name
205
+
206
+ if registry.key?(key)
207
+ ::Kernel.raise(
208
+ ::ArgumentError,
209
+ "association #{key.inspect} is already defined for #{source.to_sym.inspect} relation"
210
+ )
211
+ end
212
+
213
+ registry[key] = association
214
+ end
215
+
216
+ # @api private
217
+ def dataset_name(name)
218
+ inflector.pluralize(name).to_sym
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/class_attributes"
4
+
5
+ module ROM
6
+ class Schema
7
+ # @api private
8
+ class Inferrer
9
+ extend Dry::Core::ClassAttributes
10
+ extend Initializer
11
+
12
+ # @!method self.attributes_inferrer
13
+ # @overload attributes_inferrer
14
+ # @return [Proc]
15
+ #
16
+ # @overload attributes_inferrer(value)
17
+ # @param value [Proc]
18
+ # @return [Proc]
19
+ #
20
+ # @!method self.attr_class
21
+ # @overload attr_class
22
+ # @return [Class(ROM::Attribute)]
23
+ #
24
+ # @overload attr_class(value)
25
+ # @param value [Class(ROM::Attribute)]
26
+ # @return [Class(ROM::Attribute)]
27
+ defines :attributes_inferrer, :attr_class
28
+
29
+ MissingAttributesError = Class.new(StandardError) do
30
+ def initialize(name, attributes)
31
+ super(
32
+ "Following attributes in #{Relation::Name[name].relation.inspect} schema cannot "\
33
+ "be inferred and have to be defined explicitly: #{attributes.map(&:inspect).join(", ")}"
34
+ )
35
+ end
36
+ end
37
+
38
+ DEFAULT_ATTRIBUTES = [EMPTY_ARRAY, EMPTY_ARRAY].freeze
39
+
40
+ attributes_inferrer -> * { DEFAULT_ATTRIBUTES }
41
+
42
+ attr_class Attribute
43
+
44
+ include Dry::Equalizer(:options)
45
+
46
+ # @!attribute [r] attr_class
47
+ # @return [Class(ROM::Attribute)]
48
+ option :attr_class, default: -> { self.class.attr_class }
49
+
50
+ # @!attribute [r] enabled
51
+ # @return [Boolean]
52
+ option :enabled, default: -> { true }
53
+
54
+ alias_method :enabled?, :enabled
55
+
56
+ # @!attribute [r] attributes_inferrer
57
+ # @return [ROM::Schema::AttributesInferrer]
58
+ option :attributes_inferrer, default: -> { self.class.attributes_inferrer }
59
+
60
+ # @api private
61
+ def call(schema, gateway)
62
+ if enabled?
63
+ inferred, missing = attributes_inferrer.(schema, gateway, options)
64
+ else
65
+ inferred, missing = DEFAULT_ATTRIBUTES
66
+ end
67
+
68
+ attributes = merge_attributes(schema.attributes, inferred)
69
+
70
+ check_all_attributes_defined(schema, attributes, missing)
71
+
72
+ {attributes: attributes}
73
+ end
74
+
75
+ # @api private
76
+ def check_all_attributes_defined(schema, all_known, not_inferred)
77
+ not_defined = not_inferred - all_known.map(&:name)
78
+
79
+ raise MissingAttributesError.new(schema.name, not_defined) unless not_defined.empty?
80
+ end
81
+
82
+ # @api private
83
+ def merge_attributes(defined, inferred)
84
+ type_lookup = lambda do |attrs, name|
85
+ attrs.find { |a| a.name == name }.type
86
+ end
87
+ defined_with_type, defined_names =
88
+ defined.each_with_object([[], []]) do |attr, (attrs, names)|
89
+ attrs << if attr.type.nil?
90
+ attr.class.new(
91
+ type_lookup.(inferred, attr.name),
92
+ **attr.options
93
+ )
94
+ else
95
+ attr
96
+ end
97
+ names << attr.name
98
+ end
99
+
100
+ defined_with_type + inferred.reject do |attr|
101
+ defined_names.include?(attr.name)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end