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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +603 -0
- data/LICENSE +20 -0
- data/README.md +18 -0
- data/lib/rom-core.rb +1 -0
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +16 -0
- data/lib/rom/associations/abstract.rb +135 -0
- data/lib/rom/associations/definitions.rb +5 -0
- data/lib/rom/associations/definitions/abstract.rb +116 -0
- data/lib/rom/associations/definitions/many_to_many.rb +24 -0
- data/lib/rom/associations/definitions/many_to_one.rb +11 -0
- data/lib/rom/associations/definitions/one_to_many.rb +11 -0
- data/lib/rom/associations/definitions/one_to_one.rb +11 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +11 -0
- data/lib/rom/associations/many_to_many.rb +81 -0
- data/lib/rom/associations/many_to_one.rb +37 -0
- data/lib/rom/associations/one_to_many.rb +37 -0
- data/lib/rom/associations/one_to_one.rb +8 -0
- data/lib/rom/associations/one_to_one_through.rb +8 -0
- data/lib/rom/associations/through_identifier.rb +39 -0
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/cache.rb +46 -0
- data/lib/rom/command.rb +488 -0
- data/lib/rom/command_compiler.rb +239 -0
- data/lib/rom/command_proxy.rb +24 -0
- data/lib/rom/command_registry.rb +141 -0
- data/lib/rom/commands.rb +3 -0
- data/lib/rom/commands/class_interface.rb +270 -0
- data/lib/rom/commands/composite.rb +53 -0
- data/lib/rom/commands/create.rb +13 -0
- data/lib/rom/commands/delete.rb +14 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/graph/class_interface.rb +62 -0
- data/lib/rom/commands/graph/input_evaluator.rb +62 -0
- data/lib/rom/commands/lazy.rb +99 -0
- data/lib/rom/commands/lazy/create.rb +23 -0
- data/lib/rom/commands/lazy/delete.rb +27 -0
- data/lib/rom/commands/lazy/update.rb +34 -0
- data/lib/rom/commands/result.rb +96 -0
- data/lib/rom/commands/update.rb +14 -0
- data/lib/rom/configuration.rb +114 -0
- data/lib/rom/configuration_dsl.rb +87 -0
- data/lib/rom/configuration_dsl/command.rb +41 -0
- data/lib/rom/configuration_dsl/command_dsl.rb +35 -0
- data/lib/rom/configuration_dsl/relation.rb +26 -0
- data/lib/rom/configuration_plugin.rb +17 -0
- data/lib/rom/constants.rb +64 -0
- data/lib/rom/container.rb +147 -0
- data/lib/rom/core.rb +46 -0
- data/lib/rom/create_container.rb +60 -0
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/environment.rb +70 -0
- data/lib/rom/gateway.rb +184 -0
- data/lib/rom/global.rb +58 -0
- data/lib/rom/global/plugin_dsl.rb +47 -0
- data/lib/rom/initializer.rb +64 -0
- data/lib/rom/lint/enumerable_dataset.rb +54 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +78 -0
- data/lib/rom/lint/spec.rb +20 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/mapper_registry.rb +24 -0
- data/lib/rom/memory.rb +4 -0
- data/lib/rom/memory/associations.rb +4 -0
- data/lib/rom/memory/associations/many_to_many.rb +10 -0
- data/lib/rom/memory/associations/many_to_one.rb +10 -0
- data/lib/rom/memory/associations/one_to_many.rb +10 -0
- data/lib/rom/memory/associations/one_to_one.rb +10 -0
- data/lib/rom/memory/commands.rb +56 -0
- data/lib/rom/memory/dataset.rb +97 -0
- data/lib/rom/memory/gateway.rb +64 -0
- data/lib/rom/memory/relation.rb +62 -0
- data/lib/rom/memory/schema.rb +23 -0
- data/lib/rom/memory/storage.rb +59 -0
- data/lib/rom/memory/types.rb +9 -0
- data/lib/rom/pipeline.rb +105 -0
- data/lib/rom/plugin.rb +25 -0
- data/lib/rom/plugin_base.rb +45 -0
- data/lib/rom/plugin_registry.rb +197 -0
- data/lib/rom/plugins/command/schema.rb +37 -0
- data/lib/rom/plugins/configuration/configuration_dsl.rb +21 -0
- data/lib/rom/plugins/relation/instrumentation.rb +51 -0
- data/lib/rom/plugins/relation/registry_reader.rb +44 -0
- data/lib/rom/plugins/schema/timestamps.rb +58 -0
- data/lib/rom/registry.rb +71 -0
- data/lib/rom/relation.rb +548 -0
- data/lib/rom/relation/class_interface.rb +282 -0
- data/lib/rom/relation/commands.rb +23 -0
- data/lib/rom/relation/composite.rb +46 -0
- data/lib/rom/relation/curried.rb +103 -0
- data/lib/rom/relation/graph.rb +197 -0
- data/lib/rom/relation/loaded.rb +127 -0
- data/lib/rom/relation/materializable.rb +66 -0
- data/lib/rom/relation/name.rb +111 -0
- data/lib/rom/relation/view_dsl.rb +64 -0
- data/lib/rom/relation/wrap.rb +83 -0
- data/lib/rom/relation_registry.rb +10 -0
- data/lib/rom/schema.rb +437 -0
- data/lib/rom/schema/associations_dsl.rb +195 -0
- data/lib/rom/schema/attribute.rb +419 -0
- data/lib/rom/schema/dsl.rb +164 -0
- data/lib/rom/schema/inferrer.rb +66 -0
- data/lib/rom/schema_plugin.rb +27 -0
- data/lib/rom/setup.rb +68 -0
- data/lib/rom/setup/auto_registration.rb +74 -0
- data/lib/rom/setup/auto_registration_strategies/base.rb +16 -0
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +63 -0
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +20 -0
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +18 -0
- data/lib/rom/setup/finalize.rb +103 -0
- data/lib/rom/setup/finalize/finalize_commands.rb +60 -0
- data/lib/rom/setup/finalize/finalize_mappers.rb +56 -0
- data/lib/rom/setup/finalize/finalize_relations.rb +135 -0
- data/lib/rom/support/configurable.rb +85 -0
- data/lib/rom/support/memoizable.rb +58 -0
- data/lib/rom/support/notifications.rb +103 -0
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +26 -0
- data/lib/rom/version.rb +5 -0
- metadata +289 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rom/pipeline'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Commands
|
5
|
+
# Composite command that consists of left and right commands
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
class Composite < Pipeline::Composite
|
9
|
+
# Calls the composite command
|
10
|
+
#
|
11
|
+
# Right command is called with a result from the left one
|
12
|
+
#
|
13
|
+
# @return [Object]
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
def call(*args)
|
17
|
+
response = left.call(*args)
|
18
|
+
|
19
|
+
if response.nil? || (many? && response.size == 0)
|
20
|
+
return one? ? nil : EMPTY_ARRAY
|
21
|
+
end
|
22
|
+
|
23
|
+
if one? && !graph?
|
24
|
+
if right.is_a?(Command) || right.is_a?(Commands::Composite)
|
25
|
+
right.call([response].first)
|
26
|
+
else
|
27
|
+
right.call([response]).first
|
28
|
+
end
|
29
|
+
elsif one? && graph?
|
30
|
+
right.call(response).first
|
31
|
+
else
|
32
|
+
right.call(response)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
alias_method :[], :call
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
def graph?
|
39
|
+
left.is_a?(Graph)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def result
|
44
|
+
left.result
|
45
|
+
end
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
def decorate?(response)
|
49
|
+
super || response.is_a?(Graph)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rom/initializer'
|
2
|
+
require 'rom/pipeline'
|
3
|
+
require 'rom/commands/graph/class_interface'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Commands
|
7
|
+
# Command graph
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Graph
|
11
|
+
extend Initializer
|
12
|
+
include Dry::Equalizer(:root, :nodes)
|
13
|
+
|
14
|
+
extend ClassInterface
|
15
|
+
|
16
|
+
include Pipeline
|
17
|
+
include Pipeline::Proxy
|
18
|
+
|
19
|
+
# @attr_reader [Command] root The root command
|
20
|
+
param :root
|
21
|
+
|
22
|
+
# @attr_reader [Array<Command>] nodes The child commands
|
23
|
+
param :nodes
|
24
|
+
|
25
|
+
alias_method :left, :root
|
26
|
+
alias_method :right, :nodes
|
27
|
+
|
28
|
+
# @attr_reader [Symbol] root's relation name
|
29
|
+
option :name, default: -> { root.name }
|
30
|
+
|
31
|
+
option :mappers, default: -> { MapperRegistry.new }
|
32
|
+
|
33
|
+
# Calls root and all nodes with the result from root
|
34
|
+
#
|
35
|
+
# Graph results are mappable through `combine` operation in mapper DSL
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# create_user = rom.commands[:users].create
|
39
|
+
# create_task = rom.commands[:tasks].create
|
40
|
+
#
|
41
|
+
# command = create_user
|
42
|
+
# .with(name: 'Jane')
|
43
|
+
# .combine(create_task.with(title: 'Task'))
|
44
|
+
#
|
45
|
+
# command.call
|
46
|
+
#
|
47
|
+
# @return [Array] nested array with command results
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def call(*args)
|
51
|
+
left = root.call(*args)
|
52
|
+
|
53
|
+
right = nodes.map { |node|
|
54
|
+
response =
|
55
|
+
if node.lazy?
|
56
|
+
node.call(args.first, left)
|
57
|
+
else
|
58
|
+
node.call(left)
|
59
|
+
end
|
60
|
+
|
61
|
+
if node.one? && !node.graph?
|
62
|
+
[response]
|
63
|
+
else
|
64
|
+
response
|
65
|
+
end
|
66
|
+
}
|
67
|
+
|
68
|
+
if one?
|
69
|
+
[[left], right]
|
70
|
+
else
|
71
|
+
[left, right]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def graph?
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# @api public
|
83
|
+
def composite_class
|
84
|
+
Command::Composite
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rom/commands/graph/input_evaluator'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Commands
|
5
|
+
class Graph
|
6
|
+
# Class methods for command Graph
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
module ClassInterface
|
10
|
+
# Build a command graph recursively
|
11
|
+
#
|
12
|
+
# This is used by `Container#command` when array with options is passed in
|
13
|
+
#
|
14
|
+
# @param [Registry] registry The command registry from container
|
15
|
+
# @param [Array] options The options array
|
16
|
+
# @param [Array] path The path for input evaluator proc
|
17
|
+
#
|
18
|
+
# @return [Graph]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
def build(registry, options, path = EMPTY_ARRAY)
|
22
|
+
options.reduce { |spec, other| build_command(registry, spec, other, path) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def build_command(registry, spec, other, path)
|
27
|
+
cmd_opts, nodes = other
|
28
|
+
|
29
|
+
key, relation =
|
30
|
+
if spec.is_a?(Hash)
|
31
|
+
spec.to_a.first
|
32
|
+
else
|
33
|
+
[spec, spec]
|
34
|
+
end
|
35
|
+
|
36
|
+
name, opts =
|
37
|
+
if cmd_opts.is_a?(Hash)
|
38
|
+
cmd_opts.to_a.first
|
39
|
+
else
|
40
|
+
[cmd_opts]
|
41
|
+
end
|
42
|
+
|
43
|
+
command = registry[relation][name]
|
44
|
+
tuple_path = Array[*path] << key
|
45
|
+
input_proc = InputEvaluator.build(tuple_path, nodes)
|
46
|
+
|
47
|
+
command = command.with(input_proc, opts)
|
48
|
+
|
49
|
+
if nodes
|
50
|
+
if nodes.all? { |node| node.is_a?(Array) }
|
51
|
+
command.combine(*nodes.map { |node| build(registry, node, tuple_path) })
|
52
|
+
else
|
53
|
+
command.combine(build(registry, nodes, tuple_path))
|
54
|
+
end
|
55
|
+
else
|
56
|
+
command
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ROM
|
2
|
+
module Commands
|
3
|
+
class Graph
|
4
|
+
class InputEvaluator
|
5
|
+
include Dry::Equalizer(:tuple_path, :excluded_keys)
|
6
|
+
|
7
|
+
attr_reader :tuple_path
|
8
|
+
|
9
|
+
attr_reader :excluded_keys
|
10
|
+
|
11
|
+
attr_reader :exclude_proc
|
12
|
+
|
13
|
+
def self.build(tuple_path, nodes)
|
14
|
+
new(tuple_path, extract_excluded_keys(nodes))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.extract_excluded_keys(nodes)
|
18
|
+
return unless nodes
|
19
|
+
|
20
|
+
nodes
|
21
|
+
.map { |item| item.is_a?(Array) && item.size > 1 ? item.first : item }
|
22
|
+
.compact
|
23
|
+
.map { |item| item.is_a?(Hash) ? item.keys.first : item }
|
24
|
+
.reject { |item| item.is_a?(Array) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.exclude_proc(excluded_keys)
|
28
|
+
-> input { input.reject { |k, _| excluded_keys.include?(k) } }
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(tuple_path, excluded_keys)
|
32
|
+
@tuple_path = tuple_path
|
33
|
+
@excluded_keys = excluded_keys
|
34
|
+
@exclude_proc = self.class.exclude_proc(excluded_keys)
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(*args)
|
38
|
+
input, index = args
|
39
|
+
|
40
|
+
value =
|
41
|
+
begin
|
42
|
+
if index
|
43
|
+
tuple_path[0..tuple_path.size-2]
|
44
|
+
.reduce(input) { |a, e| a.fetch(e) }
|
45
|
+
.at(index)[tuple_path.last]
|
46
|
+
else
|
47
|
+
tuple_path.reduce(input) { |a, e| a.fetch(e) }
|
48
|
+
end
|
49
|
+
rescue KeyError => e
|
50
|
+
raise KeyMissing, e.message
|
51
|
+
end
|
52
|
+
|
53
|
+
if excluded_keys
|
54
|
+
value.is_a?(Array) ? value.map(&exclude_proc) : exclude_proc[value]
|
55
|
+
else
|
56
|
+
value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rom/commands/composite'
|
2
|
+
require 'rom/commands/graph'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module Commands
|
6
|
+
# Lazy command wraps another command and evaluates its input when called
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Lazy
|
10
|
+
include Dry::Equalizer(:command, :evaluator)
|
11
|
+
|
12
|
+
# @attr_reader [Command] command The wrapped command
|
13
|
+
attr_reader :command
|
14
|
+
|
15
|
+
alias_method :unwrap, :command
|
16
|
+
|
17
|
+
# @attr_reader [Proc] evaluator The proc that will evaluate the input
|
18
|
+
attr_reader :evaluator
|
19
|
+
|
20
|
+
attr_reader :command_proc
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
def self.[](command)
|
24
|
+
case command
|
25
|
+
when Commands::Create then Lazy::Create
|
26
|
+
when Commands::Update then Lazy::Update
|
27
|
+
when Commands::Delete then Lazy::Delete
|
28
|
+
else
|
29
|
+
self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
def initialize(command, evaluator, command_proc = nil)
|
35
|
+
@command = command
|
36
|
+
@evaluator = evaluator
|
37
|
+
@command_proc = command_proc || proc { |*| command }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Evaluate command's input using the input proc and pass to command
|
41
|
+
#
|
42
|
+
# @return [Array,Hash]
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
def call(*args)
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
|
49
|
+
# Compose a lazy command with another one
|
50
|
+
#
|
51
|
+
# @see Commands::Abstract#>>
|
52
|
+
#
|
53
|
+
# @return [Composite]
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
def >>(other)
|
57
|
+
Composite.new(self, other)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @see Abstract#combine
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
def combine(*others)
|
64
|
+
Graph.new(self, others)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
def lazy?
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
def respond_to_missing?(name, include_private = false)
|
74
|
+
super || command.respond_to?(name)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# @api private
|
80
|
+
def method_missing(name, *args, &block)
|
81
|
+
if command.respond_to?(name)
|
82
|
+
response = command.public_send(name, *args, &block)
|
83
|
+
|
84
|
+
if response.instance_of?(command.class)
|
85
|
+
self.class.new(response, evaluator, command_proc)
|
86
|
+
else
|
87
|
+
response
|
88
|
+
end
|
89
|
+
else
|
90
|
+
super
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
require 'rom/commands/lazy/create'
|
98
|
+
require 'rom/commands/lazy/update'
|
99
|
+
require 'rom/commands/lazy/delete'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ROM
|
2
|
+
module Commands
|
3
|
+
class Lazy
|
4
|
+
class Create < Lazy
|
5
|
+
def call(*args)
|
6
|
+
first = args.first
|
7
|
+
last = args.last
|
8
|
+
size = args.size
|
9
|
+
|
10
|
+
if size > 1 && last.is_a?(Array)
|
11
|
+
last.map.with_index do |parent, index|
|
12
|
+
children = evaluator.call(first, index)
|
13
|
+
command_proc[command, parent, children].call(children, parent)
|
14
|
+
end.reduce(:concat)
|
15
|
+
else
|
16
|
+
input = evaluator.call(first)
|
17
|
+
command.call(input, *args[1..size-1])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ROM
|
2
|
+
module Commands
|
3
|
+
class Lazy
|
4
|
+
class Delete < Lazy
|
5
|
+
def call(*args)
|
6
|
+
first = args.first
|
7
|
+
last = args.last
|
8
|
+
size = args.size
|
9
|
+
|
10
|
+
if size > 1 && last.is_a?(Array)
|
11
|
+
raise NotImplementedError
|
12
|
+
else
|
13
|
+
input = evaluator.call(first)
|
14
|
+
|
15
|
+
if input.is_a?(Array)
|
16
|
+
input.map do |item|
|
17
|
+
command_proc[command, *(size > 1 ? [last, item] : [input])].call
|
18
|
+
end
|
19
|
+
else
|
20
|
+
command_proc[command, input].call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|