rom 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +81 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile +12 -8
- data/Guardfile +17 -11
- data/README.md +7 -7
- data/Rakefile +29 -0
- data/lib/rom.rb +9 -66
- data/lib/rom/adapter.rb +45 -12
- data/lib/rom/adapter/memory.rb +0 -4
- data/lib/rom/adapter/memory/commands.rb +0 -10
- data/lib/rom/adapter/memory/dataset.rb +18 -6
- data/lib/rom/adapter/memory/storage.rb +0 -3
- data/lib/rom/command_registry.rb +24 -43
- data/lib/rom/commands.rb +5 -6
- data/lib/rom/commands/create.rb +5 -5
- data/lib/rom/commands/delete.rb +8 -6
- data/lib/rom/commands/result.rb +82 -0
- data/lib/rom/commands/update.rb +5 -4
- data/lib/rom/commands/with_options.rb +1 -4
- data/lib/rom/config.rb +70 -0
- data/lib/rom/env.rb +11 -3
- data/lib/rom/global.rb +107 -0
- data/lib/rom/header.rb +122 -89
- data/lib/rom/header/attribute.rb +148 -0
- data/lib/rom/mapper.rb +46 -67
- data/lib/rom/mapper_builder.rb +20 -73
- data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
- data/lib/rom/mapper_builder/model_dsl.rb +29 -0
- data/lib/rom/mapper_registry.rb +21 -0
- data/lib/rom/model_builder.rb +11 -17
- data/lib/rom/processor.rb +28 -0
- data/lib/rom/processor/transproc.rb +105 -0
- data/lib/rom/reader.rb +81 -21
- data/lib/rom/reader_builder.rb +14 -4
- data/lib/rom/relation.rb +19 -5
- data/lib/rom/relation_builder.rb +20 -6
- data/lib/rom/repository.rb +0 -2
- data/lib/rom/setup.rb +156 -0
- data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
- data/lib/rom/setup/command_dsl.rb +46 -0
- data/lib/rom/setup/finalize.rb +125 -0
- data/lib/rom/setup/mapper_dsl.rb +19 -0
- data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
- data/lib/rom/setup/schema_dsl.rb +33 -0
- data/lib/rom/support/registry.rb +10 -6
- data/lib/rom/version.rb +1 -1
- data/rom.gemspec +3 -1
- data/spec/integration/adapters/extending_relations_spec.rb +0 -2
- data/spec/integration/commands/create_spec.rb +2 -9
- data/spec/integration/commands/delete_spec.rb +4 -5
- data/spec/integration/commands/error_handling_spec.rb +4 -3
- data/spec/integration/commands/update_spec.rb +3 -8
- data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
- data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
- data/spec/integration/mappers/embedded_spec.rb +82 -0
- data/spec/integration/mappers/group_spec.rb +170 -0
- data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
- data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
- data/spec/integration/mappers/wrap_spec.rb +162 -0
- data/spec/integration/multi_repo_spec.rb +64 -0
- data/spec/integration/relations/reading_spec.rb +12 -8
- data/spec/integration/relations/registry_dsl_spec.rb +1 -3
- data/spec/integration/schema_spec.rb +10 -0
- data/spec/integration/setup_spec.rb +57 -6
- data/spec/spec_helper.rb +2 -1
- data/spec/unit/config_spec.rb +60 -0
- data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
- data/spec/unit/rom/adapter_spec.rb +31 -11
- data/spec/unit/rom/header_spec.rb +60 -16
- data/spec/unit/rom/mapper_builder_spec.rb +311 -0
- data/spec/unit/rom/mapper_registry_spec.rb +25 -0
- data/spec/unit/rom/mapper_spec.rb +4 -5
- data/spec/unit/rom/model_builder_spec.rb +15 -13
- data/spec/unit/rom/processor/transproc_spec.rb +331 -0
- data/spec/unit/rom/reader_spec.rb +73 -0
- data/spec/unit/rom/registry_spec.rb +38 -0
- data/spec/unit/rom/relation_spec.rb +0 -1
- data/spec/unit/rom/setup_spec.rb +55 -0
- data/spec/unit/rom_spec.rb +14 -0
- metadata +62 -22
- data/Gemfile.devtools +0 -71
- data/lib/rom/boot.rb +0 -197
- data/lib/rom/boot/command_dsl.rb +0 -48
- data/lib/rom/boot/dsl.rb +0 -37
- data/lib/rom/boot/mapper_dsl.rb +0 -23
- data/lib/rom/boot/schema_dsl.rb +0 -27
- data/lib/rom/ra.rb +0 -172
- data/lib/rom/ra/operation/group.rb +0 -47
- data/lib/rom/ra/operation/join.rb +0 -39
- data/lib/rom/ra/operation/wrap.rb +0 -45
- data/lib/rom/transformer.rb +0 -77
- data/spec/integration/ra/group_spec.rb +0 -46
- data/spec/integration/ra/join_spec.rb +0 -50
- data/spec/integration/ra/wrap_spec.rb +0 -37
- data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
- data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
- data/spec/unit/rom/transformer_spec.rb +0 -41
data/lib/rom/adapter/memory.rb
CHANGED
@@ -4,7 +4,6 @@ require 'rom/adapter/memory/commands'
|
|
4
4
|
|
5
5
|
module ROM
|
6
6
|
class Adapter
|
7
|
-
|
8
7
|
class Memory < Adapter
|
9
8
|
attr_accessor :logger
|
10
9
|
|
@@ -28,9 +27,6 @@ module ROM
|
|
28
27
|
def [](name)
|
29
28
|
connection[name]
|
30
29
|
end
|
31
|
-
|
32
|
-
Adapter.register(self)
|
33
30
|
end
|
34
|
-
|
35
31
|
end
|
36
32
|
end
|
@@ -1,41 +1,31 @@
|
|
1
1
|
module ROM
|
2
2
|
class Adapter
|
3
3
|
class Memory < Adapter
|
4
|
-
|
5
4
|
module Commands
|
6
|
-
|
7
5
|
class Create < ROM::Commands::Create
|
8
|
-
|
9
6
|
def execute(tuple)
|
10
7
|
attributes = input[tuple]
|
11
8
|
validator.call(attributes)
|
12
9
|
[relation.insert(attributes.to_h).to_a.last]
|
13
10
|
end
|
14
|
-
|
15
11
|
end
|
16
12
|
|
17
13
|
class Update < ROM::Commands::Update
|
18
|
-
|
19
14
|
def execute(params)
|
20
15
|
attributes = input[params]
|
21
16
|
validator.call(attributes)
|
22
17
|
relation.map { |tuple| tuple.update(attributes.to_h) }
|
23
18
|
end
|
24
|
-
|
25
19
|
end
|
26
20
|
|
27
21
|
class Delete < ROM::Commands::Delete
|
28
|
-
|
29
22
|
def execute
|
30
23
|
tuples = target.to_a
|
31
24
|
tuples.each { |tuple| relation.delete(tuple) }
|
32
25
|
tuples
|
33
26
|
end
|
34
|
-
|
35
27
|
end
|
36
|
-
|
37
28
|
end
|
38
|
-
|
39
29
|
end
|
40
30
|
end
|
41
31
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module ROM
|
2
2
|
class Adapter
|
3
3
|
class Memory < Adapter
|
4
|
-
|
5
4
|
class Dataset
|
6
5
|
include Charlatan.new(:data)
|
7
6
|
|
@@ -22,16 +21,31 @@ module ROM
|
|
22
21
|
data.each(&block)
|
23
22
|
end
|
24
23
|
|
25
|
-
def
|
24
|
+
def join(*args)
|
25
|
+
left, right = args.size > 1 ? args : [self, args.first]
|
26
|
+
|
27
|
+
join_map = left.to_a.each_with_object({}) { |tuple, h|
|
28
|
+
others = right.to_a.find_all { |t| (tuple.to_a & t.to_a).any? }
|
29
|
+
(h[tuple] ||= []).concat(others)
|
30
|
+
}
|
31
|
+
|
32
|
+
tuples = left.map { |tuple|
|
33
|
+
join_map[tuple].map { |other| tuple.merge(other) }
|
34
|
+
}.flatten
|
35
|
+
|
36
|
+
self.class.new(tuples, left.header + right.header)
|
37
|
+
end
|
38
|
+
|
39
|
+
def restrict(criteria = nil)
|
26
40
|
if criteria
|
27
|
-
find_all { |tuple| criteria.all? { |k, v| tuple[k]
|
41
|
+
find_all { |tuple| criteria.all? { |k, v| tuple[k].eql?(v) } }
|
28
42
|
else
|
29
43
|
find_all { |tuple| yield(tuple) }
|
30
44
|
end
|
31
45
|
end
|
32
46
|
|
33
47
|
def project(*names)
|
34
|
-
map { |tuple| tuple.reject { |key
|
48
|
+
map { |tuple| tuple.reject { |key| !names.include?(key) } }
|
35
49
|
end
|
36
50
|
|
37
51
|
def order(*names)
|
@@ -47,9 +61,7 @@ module ROM
|
|
47
61
|
data.delete(tuple)
|
48
62
|
self
|
49
63
|
end
|
50
|
-
|
51
64
|
end
|
52
|
-
|
53
65
|
end
|
54
66
|
end
|
55
67
|
end
|
data/lib/rom/command_registry.rb
CHANGED
@@ -1,50 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class Result
|
4
|
-
attr_reader :value, :error
|
5
|
-
|
6
|
-
def to_ary
|
7
|
-
raise NotImplementedError
|
8
|
-
end
|
9
|
-
alias_method :to_a, :to_ary
|
10
|
-
|
11
|
-
class Success < Result
|
12
|
-
def initialize(value)
|
13
|
-
@value = value
|
14
|
-
end
|
15
|
-
|
16
|
-
def >(f)
|
17
|
-
f.call(value)
|
18
|
-
end
|
19
|
-
|
20
|
-
def to_ary
|
21
|
-
value
|
22
|
-
end
|
23
|
-
alias_method :to_a, :to_ary
|
24
|
-
end
|
25
|
-
|
26
|
-
class Failure < Result
|
27
|
-
def initialize(error)
|
28
|
-
@error = error
|
29
|
-
end
|
30
|
-
|
31
|
-
def >(f)
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def to_ary
|
36
|
-
error
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
1
|
+
require 'rom/commands/result'
|
40
2
|
|
3
|
+
module ROM
|
4
|
+
# Command registry exposes "try" interface for executing commands
|
5
|
+
#
|
6
|
+
# @public
|
41
7
|
class CommandRegistry < Registry
|
42
|
-
|
43
8
|
class Evaluator
|
44
9
|
include Concord.new(:registry)
|
45
10
|
|
46
11
|
private
|
47
12
|
|
13
|
+
# Call a command when method is matching command name
|
14
|
+
#
|
15
|
+
# TODO: this will be replaced by explicit definition of methods for all
|
16
|
+
# registered commands
|
17
|
+
#
|
18
|
+
# @api public
|
48
19
|
def method_missing(name, *args, &block)
|
49
20
|
command = registry[name]
|
50
21
|
|
@@ -58,11 +29,21 @@ module ROM
|
|
58
29
|
end
|
59
30
|
end
|
60
31
|
|
32
|
+
# Try to execute a command in a block
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
#
|
36
|
+
# rom.command(:users).try { create(name: 'Jane') }
|
37
|
+
# rom.command(:users).try { update(:by_id, 1).set(name: 'Jane Doe') }
|
38
|
+
# rom.command(:users).try { delete(:by_id, 1) }
|
39
|
+
#
|
40
|
+
# @return [Commands::Result]
|
41
|
+
#
|
42
|
+
# @api public
|
61
43
|
def try(&f)
|
62
|
-
Result::Success.new(Evaluator.new(self).instance_exec(&f))
|
44
|
+
Commands::Result::Success.new(Evaluator.new(self).instance_exec(&f))
|
63
45
|
rescue CommandError => e
|
64
|
-
Result::Failure.new(e)
|
46
|
+
Commands::Result::Failure.new(e)
|
65
47
|
end
|
66
48
|
end
|
67
|
-
|
68
49
|
end
|
data/lib/rom/commands.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module ROM
|
2
2
|
module Commands
|
3
|
-
|
4
3
|
class AbstractCommand
|
5
4
|
VALID_RESULTS = [:one, :many].freeze
|
6
5
|
|
@@ -13,7 +12,7 @@ module ROM
|
|
13
12
|
|
14
13
|
@result = options[:result] || :many
|
15
14
|
|
16
|
-
|
15
|
+
unless VALID_RESULTS.include?(result)
|
17
16
|
raise InvalidOptionError.new(:result, VALID_RESULTS)
|
18
17
|
end
|
19
18
|
end
|
@@ -34,7 +33,8 @@ module ROM
|
|
34
33
|
# Target relation on which the command will operate
|
35
34
|
#
|
36
35
|
# By default this is set to the relation that's passed to the constructor.
|
37
|
-
# Specialized commands like Delete may set the target to a different
|
36
|
+
# Specialized commands like Delete may set the target to a different
|
37
|
+
# relation.
|
38
38
|
#
|
39
39
|
# @return [Relation]
|
40
40
|
#
|
@@ -43,7 +43,8 @@ module ROM
|
|
43
43
|
relation
|
44
44
|
end
|
45
45
|
|
46
|
-
# Assert that tuple count in the target relation corresponds to :result
|
46
|
+
# Assert that tuple count in the target relation corresponds to :result
|
47
|
+
# setting
|
47
48
|
#
|
48
49
|
# @raises TupleCountMismatchError
|
49
50
|
#
|
@@ -53,9 +54,7 @@ module ROM
|
|
53
54
|
raise TupleCountMismatchError, "#{inspect} expects one tuple"
|
54
55
|
end
|
55
56
|
end
|
56
|
-
|
57
57
|
end
|
58
|
-
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
data/lib/rom/commands/create.rb
CHANGED
@@ -2,7 +2,6 @@ require 'rom/commands/with_options'
|
|
2
2
|
|
3
3
|
module ROM
|
4
4
|
module Commands
|
5
|
-
|
6
5
|
# Create command
|
7
6
|
#
|
8
7
|
# This command inserts a new tuple into a relation
|
@@ -18,11 +17,12 @@ module ROM
|
|
18
17
|
# @return [Array] an array with inserted tuples
|
19
18
|
#
|
20
19
|
# @api private
|
21
|
-
def execute(
|
22
|
-
raise
|
20
|
+
def execute(_tuple)
|
21
|
+
raise(
|
22
|
+
NotImplementedError,
|
23
|
+
"#{self.class}##{__method__} must be implemented"
|
24
|
+
)
|
23
25
|
end
|
24
|
-
|
25
26
|
end
|
26
|
-
|
27
27
|
end
|
28
28
|
end
|
data/lib/rom/commands/delete.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module ROM
|
2
2
|
module Commands
|
3
|
-
|
4
3
|
# Delete command
|
5
4
|
#
|
6
5
|
# This command removes tuples from its target relation
|
@@ -28,17 +27,20 @@ module ROM
|
|
28
27
|
#
|
29
28
|
# @api private
|
30
29
|
def execute
|
31
|
-
raise
|
30
|
+
raise(
|
31
|
+
NotImplementedError,
|
32
|
+
"#{self.class}##{__method__} must be implemented"
|
33
|
+
)
|
32
34
|
end
|
33
35
|
|
34
|
-
#
|
36
|
+
# Create a new delete command scoped to specific relation and execute it
|
35
37
|
#
|
36
38
|
# @api private
|
37
39
|
def new(*args, &block)
|
38
|
-
|
40
|
+
new_options = options.merge(target: relation.public_send(*args, &block))
|
41
|
+
command = self.class.new(relation, new_options)
|
42
|
+
command.call
|
39
43
|
end
|
40
|
-
|
41
44
|
end
|
42
|
-
|
43
45
|
end
|
44
46
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module ROM
|
2
|
+
module Commands
|
3
|
+
# Abstract result class for success and error results
|
4
|
+
#
|
5
|
+
# @public
|
6
|
+
class Result
|
7
|
+
# Return command execution result
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
attr_reader :value
|
11
|
+
|
12
|
+
# Return potential command execution result error
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
attr_reader :error
|
16
|
+
|
17
|
+
# Coerce result to an array
|
18
|
+
#
|
19
|
+
# @abstract
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def to_ary
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
alias_method :to_a, :to_ary
|
26
|
+
|
27
|
+
# Success result has a value and no error
|
28
|
+
#
|
29
|
+
# @public
|
30
|
+
class Success < Result
|
31
|
+
# @api private
|
32
|
+
def initialize(value)
|
33
|
+
@value = value
|
34
|
+
end
|
35
|
+
|
36
|
+
# Call next command on continuation
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def >(other)
|
40
|
+
other.call(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the value
|
44
|
+
#
|
45
|
+
# @return [Array]
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def to_ary
|
49
|
+
value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Failure result has an error and no value
|
54
|
+
#
|
55
|
+
# @public
|
56
|
+
class Failure < Result
|
57
|
+
# @api private
|
58
|
+
def initialize(error)
|
59
|
+
@error = error
|
60
|
+
end
|
61
|
+
|
62
|
+
# Do not call next command on continuation
|
63
|
+
#
|
64
|
+
# @return [self]
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def >(_other)
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the error
|
72
|
+
#
|
73
|
+
# @return [Array<CommandError>]
|
74
|
+
#
|
75
|
+
# @api public
|
76
|
+
def to_ary
|
77
|
+
error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/rom/commands/update.rb
CHANGED
@@ -2,7 +2,6 @@ require 'rom/commands/with_options'
|
|
2
2
|
|
3
3
|
module ROM
|
4
4
|
module Commands
|
5
|
-
|
6
5
|
# Update command
|
7
6
|
#
|
8
7
|
# This command updates all tuples in its relation with new attributes
|
@@ -26,8 +25,11 @@ module ROM
|
|
26
25
|
# @abstract
|
27
26
|
#
|
28
27
|
# @api private
|
29
|
-
def execute(
|
30
|
-
raise
|
28
|
+
def execute(_params)
|
29
|
+
raise(
|
30
|
+
NotImplementedError,
|
31
|
+
"#{self.class}##{__method__} must be implemented"
|
32
|
+
)
|
31
33
|
end
|
32
34
|
|
33
35
|
# Return new update command with new relation
|
@@ -37,6 +39,5 @@ module ROM
|
|
37
39
|
self.class.new(relation.public_send(*args, &block), options)
|
38
40
|
end
|
39
41
|
end
|
40
|
-
|
41
42
|
end
|
42
43
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ROM
|
2
2
|
module Commands
|
3
|
-
|
4
3
|
# Common behavior for Create and Update commands
|
5
4
|
#
|
6
5
|
# TODO: find a better name for this module
|
@@ -11,11 +10,9 @@ module ROM
|
|
11
10
|
def initialize(relation, options)
|
12
11
|
super
|
13
12
|
|
14
|
-
@validator = options[:validator] ||
|
13
|
+
@validator = options[:validator] || proc {}
|
15
14
|
@input = options[:input] || Hash
|
16
15
|
end
|
17
|
-
|
18
16
|
end
|
19
|
-
|
20
17
|
end
|
21
18
|
end
|