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,120 @@
|
|
1
|
+
require 'rom/lint/linter'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Lint
|
5
|
+
# Ensures that a [ROM::Gateway] extension provides datasets through the
|
6
|
+
# expected methods
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
class Gateway < ROM::Lint::Linter
|
10
|
+
# The gateway identifier e.g. +:memory+
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
attr_reader :identifier
|
14
|
+
|
15
|
+
# The gateway class
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
attr_reader :gateway
|
19
|
+
|
20
|
+
# The optional URI
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
attr_reader :uri
|
24
|
+
|
25
|
+
# Gateway instance used in lint tests
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
attr_reader :gateway_instance
|
29
|
+
|
30
|
+
# Create a gateway linter
|
31
|
+
#
|
32
|
+
# @param [Symbol] identifier
|
33
|
+
# @param [Class] gateway
|
34
|
+
# @param [String] uri optional
|
35
|
+
def initialize(identifier, gateway, uri = nil)
|
36
|
+
@identifier = identifier
|
37
|
+
@gateway = gateway
|
38
|
+
@uri = uri
|
39
|
+
@gateway_instance = setup_gateway_instance
|
40
|
+
end
|
41
|
+
|
42
|
+
# Lint: Ensure that +gateway+ setups up its instance
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
def lint_gateway_setup
|
46
|
+
return if gateway_instance.instance_of? gateway
|
47
|
+
|
48
|
+
complain <<-STRING
|
49
|
+
#{gateway}.setup must return a gateway instance but
|
50
|
+
returned #{gateway_instance.inspect}
|
51
|
+
STRING
|
52
|
+
end
|
53
|
+
|
54
|
+
# Lint: Ensure that +gateway_instance+ responds to +[]+
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def lint_dataset_reader
|
58
|
+
return if gateway_instance.respond_to? :[]
|
59
|
+
|
60
|
+
complain "#{gateway_instance} must respond to []"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Lint: Ensure that +gateway_instance+ responds to +dataset?+
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def lint_dataset_predicate
|
67
|
+
return if gateway_instance.respond_to? :dataset?
|
68
|
+
|
69
|
+
complain "#{gateway_instance} must respond to dataset?"
|
70
|
+
end
|
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
|
+
|
89
|
+
# Lint: Ensure +gateway_instance+ returns adapter name
|
90
|
+
def lint_adapter_reader
|
91
|
+
if gateway_instance.adapter != identifier
|
92
|
+
complain "#{gateway_instance} must have the adapter identifier set to #{identifier.inspect}"
|
93
|
+
end
|
94
|
+
rescue MissingAdapterIdentifierError
|
95
|
+
complain "#{gateway_instance} is missing the adapter identifier"
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Setup gateway instance
|
101
|
+
#
|
102
|
+
# @api private
|
103
|
+
def setup_gateway_instance
|
104
|
+
if uri
|
105
|
+
ROM::Gateway.setup(identifier, uri)
|
106
|
+
else
|
107
|
+
ROM::Gateway.setup(identifier)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Run Gateway#disconnect
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
def after_lint
|
115
|
+
super
|
116
|
+
gateway_instance.disconnect
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module ROM
|
2
|
+
module Lint
|
3
|
+
# Base class for building linters that check source code
|
4
|
+
#
|
5
|
+
# Linters are used by authors of ROM adapters to verify that their
|
6
|
+
# integration complies with the ROM api.
|
7
|
+
#
|
8
|
+
# Most of the time, authors won't need to construct linters directly
|
9
|
+
# because the provided test helpers will automatically run when required
|
10
|
+
# in tests and specs.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# require 'rom/lint/spec'
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
class Linter
|
18
|
+
# A failure raised by +complain+
|
19
|
+
Failure = Class.new(StandardError)
|
20
|
+
|
21
|
+
# Iterate over all lint methods
|
22
|
+
#
|
23
|
+
# @yield [String, ROM::Lint]
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def self.each_lint
|
27
|
+
return to_enum unless block_given?
|
28
|
+
lints.each { |lint| yield lint, self }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Run a lint method
|
32
|
+
#
|
33
|
+
# @param [String] name
|
34
|
+
#
|
35
|
+
# @raise [ROM::Lint::Linter::Failure] if linting fails
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def lint(name)
|
39
|
+
before_lint
|
40
|
+
public_send name
|
41
|
+
after_lint
|
42
|
+
true # for assertions
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Return a list a lint methods
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
def self.lints
|
53
|
+
public_instance_methods(true).grep(/^lint_/).map(&:to_s)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Raise a failure if a lint verification fails
|
57
|
+
#
|
58
|
+
# @raise [ROM::Lint::Linter::Failure]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
def complain(*args)
|
62
|
+
raise Failure, *args
|
63
|
+
end
|
64
|
+
|
65
|
+
# Hook method executed before each lint method run
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def before_lint
|
69
|
+
end
|
70
|
+
|
71
|
+
# Hook method executed after each lint method run
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def after_lint
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rom/lint/gateway'
|
2
|
+
require 'rom/lint/enumerable_dataset'
|
3
|
+
|
4
|
+
RSpec.shared_examples "a rom gateway" do
|
5
|
+
ROM::Lint::Gateway.each_lint do |name, linter|
|
6
|
+
it name do
|
7
|
+
result = linter.new(identifier, gateway, uri).lint(name)
|
8
|
+
expect(result).to be_truthy
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.shared_examples "a rom enumerable dataset" do
|
14
|
+
ROM::Lint::EnumerableDataset.each_lint do |name, linter|
|
15
|
+
it name do
|
16
|
+
result = linter.new(dataset, data).lint(name)
|
17
|
+
expect(result).to be_truthy
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'rom/lint/gateway'
|
2
|
+
require 'rom/lint/enumerable_dataset'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module Lint
|
6
|
+
# A module that helps to define test methods
|
7
|
+
module Test
|
8
|
+
# Defines a test method converting lint failures to assertions
|
9
|
+
#
|
10
|
+
# @param [String] name
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def define_test_method(name, &block)
|
14
|
+
define_method "test_#{name}" do
|
15
|
+
begin
|
16
|
+
instance_eval(&block)
|
17
|
+
rescue ROM::Lint::Linter::Failure => f
|
18
|
+
raise Minitest::Assertion, f.message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is a simple lint-test for gateway class to ensure the
|
25
|
+
# basic interfaces are in place
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
#
|
29
|
+
# class MyGatewayTest < Minitest::Test
|
30
|
+
# include ROM::Lint::TestGateway
|
31
|
+
#
|
32
|
+
# def setup
|
33
|
+
# @gateway = MyGateway
|
34
|
+
# @uri = "super_db://something"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
module TestGateway
|
40
|
+
extend ROM::Lint::Test
|
41
|
+
|
42
|
+
# Returns the gateway identifier e.g. +:memory+
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
attr_reader :identifier
|
46
|
+
|
47
|
+
# Returns the gateway class
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
attr_reader :gateway
|
51
|
+
|
52
|
+
# Returns gateway's URI e.g. "super_db://something"
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
attr_reader :uri
|
56
|
+
|
57
|
+
ROM::Lint::Gateway.each_lint do |name, linter|
|
58
|
+
define_test_method name do
|
59
|
+
assert linter.new(identifier, gateway, uri).lint(name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# This is a simple lint-test for a gateway dataset class to ensure the
|
65
|
+
# basic behavior is correct
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
#
|
69
|
+
# class MyDatasetLintTest < Minitest::Test
|
70
|
+
# include ROM::Lint::TestEnumerableDataset
|
71
|
+
#
|
72
|
+
# def setup
|
73
|
+
# @data = [{ name: 'Jane', age: 24 }, { name: 'Joe', age: 25 }]
|
74
|
+
# @dataset = MyDataset.new(@data, [:name, :age])
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# @api public
|
78
|
+
module TestEnumerableDataset
|
79
|
+
extend ROM::Lint::Test
|
80
|
+
|
81
|
+
# Returns the dataset instance
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
attr_reader :dataset
|
85
|
+
|
86
|
+
# Returns the expected data
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
attr_reader :data
|
90
|
+
|
91
|
+
ROM::Lint::EnumerableDataset.each_lint do |name, linter|
|
92
|
+
define_test_method name do
|
93
|
+
assert linter.new(dataset, data).lint(name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rom/struct'
|
2
|
+
require 'rom/registry'
|
3
|
+
require 'rom/mapper_compiler'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
# @private
|
7
|
+
class MapperRegistry < Registry
|
8
|
+
def self.element_not_found_error
|
9
|
+
MapperMissingError
|
10
|
+
end
|
11
|
+
|
12
|
+
option :compiler, default: -> { MapperCompiler.new }
|
13
|
+
|
14
|
+
# @see Registry
|
15
|
+
# @api public
|
16
|
+
def [](*args)
|
17
|
+
if args[0].is_a?(Symbol)
|
18
|
+
super
|
19
|
+
else
|
20
|
+
cache.fetch_or_store(args.hash) { compiler.(*args) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/rom/memory.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rom/commands'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Memory
|
5
|
+
# Memory adapter commands namespace
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
module Commands
|
9
|
+
# In-memory create command
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
class Create < ROM::Commands::Create
|
13
|
+
adapter :memory
|
14
|
+
use :schema
|
15
|
+
|
16
|
+
# @see ROM::Commands::Create#execute
|
17
|
+
def execute(tuples)
|
18
|
+
Array([tuples]).flatten.map { |tuple|
|
19
|
+
attributes = input[tuple]
|
20
|
+
relation.insert(attributes.to_h)
|
21
|
+
attributes
|
22
|
+
}.to_a
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# In-memory update command
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
class Update < ROM::Commands::Update
|
30
|
+
adapter :memory
|
31
|
+
use :schema
|
32
|
+
|
33
|
+
# @see ROM::Commands::Update#execute
|
34
|
+
def execute(params)
|
35
|
+
attributes = input[params]
|
36
|
+
relation.map { |tuple| tuple.update(attributes.to_h) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# In-memory delete command
|
41
|
+
#
|
42
|
+
# @api public
|
43
|
+
class Delete < ROM::Commands::Delete
|
44
|
+
adapter :memory
|
45
|
+
|
46
|
+
# @see ROM::Commands::Delete#execute
|
47
|
+
def execute
|
48
|
+
relation.to_a.map do |tuple|
|
49
|
+
source.delete(tuple)
|
50
|
+
tuple
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|