rom 2.0.2 → 3.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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -7
- data/.yardopts +2 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +17 -2
- data/Rakefile +7 -2
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +11 -5
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/command.rb +331 -47
- data/lib/rom/command_registry.rb +7 -18
- data/lib/rom/commands/class_interface.rb +120 -6
- data/lib/rom/commands/composite.rb +0 -1
- data/lib/rom/commands/graph.rb +7 -15
- data/lib/rom/commands/lazy/update.rb +1 -1
- data/lib/rom/configuration.rb +2 -0
- data/lib/rom/configuration_dsl/command.rb +6 -8
- data/lib/rom/configuration_dsl/mapper.rb +2 -3
- data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -1
- data/lib/rom/configuration_dsl/relation.rb +4 -4
- data/lib/rom/configuration_dsl.rb +0 -4
- data/lib/rom/constants.rb +7 -1
- data/lib/rom/container.rb +11 -17
- data/lib/rom/create_container.rb +0 -2
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/gateway.rb +74 -32
- data/lib/rom/global/plugin_dsl.rb +0 -2
- data/lib/rom/global.rb +0 -2
- data/lib/rom/initializer.rb +26 -0
- data/lib/rom/lint/gateway.rb +17 -0
- data/lib/rom/mapper_registry.rb +1 -1
- data/lib/rom/memory/commands.rb +0 -2
- data/lib/rom/memory/dataset.rb +1 -2
- data/lib/rom/memory/relation.rb +14 -1
- data/lib/rom/memory/schema.rb +13 -0
- data/lib/rom/plugin_registry.rb +1 -1
- data/lib/rom/plugins/command/schema.rb +2 -2
- data/lib/rom/plugins/configuration/configuration_dsl.rb +6 -2
- data/lib/rom/plugins/relation/key_inference.rb +4 -2
- data/lib/rom/plugins/relation/registry_reader.rb +5 -1
- data/lib/rom/registry.rb +50 -0
- data/lib/rom/relation/class_interface.rb +142 -30
- data/lib/rom/relation/curried.rb +15 -15
- data/lib/rom/relation/view_dsl.rb +31 -0
- data/lib/rom/relation.rb +101 -41
- data/lib/rom/schema/attribute.rb +367 -0
- data/lib/rom/schema/dsl.rb +14 -10
- data/lib/rom/schema.rb +337 -19
- data/lib/rom/setup/auto_registration.rb +20 -17
- data/lib/rom/setup/auto_registration_strategies/base.rb +8 -3
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +4 -3
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +5 -4
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +3 -3
- data/lib/rom/setup/finalize/finalize_commands.rb +1 -1
- data/lib/rom/setup/finalize/finalize_mappers.rb +1 -1
- data/lib/rom/setup/finalize/finalize_relations.rb +4 -2
- data/lib/rom/setup/finalize.rb +1 -1
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +9 -1
- data/lib/rom/version.rb +1 -1
- data/lib/rom.rb +4 -8
- data/rom.gemspec +5 -4
- data/spec/integration/command_registry_spec.rb +1 -14
- data/spec/integration/commands/create_spec.rb +5 -25
- data/spec/integration/commands/delete_spec.rb +1 -1
- data/spec/integration/commands/error_handling_spec.rb +1 -1
- data/spec/integration/commands/graph_spec.rb +20 -14
- data/spec/integration/commands/update_spec.rb +4 -27
- data/spec/integration/commands_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/extending_relations_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/setting_logger_spec.rb +2 -2
- data/spec/integration/mappers/combine_spec.rb +1 -1
- data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
- data/spec/integration/mappers/definition_dsl_spec.rb +1 -1
- data/spec/integration/mappers/embedded_spec.rb +1 -1
- data/spec/integration/mappers/exclude_spec.rb +1 -1
- data/spec/integration/mappers/fold_spec.rb +1 -1
- data/spec/integration/mappers/group_spec.rb +1 -1
- data/spec/integration/mappers/overwrite_attributes_value_spec.rb +1 -1
- data/spec/integration/mappers/prefix_separator_spec.rb +1 -1
- data/spec/integration/mappers/prefix_spec.rb +1 -1
- data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/registering_custom_mappers_spec.rb +1 -1
- data/spec/integration/mappers/renaming_attributes_spec.rb +1 -1
- data/spec/integration/mappers/reusing_mappers_spec.rb +1 -1
- data/spec/integration/mappers/step_spec.rb +1 -1
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/unfold_spec.rb +1 -1
- data/spec/integration/mappers/ungroup_spec.rb +2 -2
- data/spec/integration/mappers/unwrap_spec.rb +2 -2
- data/spec/integration/mappers/wrap_spec.rb +1 -1
- data/spec/integration/memory/commands/create_spec.rb +1 -1
- data/spec/integration/memory/commands/delete_spec.rb +1 -1
- data/spec/integration/memory/commands/update_spec.rb +1 -1
- data/spec/integration/multi_env_spec.rb +1 -1
- data/spec/integration/multi_repo_spec.rb +1 -1
- data/spec/integration/relations/default_dataset_spec.rb +1 -1
- data/spec/integration/relations/reading_spec.rb +1 -1
- data/spec/integration/relations/registry_dsl_spec.rb +1 -1
- data/spec/integration/setup_spec.rb +10 -4
- data/spec/shared/command_graph.rb +8 -4
- data/spec/shared/enumerable_dataset.rb +1 -1
- data/spec/spec_helper.rb +7 -9
- data/spec/support/schema.rb +14 -0
- data/spec/unit/rom/array_dataset_spec.rb +59 -0
- data/spec/unit/rom/association_set_spec.rb +4 -0
- data/spec/unit/rom/auto_curry_spec.rb +63 -0
- data/spec/unit/rom/commands/graph_spec.rb +12 -11
- data/spec/unit/rom/commands/lazy_spec.rb +8 -5
- data/spec/unit/rom/commands/pre_and_post_processors_spec.rb +336 -0
- data/spec/unit/rom/commands/result_spec.rb +1 -1
- data/spec/unit/rom/commands_spec.rb +26 -3
- data/spec/unit/rom/configuration_spec.rb +1 -1
- data/spec/unit/rom/container_spec.rb +15 -5
- data/spec/unit/rom/create_container_spec.rb +1 -1
- data/spec/unit/rom/enumerable_dataset_spec.rb +15 -0
- data/spec/unit/rom/gateway_spec.rb +1 -1
- data/spec/unit/rom/mapper_registry_spec.rb +1 -1
- data/spec/unit/rom/memory/commands_spec.rb +1 -1
- data/spec/unit/rom/memory/dataset_spec.rb +1 -1
- data/spec/unit/rom/memory/{repository_spec.rb → gateway_spec.rb} +1 -1
- data/spec/unit/rom/memory/inheritance_spec.rb +32 -0
- data/spec/unit/rom/memory/relation_spec.rb +15 -3
- data/spec/unit/rom/memory/storage_spec.rb +1 -1
- data/spec/unit/rom/plugin_spec.rb +1 -1
- data/spec/unit/rom/plugins/command/schema_spec.rb +5 -5
- data/spec/unit/rom/plugins/relation/key_inference_spec.rb +1 -1
- data/spec/unit/rom/registry_spec.rb +86 -0
- data/spec/unit/rom/relation/attribute_reader_spec.rb +17 -0
- data/spec/unit/rom/relation/call_spec.rb +51 -0
- data/spec/unit/rom/relation/composite_spec.rb +1 -1
- data/spec/unit/rom/relation/graph_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy/combine_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy_spec.rb +1 -1
- data/spec/unit/rom/relation/loaded_spec.rb +1 -1
- data/spec/unit/rom/relation/schema_spec.rb +50 -6
- data/spec/unit/rom/relation/view_spec.rb +122 -0
- data/spec/unit/rom/relation_spec.rb +20 -5
- data/spec/unit/rom/schema/accessing_attributes_spec.rb +52 -0
- data/spec/unit/rom/schema/append_spec.rb +17 -0
- data/spec/unit/rom/schema/exclude_spec.rb +15 -0
- data/spec/unit/rom/schema/finalize_spec.rb +59 -0
- data/spec/unit/rom/schema/key_predicate_spec.rb +15 -0
- data/spec/unit/rom/schema/merge_spec.rb +17 -0
- data/spec/unit/rom/schema/prefix_spec.rb +16 -0
- data/spec/unit/rom/schema/project_spec.rb +15 -0
- data/spec/unit/rom/schema/rename_spec.rb +22 -0
- data/spec/unit/rom/schema/type_spec.rb +49 -0
- data/spec/unit/rom/schema/uniq_spec.rb +21 -0
- data/spec/unit/rom/schema/wrap_spec.rb +17 -0
- data/spec/unit/rom/schema_spec.rb +2 -2
- metadata +79 -17
- data/lib/rom/plugins/relation/view/dsl.rb +0 -32
- data/lib/rom/plugins/relation/view.rb +0 -95
- data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
data/lib/rom/commands/graph.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
+
require 'rom/initializer'
|
1
2
|
require 'rom/pipeline'
|
2
|
-
require 'rom/support/options'
|
3
3
|
require 'rom/commands/graph/class_interface'
|
4
4
|
|
5
5
|
module ROM
|
@@ -8,35 +8,27 @@ module ROM
|
|
8
8
|
#
|
9
9
|
# @api private
|
10
10
|
class Graph
|
11
|
+
extend Initializer
|
11
12
|
include Dry::Equalizer(:root, :nodes)
|
12
13
|
|
13
14
|
extend ClassInterface
|
14
15
|
|
15
|
-
include Options
|
16
16
|
include Pipeline
|
17
17
|
include Pipeline::Proxy
|
18
18
|
|
19
19
|
# @attr_reader [Command] root The root command
|
20
|
-
|
20
|
+
param :root
|
21
21
|
|
22
22
|
# @attr_reader [Array<Command>] nodes The child commands
|
23
|
-
|
24
|
-
|
25
|
-
# @attr_reader [Symbol] root's relation name
|
26
|
-
attr_reader :name
|
23
|
+
param :nodes
|
27
24
|
|
28
25
|
alias_method :left, :root
|
29
26
|
alias_method :right, :nodes
|
30
27
|
|
31
|
-
|
28
|
+
# @attr_reader [Symbol] root's relation name
|
29
|
+
option :name, reader: true, default: -> g { g.root.name }
|
32
30
|
|
33
|
-
|
34
|
-
def initialize(root, nodes, options = EMPTY_HASH)
|
35
|
-
super
|
36
|
-
@root = root
|
37
|
-
@nodes = nodes
|
38
|
-
@name = root.name
|
39
|
-
end
|
31
|
+
option :mappers, reader: true, default: proc { MapperRegistry.new }
|
40
32
|
|
41
33
|
# Calls root and all nodes with the result from root
|
42
34
|
#
|
@@ -20,7 +20,7 @@ module ROM
|
|
20
20
|
|
21
21
|
if input.is_a?(Array)
|
22
22
|
input.map.with_index do |item, index|
|
23
|
-
command_proc[command, last, item].call(item,
|
23
|
+
command_proc[command, last, item].call(item, *args[1..size-1])
|
24
24
|
end
|
25
25
|
else
|
26
26
|
command_proc[command, *(size > 1 ? [last, input] : [input])]
|
data/lib/rom/configuration.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require 'rom/support/inflector'
|
4
|
-
require 'rom/support/class_builder'
|
1
|
+
require 'dry/core/inflector'
|
2
|
+
require 'dry/core/class_builder'
|
5
3
|
|
6
4
|
module ROM
|
7
5
|
module ConfigurationDSL
|
@@ -16,12 +14,12 @@ module ROM
|
|
16
14
|
# @api private
|
17
15
|
def self.build_class(name, relation, options = EMPTY_HASH, &block)
|
18
16
|
type = options.fetch(:type) { name }
|
19
|
-
command_type = Inflector.classify(type)
|
17
|
+
command_type = Dry::Core::Inflector.classify(type)
|
20
18
|
adapter = options.fetch(:adapter)
|
21
19
|
parent = ROM::Command.adapter_namespace(adapter).const_get(command_type)
|
22
20
|
class_name = generate_class_name(adapter, command_type, relation)
|
23
21
|
|
24
|
-
ClassBuilder.new(name: class_name, parent: parent).call do |klass|
|
22
|
+
Dry::Core::ClassBuilder.new(name: class_name, parent: parent).call do |klass|
|
25
23
|
klass.register_as(name)
|
26
24
|
klass.relation(relation)
|
27
25
|
klass.class_eval(&block) if block
|
@@ -33,9 +31,9 @@ module ROM
|
|
33
31
|
# @api private
|
34
32
|
def self.generate_class_name(adapter, command_type, relation)
|
35
33
|
pieces = ['ROM']
|
36
|
-
pieces << Inflector.classify(adapter)
|
34
|
+
pieces << Dry::Core::Inflector.classify(adapter)
|
37
35
|
pieces << 'Commands'
|
38
|
-
pieces << "#{command_type}[#{Inflector.classify(relation)}s]"
|
36
|
+
pieces << "#{command_type}[#{Dry::Core::Inflector.classify(relation)}s]"
|
39
37
|
pieces.join('::')
|
40
38
|
end
|
41
39
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'rom/support/class_builder'
|
1
|
+
require 'dry/core/class_builder'
|
3
2
|
|
4
3
|
module ROM
|
5
4
|
module ConfigurationDSL
|
@@ -25,7 +24,7 @@ module ROM
|
|
25
24
|
ROM::Mapper
|
26
25
|
end
|
27
26
|
|
28
|
-
ClassBuilder.new(name: class_name, parent: parent_class).call do |klass|
|
27
|
+
Dry::Core::ClassBuilder.new(name: class_name, parent: parent_class).call do |klass|
|
29
28
|
klass.relation(name)
|
30
29
|
klass.inherit_header(inherit_header)
|
31
30
|
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'dry/core/class_builder'
|
2
|
+
require 'dry/core/inflector'
|
3
3
|
|
4
4
|
module ROM
|
5
5
|
module ConfigurationDSL
|
@@ -13,10 +13,10 @@ module ROM
|
|
13
13
|
#
|
14
14
|
# @api private
|
15
15
|
def self.build_class(name, options = EMPTY_HASH)
|
16
|
-
class_name = "ROM::Relation[#{Inflector.camelize(name)}]"
|
16
|
+
class_name = "ROM::Relation[#{Dry::Core::Inflector.camelize(name)}]"
|
17
17
|
adapter = options.fetch(:adapter)
|
18
18
|
|
19
|
-
ClassBuilder.new(name: class_name, parent: ROM::Relation[adapter]).call do |klass|
|
19
|
+
Dry::Core::ClassBuilder.new(name: class_name, parent: ROM::Relation[adapter]).call do |klass|
|
20
20
|
klass.gateway(options.fetch(:gateway, :default))
|
21
21
|
klass.dataset(name)
|
22
22
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'rom/support/constants'
|
2
|
-
|
3
1
|
require 'rom/configuration_dsl/relation'
|
4
2
|
require 'rom/configuration_dsl/mapper_dsl'
|
5
3
|
require 'rom/configuration_dsl/command_dsl'
|
@@ -55,13 +53,11 @@ module ROM
|
|
55
53
|
# setup.commands(:users) do
|
56
54
|
# define(:create) do
|
57
55
|
# input NewUserParams
|
58
|
-
# validator NewUserValidator
|
59
56
|
# result :one
|
60
57
|
# end
|
61
58
|
#
|
62
59
|
# define(:update) do
|
63
60
|
# input UserParams
|
64
|
-
# validator UserValidator
|
65
61
|
# result :many
|
66
62
|
# end
|
67
63
|
#
|
data/lib/rom/constants.rb
CHANGED
@@ -22,8 +22,14 @@ module ROM
|
|
22
22
|
UnsupportedRelationError = Class.new(StandardError)
|
23
23
|
MissingAdapterIdentifierError = Class.new(StandardError)
|
24
24
|
|
25
|
+
MissingSchemaClassError = Class.new(StandardError) do
|
26
|
+
def initialize(klass)
|
27
|
+
super("#{klass.inspect} relation is missing schema_class")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
25
31
|
DuplicateConfigurationError = Class.new(StandardError)
|
26
|
-
DuplicateContainerError = Class.new(StandardError)
|
32
|
+
DuplicateContainerError = Class.new(StandardError)
|
27
33
|
|
28
34
|
InvalidOptionValueError = Class.new(StandardError)
|
29
35
|
InvalidOptionKeyError = Class.new(StandardError)
|
data/lib/rom/container.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'rom/relation/loaded'
|
2
2
|
require 'rom/commands/graph'
|
3
3
|
require 'rom/commands/graph/builder'
|
4
|
-
require 'rom/support/publisher'
|
5
4
|
|
6
5
|
module ROM
|
7
6
|
# ROM container is an isolated environment with no global state where all
|
@@ -12,14 +11,14 @@ module ROM
|
|
12
11
|
#
|
13
12
|
# There are 3 types of container setup:
|
14
13
|
#
|
15
|
-
# *
|
14
|
+
# * Setup DSL - a simple block-based configuration which allows configuring
|
16
15
|
# all components and gives you back a container instance. This type is suitable
|
17
16
|
# for small scripts, or in some cases rake tasks
|
18
|
-
# *
|
17
|
+
# * Explicit setup - this type requires creating a configuration object,
|
19
18
|
# registering component classes (ie relation classes) and passing the config
|
20
19
|
# to container builder function. This type is suitable when your environment
|
21
20
|
# is not typical and you need full control over component registration
|
22
|
-
# *
|
21
|
+
# * Explicit setup with auto-registration - same as explicit setup but allows
|
23
22
|
# you to configure auto-registration mechanism which will register component
|
24
23
|
# classes for you, based on dir/file naming conventions. This is the most
|
25
24
|
# common type of setup that's used by framework integrations
|
@@ -98,27 +97,22 @@ module ROM
|
|
98
97
|
#
|
99
98
|
# @api public
|
100
99
|
class Container
|
101
|
-
include ROM::Support::Publisher
|
102
100
|
include Dry::Equalizer(:gateways, :relations, :mappers, :commands)
|
103
101
|
|
104
|
-
#
|
105
|
-
#
|
106
|
-
# @api public
|
102
|
+
# @!attribute [r] gateways
|
103
|
+
# @return [Hash] A hash with configured gateways
|
107
104
|
attr_reader :gateways
|
108
105
|
|
109
|
-
#
|
110
|
-
#
|
111
|
-
# @api public
|
106
|
+
# @!attribute [r] relations
|
107
|
+
# @return [RelationRegistry] The relation registry
|
112
108
|
attr_reader :relations
|
113
109
|
|
114
|
-
#
|
115
|
-
#
|
116
|
-
# @api public
|
110
|
+
# @!attribute [r] gateways
|
111
|
+
# @return [CommandRegistry] The command registry
|
117
112
|
attr_reader :commands
|
118
113
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
# @api public
|
114
|
+
# @!attribute [r] mappers
|
115
|
+
# @return [Hash] A hash with configured custom mappers
|
122
116
|
attr_reader :mappers
|
123
117
|
|
124
118
|
# @api private
|
data/lib/rom/create_container.rb
CHANGED
@@ -0,0 +1,94 @@
|
|
1
|
+
module ROM
|
2
|
+
# Helper module for dataset classes
|
3
|
+
#
|
4
|
+
# It provides a constructor accepting data, header and an optional row_proc.
|
5
|
+
# This module is used internally by EnumerableDataset and ArrayDataset.
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
module DataProxy
|
9
|
+
NON_FORWARDABLE = [
|
10
|
+
:each, :to_a, :to_ary, :kind_of?, :instance_of?, :is_a?
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
# Wrapped data array
|
14
|
+
#
|
15
|
+
# @return [Object] Data object for the iterator
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
attr_reader :data
|
19
|
+
|
20
|
+
# @return [Proc] tuple processing proc
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
attr_reader :row_proc
|
24
|
+
|
25
|
+
# Extends the class with `forward` DSL and Equalizer using `data` attribute
|
26
|
+
#
|
27
|
+
# @see ClassMethods#forward
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def self.included(klass)
|
31
|
+
klass.class_eval do
|
32
|
+
extend ClassMethods
|
33
|
+
|
34
|
+
include Dry::Equalizer(:data)
|
35
|
+
|
36
|
+
option :row_proc, reader: true, default: proc { |obj| obj.class.row_proc }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Iterate over data using row_proc
|
41
|
+
#
|
42
|
+
# @return [Enumerator] if block is not given
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
def each
|
46
|
+
return to_enum unless block_given?
|
47
|
+
data.each { |tuple| yield(row_proc[tuple]) }
|
48
|
+
end
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
# Default no-op tuple proc
|
52
|
+
#
|
53
|
+
# @return [Proc]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
def row_proc
|
57
|
+
-> tuple { tuple }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Forward provided methods to the underlaying data object
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
#
|
64
|
+
# class MyDataset
|
65
|
+
# include DataProxy
|
66
|
+
#
|
67
|
+
# forward(:find_all, :map)
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @return [undefined]
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def forward(*methods)
|
74
|
+
# FIXME: we should probably raise if one of the non-forwardable methods
|
75
|
+
# was provided
|
76
|
+
(methods - NON_FORWARDABLE).each do |method_name|
|
77
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
78
|
+
def #{method_name}(*args, &block)
|
79
|
+
response = data.public_send(#{method_name.inspect}, *args, &block)
|
80
|
+
|
81
|
+
if response.equal?(data)
|
82
|
+
self
|
83
|
+
elsif response.is_a?(data.class)
|
84
|
+
self.class.new(response)
|
85
|
+
else
|
86
|
+
response
|
87
|
+
end
|
88
|
+
end
|
89
|
+
RUBY
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rom/initializer'
|
2
|
+
require 'rom/data_proxy'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
# A helper module that adds data-proxy behavior to an enumerable object
|
6
|
+
#
|
7
|
+
# This module is intended to be used by gateways
|
8
|
+
#
|
9
|
+
# Class that includes this module can define `row_proc` class method which
|
10
|
+
# must return a proc-like object which will be used to process each element
|
11
|
+
# in the enumerable
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# class MyDataset
|
15
|
+
# include ROM::EnumerableDataset
|
16
|
+
#
|
17
|
+
# def self.row_proc
|
18
|
+
# -> tuple { tuple.each_with_object({}) { |(k,v), h| h[k.to_sym] = v } }
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# ds = MyDataset.new([{ 'name' => 'Jane' }, [:name])
|
23
|
+
# ds.to_a # => { :name => 'Jane' }
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
module EnumerableDataset
|
27
|
+
extend DataProxy::ClassMethods
|
28
|
+
include Enumerable
|
29
|
+
|
30
|
+
# Coerce a dataset to an array
|
31
|
+
#
|
32
|
+
# @return [Array]
|
33
|
+
#
|
34
|
+
# @api public
|
35
|
+
alias_method :to_ary, :to_a
|
36
|
+
|
37
|
+
# Included hook which extends a class with DataProxy behavior
|
38
|
+
#
|
39
|
+
# This module can also be included into other modules so we apply the
|
40
|
+
# extension only for classes
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
def self.included(klass)
|
44
|
+
return unless klass.is_a?(Class)
|
45
|
+
|
46
|
+
klass.class_eval do
|
47
|
+
extend Initializer
|
48
|
+
include DataProxy
|
49
|
+
|
50
|
+
param :data
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
forward :take
|
55
|
+
|
56
|
+
[
|
57
|
+
:chunk, :collect, :collect_concat, :drop_while, :find_all, :flat_map,
|
58
|
+
:grep, :map, :reject, :select, :sort, :sort_by, :take_while
|
59
|
+
].each do |method|
|
60
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
61
|
+
def #{method}(*args, &block)
|
62
|
+
return to_enum unless block
|
63
|
+
self.class.new(super(*args, &block), options)
|
64
|
+
end
|
65
|
+
RUBY
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/rom/gateway.rb
CHANGED
@@ -1,49 +1,65 @@
|
|
1
|
+
require 'dry/core/class_attributes'
|
2
|
+
|
3
|
+
require 'rom/transaction'
|
4
|
+
|
1
5
|
module ROM
|
2
6
|
# Abstract gateway class
|
3
7
|
#
|
8
|
+
# Every adapter needs to inherit from this class and implement
|
9
|
+
# required interface
|
10
|
+
#
|
11
|
+
# @abstract
|
12
|
+
#
|
4
13
|
# @api public
|
5
14
|
class Gateway
|
6
|
-
extend
|
15
|
+
extend Dry::Core::ClassAttributes
|
7
16
|
|
8
17
|
defines :adapter
|
9
18
|
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# @return [Object] type varies depending on the gateway
|
13
|
-
#
|
14
|
-
# @api public
|
19
|
+
# @!attribute [r] connection
|
20
|
+
# @return [Object] The gateway's connection object (type varies across adapters)
|
15
21
|
attr_reader :connection
|
16
22
|
|
17
|
-
#
|
23
|
+
# Set up a gateway
|
18
24
|
#
|
19
25
|
# @overload setup(type, *args)
|
20
26
|
# Sets up a single-gateway given a gateway type.
|
21
27
|
# For custom gateways, create an instance and pass it directly.
|
22
28
|
#
|
23
|
-
# @
|
24
|
-
#
|
29
|
+
# @example
|
30
|
+
# module SuperDB
|
31
|
+
# class Gateway < ROM::Gateway
|
32
|
+
# def initialize(options)
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
# end
|
25
36
|
#
|
26
|
-
#
|
27
|
-
# @param [Gateway] gateway
|
37
|
+
# ROM.register_adapter(:super_db, SuperDB)
|
28
38
|
#
|
29
|
-
#
|
39
|
+
# Gateway.setup(:super_db, some: 'options')
|
40
|
+
# # SuperDB::Gateway.new(some: 'options') is called
|
41
|
+
#
|
42
|
+
# @param [Symbol] type Registered gateway identifier
|
43
|
+
# @param [Array] args Additional gateway options
|
30
44
|
#
|
31
|
-
# @
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
45
|
+
# @overload setup(gateway)
|
46
|
+
# Set up a gateway instance
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# module SuperDB
|
50
|
+
# class Gateway < ROM::Gateway
|
51
|
+
# def initialize(options)
|
52
|
+
# end
|
35
53
|
# end
|
36
54
|
# end
|
37
|
-
# end
|
38
55
|
#
|
39
|
-
#
|
56
|
+
# ROM.register_adapter(:super_db, SuperDB)
|
40
57
|
#
|
41
|
-
#
|
42
|
-
#
|
58
|
+
# Gateway.setup(SuperDB::Gateway.new(some: 'options'))
|
59
|
+
#
|
60
|
+
# @param [Gateway] gateway
|
43
61
|
#
|
44
|
-
#
|
45
|
-
# super_db = Gateway.setup(SuperDB::Gateway.new(some: 'options'))
|
46
|
-
# Gateway.setup(super_db)
|
62
|
+
# @return [Gateway] a specific gateway subclass
|
47
63
|
#
|
48
64
|
# @api public
|
49
65
|
def self.setup(gateway_or_scheme, *args)
|
@@ -72,7 +88,7 @@ module ROM
|
|
72
88
|
|
73
89
|
# Get gateway subclass for a specific adapter
|
74
90
|
#
|
75
|
-
# @param [Symbol] type
|
91
|
+
# @param [Symbol] type Adapter identifier
|
76
92
|
#
|
77
93
|
# @return [Class]
|
78
94
|
#
|
@@ -88,11 +104,7 @@ module ROM
|
|
88
104
|
ROM.adapters.fetch(type)
|
89
105
|
}
|
90
106
|
|
91
|
-
|
92
|
-
adapter.const_get(:Gateway)
|
93
|
-
else
|
94
|
-
adapter.const_get(:Repository)
|
95
|
-
end
|
107
|
+
adapter.const_get(:Gateway)
|
96
108
|
end
|
97
109
|
|
98
110
|
# Returns the adapter, defined for the class
|
@@ -109,6 +121,10 @@ module ROM
|
|
109
121
|
|
110
122
|
# A generic interface for setting up a logger
|
111
123
|
#
|
124
|
+
# This is not a required interface, it's a no-op by default
|
125
|
+
#
|
126
|
+
# @abstract
|
127
|
+
#
|
112
128
|
# @api public
|
113
129
|
def use_logger(*)
|
114
130
|
# noop
|
@@ -116,6 +132,11 @@ module ROM
|
|
116
132
|
|
117
133
|
# A generic interface for returning default logger
|
118
134
|
#
|
135
|
+
# Adapters should implement this method as handling loggers is different
|
136
|
+
# across adapters. This is a no-op by default and returns nil.
|
137
|
+
#
|
138
|
+
# @return [NilClass]
|
139
|
+
#
|
119
140
|
# @api public
|
120
141
|
def logger
|
121
142
|
# noop
|
@@ -123,8 +144,10 @@ module ROM
|
|
123
144
|
|
124
145
|
# Extension hook for adding gateway-specific behavior to a command class
|
125
146
|
#
|
126
|
-
#
|
127
|
-
#
|
147
|
+
# This simply returns back the class by default
|
148
|
+
#
|
149
|
+
# @param [Class] klass The command class
|
150
|
+
# @param [Object] _dataset The dataset that will be used with this command class
|
128
151
|
#
|
129
152
|
# @return [Class]
|
130
153
|
#
|
@@ -137,7 +160,7 @@ module ROM
|
|
137
160
|
#
|
138
161
|
# Every gateway that supports schema inference should implement this method
|
139
162
|
#
|
140
|
-
# @return [Array] array with
|
163
|
+
# @return [Array] An array with dataset names
|
141
164
|
#
|
142
165
|
# @api private
|
143
166
|
def schema
|
@@ -150,5 +173,24 @@ module ROM
|
|
150
173
|
def disconnect
|
151
174
|
# noop
|
152
175
|
end
|
176
|
+
|
177
|
+
# Runs a block inside a transaction. The underlying transaction engine
|
178
|
+
# is adapter-specific
|
179
|
+
#
|
180
|
+
# @param [Hash] Transaction options
|
181
|
+
# @return The result of yielding the block or +nil+ if
|
182
|
+
# the transaction was rolled back
|
183
|
+
#
|
184
|
+
# @api public
|
185
|
+
def transaction(opts = EMPTY_HASH, &block)
|
186
|
+
transaction_runner(opts).run(opts, &block)
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
# @api private
|
192
|
+
def transaction_runner(_)
|
193
|
+
Transaction::NoOp
|
194
|
+
end
|
153
195
|
end
|
154
196
|
end
|
data/lib/rom/global.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'dry-initializer'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
|
5
|
+
# @api private
|
6
|
+
module Initializer
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
def self.extended(base)
|
10
|
+
base.extend(Dry::Initializer::Mixin)
|
11
|
+
base.include(InstanceMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
module InstanceMethods
|
16
|
+
# Instance options
|
17
|
+
#
|
18
|
+
# @return [Hash]
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
def options
|
22
|
+
@__options__
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rom/lint/gateway.rb
CHANGED
@@ -69,6 +69,23 @@ module ROM
|
|
69
69
|
complain "#{gateway_instance} must respond to dataset?"
|
70
70
|
end
|
71
71
|
|
72
|
+
# Lint: Ensure +gateway_instance+ supports +transaction+ interface
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
def lint_transaction_support
|
76
|
+
result = gateway_instance.transaction { 1 }
|
77
|
+
|
78
|
+
if result != 1
|
79
|
+
complain "#{gateway_instance} must return the result of a transaction block"
|
80
|
+
end
|
81
|
+
|
82
|
+
gateway_instance.transaction do |t|
|
83
|
+
t.rollback!
|
84
|
+
|
85
|
+
complain "#{gateway_instance} must interrupt a transaction on rollback"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
72
89
|
private
|
73
90
|
|
74
91
|
# Setup gateway instance
|
data/lib/rom/mapper_registry.rb
CHANGED
data/lib/rom/memory/commands.rb
CHANGED
@@ -17,7 +17,6 @@ module ROM
|
|
17
17
|
def execute(tuples)
|
18
18
|
Array([tuples]).flatten.map { |tuple|
|
19
19
|
attributes = input[tuple]
|
20
|
-
validator.call(attributes)
|
21
20
|
relation.insert(attributes.to_h)
|
22
21
|
attributes
|
23
22
|
}.to_a
|
@@ -34,7 +33,6 @@ module ROM
|
|
34
33
|
# @see ROM::Commands::Update#execute
|
35
34
|
def execute(params)
|
36
35
|
attributes = input[params]
|
37
|
-
validator.call(attributes)
|
38
36
|
relation.map { |tuple| tuple.update(attributes.to_h) }
|
39
37
|
end
|
40
38
|
end
|