rom 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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