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/relation_builder.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
module ROM
|
2
|
-
|
3
2
|
# @api private
|
4
3
|
class RelationBuilder
|
5
4
|
attr_reader :schema, :mod
|
6
5
|
|
7
6
|
# @api private
|
8
|
-
def initialize(schema)
|
7
|
+
def initialize(schema, relations)
|
9
8
|
@schema = schema
|
10
|
-
|
11
|
-
|
9
|
+
|
10
|
+
@mod = Module.new
|
11
|
+
|
12
|
+
@mod.module_exec do
|
13
|
+
define_method(:__relations__) { relations }
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -34,6 +36,20 @@ module ROM
|
|
34
36
|
def name
|
35
37
|
#{name.inspect}
|
36
38
|
end
|
39
|
+
|
40
|
+
def respond_to_missing?(name, _include_private = false)
|
41
|
+
__relations__.key?(name) || super
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def method_missing(name, *args, &block)
|
47
|
+
if __relations__.key?(name)
|
48
|
+
__relations__[name]
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
37
53
|
RUBY
|
38
54
|
|
39
55
|
klass.send(:include, mod)
|
@@ -42,7 +58,5 @@ module ROM
|
|
42
58
|
|
43
59
|
klass.new(schema_relation.dataset, schema_relation.header)
|
44
60
|
end
|
45
|
-
|
46
61
|
end
|
47
|
-
|
48
62
|
end
|
data/lib/rom/repository.rb
CHANGED
data/lib/rom/setup.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'rom/setup/schema_dsl'
|
2
|
+
require 'rom/setup/mapper_dsl'
|
3
|
+
require 'rom/setup/command_dsl'
|
4
|
+
|
5
|
+
require 'rom/setup/finalize'
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
# Exposes DSL for defining schema, relations, mappers and commands
|
9
|
+
#
|
10
|
+
# @public
|
11
|
+
class Setup
|
12
|
+
include Equalizer.new(:repositories, :env)
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
attr_reader :repositories, :env
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def initialize(repositories)
|
19
|
+
@repositories = repositories
|
20
|
+
@schema = {}
|
21
|
+
@relations = {}
|
22
|
+
@mappers = []
|
23
|
+
@commands = {}
|
24
|
+
@adapter_relation_map = {}
|
25
|
+
@env = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Schema definition DSL
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
#
|
32
|
+
# setup.schema do
|
33
|
+
# base_relation(:users) do
|
34
|
+
# repository :sqlite
|
35
|
+
#
|
36
|
+
# attribute :id
|
37
|
+
# attribute :name
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
def schema(&block)
|
43
|
+
SchemaDSL.new(self, @schema, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Relation definition DSL
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
#
|
50
|
+
# setup.relation(:users) do
|
51
|
+
# def names
|
52
|
+
# project(:name)
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def relation(name, &block)
|
58
|
+
@relations.update(name => block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Mapper definition DSL
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
#
|
65
|
+
# setup.mappers do
|
66
|
+
# define(:users) do
|
67
|
+
# model name: 'User'
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# define(:names, parent: :users) do
|
71
|
+
# exclude :id
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# @api public
|
76
|
+
def mappers(&block)
|
77
|
+
dsl = MapperDSL.new(&block)
|
78
|
+
@mappers.concat(dsl.mappers)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Command definition DSL
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
#
|
85
|
+
# setup.commands(:users) do
|
86
|
+
# define(:create) do
|
87
|
+
# input NewUserParams
|
88
|
+
# validator NewUserValidator
|
89
|
+
# result :one
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# define(:update) do
|
93
|
+
# input UserParams
|
94
|
+
# validator UserValidator
|
95
|
+
# result :many
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# define(:delete) do
|
99
|
+
# result :many
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
def commands(name, &block)
|
105
|
+
dsl = CommandDSL.new(&block)
|
106
|
+
@commands.update(name => dsl.commands)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Finalize the setup
|
110
|
+
#
|
111
|
+
# @return [Env] frozen env with access to repositories, schema, relations,
|
112
|
+
# mappers and commands
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
def finalize
|
116
|
+
raise EnvAlreadyFinalizedError if env
|
117
|
+
|
118
|
+
finalize = Finalize.new(
|
119
|
+
repositories, @schema, @relations, @mappers, @commands
|
120
|
+
)
|
121
|
+
|
122
|
+
@env = finalize.run!
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns repository identified by name
|
126
|
+
#
|
127
|
+
# @return [Repository]
|
128
|
+
#
|
129
|
+
# @api private
|
130
|
+
def [](name)
|
131
|
+
repositories.fetch(name)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Hook for respond_to? used internally
|
135
|
+
#
|
136
|
+
# @api private
|
137
|
+
def respond_to_missing?(name, _include_context = false)
|
138
|
+
repositories.key?(name)
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
# Returns repository if method is a name of a registered repository
|
144
|
+
#
|
145
|
+
# @return [Repository]
|
146
|
+
#
|
147
|
+
# @api private
|
148
|
+
def method_missing(name, *)
|
149
|
+
if repositories.key?(name)
|
150
|
+
repositories.fetch(name)
|
151
|
+
else
|
152
|
+
super
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module ROM
|
2
|
-
class
|
3
|
-
|
2
|
+
class Setup
|
4
3
|
class BaseRelationDSL
|
5
4
|
attr_reader :env, :name, :header
|
6
5
|
|
7
|
-
def initialize(env, name)
|
6
|
+
def initialize(env, name, &block)
|
8
7
|
@env = env
|
9
8
|
@name = name
|
10
9
|
@header = []
|
11
10
|
@repository = nil
|
11
|
+
instance_exec(&block)
|
12
12
|
end
|
13
13
|
|
14
14
|
def repository(name = nil)
|
@@ -23,9 +23,7 @@ module ROM
|
|
23
23
|
header << name
|
24
24
|
end
|
25
25
|
|
26
|
-
def call
|
27
|
-
instance_exec(&block)
|
28
|
-
|
26
|
+
def call
|
29
27
|
dataset =
|
30
28
|
if adapter.respond_to?(:dataset)
|
31
29
|
adapter.dataset(name, header)
|
@@ -43,8 +41,6 @@ module ROM
|
|
43
41
|
def adapter
|
44
42
|
repository.adapter
|
45
43
|
end
|
46
|
-
|
47
44
|
end
|
48
|
-
|
49
45
|
end
|
50
46
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rom/mapper_builder'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
class Setup
|
5
|
+
class CommandDSL
|
6
|
+
attr_reader :commands
|
7
|
+
|
8
|
+
class CommandDefinition
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
def initialize(options, &block)
|
12
|
+
@options = options
|
13
|
+
instance_exec(&block) if block
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
options
|
18
|
+
end
|
19
|
+
|
20
|
+
def type
|
21
|
+
options[:type]
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def method_missing(name, *args, &block)
|
27
|
+
if args.size == 1
|
28
|
+
options[name] = args.first
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(&block)
|
36
|
+
@commands = {}
|
37
|
+
instance_exec(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def define(name, options = {}, &block)
|
41
|
+
commands[name] = CommandDefinition.new(options, &block)
|
42
|
+
self
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'rom/relation_builder'
|
2
|
+
require 'rom/reader_builder'
|
3
|
+
require 'rom/command_registry'
|
4
|
+
|
5
|
+
require 'rom/env'
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
class Setup
|
9
|
+
# @private
|
10
|
+
class Finalize
|
11
|
+
attr_reader :repositories, :adapter_relation_map
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
def initialize(repositories, schema, relations, mappers, commands)
|
15
|
+
@repositories = repositories
|
16
|
+
@schema = schema
|
17
|
+
@relations = relations
|
18
|
+
@mappers = mappers
|
19
|
+
@commands = commands
|
20
|
+
@adapter_relation_map = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def run!
|
25
|
+
schema = load_schema
|
26
|
+
relations = load_relations(schema)
|
27
|
+
readers = load_readers(relations)
|
28
|
+
commands = load_commands(relations)
|
29
|
+
|
30
|
+
Env.new(repositories, schema, relations, readers, commands)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def load_schema
|
37
|
+
repositories.each_value do |repo|
|
38
|
+
(@schema[repo] ||= []).concat(repo.schema)
|
39
|
+
end
|
40
|
+
|
41
|
+
base_relations = @schema.each_with_object({}) do |(repo, schema), h|
|
42
|
+
schema.each do |name, dataset, header|
|
43
|
+
adapter_relation_map[name] = repo.adapter
|
44
|
+
h[name] = Relation.new(dataset, header)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Schema.new(base_relations)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def load_relations(schema)
|
53
|
+
return RelationRegistry.new unless adapter_relation_map.any?
|
54
|
+
|
55
|
+
relations = {}
|
56
|
+
builder = RelationBuilder.new(schema, relations)
|
57
|
+
|
58
|
+
@relations.each do |name, block|
|
59
|
+
relations[name] = build_relation(name, builder, block)
|
60
|
+
end
|
61
|
+
|
62
|
+
(schema.elements.keys - relations.keys).each do |name|
|
63
|
+
relations[name] = build_relation(name, builder)
|
64
|
+
end
|
65
|
+
|
66
|
+
relations.each_value do |relation|
|
67
|
+
relation.class.finalize(relations, relation)
|
68
|
+
end
|
69
|
+
|
70
|
+
RelationRegistry.new(relations)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @api private
|
74
|
+
def build_relation(name, builder, block = nil)
|
75
|
+
adapter = adapter_relation_map[name]
|
76
|
+
|
77
|
+
relation = builder.call(name) do |klass|
|
78
|
+
adapter.extend_relation_class(klass)
|
79
|
+
methods = klass.public_instance_methods
|
80
|
+
|
81
|
+
klass.class_eval(&block) if block
|
82
|
+
|
83
|
+
klass.relation_methods = klass.public_instance_methods - methods
|
84
|
+
end
|
85
|
+
|
86
|
+
adapter.extend_relation_instance(relation)
|
87
|
+
|
88
|
+
relation
|
89
|
+
end
|
90
|
+
|
91
|
+
# @api private
|
92
|
+
def load_readers(relations)
|
93
|
+
return ReaderRegistry.new unless adapter_relation_map.any?
|
94
|
+
|
95
|
+
reader_builder = ReaderBuilder.new(relations)
|
96
|
+
|
97
|
+
readers = @mappers.each_with_object({}) do |(name, options, block), h|
|
98
|
+
h[name] = reader_builder.call(name, options, &block)
|
99
|
+
end
|
100
|
+
|
101
|
+
ReaderRegistry.new(readers)
|
102
|
+
end
|
103
|
+
|
104
|
+
def load_commands(relations)
|
105
|
+
return Registry.new unless relations.elements.any?
|
106
|
+
|
107
|
+
commands = @commands.each_with_object({}) do |(name, definitions), h|
|
108
|
+
adapter = adapter_relation_map[name]
|
109
|
+
|
110
|
+
rel_commands = {}
|
111
|
+
|
112
|
+
definitions.each do |command_name, definition|
|
113
|
+
rel_commands[command_name] = adapter.command(
|
114
|
+
command_name, relations[name], definition
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
h[name] = CommandRegistry.new(rel_commands)
|
119
|
+
end
|
120
|
+
|
121
|
+
Registry.new(commands)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rom/mapper_builder'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
class Setup
|
5
|
+
class MapperDSL
|
6
|
+
attr_reader :mappers
|
7
|
+
|
8
|
+
def initialize(&block)
|
9
|
+
@mappers = []
|
10
|
+
instance_exec(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def define(name, options = {}, &block)
|
14
|
+
mappers << [name, options, block]
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|