rom 2.0.2 → 4.2.1

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 (203) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +35 -430
  3. data/LICENSE +1 -1
  4. data/README.md +83 -11
  5. data/lib/rom/version.rb +1 -1
  6. data/lib/rom.rb +3 -46
  7. metadata +30 -236
  8. data/.gitignore +0 -24
  9. data/.rspec +0 -3
  10. data/.rubocop.yml +0 -87
  11. data/.rubocop_todo.yml +0 -46
  12. data/.travis.yml +0 -28
  13. data/CODE_OF_CONDUCT.md +0 -13
  14. data/CONTRIBUTING.md +0 -1
  15. data/Gemfile +0 -41
  16. data/Guardfile +0 -24
  17. data/Rakefile +0 -22
  18. data/lib/rom/association_set.rb +0 -26
  19. data/lib/rom/command.rb +0 -173
  20. data/lib/rom/command_registry.rb +0 -153
  21. data/lib/rom/commands/class_interface.rb +0 -148
  22. data/lib/rom/commands/composite.rb +0 -54
  23. data/lib/rom/commands/create.rb +0 -13
  24. data/lib/rom/commands/delete.rb +0 -14
  25. data/lib/rom/commands/graph/builder.rb +0 -176
  26. data/lib/rom/commands/graph/class_interface.rb +0 -62
  27. data/lib/rom/commands/graph/input_evaluator.rb +0 -62
  28. data/lib/rom/commands/graph.rb +0 -103
  29. data/lib/rom/commands/lazy/create.rb +0 -23
  30. data/lib/rom/commands/lazy/delete.rb +0 -27
  31. data/lib/rom/commands/lazy/update.rb +0 -34
  32. data/lib/rom/commands/lazy.rb +0 -99
  33. data/lib/rom/commands/result.rb +0 -96
  34. data/lib/rom/commands/update.rb +0 -14
  35. data/lib/rom/commands.rb +0 -3
  36. data/lib/rom/configuration.rb +0 -88
  37. data/lib/rom/configuration_dsl/command.rb +0 -43
  38. data/lib/rom/configuration_dsl/command_dsl.rb +0 -35
  39. data/lib/rom/configuration_dsl/mapper.rb +0 -37
  40. data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -44
  41. data/lib/rom/configuration_dsl/relation.rb +0 -26
  42. data/lib/rom/configuration_dsl.rb +0 -78
  43. data/lib/rom/configuration_plugin.rb +0 -17
  44. data/lib/rom/constants.rb +0 -30
  45. data/lib/rom/container.rb +0 -231
  46. data/lib/rom/create_container.rb +0 -61
  47. data/lib/rom/environment.rb +0 -70
  48. data/lib/rom/gateway.rb +0 -154
  49. data/lib/rom/global/plugin_dsl.rb +0 -49
  50. data/lib/rom/global.rb +0 -60
  51. data/lib/rom/lint/enumerable_dataset.rb +0 -54
  52. data/lib/rom/lint/gateway.rb +0 -94
  53. data/lib/rom/lint/linter.rb +0 -78
  54. data/lib/rom/lint/spec.rb +0 -20
  55. data/lib/rom/lint/test.rb +0 -98
  56. data/lib/rom/mapper_registry.rb +0 -35
  57. data/lib/rom/memory/commands.rb +0 -58
  58. data/lib/rom/memory/dataset.rb +0 -98
  59. data/lib/rom/memory/gateway.rb +0 -64
  60. data/lib/rom/memory/relation.rb +0 -49
  61. data/lib/rom/memory/storage.rb +0 -59
  62. data/lib/rom/memory/types.rb +0 -9
  63. data/lib/rom/memory.rb +0 -4
  64. data/lib/rom/pipeline.rb +0 -106
  65. data/lib/rom/plugin.rb +0 -17
  66. data/lib/rom/plugin_base.rb +0 -31
  67. data/lib/rom/plugin_registry.rb +0 -173
  68. data/lib/rom/plugins/command/schema.rb +0 -37
  69. data/lib/rom/plugins/configuration/configuration_dsl.rb +0 -17
  70. data/lib/rom/plugins/relation/key_inference.rb +0 -46
  71. data/lib/rom/plugins/relation/registry_reader.rb +0 -32
  72. data/lib/rom/plugins/relation/view/dsl.rb +0 -32
  73. data/lib/rom/plugins/relation/view.rb +0 -95
  74. data/lib/rom/relation/class_interface.rb +0 -230
  75. data/lib/rom/relation/composite.rb +0 -46
  76. data/lib/rom/relation/curried.rb +0 -104
  77. data/lib/rom/relation/graph.rb +0 -115
  78. data/lib/rom/relation/loaded.rb +0 -118
  79. data/lib/rom/relation/materializable.rb +0 -66
  80. data/lib/rom/relation/name.rb +0 -102
  81. data/lib/rom/relation.rb +0 -172
  82. data/lib/rom/relation_registry.rb +0 -9
  83. data/lib/rom/schema/dsl.rb +0 -58
  84. data/lib/rom/schema.rb +0 -89
  85. data/lib/rom/setup/auto_registration.rb +0 -69
  86. data/lib/rom/setup/auto_registration_strategies/base.rb +0 -11
  87. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +0 -22
  88. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +0 -19
  89. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +0 -18
  90. data/lib/rom/setup/finalize/finalize_commands.rb +0 -47
  91. data/lib/rom/setup/finalize/finalize_mappers.rb +0 -36
  92. data/lib/rom/setup/finalize/finalize_relations.rb +0 -60
  93. data/lib/rom/setup/finalize.rb +0 -146
  94. data/lib/rom/setup.rb +0 -55
  95. data/lib/rom/support/configurable.rb +0 -80
  96. data/lib/rom/types.rb +0 -18
  97. data/log/.gitkeep +0 -0
  98. data/rakelib/benchmark.rake +0 -15
  99. data/rakelib/mutant.rake +0 -19
  100. data/rakelib/rubocop.rake +0 -18
  101. data/rom.gemspec +0 -26
  102. data/spec/fixtures/app/commands/create_user.rb +0 -2
  103. data/spec/fixtures/app/mappers/user_list.rb +0 -2
  104. data/spec/fixtures/app/my_commands/create_user.rb +0 -2
  105. data/spec/fixtures/app/my_mappers/user_list.rb +0 -2
  106. data/spec/fixtures/app/my_relations/users.rb +0 -2
  107. data/spec/fixtures/app/relations/users.rb +0 -2
  108. data/spec/fixtures/custom/commands/create_user.rb +0 -6
  109. data/spec/fixtures/custom/mappers/user_list.rb +0 -6
  110. data/spec/fixtures/custom/relations/users.rb +0 -6
  111. data/spec/fixtures/lib/persistence/commands/create_user.rb +0 -6
  112. data/spec/fixtures/lib/persistence/mappers/user_list.rb +0 -6
  113. data/spec/fixtures/lib/persistence/my_commands/create_user.rb +0 -6
  114. data/spec/fixtures/lib/persistence/my_mappers/user_list.rb +0 -6
  115. data/spec/fixtures/lib/persistence/my_relations/users.rb +0 -6
  116. data/spec/fixtures/lib/persistence/relations/users.rb +0 -6
  117. data/spec/integration/command_registry_spec.rb +0 -60
  118. data/spec/integration/commands/create_spec.rb +0 -177
  119. data/spec/integration/commands/delete_spec.rb +0 -67
  120. data/spec/integration/commands/error_handling_spec.rb +0 -25
  121. data/spec/integration/commands/graph_builder_spec.rb +0 -213
  122. data/spec/integration/commands/graph_spec.rb +0 -288
  123. data/spec/integration/commands/update_spec.rb +0 -109
  124. data/spec/integration/commands_spec.rb +0 -67
  125. data/spec/integration/mappers/combine_spec.rb +0 -117
  126. data/spec/integration/mappers/deep_embedded_spec.rb +0 -44
  127. data/spec/integration/mappers/definition_dsl_spec.rb +0 -206
  128. data/spec/integration/mappers/embedded_spec.rb +0 -62
  129. data/spec/integration/mappers/exclude_spec.rb +0 -27
  130. data/spec/integration/mappers/fold_spec.rb +0 -71
  131. data/spec/integration/mappers/group_spec.rb +0 -163
  132. data/spec/integration/mappers/overwrite_attributes_value_spec.rb +0 -51
  133. data/spec/integration/mappers/prefix_separator_spec.rb +0 -52
  134. data/spec/integration/mappers/prefix_spec.rb +0 -48
  135. data/spec/integration/mappers/prefixing_attributes_spec.rb +0 -37
  136. data/spec/integration/mappers/registering_custom_mappers_spec.rb +0 -28
  137. data/spec/integration/mappers/renaming_attributes_spec.rb +0 -125
  138. data/spec/integration/mappers/reusing_mappers_spec.rb +0 -43
  139. data/spec/integration/mappers/step_spec.rb +0 -119
  140. data/spec/integration/mappers/symbolizing_attributes_spec.rb +0 -77
  141. data/spec/integration/mappers/unfold_spec.rb +0 -92
  142. data/spec/integration/mappers/ungroup_spec.rb +0 -126
  143. data/spec/integration/mappers/unwrap_spec.rb +0 -93
  144. data/spec/integration/mappers/wrap_spec.rb +0 -155
  145. data/spec/integration/memory/commands/create_spec.rb +0 -23
  146. data/spec/integration/memory/commands/delete_spec.rb +0 -23
  147. data/spec/integration/memory/commands/update_spec.rb +0 -23
  148. data/spec/integration/multi_env_spec.rb +0 -69
  149. data/spec/integration/multi_repo_spec.rb +0 -46
  150. data/spec/integration/relations/default_dataset_spec.rb +0 -38
  151. data/spec/integration/relations/inheritance_spec.rb +0 -37
  152. data/spec/integration/relations/reading_spec.rb +0 -169
  153. data/spec/integration/relations/registry_dsl_spec.rb +0 -45
  154. data/spec/integration/repositories/extending_relations_spec.rb +0 -58
  155. data/spec/integration/repositories/setting_logger_spec.rb +0 -34
  156. data/spec/integration/setup_spec.rb +0 -160
  157. data/spec/shared/command_behavior.rb +0 -28
  158. data/spec/shared/command_graph.rb +0 -50
  159. data/spec/shared/container.rb +0 -9
  160. data/spec/shared/enumerable_dataset.rb +0 -52
  161. data/spec/shared/gateway_only.rb +0 -6
  162. data/spec/shared/materializable.rb +0 -36
  163. data/spec/shared/no_container.rb +0 -16
  164. data/spec/shared/one_behavior.rb +0 -26
  165. data/spec/shared/proxy.rb +0 -0
  166. data/spec/shared/users_and_tasks.rb +0 -10
  167. data/spec/spec_helper.rb +0 -52
  168. data/spec/support/constant_leak_finder.rb +0 -14
  169. data/spec/support/mutant.rb +0 -10
  170. data/spec/support/types.rb +0 -5
  171. data/spec/test/memory_repository_lint_test.rb +0 -27
  172. data/spec/unit/rom/association_set_spec.rb +0 -23
  173. data/spec/unit/rom/commands/graph_spec.rb +0 -191
  174. data/spec/unit/rom/commands/lazy_spec.rb +0 -307
  175. data/spec/unit/rom/commands/result_spec.rb +0 -70
  176. data/spec/unit/rom/commands_spec.rb +0 -165
  177. data/spec/unit/rom/configurable_spec.rb +0 -49
  178. data/spec/unit/rom/configuration_spec.rb +0 -61
  179. data/spec/unit/rom/container_spec.rb +0 -99
  180. data/spec/unit/rom/create_container_spec.rb +0 -151
  181. data/spec/unit/rom/environment_spec.rb +0 -123
  182. data/spec/unit/rom/gateway_spec.rb +0 -146
  183. data/spec/unit/rom/mapper_registry_spec.rb +0 -25
  184. data/spec/unit/rom/memory/commands_spec.rb +0 -43
  185. data/spec/unit/rom/memory/dataset_spec.rb +0 -31
  186. data/spec/unit/rom/memory/relation_spec.rb +0 -109
  187. data/spec/unit/rom/memory/repository_spec.rb +0 -12
  188. data/spec/unit/rom/memory/storage_spec.rb +0 -45
  189. data/spec/unit/rom/plugin_spec.rb +0 -150
  190. data/spec/unit/rom/plugins/command/schema_spec.rb +0 -66
  191. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +0 -85
  192. data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
  193. data/spec/unit/rom/relation/composite_spec.rb +0 -89
  194. data/spec/unit/rom/relation/curried_spec.rb +0 -52
  195. data/spec/unit/rom/relation/graph_spec.rb +0 -92
  196. data/spec/unit/rom/relation/lazy/combine_spec.rb +0 -165
  197. data/spec/unit/rom/relation/lazy_spec.rb +0 -214
  198. data/spec/unit/rom/relation/loaded_spec.rb +0 -53
  199. data/spec/unit/rom/relation/name_spec.rb +0 -58
  200. data/spec/unit/rom/relation/schema_spec.rb +0 -117
  201. data/spec/unit/rom/relation_spec.rb +0 -237
  202. data/spec/unit/rom/schema_spec.rb +0 -10
  203. data/spec/unit/rom/setup/auto_registration_spec.rb +0 -152
@@ -1,230 +0,0 @@
1
- require 'set'
2
-
3
- require 'rom/support/auto_curry'
4
- require 'rom/relation/curried'
5
- require 'rom/relation/name'
6
- require 'rom/schema'
7
-
8
- module ROM
9
- class Relation
10
- module ClassInterface
11
- # Register adapter relation subclasses during setup phase
12
- #
13
- # In adition those subclasses are extended with an interface for accessing
14
- # relation registry and to define `register_as` setting
15
- #
16
- # @api private
17
- def inherited(klass)
18
- super
19
-
20
- klass.extend ClassMacros
21
- klass.defines :adapter
22
-
23
- if respond_to?(:adapter) && adapter.nil?
24
- raise MissingAdapterIdentifierError,
25
- "relation class +#{self}+ is missing the adapter identifier"
26
- end
27
-
28
- # Extend with functionality required by adapters *only* if this is a direct
29
- # descendant of an adapter-specific relation subclass
30
- return unless respond_to?(:adapter) && klass.superclass == ROM::Relation[adapter]
31
-
32
- klass.class_eval do
33
- use :registry_reader
34
-
35
- defines :gateway, :dataset, :dataset_proc, :register_as, :schema_dsl, :schema_inferrer
36
-
37
- gateway :default
38
- schema_dsl Schema::DSL
39
- schema_inferrer nil
40
-
41
- dataset default_name
42
-
43
- # Relation's dataset name
44
- #
45
- # In example a table name in an SQL database
46
- #
47
- # @return [Symbol]
48
- #
49
- # @api public
50
- attr_reader :name
51
-
52
- # Set dataset name
53
- #
54
- # If a block is passed it will be evaluated in the context of the dataset
55
- # to define the default dataset which will be injected into a relation
56
- # when setting up relation registry
57
- #
58
- # @example
59
- # class Relations::Users < ROM::Relation[:memory]
60
- # dataset :users
61
- # end
62
- #
63
- # class Users < ROM::Relation[:memory]
64
- # dataset { sort_by(:id) }
65
- # end
66
- #
67
- # @param [Symbol] value The name of the dataset
68
- #
69
- # @api public
70
- def self.dataset(value = Undefined, &block)
71
- dataset_proc(block) if block
72
- super
73
- end
74
-
75
- # Set or get name under which a relation will be registered
76
- #
77
- # This defaults to `dataset` or `default_name` for descendant relations
78
- #
79
- # @return [Symbol]
80
- #
81
- # @api public
82
- def self.register_as(value = Undefined)
83
- if value == Undefined
84
- return @register_as if defined?(@register_as)
85
-
86
- super_val = super()
87
-
88
- if superclass == ROM::Relation[adapter]
89
- super_val || dataset
90
- else
91
- super_val == dataset ? default_name : super_val
92
- end
93
- else
94
- super
95
- end
96
- end
97
-
98
- # @api private
99
- def initialize(dataset, options = EMPTY_HASH)
100
- @name = Name.new(self.class.register_as, self.class.dataset)
101
- super
102
- end
103
-
104
- # Return name of the source gateway of this relation
105
- #
106
- # @return [Symbol]
107
- #
108
- # @api private
109
- def gateway
110
- self.class.gateway
111
- end
112
- end
113
-
114
- klass.extend(AutoCurry)
115
- end
116
-
117
- # Return adapter-specific relation subclass
118
- #
119
- # @example
120
- # ROM::Relation[:memory]
121
- # # => ROM::Memory::Relation
122
- #
123
- # @return [Class]
124
- #
125
- # @api public
126
- def [](adapter)
127
- ROM.adapters.fetch(adapter).const_get(:Relation)
128
- rescue KeyError
129
- raise AdapterNotPresentError.new(adapter, :relation)
130
- end
131
-
132
- # Specify canonical schema for a relation
133
- #
134
- # With a schema defined commands will set up a type-safe input handler
135
- # automatically
136
- #
137
- # @example
138
- # class Users < ROM::Relation[:sql]
139
- # schema do
140
- # attribute :id, Types::Serial
141
- # attribute :name, Types::String
142
- # end
143
- # end
144
- #
145
- # # access schema
146
- # Users.schema
147
- #
148
- # @return [Schema]
149
- #
150
- # @param [Symbol] dataset An optional dataset name
151
- # @param [Boolean] infer Whether to do an automatic schema inferring
152
- #
153
- # @api public
154
- def schema(dataset = nil, infer: false, &block)
155
- if defined?(@schema)
156
- @schema
157
- elsif block || infer
158
- self.dataset(dataset) if dataset
159
- self.register_as(self.dataset) unless register_as
160
-
161
- name = Name[register_as, self.dataset]
162
- inferrer = infer ? schema_inferrer : nil
163
- dsl = schema_dsl.new(name, inferrer, &block)
164
-
165
- @schema = dsl.call
166
- end
167
- end
168
-
169
- # Dynamically define a method that will forward to the dataset and wrap
170
- # response in the relation itself
171
- #
172
- # @example
173
- # class SomeAdapterRelation < ROM::Relation
174
- # forward :super_query
175
- # end
176
- #
177
- # @api public
178
- def forward(*methods)
179
- methods.each do |method|
180
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
181
- def #{method}(*args, &block)
182
- __new__(dataset.__send__(:#{method}, *args, &block))
183
- end
184
- RUBY
185
- end
186
- end
187
-
188
- # Include a registered plugin in this relation class
189
- #
190
- # @param [Symbol] plugin
191
- # @param [Hash] options
192
- # @option options [Symbol] :adapter (:default) first adapter to check for plugin
193
- #
194
- # @api public
195
- def use(plugin, _options = EMPTY_HASH)
196
- ROM.plugin_registry.relations.fetch(plugin, adapter).apply_to(self)
197
- end
198
-
199
- # Return default relation name used for `register_as` setting
200
- #
201
- # @return [Symbol]
202
- #
203
- # @api private
204
- def default_name
205
- return unless name
206
- Inflector.underscore(name).tr('/', '_').to_sym
207
- end
208
-
209
- # @api private
210
- def curried
211
- Curried
212
- end
213
-
214
- # @api private
215
- def view_methods
216
- ancestor_methods = ancestors.reject { |klass| klass == self }
217
- .map(&:instance_methods).flatten
218
-
219
- instance_methods - ancestor_methods + auto_curried_methods
220
- end
221
-
222
- # Hook to finalize a relation after its instance was created
223
- #
224
- # @api private
225
- def finalize(_container, _relation)
226
- # noop
227
- end
228
- end
229
- end
230
- end
@@ -1,46 +0,0 @@
1
- require 'rom/relation/loaded'
2
- require 'rom/relation/materializable'
3
- require 'rom/pipeline'
4
-
5
- module ROM
6
- class Relation
7
- # Left-to-right relation composition used for data-pipelining
8
- #
9
- # @api public
10
- class Composite < Pipeline::Composite
11
- include Materializable
12
-
13
- # Call the pipeline by passing results from left to right
14
- #
15
- # Optional args are passed to the left object
16
- #
17
- # @return [Loaded]
18
- #
19
- # @api public
20
- def call(*args)
21
- relation = left.call(*args)
22
- response = right.call(relation)
23
-
24
- if response.is_a?(Loaded)
25
- response
26
- elsif relation.is_a?(Loaded)
27
- relation.new(response)
28
- else
29
- Loaded.new(relation, response)
30
- end
31
- end
32
- alias_method :[], :call
33
-
34
- private
35
-
36
- # @api private
37
- #
38
- # @see Pipeline::Proxy#decorate?
39
- #
40
- # @api private
41
- def decorate?(response)
42
- super || response.is_a?(Graph)
43
- end
44
- end
45
- end
46
- end
@@ -1,104 +0,0 @@
1
- require 'rom/support/options'
2
-
3
- require 'rom/pipeline'
4
- require 'rom/relation/name'
5
- require 'rom/relation/materializable'
6
-
7
- module ROM
8
- class Relation
9
- class Curried
10
- include Options
11
- include Materializable
12
- include Pipeline
13
-
14
- option :name, type: Symbol
15
- option :arity, type: Integer, reader: true, default: -1
16
- option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
17
-
18
- attr_reader :relation
19
-
20
- attr_reader :name
21
-
22
- # @api private
23
- def initialize(relation, options = EMPTY_HASH)
24
- @relation = relation
25
- @name = relation.name.with(options[:name])
26
- super
27
- end
28
-
29
- # Load relation if args match the arity
30
- #
31
- # @return [Loaded,Lazy,Curried]
32
- # @see Lazy#call
33
- #
34
- # @api public
35
- def call(*args)
36
- if arity != -1
37
- all_args = curry_args + args
38
-
39
- if arity == all_args.size
40
- Loaded.new(relation.__send__(name.relation, *all_args))
41
- else
42
- __new__(relation, curry_args: all_args)
43
- end
44
- else
45
- super
46
- end
47
- end
48
- alias_method :[], :call
49
-
50
- # @api public
51
- def to_a
52
- raise(
53
- ArgumentError,
54
- "#{relation.class}##{name.relation} arity is #{arity} " \
55
- "(#{curry_args.size} args given)"
56
- )
57
- end
58
- alias_method :to_ary, :to_a
59
-
60
- # Return if this lazy relation is curried
61
- #
62
- # @return [true]
63
- #
64
- # @api private
65
- def curried?
66
- true
67
- end
68
-
69
- # @api private
70
- def respond_to_missing?(name, include_private = false)
71
- super || relation.respond_to?(name, include_private)
72
- end
73
-
74
- private
75
-
76
- # @api private
77
- def __new__(relation, new_opts = EMPTY_HASH)
78
- Curried.new(relation, options.merge(new_opts))
79
- end
80
-
81
- # @api private
82
- def composite_class
83
- Relation::Composite
84
- end
85
-
86
- # @api private
87
- def method_missing(meth, *args, &block)
88
- if relation.respond_to?(meth)
89
- response = relation.__send__(meth, *args, &block)
90
-
91
- super if response.is_a?(self.class)
92
-
93
- if response.is_a?(Relation) || response.is_a?(Graph)
94
- __new__(response)
95
- else
96
- response
97
- end
98
- else
99
- super
100
- end
101
- end
102
- end
103
- end
104
- end
@@ -1,115 +0,0 @@
1
- require 'rom/relation/loaded'
2
- require 'rom/relation/composite'
3
- require 'rom/relation/materializable'
4
- require 'rom/pipeline'
5
-
6
- module ROM
7
- class Relation
8
- # Compose relations using join-keys
9
- #
10
- # @example
11
- # class Users < ROM::Relation[:memory]
12
- # end
13
- #
14
- # class Tasks < ROM::Relation[:memory]
15
- # def for_users(users)
16
- # restrict(user: users.map { |user| user[:name] })
17
- # end
18
- # end
19
- #
20
- # rom.relations[:users] << { name: 'Jane' }
21
- # rom.relations[:tasks] << { user: 'Jane', title: 'Do something' }
22
- #
23
- # rom.relation(:users).combine(rom.relation(:tasks).for_users)
24
- #
25
- # @api public
26
- class Graph
27
- include Materializable
28
- include Pipeline
29
- include Pipeline::Proxy
30
-
31
- # Root aka parent relation
32
- #
33
- # @return [Relation::Lazy]
34
- #
35
- # @api private
36
- attr_reader :root
37
-
38
- # Child relation nodes
39
- #
40
- # @return [Array<Relation::Lazy>]
41
- #
42
- # @api private
43
- attr_reader :nodes
44
-
45
- alias_method :left, :root
46
- alias_method :right, :nodes
47
-
48
- # @api private
49
- def self.build(root, nodes)
50
- if nodes.any? { |node| node.instance_of?(Composite) }
51
- raise UnsupportedRelationError,
52
- "Combining with composite relations is not supported"
53
- else
54
- new(root, nodes)
55
- end
56
- end
57
-
58
- # @api private
59
- def initialize(root, nodes)
60
- @root = root
61
- @nodes = nodes
62
- end
63
-
64
- # Return if this is a graph relation
65
- #
66
- # @return [true]
67
- #
68
- # @api private
69
- def graph?
70
- true
71
- end
72
-
73
- # Combine this graph with more nodes
74
- #
75
- # @param [Array<Relation::Lazy>]
76
- #
77
- # @return [Graph]
78
- #
79
- # @api public
80
- def combine(*others)
81
- self.class.new(root, nodes + others)
82
- end
83
-
84
- # Materialize this relation graph
85
- #
86
- # @return [Loaded]
87
- #
88
- # @api public
89
- def call(*args)
90
- left = root.call(*args)
91
-
92
- right =
93
- if left.count > 0
94
- nodes.map { |node| node.call(left) }
95
- else
96
- nodes.map { |node| Loaded.new(node, []) }
97
- end
98
-
99
- Loaded.new(self, [left, right])
100
- end
101
-
102
- private
103
-
104
- # @api private
105
- def decorate?(other)
106
- super || other.is_a?(Curried)
107
- end
108
-
109
- # @api private
110
- def composite_class
111
- Relation::Composite
112
- end
113
- end
114
- end
115
- end
@@ -1,118 +0,0 @@
1
- module ROM
2
- class Relation
3
- # Materializes a relation and exposes interface to access the data
4
- #
5
- # @api public
6
- class Loaded
7
- include Enumerable
8
-
9
- # Coerce loaded relation to an array
10
- #
11
- # @return [Array]
12
- #
13
- # @api public
14
- alias_method :to_ary, :to_a
15
-
16
- # Source relation
17
- #
18
- # @return [Relation]
19
- #
20
- # @api private
21
- attr_reader :source
22
-
23
- # Materialized relation
24
- #
25
- # @return [Object]
26
- #
27
- # @api private
28
- attr_reader :collection
29
-
30
- # @api private
31
- def initialize(source, collection = source.to_a)
32
- @source = source
33
- @collection = collection
34
- end
35
-
36
- # Yield relation tuples
37
- #
38
- # @yield [Hash]
39
- #
40
- # @api public
41
- def each(&block)
42
- return to_enum unless block
43
- collection.each { |tuple| yield(tuple) }
44
- end
45
-
46
- # Returns a single tuple from the relation if there is one.
47
- #
48
- # @raise [ROM::TupleCountMismatchError] if the relation contains more than
49
- # one tuple
50
- #
51
- # @api public
52
- def one
53
- if collection.count > 1
54
- raise(
55
- TupleCountMismatchError,
56
- 'The relation consists of more than one tuple'
57
- )
58
- else
59
- collection.first
60
- end
61
- end
62
-
63
- # Like [one], but additionally raises an error if the relation is empty.
64
- #
65
- # @raise [ROM::TupleCountMismatchError] if the relation does not contain
66
- # exactly one tuple
67
- #
68
- # @api public
69
- def one!
70
- one || raise(
71
- TupleCountMismatchError,
72
- 'The relation does not contain any tuples'
73
- )
74
- end
75
-
76
- # Return a list of values under provided key
77
- #
78
- # @example
79
- # all_users = rom.relations[:users].call
80
- # all_users.pluck(:name)
81
- # # ["Jane", "Joe"]
82
- #
83
- # @param [Symbol] key The key name
84
- #
85
- # @return [Array]
86
- # @raises KeyError when provided key doesn't exist in any of the tuples
87
- #
88
- # @api public
89
- def pluck(key)
90
- map { |tuple| tuple.fetch(key) }
91
- end
92
-
93
- # Pluck primary key values
94
- #
95
- # This method *may not work* with adapters that don't provide relations
96
- # that have primary key configured
97
- #
98
- # @example
99
- # users = rom.relations[:users].call
100
- # users.primary_keys
101
- # # [1, 2, 3]
102
- #
103
- # @return [Array]
104
- #
105
- # @api public
106
- def primary_keys
107
- pluck(source.primary_key)
108
- end
109
-
110
- # Return a loaded relation with a new collection
111
- #
112
- # @api public
113
- def new(collection)
114
- self.class.new(source, collection)
115
- end
116
- end
117
- end
118
- end
@@ -1,66 +0,0 @@
1
- module ROM
2
- class Relation
3
- # Interface for objects that can be materialized into a loaded relation
4
- #
5
- # @api public
6
- module Materializable
7
- # @abstract
8
- #
9
- # @api public
10
- def call(*)
11
- raise NotImplementedError, "#{self.class}#call must be implemented"
12
- end
13
-
14
- # Coerce the relation to an array
15
- #
16
- # @return [Array]
17
- #
18
- # @api public
19
- def to_a
20
- call.to_a
21
- end
22
- alias_method :to_ary, :to_a
23
-
24
- # Yield relation tuples
25
- #
26
- # @yield [Hash,Object]
27
- #
28
- # @api public
29
- def each(&block)
30
- return to_enum unless block
31
- to_a.each { |tuple| yield(tuple) }
32
- end
33
-
34
- # Delegate to loaded relation and return one object
35
- #
36
- # @return [Object]
37
- #
38
- # @see Loaded#one
39
- #
40
- # @api public
41
- def one
42
- call.one
43
- end
44
-
45
- # Delegate to loaded relation and return one object
46
- #
47
- # @return [Object]
48
- #
49
- # @see Loaded#one
50
- #
51
- # @api public
52
- def one!
53
- call.one!
54
- end
55
-
56
- # Return first tuple from a relation coerced to an array
57
- #
58
- # @return [Object]
59
- #
60
- # @api public
61
- def first
62
- to_a.first
63
- end
64
- end
65
- end
66
- end