rom-core 4.0.0.beta1

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 (122) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +603 -0
  3. data/LICENSE +20 -0
  4. data/README.md +18 -0
  5. data/lib/rom-core.rb +1 -0
  6. data/lib/rom/array_dataset.rb +44 -0
  7. data/lib/rom/association_set.rb +16 -0
  8. data/lib/rom/associations/abstract.rb +135 -0
  9. data/lib/rom/associations/definitions.rb +5 -0
  10. data/lib/rom/associations/definitions/abstract.rb +116 -0
  11. data/lib/rom/associations/definitions/many_to_many.rb +24 -0
  12. data/lib/rom/associations/definitions/many_to_one.rb +11 -0
  13. data/lib/rom/associations/definitions/one_to_many.rb +11 -0
  14. data/lib/rom/associations/definitions/one_to_one.rb +11 -0
  15. data/lib/rom/associations/definitions/one_to_one_through.rb +11 -0
  16. data/lib/rom/associations/many_to_many.rb +81 -0
  17. data/lib/rom/associations/many_to_one.rb +37 -0
  18. data/lib/rom/associations/one_to_many.rb +37 -0
  19. data/lib/rom/associations/one_to_one.rb +8 -0
  20. data/lib/rom/associations/one_to_one_through.rb +8 -0
  21. data/lib/rom/associations/through_identifier.rb +39 -0
  22. data/lib/rom/auto_curry.rb +55 -0
  23. data/lib/rom/cache.rb +46 -0
  24. data/lib/rom/command.rb +488 -0
  25. data/lib/rom/command_compiler.rb +239 -0
  26. data/lib/rom/command_proxy.rb +24 -0
  27. data/lib/rom/command_registry.rb +141 -0
  28. data/lib/rom/commands.rb +3 -0
  29. data/lib/rom/commands/class_interface.rb +270 -0
  30. data/lib/rom/commands/composite.rb +53 -0
  31. data/lib/rom/commands/create.rb +13 -0
  32. data/lib/rom/commands/delete.rb +14 -0
  33. data/lib/rom/commands/graph.rb +88 -0
  34. data/lib/rom/commands/graph/class_interface.rb +62 -0
  35. data/lib/rom/commands/graph/input_evaluator.rb +62 -0
  36. data/lib/rom/commands/lazy.rb +99 -0
  37. data/lib/rom/commands/lazy/create.rb +23 -0
  38. data/lib/rom/commands/lazy/delete.rb +27 -0
  39. data/lib/rom/commands/lazy/update.rb +34 -0
  40. data/lib/rom/commands/result.rb +96 -0
  41. data/lib/rom/commands/update.rb +14 -0
  42. data/lib/rom/configuration.rb +114 -0
  43. data/lib/rom/configuration_dsl.rb +87 -0
  44. data/lib/rom/configuration_dsl/command.rb +41 -0
  45. data/lib/rom/configuration_dsl/command_dsl.rb +35 -0
  46. data/lib/rom/configuration_dsl/relation.rb +26 -0
  47. data/lib/rom/configuration_plugin.rb +17 -0
  48. data/lib/rom/constants.rb +64 -0
  49. data/lib/rom/container.rb +147 -0
  50. data/lib/rom/core.rb +46 -0
  51. data/lib/rom/create_container.rb +60 -0
  52. data/lib/rom/data_proxy.rb +94 -0
  53. data/lib/rom/enumerable_dataset.rb +68 -0
  54. data/lib/rom/environment.rb +70 -0
  55. data/lib/rom/gateway.rb +184 -0
  56. data/lib/rom/global.rb +58 -0
  57. data/lib/rom/global/plugin_dsl.rb +47 -0
  58. data/lib/rom/initializer.rb +64 -0
  59. data/lib/rom/lint/enumerable_dataset.rb +54 -0
  60. data/lib/rom/lint/gateway.rb +120 -0
  61. data/lib/rom/lint/linter.rb +78 -0
  62. data/lib/rom/lint/spec.rb +20 -0
  63. data/lib/rom/lint/test.rb +98 -0
  64. data/lib/rom/mapper_registry.rb +24 -0
  65. data/lib/rom/memory.rb +4 -0
  66. data/lib/rom/memory/associations.rb +4 -0
  67. data/lib/rom/memory/associations/many_to_many.rb +10 -0
  68. data/lib/rom/memory/associations/many_to_one.rb +10 -0
  69. data/lib/rom/memory/associations/one_to_many.rb +10 -0
  70. data/lib/rom/memory/associations/one_to_one.rb +10 -0
  71. data/lib/rom/memory/commands.rb +56 -0
  72. data/lib/rom/memory/dataset.rb +97 -0
  73. data/lib/rom/memory/gateway.rb +64 -0
  74. data/lib/rom/memory/relation.rb +62 -0
  75. data/lib/rom/memory/schema.rb +23 -0
  76. data/lib/rom/memory/storage.rb +59 -0
  77. data/lib/rom/memory/types.rb +9 -0
  78. data/lib/rom/pipeline.rb +105 -0
  79. data/lib/rom/plugin.rb +25 -0
  80. data/lib/rom/plugin_base.rb +45 -0
  81. data/lib/rom/plugin_registry.rb +197 -0
  82. data/lib/rom/plugins/command/schema.rb +37 -0
  83. data/lib/rom/plugins/configuration/configuration_dsl.rb +21 -0
  84. data/lib/rom/plugins/relation/instrumentation.rb +51 -0
  85. data/lib/rom/plugins/relation/registry_reader.rb +44 -0
  86. data/lib/rom/plugins/schema/timestamps.rb +58 -0
  87. data/lib/rom/registry.rb +71 -0
  88. data/lib/rom/relation.rb +548 -0
  89. data/lib/rom/relation/class_interface.rb +282 -0
  90. data/lib/rom/relation/commands.rb +23 -0
  91. data/lib/rom/relation/composite.rb +46 -0
  92. data/lib/rom/relation/curried.rb +103 -0
  93. data/lib/rom/relation/graph.rb +197 -0
  94. data/lib/rom/relation/loaded.rb +127 -0
  95. data/lib/rom/relation/materializable.rb +66 -0
  96. data/lib/rom/relation/name.rb +111 -0
  97. data/lib/rom/relation/view_dsl.rb +64 -0
  98. data/lib/rom/relation/wrap.rb +83 -0
  99. data/lib/rom/relation_registry.rb +10 -0
  100. data/lib/rom/schema.rb +437 -0
  101. data/lib/rom/schema/associations_dsl.rb +195 -0
  102. data/lib/rom/schema/attribute.rb +419 -0
  103. data/lib/rom/schema/dsl.rb +164 -0
  104. data/lib/rom/schema/inferrer.rb +66 -0
  105. data/lib/rom/schema_plugin.rb +27 -0
  106. data/lib/rom/setup.rb +68 -0
  107. data/lib/rom/setup/auto_registration.rb +74 -0
  108. data/lib/rom/setup/auto_registration_strategies/base.rb +16 -0
  109. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +63 -0
  110. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +20 -0
  111. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +18 -0
  112. data/lib/rom/setup/finalize.rb +103 -0
  113. data/lib/rom/setup/finalize/finalize_commands.rb +60 -0
  114. data/lib/rom/setup/finalize/finalize_mappers.rb +56 -0
  115. data/lib/rom/setup/finalize/finalize_relations.rb +135 -0
  116. data/lib/rom/support/configurable.rb +85 -0
  117. data/lib/rom/support/memoizable.rb +58 -0
  118. data/lib/rom/support/notifications.rb +103 -0
  119. data/lib/rom/transaction.rb +24 -0
  120. data/lib/rom/types.rb +26 -0
  121. data/lib/rom/version.rb +5 -0
  122. metadata +289 -0
@@ -0,0 +1,71 @@
1
+ require 'dry/equalizer'
2
+
3
+ require 'rom/initializer'
4
+ require 'rom/cache'
5
+ require 'rom/constants'
6
+
7
+ module ROM
8
+ # @api private
9
+ class Registry
10
+ extend Initializer
11
+
12
+ include Enumerable
13
+ include Dry::Equalizer(:elements)
14
+
15
+ param :elements
16
+
17
+ option :cache, reader: true, default: -> { Cache.new }
18
+
19
+ def self.new(*args)
20
+ case args.size
21
+ when 0
22
+ super({}, {})
23
+ when 1
24
+ super(*args, {})
25
+ else
26
+ super(*args)
27
+ end
28
+ end
29
+
30
+ def self.element_not_found_error
31
+ ElementNotFoundError
32
+ end
33
+
34
+ def map(&block)
35
+ new_elements = elements.each_with_object({}) do |(name, element), h|
36
+ h[name] = yield(element)
37
+ end
38
+ self.class.new(new_elements, options)
39
+ end
40
+
41
+ def each(&block)
42
+ return to_enum unless block
43
+ elements.each { |element| yield(element) }
44
+ end
45
+
46
+ def key?(name)
47
+ !name.nil? && elements.key?(name.to_sym)
48
+ end
49
+
50
+ def fetch(key)
51
+ raise ArgumentError.new('key cannot be nil') if key.nil?
52
+
53
+ elements.fetch(key.to_sym) do
54
+ return yield if block_given?
55
+
56
+ raise self.class.element_not_found_error.new(key, self)
57
+ end
58
+ end
59
+ alias_method :[], :fetch
60
+
61
+ def respond_to_missing?(name, include_private = false)
62
+ elements.key?(name) || super
63
+ end
64
+
65
+ private
66
+
67
+ def method_missing(name, *)
68
+ elements.fetch(name) { super }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,548 @@
1
+ require 'dry/core/class_attributes'
2
+
3
+ require 'rom/struct'
4
+ require 'rom/constants'
5
+ require 'rom/initializer'
6
+ require 'rom/support/memoizable'
7
+
8
+ require 'rom/relation/class_interface'
9
+
10
+ require 'rom/auto_curry'
11
+ require 'rom/pipeline'
12
+ require 'rom/mapper_registry'
13
+ require 'rom/command_registry'
14
+
15
+ require 'rom/relation/loaded'
16
+ require 'rom/relation/curried'
17
+ require 'rom/relation/composite'
18
+ require 'rom/relation/graph'
19
+ require 'rom/relation/wrap'
20
+ require 'rom/relation/materializable'
21
+ require 'rom/relation/commands'
22
+ require 'rom/association_set'
23
+
24
+ require 'rom/types'
25
+ require 'rom/schema'
26
+
27
+ module ROM
28
+ # Base relation class
29
+ #
30
+ # Relation is a proxy for the dataset object provided by the gateway. It
31
+ # can forward methods to the dataset, which is why the "native" interface of
32
+ # the underlying gateway is available in the relation. This interface,
33
+ # however, is considered private and should not be used outside of the
34
+ # relation instance.
35
+ #
36
+ # Individual adapters sets up their relation classes and provide different APIs
37
+ # depending on their persistence backend.
38
+ #
39
+ # Vanilla Relation class doesn't have APIs that are specific to ROM container setup.
40
+ # When adapter Relation class inherits from this class, these APIs are added automatically,
41
+ # so that they can be registered within a container.
42
+ #
43
+ # @see ROM::Relation::ClassInterface
44
+ #
45
+ # @api public
46
+ class Relation
47
+ # Default no-op output schema which is called in `Relation#each`
48
+ NOOP_OUTPUT_SCHEMA = -> tuple { tuple }.freeze
49
+
50
+ extend Initializer
51
+ extend ClassInterface
52
+
53
+ include Relation::Commands
54
+ include Memoizable
55
+
56
+ extend Dry::Core::ClassAttributes
57
+
58
+ defines :adapter, :gateway, :schema_opts, :schema_class,
59
+ :schema_attr_class, :schema_inferrer, :schema_dsl,
60
+ :wrap_class, :auto_map, :auto_struct, :struct_namespace
61
+
62
+ gateway :default
63
+
64
+ auto_map true
65
+ auto_struct false
66
+ struct_namespace ROM::Struct
67
+
68
+ schema_opts EMPTY_HASH
69
+ schema_dsl Schema::DSL
70
+ schema_attr_class Schema::Attribute
71
+ schema_class Schema
72
+ schema_inferrer Schema::DEFAULT_INFERRER
73
+
74
+ wrap_class Relation::Wrap
75
+
76
+ include Dry::Equalizer(:name, :dataset)
77
+ include Materializable
78
+ include Pipeline
79
+
80
+ # @!attribute [r] dataset
81
+ # @return [Object] dataset used by the relation provided by relation's gateway
82
+ # @api public
83
+ param :dataset
84
+
85
+ # @!attribute [r] schema
86
+ # @return [Schema] relation schema, defaults to class-level canonical
87
+ # schema (if it was defined) and sets an empty one as
88
+ # the fallback
89
+ # @api public
90
+ option :schema, default: -> { self.class.schema || self.class.default_schema }
91
+
92
+ # @!attribute [r] name
93
+ # @return [Object] The relation name
94
+ # @api public
95
+ option :name, default: -> { self.class.schema ? self.class.schema.name : self.class.default_name }
96
+
97
+ # @!attribute [r] input_schema
98
+ # @return [Object#[]] tuple processing function, uses schema or defaults to Hash[]
99
+ # @api private
100
+ option :input_schema, default: -> { schema.to_input_hash }
101
+
102
+ # @!attribute [r] output_schema
103
+ # @return [Object#[]] tuple processing function, uses schema or defaults to NOOP_OUTPUT_SCHEMA
104
+ # @api private
105
+ option :output_schema, default: -> {
106
+ schema.any?(&:read?) ? schema.to_output_hash : NOOP_OUTPUT_SCHEMA
107
+ }
108
+
109
+ # @!attribute [r] auto_map
110
+ # @return [TrueClass,FalseClass] Whether or not a relation and its compositions should be auto-mapped
111
+ # @api private
112
+ option :auto_map, reader: true, default: -> { self.class.auto_map }
113
+
114
+ # @!attribute [r] auto_struct
115
+ # @return [TrueClass,FalseClass] Whether or not tuples should be auto-mapped to structs
116
+ # @api private
117
+ option :auto_struct, reader: true, default: -> { self.class.auto_struct }
118
+
119
+ # @!attribute [r] struct_namespace
120
+ # @return [Module] Custom struct namespace
121
+ # @api private
122
+ option :struct_namespace, reader: false, default: -> { self.class.struct_namespace }
123
+
124
+ # @!attribute [r] mappers
125
+ # @return [MapperRegistry] an optional mapper registry (empty by default)
126
+ option :mappers, default: -> { MapperRegistry.new }
127
+
128
+ # @!attribute [r] commands
129
+ # @return [CommandRegistry] Command registry
130
+ # @api private
131
+ option :commands, default: -> { CommandRegistry.new({}, relation_name: name.relation) }
132
+
133
+ # @!attribute [r] meta
134
+ # @return [Hash] Meta data stored in a hash
135
+ # @api private
136
+ option :meta, reader: true, default: -> { EMPTY_HASH }
137
+
138
+ # Return schema attribute
139
+ #
140
+ # @example accessing canonical attribute
141
+ # users[:id]
142
+ # # => #<ROM::SQL::Attribute[Integer] primary_key=true name=:id source=ROM::Relation::Name(users)>
143
+ #
144
+ # @example accessing joined attribute
145
+ # tasks_with_users = tasks.join(users).select_append(tasks[:title])
146
+ # tasks_with_users[:title, :tasks]
147
+ # # => #<ROM::SQL::Attribute[String] primary_key=false name=:title source=ROM::Relation::Name(tasks)>
148
+ #
149
+ # @return [Schema::Attribute]
150
+ #
151
+ # @api public
152
+ def [](name)
153
+ schema[name]
154
+ end
155
+
156
+ # Yields relation tuples
157
+ #
158
+ # Every tuple is processed through Relation#output_schema, it's a no-op by default
159
+ #
160
+ # @yield [Hash]
161
+ #
162
+ # @return [Enumerator] if block is not provided
163
+ #
164
+ # @api public
165
+ def each(&block)
166
+ return to_enum unless block
167
+
168
+ if auto_struct?
169
+ mapper.(dataset.map { |tuple| output_schema[tuple] }).each { |struct| yield(struct) }
170
+ else
171
+ dataset.each { |tuple| yield(output_schema[tuple]) }
172
+ end
173
+ end
174
+
175
+ # Composes with other relations
176
+ #
177
+ # @param [Array<Relation>] others The other relation(s) to compose with
178
+ #
179
+ # @return [Relation::Graph]
180
+ #
181
+ # @api public
182
+ def graph(*others)
183
+ Graph.build(self, others)
184
+ end
185
+
186
+ # Combine with other relations
187
+ #
188
+ # @overload combine(*associations)
189
+ # Composes relations using configured associations
190
+
191
+ # @example
192
+ # users.combine(:tasks, :posts)
193
+ # @param *associations [Array<Symbol>] A list of association names
194
+ #
195
+ # @return [Relation]
196
+ #
197
+ # @api public
198
+ def combine(*args)
199
+ graph(*nodes(*args))
200
+ end
201
+
202
+ # @api private
203
+ def nodes(*args)
204
+ args.map do |arg|
205
+ case arg
206
+ when Symbol
207
+ node(arg)
208
+ when Hash
209
+ arg.reduce(self) { |r, (k, v)| r.node(k).combine(*v) }
210
+ when Array
211
+ arg.map { |opts| nodes(opts) }
212
+ end
213
+ end.flatten(0)
214
+ end
215
+
216
+ # @api public
217
+ def node(name)
218
+ assoc = associations[name]
219
+ other = assoc.node
220
+ other.eager_load(assoc)
221
+ end
222
+
223
+ # @api public
224
+ def eager_load(assoc)
225
+ relation = assoc.prepare(self)
226
+
227
+ if assoc.override?
228
+ relation.(assoc)
229
+ else
230
+ relation.preload_assoc(assoc)
231
+ end
232
+ end
233
+
234
+ # @api private
235
+ def preload_assoc(assoc, other)
236
+ assoc.preload(self, other)
237
+ end
238
+
239
+ # Wrap other relations
240
+ #
241
+ # @example
242
+ # tasks.wrap(:owner)
243
+ #
244
+ # @param [Hash] options
245
+ #
246
+ # @return [RelationProxy]
247
+ #
248
+ # @api public
249
+ def wrap(*names)
250
+ wrap_class.new(self, names.map { |n| associations[n].wrap })
251
+ end
252
+
253
+ # Loads relation
254
+ #
255
+ # @return [Relation::Loaded]
256
+ #
257
+ # @api public
258
+ def call
259
+ Loaded.new(self)
260
+ end
261
+
262
+ # Materializes a relation into an array
263
+ #
264
+ # @return [Array<Hash>]
265
+ #
266
+ # @api public
267
+ def to_a
268
+ to_enum.to_a
269
+ end
270
+
271
+ # Returns if this relation is curried
272
+ #
273
+ # @return [false]
274
+ #
275
+ # @api private
276
+ def curried?
277
+ false
278
+ end
279
+
280
+ # Returns if this relation is a graph
281
+ #
282
+ # @return [false]
283
+ #
284
+ # @api private
285
+ def graph?
286
+ false
287
+ end
288
+
289
+ # Return if this is a wrap relation
290
+ #
291
+ # @return [false]
292
+ #
293
+ # @api private
294
+ def wrap?
295
+ false
296
+ end
297
+
298
+ # Returns true if a relation has schema defined
299
+ #
300
+ # @return [TrueClass, FalseClass]
301
+ #
302
+ # @api private
303
+ def schema?
304
+ ! schema.empty?
305
+ end
306
+
307
+ # Return a new relation with provided dataset and additional options
308
+ #
309
+ # Use this method whenever you need to use dataset API to get a new dataset
310
+ # and you want to return a relation back. Typically relation API should be
311
+ # enough though. If you find yourself using this method, it might be worth
312
+ # to consider reporting an issue that some dataset functionality is not available
313
+ # through relation API.
314
+ #
315
+ # @example with a new dataset
316
+ # users.new(users.dataset.some_method)
317
+ #
318
+ # @example with a new dataset and options
319
+ # users.new(users.dataset.some_method, other: 'options')
320
+ #
321
+ # @param [Object] dataset
322
+ # @param [Hash] new_opts Additional options
323
+ #
324
+ # @api public
325
+ def new(dataset, new_opts = EMPTY_HASH)
326
+ if new_opts.empty?
327
+ opts = options
328
+ elsif new_opts.key?(:schema)
329
+ opts = options.reject { |k, _| k == :input_schema || k == :output_schema }.merge(new_opts)
330
+ else
331
+ opts = options.merge(new_opts)
332
+ end
333
+
334
+ self.class.new(dataset, opts)
335
+ end
336
+
337
+ # Returns a new instance with the same dataset but new options
338
+ #
339
+ # @example
340
+ # users.with(output_schema: -> tuple { .. })
341
+ #
342
+ # @param new_options [Hash]
343
+ #
344
+ # @return [Relation]
345
+ #
346
+ # @api private
347
+ def with(opts)
348
+ new_options =
349
+ if opts.key?(:meta)
350
+ opts.merge(meta: meta.merge(opts[:meta]))
351
+ else
352
+ opts
353
+ end
354
+
355
+ new(dataset, options.merge(new_options))
356
+ end
357
+
358
+ # Return schema's association set (empty by default)
359
+ #
360
+ # @return [AssociationSet] Schema's association set (empty by default)
361
+ #
362
+ # @api public
363
+ def associations
364
+ schema.associations
365
+ end
366
+
367
+ # Returns AST for the wrapped relation
368
+ #
369
+ # @return [Array]
370
+ #
371
+ # @api public
372
+ def to_ast
373
+ [:relation, [name.relation, attr_ast, meta_ast]]
374
+ end
375
+
376
+ # @api private
377
+ def attr_ast
378
+ schema.map { |t| t.to_read_ast }
379
+ end
380
+
381
+ # @api private
382
+ def meta_ast
383
+ meta = self.meta.merge(dataset: name.dataset, alias: name.aliaz, struct_namespace: options[:struct_namespace])
384
+ meta[:model] = false unless auto_struct? || meta[:model]
385
+ meta
386
+ end
387
+
388
+ # @api private
389
+ def auto_map?
390
+ (auto_map || auto_struct) && !meta[:combine_type]
391
+ end
392
+
393
+ # @api private
394
+ def auto_struct?
395
+ auto_struct && !meta[:combine_type]
396
+ end
397
+
398
+ # @api private
399
+ def mapper
400
+ mappers[to_ast]
401
+ end
402
+
403
+ # Maps the wrapped relation with other mappers available in the registry
404
+ #
405
+ # @overload map_with(model)
406
+ # Map tuples to the provided custom model class
407
+ #
408
+ # @example
409
+ # users.as(MyUserModel)
410
+ #
411
+ # @param [Class>] model Your custom model class
412
+ #
413
+ # @overload map_with(*mappers)
414
+ # Map tuples using registered mappers
415
+ #
416
+ # @example
417
+ # users.map_with(:my_mapper, :my_other_mapper)
418
+ #
419
+ # @param [Array<Symbol>] mappers A list of mapper identifiers
420
+ #
421
+ # @overload map_with(*mappers, auto_map: true)
422
+ # Map tuples using auto-mapping and custom registered mappers
423
+ #
424
+ # If `auto_map` is enabled, your mappers will be applied after performing
425
+ # default auto-mapping. This means that you can compose complex relations
426
+ # and have them auto-mapped, and use much simpler custom mappers to adjust
427
+ # resulting data according to your requirements.
428
+ #
429
+ # @example
430
+ # users.map_with(:my_mapper, :my_other_mapper, auto_map: true)
431
+ #
432
+ # @param [Array<Symbol>] mappers A list of mapper identifiers
433
+ #
434
+ # @return [RelationProxy] A new relation proxy with pipelined relation
435
+ #
436
+ # @api public
437
+ def map_with(*names, **opts)
438
+ super(*names).with(opts)
439
+ end
440
+
441
+ # Return a new relation that will map its tuples to instance of the provided class
442
+ #
443
+ # @example
444
+ # users.map_to(MyUserModel)
445
+ #
446
+ # @param [Class] klass Your custom model class
447
+ #
448
+ # @return [Relation::Composite]
449
+ #
450
+ # @api public
451
+ def map_to(klass, **opts)
452
+ with(opts.merge(meta: { model: klass }))
453
+ end
454
+
455
+ # Return a new relation with an aliased name
456
+ #
457
+ # @example
458
+ # users.as(:people)
459
+ #
460
+ # @param [Class] klass Your custom model class
461
+ #
462
+ # @return [Relation::Composite]
463
+ #
464
+ # @api public
465
+ def as(aliaz)
466
+ with(name: name.as(aliaz))
467
+ end
468
+
469
+ # @return [Symbol] The wrapped relation's adapter identifier ie :sql or :http
470
+ #
471
+ # @api private
472
+ def adapter
473
+ self.class.adapter
474
+ end
475
+
476
+ # Return name of the source gateway of this relation
477
+ #
478
+ # @return [Symbol]
479
+ #
480
+ # @api private
481
+ def gateway
482
+ self.class.gateway
483
+ end
484
+
485
+ # Return all registered relation schemas
486
+ #
487
+ # This holds all schemas defined via `view` DSL
488
+ #
489
+ # @return [Hash<Symbol=>Schema>]
490
+ #
491
+ # @api public
492
+ def schemas
493
+ self.class.schemas
494
+ end
495
+
496
+ # Return a foreign key name for the provided relation name
497
+ #
498
+ # @param [Name] name The relation name object
499
+ #
500
+ # @return [Symbol]
501
+ #
502
+ # @api private
503
+ def foreign_key(name)
504
+ attr = schema.foreign_key(name.dataset)
505
+
506
+ if attr
507
+ attr.name
508
+ else
509
+ :"#{Dry::Core::Inflector.singularize(name.dataset)}_id"
510
+ end
511
+ end
512
+
513
+ # Return a new relation configured with the provided struct namespace
514
+ #
515
+ # @param [Module] namespace
516
+ #
517
+ # @return [Relation]
518
+ #
519
+ # @api public
520
+ def struct_namespace(ns)
521
+ options[:struct_namespace] == ns ? self : with(struct_namespace: ns)
522
+ end
523
+
524
+ memoize :to_ast, :auto_map?, :auto_struct?, :foreign_key, :combine, :wrap, :node
525
+
526
+ # we do it here because we want to avoid previous methods to be auto_curried
527
+ # via method_added hook, which is what AutoCurry uses
528
+ extend AutoCurry
529
+
530
+ auto_curry :preload_assoc
531
+
532
+ private
533
+
534
+ # Hook used by `Pipeline` to get the class that should be used for composition
535
+ #
536
+ # @return [Class]
537
+ #
538
+ # @api private
539
+ def composite_class
540
+ Relation::Composite
541
+ end
542
+
543
+ # @api private
544
+ def wrap_class
545
+ self.class.wrap_class
546
+ end
547
+ end
548
+ end