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,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/constants"
4
+
5
+ module ROM
6
+ module Plugins
7
+ # Plugin registration DSL
8
+ #
9
+ # @private
10
+ class DSL
11
+ # Default options passed to plugin registration
12
+ #
13
+ # @return [Hash]
14
+ #
15
+ # @api private
16
+ attr_reader :defaults
17
+
18
+ # Plugin registry
19
+ #
20
+ # @return [PluginRegistry]
21
+ #
22
+ # @api private
23
+ attr_reader :registry
24
+
25
+ # @api private
26
+ def initialize(registry, defaults = EMPTY_HASH, &block)
27
+ @registry = registry
28
+ @defaults = defaults
29
+ instance_exec(&block)
30
+ end
31
+
32
+ # Register a plugin
33
+ #
34
+ # @param [Symbol] name Name of a plugin
35
+ # @param [Module] mod Plugin module
36
+ # @param [Hash] options
37
+ #
38
+ # @api public
39
+ def register(name, mod, options = EMPTY_HASH)
40
+ registry.register(name, mod: mod, **defaults, **options)
41
+ end
42
+
43
+ # Register plugins for a specific adapter
44
+ #
45
+ # @param [Symbol] type The adapter identifier
46
+ #
47
+ # @api public
48
+ def adapter(type, &block)
49
+ self.class.new(registry, adapter: type, &block)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/changeset"
4
+ require "rom/changeset/extensions/relation"
5
+
6
+ module ROM
7
+ module Plugins
8
+ module Relation
9
+ # Relation plugin which adds `Relation#changeset` method
10
+ #
11
+ # @api public
12
+ module Changeset
13
+ TYPES = {
14
+ create: ROM::Changeset::Create,
15
+ update: ROM::Changeset::Update,
16
+ delete: ROM::Changeset::Delete
17
+ }.freeze
18
+
19
+ # @api private
20
+ def self.apply(target, **)
21
+ target.include(InstanceMethods)
22
+ end
23
+
24
+ # Relation instance methods provided by the Changeset plugin
25
+ #
26
+ # @api public
27
+ module InstanceMethods
28
+ # Create a changeset for a relation
29
+ #
30
+ # @overload changeset(type, data)
31
+ # Create a changeset of one of predefined types
32
+ #
33
+ # @example creating a record
34
+ # users.
35
+ # changeset(:create, name: 'Jane').
36
+ # commit
37
+ # # => #<ROM::Struct::User id=1 name="Jane">
38
+ #
39
+ # @example updating a record
40
+ # users.
41
+ # by_pk(1).
42
+ # changeset(:update, name: 'Jack').
43
+ # commit
44
+ # # => #<ROM::Struct::User id=1 name="Jane">
45
+ #
46
+ # @example providing data as a separate step
47
+ # changeset = users.changeset(:create)
48
+ # jack = changeset.data(name: 'Jack').commit
49
+ # jane = changeset.data(name: 'Jane').commit
50
+ #
51
+ # @example using a command graph
52
+ # users.
53
+ # changeset(
54
+ # :create,
55
+ # name: "Jane",
56
+ # posts: [{ title: "Something about aliens" }]
57
+ # )
58
+ #
59
+ # @param [Symbol] type The changeset type
60
+ # @param [Hash] data
61
+ # @return [Changeset]
62
+ #
63
+ # @overload changeset(changeset_class, data)
64
+ # @example using a custom changeset class
65
+ # class NewUser < ROM::Changeset::Create
66
+ # map do |tuple|
67
+ # { **tuple, name: tuple.values_at(:first_name, :last_name).join(' ') }
68
+ # end
69
+ # end
70
+ #
71
+ # users.changeset(NewUser, first_name: 'John', last_name: 'Doe').commit
72
+ #
73
+ # @param [Class] changeset_class A custom changeset class
74
+ # @return [Changeset]
75
+ #
76
+ # @api public
77
+ def changeset(type, data = EMPTY_HASH)
78
+ klass = type.is_a?(Symbol) ? TYPES.fetch(type) : type
79
+
80
+ unless klass < ROM::Changeset
81
+ raise ArgumentError, "+#{type.name}+ must be a Changeset descendant"
82
+ end
83
+
84
+ if klass < ROM::Changeset::Stateful
85
+ klass.new(self, __data__: data)
86
+ else
87
+ klass.new(self)
88
+ end
89
+ rescue KeyError
90
+ raise ArgumentError,
91
+ "+#{type.inspect}+ is not a valid changeset type. Must be one of: #{TYPES.keys.inspect}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/class_attributes"
4
+
5
+ module ROM
6
+ module Plugins
7
+ module Relation
8
+ # Experimental plugin for configuring relations with an external
9
+ # instrumentation system like dry-monitor or ActiveSupport::Notifications
10
+ #
11
+ # @api public
12
+ module Instrumentation
13
+ extend Dry::Core::ClassAttributes
14
+
15
+ # This hooks sets up a relation class with injectible notifications object
16
+ #
17
+ # @api private
18
+ def self.included(klass)
19
+ super
20
+ klass.option :notifications
21
+ klass.extend(ClassInterface)
22
+ klass.prepend(mixin)
23
+ klass.instrument(:to_a)
24
+ end
25
+
26
+ defines :mixin
27
+ mixin Module.new
28
+
29
+ # Instrumentation extension for relation classes
30
+ #
31
+ # @api private
32
+ module ClassInterface
33
+ # Configure provided methods for instrumentation
34
+ #
35
+ # @param [Array<Symbol>] methods A list of method names
36
+ #
37
+ # @api public
38
+ def instrument(*methods)
39
+ (methods - Instrumentation.mixin.instance_methods).each do |meth|
40
+ Instrumentation.mixin.send(:define_method, meth) do
41
+ instrument { super() }
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ # Execute a block using instrumentation
48
+ #
49
+ # @api public
50
+ def instrument(&block)
51
+ notifications.instrument(
52
+ config.component.adapter,
53
+ name: name.relation, **notification_payload(self), &block
54
+ )
55
+ end
56
+
57
+ private
58
+
59
+ # @api private
60
+ def notification_payload(_relation)
61
+ EMPTY_HASH
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/constants"
4
+
5
+ module ROM
6
+ module Plugins
7
+ module Relation
8
+ # Allows relations to access all other relations through registry
9
+ #
10
+ # For now this plugin is always enabled
11
+ #
12
+ # @api public
13
+ class RegistryReader < ::Module
14
+ EMPTY_REGISTRY = EMPTY_HASH
15
+
16
+ # @api private
17
+ attr_reader :relations
18
+
19
+ # @api private
20
+ def initialize(relations:)
21
+ @relations = relations
22
+ define_readers!
23
+ end
24
+
25
+ private
26
+
27
+ # @api private
28
+ def define_readers!
29
+ relations.each do |name|
30
+ define_method(name) { registry.relations[name] }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Plugins
5
+ module Schema
6
+ # A plugin for automatically adding timestamp fields
7
+ # to the schema definition
8
+ #
9
+ # @example
10
+ # schema do
11
+ # use :timestamps
12
+ # end
13
+ #
14
+ # # using non-default names
15
+ # schema do
16
+ # use :timestamps, attributes: %i(created_on updated_on)
17
+ # end
18
+ #
19
+ # # using other types
20
+ # schema do
21
+ # use :timestamps, type: Types::Date
22
+ # end
23
+ #
24
+ # @api public
25
+ module Timestamps
26
+ DEFAULT_TIMESTAMPS = %i[created_at updated_at].freeze
27
+ DEFAULT_TYPE = ROM::Types::Time
28
+
29
+ # @api private
30
+ def self.apply(schema, **options)
31
+ attributes = options.fetch(:attributes, DEFAULT_TIMESTAMPS)
32
+ attrs_type = options.fetch(:type, DEFAULT_TYPE)
33
+
34
+ attributes.each do |name|
35
+ schema.attribute(name, attrs_type)
36
+ end
37
+
38
+ schema
39
+ end
40
+
41
+ # @api private
42
+ module DSL
43
+ # Sets non-default timestamp attributes
44
+ #
45
+ # @example
46
+ # schema do
47
+ # use :timestamps
48
+ # timestamps :create_on, :updated_on
49
+ # end
50
+ #
51
+ # @api public
52
+ def timestamps(*names)
53
+ plugin(:timestamps, attributes: names).apply
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/container"
4
+
5
+ require "rom/constants"
6
+ require "rom/plugin"
7
+
8
+ require "rom/plugins/dsl"
9
+ require "rom/plugins/relation/registry_reader"
10
+ require "rom/plugins/relation/instrumentation"
11
+ require "rom/plugins/relation/changeset"
12
+ require "rom/plugins/command/schema"
13
+ require "rom/plugins/command/timestamps"
14
+ require "rom/plugins/schema/timestamps"
15
+
16
+ module ROM
17
+ # Registry of all known plugins
18
+ #
19
+ # @api public
20
+ module Plugins
21
+ extend Dry::Container::Mixin
22
+ extend Enumerable
23
+
24
+ module_function
25
+
26
+ def dsl(*args, &block)
27
+ Plugins::DSL.new(self, *args, &block)
28
+ end
29
+
30
+ # @api private
31
+ def register(name, type:, **options)
32
+ Plugin.new(name: name, type: type, **options).tap do |plugin|
33
+ super(plugin.key, plugin)
34
+ end
35
+ end
36
+
37
+ # @api private
38
+ def each
39
+ keys.each { |key| yield(self[key]) }
40
+ end
41
+
42
+ # @api private
43
+ def resolve(key)
44
+ super
45
+ rescue Dry::Container::Error
46
+ raise ROM::UnknownPluginError, "+#{key}+ plugin was not found"
47
+ end
48
+
49
+ # TODO: move to rom/compat
50
+ # @api private
51
+ class Resolver
52
+ attr_reader :container, :type, :_adapter
53
+
54
+ # @api private
55
+ def initialize(container, type:, adapter: nil)
56
+ @container = container
57
+ @type = type
58
+ @_adapter = adapter
59
+ end
60
+
61
+ # @api private
62
+ def adapter(name)
63
+ self.class.new(container, type: type, adapter: name)
64
+ end
65
+
66
+ # @api private
67
+ def fetch(name, adapter = nil)
68
+ if adapter
69
+ key = [adapter, type, name].compact.join(".")
70
+
71
+ if container.key?(key)
72
+ container.resolve(key)
73
+ else
74
+ fetch(name)
75
+ end
76
+ elsif _adapter && key?(name)
77
+ fetch(name, _adapter)
78
+ else
79
+ key = "#{type}.#{name}"
80
+ container.resolve(key)
81
+ end
82
+ end
83
+ alias_method :[], :fetch
84
+
85
+ # @api private
86
+ def key?(name)
87
+ container.key?([_adapter, type, name].compact.join("."))
88
+ end
89
+ end
90
+
91
+ # @api private
92
+ def [](key)
93
+ if key?(key)
94
+ super
95
+ else
96
+ Resolver.new(self, type: key)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ class Processor
5
+ # @api private
6
+ module Composer
7
+ # @api private
8
+ class Factory
9
+ attr_reader :fns, :default
10
+
11
+ # @api private
12
+ def initialize(default = nil)
13
+ @fns = []
14
+ @default = default
15
+ end
16
+
17
+ # @api private
18
+ def <<(other)
19
+ fns.concat(Array(other).compact)
20
+ self
21
+ end
22
+
23
+ # @api private
24
+ def to_fn
25
+ fns.reduce(:+) || default
26
+ end
27
+ end
28
+
29
+ # @api private
30
+ def compose(default = nil)
31
+ factory = Factory.new(default)
32
+ yield(factory)
33
+ factory.to_fn
34
+ end
35
+ end
36
+ end
37
+ end