rom 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +81 -0
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +12 -8
  6. data/Guardfile +17 -11
  7. data/README.md +7 -7
  8. data/Rakefile +29 -0
  9. data/lib/rom.rb +9 -66
  10. data/lib/rom/adapter.rb +45 -12
  11. data/lib/rom/adapter/memory.rb +0 -4
  12. data/lib/rom/adapter/memory/commands.rb +0 -10
  13. data/lib/rom/adapter/memory/dataset.rb +18 -6
  14. data/lib/rom/adapter/memory/storage.rb +0 -3
  15. data/lib/rom/command_registry.rb +24 -43
  16. data/lib/rom/commands.rb +5 -6
  17. data/lib/rom/commands/create.rb +5 -5
  18. data/lib/rom/commands/delete.rb +8 -6
  19. data/lib/rom/commands/result.rb +82 -0
  20. data/lib/rom/commands/update.rb +5 -4
  21. data/lib/rom/commands/with_options.rb +1 -4
  22. data/lib/rom/config.rb +70 -0
  23. data/lib/rom/env.rb +11 -3
  24. data/lib/rom/global.rb +107 -0
  25. data/lib/rom/header.rb +122 -89
  26. data/lib/rom/header/attribute.rb +148 -0
  27. data/lib/rom/mapper.rb +46 -67
  28. data/lib/rom/mapper_builder.rb +20 -73
  29. data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
  30. data/lib/rom/mapper_builder/model_dsl.rb +29 -0
  31. data/lib/rom/mapper_registry.rb +21 -0
  32. data/lib/rom/model_builder.rb +11 -17
  33. data/lib/rom/processor.rb +28 -0
  34. data/lib/rom/processor/transproc.rb +105 -0
  35. data/lib/rom/reader.rb +81 -21
  36. data/lib/rom/reader_builder.rb +14 -4
  37. data/lib/rom/relation.rb +19 -5
  38. data/lib/rom/relation_builder.rb +20 -6
  39. data/lib/rom/repository.rb +0 -2
  40. data/lib/rom/setup.rb +156 -0
  41. data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
  42. data/lib/rom/setup/command_dsl.rb +46 -0
  43. data/lib/rom/setup/finalize.rb +125 -0
  44. data/lib/rom/setup/mapper_dsl.rb +19 -0
  45. data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
  46. data/lib/rom/setup/schema_dsl.rb +33 -0
  47. data/lib/rom/support/registry.rb +10 -6
  48. data/lib/rom/version.rb +1 -1
  49. data/rom.gemspec +3 -1
  50. data/spec/integration/adapters/extending_relations_spec.rb +0 -2
  51. data/spec/integration/commands/create_spec.rb +2 -9
  52. data/spec/integration/commands/delete_spec.rb +4 -5
  53. data/spec/integration/commands/error_handling_spec.rb +4 -3
  54. data/spec/integration/commands/update_spec.rb +3 -8
  55. data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
  56. data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
  57. data/spec/integration/mappers/embedded_spec.rb +82 -0
  58. data/spec/integration/mappers/group_spec.rb +170 -0
  59. data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
  60. data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
  61. data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
  62. data/spec/integration/mappers/wrap_spec.rb +162 -0
  63. data/spec/integration/multi_repo_spec.rb +64 -0
  64. data/spec/integration/relations/reading_spec.rb +12 -8
  65. data/spec/integration/relations/registry_dsl_spec.rb +1 -3
  66. data/spec/integration/schema_spec.rb +10 -0
  67. data/spec/integration/setup_spec.rb +57 -6
  68. data/spec/spec_helper.rb +2 -1
  69. data/spec/unit/config_spec.rb +60 -0
  70. data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
  71. data/spec/unit/rom/adapter_spec.rb +31 -11
  72. data/spec/unit/rom/header_spec.rb +60 -16
  73. data/spec/unit/rom/mapper_builder_spec.rb +311 -0
  74. data/spec/unit/rom/mapper_registry_spec.rb +25 -0
  75. data/spec/unit/rom/mapper_spec.rb +4 -5
  76. data/spec/unit/rom/model_builder_spec.rb +15 -13
  77. data/spec/unit/rom/processor/transproc_spec.rb +331 -0
  78. data/spec/unit/rom/reader_spec.rb +73 -0
  79. data/spec/unit/rom/registry_spec.rb +38 -0
  80. data/spec/unit/rom/relation_spec.rb +0 -1
  81. data/spec/unit/rom/setup_spec.rb +55 -0
  82. data/spec/unit/rom_spec.rb +14 -0
  83. metadata +62 -22
  84. data/Gemfile.devtools +0 -71
  85. data/lib/rom/boot.rb +0 -197
  86. data/lib/rom/boot/command_dsl.rb +0 -48
  87. data/lib/rom/boot/dsl.rb +0 -37
  88. data/lib/rom/boot/mapper_dsl.rb +0 -23
  89. data/lib/rom/boot/schema_dsl.rb +0 -27
  90. data/lib/rom/ra.rb +0 -172
  91. data/lib/rom/ra/operation/group.rb +0 -47
  92. data/lib/rom/ra/operation/join.rb +0 -39
  93. data/lib/rom/ra/operation/wrap.rb +0 -45
  94. data/lib/rom/transformer.rb +0 -77
  95. data/spec/integration/ra/group_spec.rb +0 -46
  96. data/spec/integration/ra/join_spec.rb +0 -50
  97. data/spec/integration/ra/wrap_spec.rb +0 -37
  98. data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
  99. data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
  100. data/spec/unit/rom/transformer_spec.rb +0 -41
@@ -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
- @mod = schema.each_with_object(Module.new) do |(name, relation), m|
11
- m.send(:define_method, name) { relation.dataset }
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
@@ -1,5 +1,4 @@
1
1
  module ROM
2
-
3
2
  # Repository exposes native database connection and schema when it's
4
3
  # supported by the adapter
5
4
  #
@@ -64,5 +63,4 @@ module ROM
64
63
  end
65
64
  end
66
65
  end
67
-
68
66
  end
@@ -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 Boot
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(&block)
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