rom 2.0.2 → 5.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +122 -324
  3. data/LICENSE +17 -17
  4. data/README.md +91 -22
  5. data/lib/rom/version.rb +3 -1
  6. data/lib/rom.rb +4 -46
  7. metadata +42 -245
  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