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,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/commands/composite"
4
+ require "rom/commands/graph"
5
+
6
+ module ROM
7
+ module Commands
8
+ # Lazy command wraps another command and evaluates its input when called
9
+ #
10
+ # @api private
11
+ class Lazy
12
+ include Dry::Equalizer(:command, :evaluator)
13
+
14
+ # @attr_reader [Command] command The wrapped command
15
+ attr_reader :command
16
+
17
+ alias_method :unwrap, :command
18
+
19
+ # @attr_reader [Proc] evaluator The proc that will evaluate the input
20
+ attr_reader :evaluator
21
+
22
+ attr_reader :command_proc
23
+
24
+ # @api private
25
+ def self.[](command)
26
+ case command
27
+ when Commands::Create then Lazy::Create
28
+ when Commands::Update then Lazy::Update
29
+ when Commands::Delete then Lazy::Delete
30
+ else
31
+ self
32
+ end
33
+ end
34
+
35
+ # @api private
36
+ def initialize(command, evaluator, command_proc = nil)
37
+ @command = command
38
+ @evaluator = evaluator
39
+ @command_proc = command_proc || proc { |*| command }
40
+ end
41
+
42
+ # Evaluate command's input using the input proc and pass to command
43
+ #
44
+ # @return [Array,Hash]
45
+ #
46
+ # @api public
47
+ def call(*_args)
48
+ raise NotImplementedError
49
+ end
50
+
51
+ # Compose a lazy command with another one
52
+ #
53
+ # @see Commands::Abstract#>>
54
+ #
55
+ # @return [Composite]
56
+ #
57
+ # @api public
58
+ def >>(other)
59
+ Composite.new(self, other)
60
+ end
61
+
62
+ # Combine with other lazy commands
63
+ #
64
+ # @see Abstract#combine
65
+ #
66
+ # @return [Graph]
67
+ #
68
+ # @api public
69
+ def combine(*others)
70
+ Graph.new(self, others)
71
+ end
72
+
73
+ # @api private
74
+ def lazy?
75
+ true
76
+ end
77
+
78
+ # @api private
79
+ def respond_to_missing?(name, include_private = false)
80
+ super || command.respond_to?(name)
81
+ end
82
+
83
+ private
84
+
85
+ # @api private
86
+ def method_missing(name, *args, &block)
87
+ if command.respond_to?(name)
88
+ response = command.public_send(name, *args, &block)
89
+
90
+ if response.instance_of?(command.class)
91
+ self.class.new(response, evaluator, command_proc)
92
+ else
93
+ response
94
+ end
95
+ else
96
+ super
97
+ end
98
+ end
99
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
100
+ end
101
+ end
102
+ end
103
+
104
+ require "rom/commands/lazy/create"
105
+ require "rom/commands/lazy/update"
106
+ require "rom/commands/lazy/delete"
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/command"
4
+
5
+ module ROM
6
+ module Commands
7
+ # Update command
8
+ #
9
+ # This command updates all tuples in its relation with new attributes
10
+ #
11
+ # @abstract
12
+ class Update < Command
13
+ config.restrictable = true
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/commands/create"
4
+ require "rom/commands/update"
5
+ require "rom/commands/delete"
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ require "rom/support/inflector"
6
+
7
+ require "rom/types"
8
+ require "rom/initializer"
9
+
10
+ require_relative "auto_registration_strategies/no_namespace"
11
+ require_relative "auto_registration_strategies/with_namespace"
12
+ require_relative "auto_registration_strategies/custom_namespace"
13
+
14
+ module ROM
15
+ # AutoRegistration is used to load component files automatically from the provided directory path
16
+ #
17
+ # @api public
18
+ class AutoRegistration
19
+ extend Initializer
20
+
21
+ NamespaceType = Types::Strict::Bool | Types::Strict::String
22
+
23
+ PathnameType = Types.Constructor(Pathname, &Kernel.method(:Pathname))
24
+
25
+ InflectorType = Types.Strict(Dry::Inflector)
26
+
27
+ DEFAULT_MAPPING = {
28
+ relations: :relations,
29
+ mappers: :mappers,
30
+ commands: :commands
31
+ }.freeze
32
+
33
+ # @!attribute [r] directory
34
+ # @return [Pathname] The root path
35
+ param :directory, type: PathnameType
36
+
37
+ # @!attribute [r] namespace
38
+ # @return [Boolean,String]
39
+ # The name of the top level namespace or true/false which
40
+ # enables/disables default top level namespace inferred from the dir name
41
+ option :namespace, type: NamespaceType, default: -> { true }
42
+
43
+ # @!attribute [r] component_dirs
44
+ # @return [Hash] component => dir-name map
45
+ option :component_dirs, type: Types::Strict::Hash, default: -> { DEFAULT_MAPPING }
46
+
47
+ # @!attribute [r] globs
48
+ # @return [Hash] File globbing functions for each component dir
49
+ option :globs, default: lambda {
50
+ component_dirs.map { |component, path|
51
+ [component, directory.join("#{path}/**/*.rb")]
52
+ }.to_h
53
+ }
54
+
55
+ # @!attribute [r] inflector
56
+ # @return [Dry::Inflector] String inflector
57
+ # @api private
58
+ option :inflector, type: InflectorType, default: -> { Inflector }
59
+
60
+ # Load relation files
61
+ #
62
+ # @api private
63
+ def relations
64
+ load_entities(:relations)
65
+ end
66
+
67
+ # Load command files
68
+ #
69
+ # @api private
70
+ def commands
71
+ load_entities(:commands)
72
+ end
73
+
74
+ # Load mapper files
75
+ #
76
+ # @api private
77
+ def mappers
78
+ load_entities(:mappers)
79
+ end
80
+
81
+ private
82
+
83
+ # Load given component files
84
+ #
85
+ # @api private
86
+ def load_entities(entity)
87
+ Dir[globs[entity]].sort.map do |file|
88
+ require file
89
+ klass_name =
90
+ case namespace
91
+ when String
92
+ AutoRegistrationStrategies::CustomNamespace.new(
93
+ namespace: namespace,
94
+ file: file,
95
+ directory: directory,
96
+ inflector: inflector
97
+ ).call
98
+ when TrueClass
99
+ AutoRegistrationStrategies::WithNamespace.new(
100
+ file: file, directory: directory, inflector: inflector
101
+ ).call
102
+ when FalseClass
103
+ AutoRegistrationStrategies::NoNamespace.new(
104
+ file: file,
105
+ directory: directory,
106
+ entity: component_dirs.fetch(entity),
107
+ inflector: inflector
108
+ ).call
109
+ end
110
+
111
+ inflector.constantize(klass_name)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/types"
4
+ require "rom/initializer"
5
+ require "rom/support/inflector"
6
+
7
+ module ROM
8
+ module AutoRegistrationStrategies
9
+ # Base class for registration strategies
10
+ #
11
+ # @api private
12
+ class Base
13
+ extend Initializer
14
+
15
+ PathnameType = Types.Instance(Pathname)
16
+
17
+ EXTENSION_REGEX = /\.rb\z/.freeze
18
+
19
+ # @!attribute [r] file
20
+ # @return [String] Name of a component file
21
+ option :file, type: Types::Strict::String
22
+
23
+ # @!attribute [r] inflector
24
+ # @return [Dry::Inflector] String inflector
25
+ # @api private
26
+ option :inflector, reader: true, default: -> { Inflector }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ require "rom/support/inflector"
6
+ require "rom/types"
7
+
8
+ require_relative "base"
9
+
10
+ module ROM
11
+ module AutoRegistrationStrategies
12
+ # Custom namespace strategy loads components and assumes they are defined
13
+ # within the provided namespace
14
+ #
15
+ # @api private
16
+ class CustomNamespace < Base
17
+ # @!attribute [r] directory
18
+ # @return [Pathname] The path to dir with components
19
+ option :directory, type: PathnameType
20
+
21
+ # @!attribute [r] namespace
22
+ # @return [String] Name of a namespace
23
+ option :namespace, type: Types::Strict::String
24
+
25
+ # Loads components
26
+ #
27
+ # @api private
28
+ def call
29
+ parts = path_arr.map { |part| inflector.camelize(part) }
30
+ potential = parts.map.with_index do |_, i|
31
+ parts[(i - parts.size)..parts.size]
32
+ end
33
+ attempted = []
34
+
35
+ potential.map do |path|
36
+ const_fragment = path.join("::")
37
+
38
+ constant = "#{namespace}::#{const_fragment}"
39
+
40
+ return constant if ns_const.const_defined?(const_fragment)
41
+
42
+ attempted << constant
43
+ end
44
+
45
+ # If we have reached this point, its means constant is not defined and
46
+ # NameError will be thrown if we attempt to camelize something like:
47
+ # `"#{namespace}::#{Inflector.camelize(filename)}"`
48
+ # so we can assume naming convention was not respected in required
49
+ # file.
50
+
51
+ raise NameError, name_error_message(attempted)
52
+ end
53
+
54
+ private
55
+
56
+ # @api private
57
+ def name_error_message(attempted)
58
+ "required file does not define expected constant name; either " \
59
+ "register your constant explicitly of try following the path" \
60
+ "naming convention like:\n\n\t- #{attempted.join("\n\t- ")}\n"
61
+ end
62
+
63
+ # @api private
64
+ def filename
65
+ Pathname(file).basename(".rb")
66
+ end
67
+
68
+ # @api private
69
+ def ns_const
70
+ @namespace_constant ||= inflector.constantize(namespace)
71
+ end
72
+
73
+ # @api private
74
+ def path_arr
75
+ file_path << filename
76
+ end
77
+
78
+ # @api private
79
+ def file_path
80
+ File.dirname(file).split("/") - directory.to_s.split("/")
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ require "rom/support/inflector"
6
+ require "rom/types"
7
+ require_relative "base"
8
+
9
+ module ROM
10
+ module AutoRegistrationStrategies
11
+ # NoNamespace strategy assumes components are not defined within a namespace
12
+ #
13
+ # @api private
14
+ class NoNamespace < Base
15
+ # @!attribute [r] directory
16
+ # @return [Pathname] The path to dir with components
17
+ option :directory, type: PathnameType
18
+
19
+ # @!attribute [r] entity
20
+ # @return [Symbol] Component identifier
21
+ option :entity, type: Types::Strict::Symbol
22
+
23
+ # Load components
24
+ #
25
+ # @api private
26
+ def call
27
+ inflector.camelize(
28
+ file.sub(%r{^#{directory}/#{entity}/}, "").sub(EXTENSION_REGEX, "")
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ require "rom/support/inflector"
6
+ require_relative "base"
7
+
8
+ module ROM
9
+ module AutoRegistrationStrategies
10
+ # WithNamespace strategy assumes components are defined within a namespace
11
+ # that matches top-level directory name.
12
+ #
13
+ # @api private
14
+ class WithNamespace < Base
15
+ # @!attribute [r] directory
16
+ # @return [Pathname] The path to dir with components
17
+ option :directory, type: PathnameType
18
+
19
+ # Load components
20
+ #
21
+ # @api private
22
+ def call
23
+ inflector.camelize(
24
+ file.sub(%r{^#{directory.dirname}/}, "").sub(EXTENSION_REGEX, "")
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/class_attributes"
4
+ require "rom/command"
5
+
6
+ module ROM
7
+ class Command
8
+ extend Dry::Core::ClassAttributes
9
+
10
+ module Restrictable
11
+ extend ROM::Notifications::Listener
12
+
13
+ subscribe("configuration.commands.class.before_build") do |event|
14
+ command = event[:command]
15
+ relation = event[:relation]
16
+ command.extend_for_relation(relation) if command.restrictable
17
+ end
18
+
19
+ # @api private
20
+ def create_class(relation: nil, **, &block)
21
+ klass = super
22
+ klass.extend_for_relation(relation) if relation && klass.restrictable
23
+ klass
24
+ end
25
+ end
26
+
27
+ class << self
28
+ prepend Restrictable
29
+ prepend SettingProxy
30
+
31
+ def setting_mapping
32
+ @setting_mapper ||= {
33
+ adapter: [:component, :adapter],
34
+ relation: [:component, %i[relation namespace]],
35
+ register_as: [:component, :id],
36
+ restrictable: [],
37
+ result: [],
38
+ input: []
39
+ }.freeze
40
+ end
41
+ end
42
+
43
+ # Extend a command class with relation view methods
44
+ #
45
+ # @param [Relation] relation
46
+ #
47
+ # @return [Class]
48
+ #
49
+ # @api public
50
+ # @deprecated
51
+ def self.extend_for_relation(relation)
52
+ include(relation_methods_mod(relation.class))
53
+ end
54
+
55
+ # @api private
56
+ def self.relation_methods_mod(relation_class)
57
+ Module.new do
58
+ relation_class.view_methods.each do |meth|
59
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
60
+ def #{meth}(*args)
61
+ response = relation.public_send(:#{meth}, *args)
62
+
63
+ if response.is_a?(relation.class)
64
+ new(response)
65
+ else
66
+ response
67
+ end
68
+ end
69
+ RUBY
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/relation/name"
4
+
5
+ require "rom/components/dsl/schema"
6
+ require "rom/compat/schema/dsl"
7
+
8
+ module ROM
9
+ module Components
10
+ module DSL
11
+ # @private
12
+ #
13
+ # rubocop:disable Metrics/AbcSize
14
+ # rubocop:disable Metrics/CyclomaticComplexity
15
+ # rubocop:disable Metrics/PerceivedComplexity
16
+ class Schema < Core
17
+ mod = Module.new do
18
+ # @api private
19
+ def call
20
+ return super unless config.dsl_class || config.view
21
+
22
+ configure
23
+
24
+ if config.view
25
+ components.add(key, name: name, config: config, block: block)
26
+ else
27
+ dsl_config = backend.config
28
+ associations = dsl_config[:associations]
29
+
30
+ component = components.add(key, name: name, config: config.join(dsl_config, :right))
31
+
32
+ associations.each do |definition|
33
+ components.add(
34
+ :associations,
35
+ definition: definition,
36
+ config: dsl_assoc_config.join({namespace: relation, **definition.to_h}, :right)
37
+ )
38
+ end
39
+
40
+ component
41
+ end
42
+ end
43
+
44
+ # @api public
45
+ #
46
+ # @deprecated
47
+ def associations(&block)
48
+ backend.associations(&block)
49
+ end
50
+
51
+ private
52
+
53
+ # @api private
54
+ def name
55
+ ROM::Relation::Name[relation, config.dataset]
56
+ end
57
+
58
+ # @api private
59
+ def dsl_assoc_config
60
+ provider.config.association.merge(adapter: adapter, inflector: inflector)
61
+ end
62
+
63
+ # @api private
64
+ def backend
65
+ @backend ||= config.dsl_class.new(
66
+ **config,
67
+ attributes: attributes,
68
+ inferrer: inferrer,
69
+ inflector: inflector,
70
+ plugins: config.plugins,
71
+ relation: name,
72
+ definition: block
73
+ )
74
+ end
75
+
76
+ # @api private
77
+ def configure
78
+ if !config.view && provider.config.component.type == :relation
79
+ provider.config.component.update(dataset: config.dataset) if config.dataset
80
+ provider.config.component.update(id: config.as) if config.as
81
+
82
+ if provider.config.component.id == :anonymous
83
+ provider.config.component.update(id: config.id)
84
+ end
85
+
86
+ if config.id.nil?
87
+ config.update(id: provider.config.component.id)
88
+ end
89
+
90
+ if config.relation.nil?
91
+ config.update(relation: provider.config.component.id)
92
+ end
93
+
94
+ if config.adapter.nil?
95
+ config.update(adapter: provider.config.component.adapter)
96
+ end
97
+ end
98
+
99
+ config.update(id: relation) if relation && (config.id.nil? || config.as)
100
+
101
+ if provider.config.component.type == :relation
102
+ provider.config.component.inherit!(config)
103
+ end
104
+
105
+ if config.view
106
+ config.join!({namespace: relation}, :right)
107
+ end
108
+
109
+ super
110
+ end
111
+
112
+ # @api private
113
+ def relation
114
+ config.relation || config.as || config.id
115
+ end
116
+
117
+ # @api private
118
+ def inferrer
119
+ config.inferrer.with(enabled: config.infer)
120
+ end
121
+ end
122
+ # rubocop:enable Metrics/AbcSize
123
+ # rubocop:enable Metrics/CyclomaticComplexity
124
+ # rubocop:enable Metrics/PerceivedComplexity
125
+
126
+ prepend(mod)
127
+ end
128
+ end
129
+ end
130
+ end