rom-core 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|