rom-core 4.2.1 → 5.0.0

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -2
  3. data/lib/rom-core.rb +2 -0
  4. data/lib/rom/array_dataset.rb +2 -0
  5. data/lib/rom/association_set.rb +2 -0
  6. data/lib/rom/associations/abstract.rb +2 -0
  7. data/lib/rom/associations/definitions.rb +2 -0
  8. data/lib/rom/associations/definitions/abstract.rb +2 -0
  9. data/lib/rom/associations/definitions/many_to_many.rb +2 -0
  10. data/lib/rom/associations/definitions/many_to_one.rb +2 -0
  11. data/lib/rom/associations/definitions/one_to_many.rb +2 -0
  12. data/lib/rom/associations/definitions/one_to_one.rb +2 -0
  13. data/lib/rom/associations/definitions/one_to_one_through.rb +2 -0
  14. data/lib/rom/associations/many_to_many.rb +2 -0
  15. data/lib/rom/associations/many_to_one.rb +2 -0
  16. data/lib/rom/associations/one_to_many.rb +2 -0
  17. data/lib/rom/associations/one_to_one.rb +2 -0
  18. data/lib/rom/associations/one_to_one_through.rb +2 -0
  19. data/lib/rom/associations/through_identifier.rb +2 -0
  20. data/lib/rom/attribute.rb +58 -72
  21. data/lib/rom/auto_curry.rb +2 -0
  22. data/lib/rom/cache.rb +2 -0
  23. data/lib/rom/command.rb +7 -5
  24. data/lib/rom/command_compiler.rb +2 -0
  25. data/lib/rom/command_proxy.rb +2 -0
  26. data/lib/rom/command_registry.rb +13 -7
  27. data/lib/rom/commands.rb +2 -0
  28. data/lib/rom/commands/class_interface.rb +4 -2
  29. data/lib/rom/commands/composite.rb +2 -0
  30. data/lib/rom/commands/create.rb +2 -0
  31. data/lib/rom/commands/delete.rb +2 -0
  32. data/lib/rom/commands/graph.rb +2 -0
  33. data/lib/rom/commands/graph/class_interface.rb +2 -0
  34. data/lib/rom/commands/graph/input_evaluator.rb +2 -0
  35. data/lib/rom/commands/lazy.rb +2 -0
  36. data/lib/rom/commands/lazy/create.rb +2 -0
  37. data/lib/rom/commands/lazy/delete.rb +2 -0
  38. data/lib/rom/commands/lazy/update.rb +2 -0
  39. data/lib/rom/commands/update.rb +2 -0
  40. data/lib/rom/configuration.rb +2 -0
  41. data/lib/rom/configuration_dsl.rb +2 -0
  42. data/lib/rom/configuration_dsl/command.rb +2 -0
  43. data/lib/rom/configuration_dsl/command_dsl.rb +2 -0
  44. data/lib/rom/configuration_dsl/relation.rb +2 -0
  45. data/lib/rom/configuration_plugin.rb +2 -0
  46. data/lib/rom/constants.rb +3 -0
  47. data/lib/rom/container.rb +2 -0
  48. data/lib/rom/core.rb +4 -1
  49. data/lib/rom/create_container.rb +2 -0
  50. data/lib/rom/data_proxy.rb +2 -0
  51. data/lib/rom/enumerable_dataset.rb +2 -0
  52. data/lib/rom/environment.rb +2 -0
  53. data/lib/rom/gateway.rb +2 -0
  54. data/lib/rom/global.rb +2 -0
  55. data/lib/rom/global/plugin_dsl.rb +2 -0
  56. data/lib/rom/header.rb +198 -0
  57. data/lib/rom/header/attribute.rb +192 -0
  58. data/lib/rom/initializer.rb +2 -0
  59. data/lib/rom/lint/enumerable_dataset.rb +2 -0
  60. data/lib/rom/lint/gateway.rb +2 -0
  61. data/lib/rom/lint/linter.rb +2 -0
  62. data/lib/rom/lint/spec.rb +2 -0
  63. data/lib/rom/lint/test.rb +2 -0
  64. data/lib/rom/mapper.rb +100 -0
  65. data/lib/rom/mapper/attribute_dsl.rb +480 -0
  66. data/lib/rom/mapper/builder.rb +39 -0
  67. data/lib/rom/mapper/configuration_plugin.rb +28 -0
  68. data/lib/rom/mapper/dsl.rb +123 -0
  69. data/lib/rom/mapper/mapper_dsl.rb +45 -0
  70. data/lib/rom/mapper/model_dsl.rb +60 -0
  71. data/lib/rom/mapper_compiler.rb +84 -0
  72. data/lib/rom/mapper_registry.rb +2 -0
  73. data/lib/rom/memory.rb +2 -0
  74. data/lib/rom/memory/associations.rb +2 -0
  75. data/lib/rom/memory/associations/many_to_many.rb +2 -0
  76. data/lib/rom/memory/associations/many_to_one.rb +2 -0
  77. data/lib/rom/memory/associations/one_to_many.rb +2 -0
  78. data/lib/rom/memory/associations/one_to_one.rb +2 -0
  79. data/lib/rom/memory/commands.rb +2 -0
  80. data/lib/rom/memory/dataset.rb +2 -0
  81. data/lib/rom/memory/gateway.rb +2 -0
  82. data/lib/rom/memory/mapper_compiler.rb +2 -0
  83. data/lib/rom/memory/relation.rb +2 -0
  84. data/lib/rom/memory/schema.rb +2 -0
  85. data/lib/rom/memory/storage.rb +2 -0
  86. data/lib/rom/memory/types.rb +2 -0
  87. data/lib/rom/model_builder.rb +103 -0
  88. data/lib/rom/open_struct.rb +37 -0
  89. data/lib/rom/pipeline.rb +2 -0
  90. data/lib/rom/plugin.rb +2 -0
  91. data/lib/rom/plugin_base.rb +2 -0
  92. data/lib/rom/plugin_registry.rb +2 -0
  93. data/lib/rom/plugins/command/schema.rb +2 -0
  94. data/lib/rom/plugins/command/timestamps.rb +2 -0
  95. data/lib/rom/plugins/relation/instrumentation.rb +2 -0
  96. data/lib/rom/plugins/relation/registry_reader.rb +2 -0
  97. data/lib/rom/plugins/schema/timestamps.rb +8 -1
  98. data/lib/rom/processor.rb +30 -0
  99. data/lib/rom/processor/transproc.rb +417 -0
  100. data/lib/rom/registry.rb +2 -0
  101. data/lib/rom/relation.rb +4 -2
  102. data/lib/rom/relation/class_interface.rb +2 -0
  103. data/lib/rom/relation/combined.rb +2 -0
  104. data/lib/rom/relation/commands.rb +2 -0
  105. data/lib/rom/relation/composite.rb +2 -0
  106. data/lib/rom/relation/curried.rb +3 -1
  107. data/lib/rom/relation/graph.rb +2 -0
  108. data/lib/rom/relation/loaded.rb +2 -0
  109. data/lib/rom/relation/materializable.rb +2 -0
  110. data/lib/rom/relation/name.rb +2 -0
  111. data/lib/rom/relation/view_dsl.rb +2 -0
  112. data/lib/rom/relation/wrap.rb +2 -0
  113. data/lib/rom/relation_registry.rb +2 -0
  114. data/lib/rom/schema.rb +39 -6
  115. data/lib/rom/schema/associations_dsl.rb +5 -3
  116. data/lib/rom/schema/dsl.rb +41 -11
  117. data/lib/rom/schema/inferrer.rb +21 -3
  118. data/lib/rom/schema_plugin.rb +2 -0
  119. data/lib/rom/setup.rb +2 -0
  120. data/lib/rom/setup/auto_registration.rb +2 -0
  121. data/lib/rom/setup/auto_registration_strategies/base.rb +3 -1
  122. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +2 -0
  123. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +2 -0
  124. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +2 -0
  125. data/lib/rom/setup/finalize.rb +2 -0
  126. data/lib/rom/setup/finalize/finalize_commands.rb +2 -0
  127. data/lib/rom/setup/finalize/finalize_mappers.rb +2 -0
  128. data/lib/rom/setup/finalize/finalize_relations.rb +2 -0
  129. data/lib/rom/struct.rb +108 -0
  130. data/lib/rom/struct_compiler.rb +110 -0
  131. data/lib/rom/support/configurable.rb +2 -0
  132. data/lib/rom/support/inflector.rb +2 -0
  133. data/lib/rom/support/memoizable.rb +2 -0
  134. data/lib/rom/support/notifications.rb +2 -0
  135. data/lib/rom/transaction.rb +2 -0
  136. data/lib/rom/transformer.rb +34 -0
  137. data/lib/rom/types.rb +10 -3
  138. data/lib/rom/version.rb +3 -1
  139. metadata +37 -21
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/core/class_builder'
4
+
5
+ module ROM
6
+ class Mapper
7
+ # Setup DSL-specific mapper extensions
8
+ #
9
+ # @private
10
+ class Builder
11
+ # Generate a mapper subclass
12
+ #
13
+ # This is used by Setup#mappers DSL
14
+ #
15
+ # @api private
16
+ def self.build_class(name, mapper_registry, options = EMPTY_HASH, &block)
17
+ class_name = "ROM::Mapper[#{name}]"
18
+
19
+ parent = options[:parent]
20
+ inherit_header = options.fetch(:inherit_header) { ROM::Mapper.inherit_header }
21
+
22
+ parent_class =
23
+ if parent
24
+ mapper_registry.detect { |klass| klass.relation == parent }
25
+ else
26
+ ROM::Mapper
27
+ end
28
+
29
+ Dry::Core::ClassBuilder.new(name: class_name, parent: parent_class).call do |klass|
30
+ klass.register_as(name)
31
+ klass.relation(name)
32
+ klass.inherit_header(inherit_header)
33
+
34
+ klass.class_eval(&block) if block
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/mapper/mapper_dsl'
4
+
5
+ module ROM
6
+ class Mapper
7
+ # Model DSL allows setting a model class
8
+ #
9
+ # @private
10
+ module ConfigurationPlugin
11
+ # Mapper definition DSL used by Setup DSL
12
+ #
13
+ # @private
14
+
15
+ def self.apply(configuration, options = {})
16
+ configuration.extend Methods
17
+ configuration
18
+ end
19
+
20
+ module Methods
21
+ def mappers(&block)
22
+ register_mapper(*MapperDSL.new(self, mapper_classes, block).mapper_classes)
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/core/class_attributes'
4
+ require 'rom/mapper/attribute_dsl'
5
+
6
+ module ROM
7
+ class Mapper
8
+ # Mapper class-level DSL including Attribute DSL and Model DSL
9
+ module DSL
10
+ # Extend mapper class with macros and DSL methods
11
+ #
12
+ # @api private
13
+ def self.included(klass)
14
+ klass.extend(Dry::Core::ClassAttributes)
15
+ klass.extend(ClassMethods)
16
+ end
17
+
18
+ # Class methods for all mappers
19
+ #
20
+ # @private
21
+ module ClassMethods
22
+ # Set base ivars for the mapper class
23
+ #
24
+ # @api private
25
+ def inherited(klass)
26
+ super
27
+
28
+ klass.instance_variable_set('@attributes', nil)
29
+ klass.instance_variable_set('@header', nil)
30
+ klass.instance_variable_set('@dsl', nil)
31
+ end
32
+
33
+ # include a registered plugin in this mapper
34
+ #
35
+ # @param [Symbol] plugin
36
+ # @param [Hash] options
37
+ # @option options [Symbol] :adapter (:default) first adapter to check for plugin
38
+ #
39
+ # @api public
40
+ def use(plugin, options = {})
41
+ adapter = options.fetch(:adapter, :default)
42
+
43
+ ROM.plugin_registry.mappers.fetch(plugin, adapter).apply_to(self)
44
+ end
45
+
46
+ # Return base_relation used for creating mapper registry
47
+ #
48
+ # This is used to "gather" mappers under same root name
49
+ #
50
+ # @api private
51
+ def base_relation
52
+ if superclass.relation
53
+ superclass.relation
54
+ else
55
+ relation
56
+ end
57
+ end
58
+
59
+ # Return header of the mapper
60
+ #
61
+ # This is memoized so mutating mapper class won't have an effect wrt
62
+ # header after it was initialized for the first time.
63
+ #
64
+ # TODO: freezing mapper class here is probably a good idea
65
+ #
66
+ # @api private
67
+ def header
68
+ @header ||= dsl.header
69
+ end
70
+
71
+ # @api private
72
+ def respond_to_missing?(name, _include_private = false)
73
+ dsl.respond_to?(name) || super
74
+ end
75
+
76
+ private
77
+
78
+ # Return default Attribute DSL options based on settings of the mapper
79
+ # class
80
+ #
81
+ # @api private
82
+ def options
83
+ { copy_keys: copy_keys,
84
+ prefix: prefix,
85
+ prefix_separator: prefix_separator,
86
+ symbolize_keys: symbolize_keys,
87
+ reject_keys: reject_keys }
88
+ end
89
+
90
+ # Return default attributes that might have been inherited from the
91
+ # superclass
92
+ #
93
+ # @api private
94
+ def attributes
95
+ @attributes ||=
96
+ if superclass.respond_to?(:attributes, true) && inherit_header
97
+ superclass.attributes.dup
98
+ else
99
+ []
100
+ end
101
+ end
102
+
103
+ # Create the attribute DSL instance used by the mapper class
104
+ #
105
+ # @api private
106
+ def dsl
107
+ @dsl ||= AttributeDSL.new(attributes, options)
108
+ end
109
+
110
+ # Delegate Attribute DSL method to the dsl instance
111
+ #
112
+ # @api private
113
+ def method_missing(name, *args, &block)
114
+ if dsl.respond_to?(name)
115
+ dsl.public_send(name, *args, &block)
116
+ else
117
+ super
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/mapper/builder'
4
+
5
+ module ROM
6
+ class Mapper
7
+ # Mapper definition DSL used by Setup DSL
8
+ #
9
+ # @private
10
+ class MapperDSL
11
+ attr_reader :configuration, :mapper_classes, :defined_mappers
12
+
13
+ # @api private
14
+ def initialize(configuration, mapper_classes, block)
15
+ @configuration = configuration
16
+ @mapper_classes = mapper_classes
17
+ @defined_mappers = []
18
+
19
+ instance_exec(&block)
20
+
21
+ @mapper_classes = @defined_mappers
22
+ end
23
+
24
+ # Define a mapper class
25
+ #
26
+ # @param [Symbol] name of the mapper
27
+ # @param [Hash] options
28
+ #
29
+ # @return [Class]
30
+ #
31
+ # @api public
32
+ def define(name, options = EMPTY_HASH, &block)
33
+ @defined_mappers << Builder.build_class(name, (@mapper_classes + @defined_mappers), options, &block)
34
+ self
35
+ end
36
+
37
+ # TODO
38
+ #
39
+ # @api public
40
+ def register(relation, mappers)
41
+ configuration.register_mapper(relation => mappers)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/model_builder'
4
+
5
+ module ROM
6
+ class Mapper
7
+ # Model DSL allows setting a model class
8
+ #
9
+ # @private
10
+ module ModelDSL
11
+ attr_reader :attributes, :builder, :klass
12
+
13
+ DEFAULT_TYPE = :poro
14
+
15
+ # Set or generate a model
16
+ #
17
+ # @example
18
+ # class MyDefinition
19
+ # include ROM::Mapper::ModelDSL
20
+ #
21
+ # def initialize
22
+ # @attributes = [[:name], [:title]]
23
+ # end
24
+ # end
25
+ #
26
+ # definition = MyDefinition.new
27
+ #
28
+ # # just set a model constant
29
+ # definition.model(User)
30
+ #
31
+ # # generate model class for the attributes
32
+ # definition.model(name: 'User')
33
+ #
34
+ # @api public
35
+ def model(options = nil)
36
+ if options.is_a?(Class)
37
+ @klass = options
38
+ elsif options
39
+ type = options.fetch(:type) { DEFAULT_TYPE }
40
+ @builder = ModelBuilder[type].new(options)
41
+ end
42
+
43
+ build_class unless options
44
+ end
45
+
46
+ private
47
+
48
+ # Build a model class using a specialized builder
49
+ #
50
+ # @api private
51
+ def build_class
52
+ return klass if klass
53
+ included_attrs = attributes.reject do |_name, opts|
54
+ opts && opts[:exclude]
55
+ end
56
+ builder.call(included_attrs.map(&:first)) if builder
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/core/class_attributes'
4
+
5
+ require 'rom/constants'
6
+ require 'rom/initializer'
7
+ require 'rom/mapper'
8
+ require 'rom/struct'
9
+ require 'rom/struct_compiler'
10
+ require 'rom/cache'
11
+
12
+ module ROM
13
+ # @api private
14
+ class MapperCompiler
15
+ extend Dry::Core::ClassAttributes
16
+ extend Initializer
17
+
18
+ defines :mapper_options
19
+
20
+ mapper_options(EMPTY_HASH)
21
+
22
+ option :cache, default: -> { Cache.new }
23
+
24
+ attr_reader :struct_compiler
25
+
26
+ attr_reader :mapper_options
27
+
28
+ def initialize(*args)
29
+ super
30
+ @struct_compiler = StructCompiler.new(cache: cache)
31
+ @cache = cache.namespaced(:mappers)
32
+ @mapper_options = self.class.mapper_options
33
+ end
34
+
35
+ def call(ast)
36
+ cache.fetch_or_store(ast.hash) { Mapper.build(Header.coerce(*visit(ast))) }
37
+ end
38
+ alias_method :[], :call
39
+
40
+ private
41
+
42
+ def visit(node)
43
+ name, node = node
44
+ __send__("visit_#{name}", node)
45
+ end
46
+
47
+ def visit_relation(node)
48
+ rel_name, header, meta_options = node
49
+ name = meta_options[:combine_name] || meta_options[:alias] || rel_name
50
+ namespace = meta_options.fetch(:struct_namespace)
51
+
52
+ model = meta_options.fetch(:model) do
53
+ if meta_options[:combine_name]
54
+ false
55
+ else
56
+ struct_compiler[name, header, namespace]
57
+ end
58
+ end
59
+
60
+ options = [header.map(&method(:visit)), mapper_options.merge(model: model)]
61
+
62
+ if meta_options[:combine_type]
63
+ type = meta_options[:combine_type] == :many ? :array : :hash
64
+ keys = meta_options.fetch(:keys)
65
+
66
+ [name, combine: true, type: type, keys: keys, header: Header.coerce(*options)]
67
+ elsif meta_options[:wrap]
68
+ [name, wrap: true, type: :hash, header: Header.coerce(*options)]
69
+ else
70
+ options
71
+ end
72
+ end
73
+
74
+ def visit_attribute(node)
75
+ name, _, meta_options = node
76
+
77
+ if meta_options[:alias]
78
+ [meta_options[:alias], from: name]
79
+ else
80
+ [name]
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/struct'
2
4
  require 'rom/registry'
3
5
  require 'rom/mapper_compiler'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/memory/gateway'
2
4
  require 'rom/memory/relation'
3
5
  require 'rom/memory/mapper_compiler'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/memory/associations/many_to_many'
2
4
  require 'rom/memory/associations/many_to_one'
3
5
  require 'rom/memory/associations/one_to_many'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/associations/many_to_many'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/associations/many_to_one'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/associations/one_to_many'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/memory/associations/one_to_many'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/commands'
2
4
 
3
5
  module ROM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rom/array_dataset'
2
4
 
3
5
  module ROM