rom 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -7
  3. data/.yardopts +2 -0
  4. data/CHANGELOG.md +35 -1
  5. data/Gemfile +17 -2
  6. data/Rakefile +7 -2
  7. data/lib/rom/array_dataset.rb +44 -0
  8. data/lib/rom/association_set.rb +11 -5
  9. data/lib/rom/auto_curry.rb +55 -0
  10. data/lib/rom/command.rb +331 -47
  11. data/lib/rom/command_registry.rb +7 -18
  12. data/lib/rom/commands/class_interface.rb +120 -6
  13. data/lib/rom/commands/composite.rb +0 -1
  14. data/lib/rom/commands/graph.rb +7 -15
  15. data/lib/rom/commands/lazy/update.rb +1 -1
  16. data/lib/rom/configuration.rb +2 -0
  17. data/lib/rom/configuration_dsl/command.rb +6 -8
  18. data/lib/rom/configuration_dsl/mapper.rb +2 -3
  19. data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -1
  20. data/lib/rom/configuration_dsl/relation.rb +4 -4
  21. data/lib/rom/configuration_dsl.rb +0 -4
  22. data/lib/rom/constants.rb +7 -1
  23. data/lib/rom/container.rb +11 -17
  24. data/lib/rom/create_container.rb +0 -2
  25. data/lib/rom/data_proxy.rb +94 -0
  26. data/lib/rom/enumerable_dataset.rb +68 -0
  27. data/lib/rom/gateway.rb +74 -32
  28. data/lib/rom/global/plugin_dsl.rb +0 -2
  29. data/lib/rom/global.rb +0 -2
  30. data/lib/rom/initializer.rb +26 -0
  31. data/lib/rom/lint/gateway.rb +17 -0
  32. data/lib/rom/mapper_registry.rb +1 -1
  33. data/lib/rom/memory/commands.rb +0 -2
  34. data/lib/rom/memory/dataset.rb +1 -2
  35. data/lib/rom/memory/relation.rb +14 -1
  36. data/lib/rom/memory/schema.rb +13 -0
  37. data/lib/rom/plugin_registry.rb +1 -1
  38. data/lib/rom/plugins/command/schema.rb +2 -2
  39. data/lib/rom/plugins/configuration/configuration_dsl.rb +6 -2
  40. data/lib/rom/plugins/relation/key_inference.rb +4 -2
  41. data/lib/rom/plugins/relation/registry_reader.rb +5 -1
  42. data/lib/rom/registry.rb +50 -0
  43. data/lib/rom/relation/class_interface.rb +142 -30
  44. data/lib/rom/relation/curried.rb +15 -15
  45. data/lib/rom/relation/view_dsl.rb +31 -0
  46. data/lib/rom/relation.rb +101 -41
  47. data/lib/rom/schema/attribute.rb +367 -0
  48. data/lib/rom/schema/dsl.rb +14 -10
  49. data/lib/rom/schema.rb +337 -19
  50. data/lib/rom/setup/auto_registration.rb +20 -17
  51. data/lib/rom/setup/auto_registration_strategies/base.rb +8 -3
  52. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +4 -3
  53. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +5 -4
  54. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +3 -3
  55. data/lib/rom/setup/finalize/finalize_commands.rb +1 -1
  56. data/lib/rom/setup/finalize/finalize_mappers.rb +1 -1
  57. data/lib/rom/setup/finalize/finalize_relations.rb +4 -2
  58. data/lib/rom/setup/finalize.rb +1 -1
  59. data/lib/rom/transaction.rb +24 -0
  60. data/lib/rom/types.rb +9 -1
  61. data/lib/rom/version.rb +1 -1
  62. data/lib/rom.rb +4 -8
  63. data/rom.gemspec +5 -4
  64. data/spec/integration/command_registry_spec.rb +1 -14
  65. data/spec/integration/commands/create_spec.rb +5 -25
  66. data/spec/integration/commands/delete_spec.rb +1 -1
  67. data/spec/integration/commands/error_handling_spec.rb +1 -1
  68. data/spec/integration/commands/graph_spec.rb +20 -14
  69. data/spec/integration/commands/update_spec.rb +4 -27
  70. data/spec/integration/commands_spec.rb +1 -1
  71. data/spec/integration/{repositories → gateways}/extending_relations_spec.rb +1 -1
  72. data/spec/integration/{repositories → gateways}/setting_logger_spec.rb +2 -2
  73. data/spec/integration/mappers/combine_spec.rb +1 -1
  74. data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
  75. data/spec/integration/mappers/definition_dsl_spec.rb +1 -1
  76. data/spec/integration/mappers/embedded_spec.rb +1 -1
  77. data/spec/integration/mappers/exclude_spec.rb +1 -1
  78. data/spec/integration/mappers/fold_spec.rb +1 -1
  79. data/spec/integration/mappers/group_spec.rb +1 -1
  80. data/spec/integration/mappers/overwrite_attributes_value_spec.rb +1 -1
  81. data/spec/integration/mappers/prefix_separator_spec.rb +1 -1
  82. data/spec/integration/mappers/prefix_spec.rb +1 -1
  83. data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
  84. data/spec/integration/mappers/registering_custom_mappers_spec.rb +1 -1
  85. data/spec/integration/mappers/renaming_attributes_spec.rb +1 -1
  86. data/spec/integration/mappers/reusing_mappers_spec.rb +1 -1
  87. data/spec/integration/mappers/step_spec.rb +1 -1
  88. data/spec/integration/mappers/symbolizing_attributes_spec.rb +1 -1
  89. data/spec/integration/mappers/unfold_spec.rb +1 -1
  90. data/spec/integration/mappers/ungroup_spec.rb +2 -2
  91. data/spec/integration/mappers/unwrap_spec.rb +2 -2
  92. data/spec/integration/mappers/wrap_spec.rb +1 -1
  93. data/spec/integration/memory/commands/create_spec.rb +1 -1
  94. data/spec/integration/memory/commands/delete_spec.rb +1 -1
  95. data/spec/integration/memory/commands/update_spec.rb +1 -1
  96. data/spec/integration/multi_env_spec.rb +1 -1
  97. data/spec/integration/multi_repo_spec.rb +1 -1
  98. data/spec/integration/relations/default_dataset_spec.rb +1 -1
  99. data/spec/integration/relations/reading_spec.rb +1 -1
  100. data/spec/integration/relations/registry_dsl_spec.rb +1 -1
  101. data/spec/integration/setup_spec.rb +10 -4
  102. data/spec/shared/command_graph.rb +8 -4
  103. data/spec/shared/enumerable_dataset.rb +1 -1
  104. data/spec/spec_helper.rb +7 -9
  105. data/spec/support/schema.rb +14 -0
  106. data/spec/unit/rom/array_dataset_spec.rb +59 -0
  107. data/spec/unit/rom/association_set_spec.rb +4 -0
  108. data/spec/unit/rom/auto_curry_spec.rb +63 -0
  109. data/spec/unit/rom/commands/graph_spec.rb +12 -11
  110. data/spec/unit/rom/commands/lazy_spec.rb +8 -5
  111. data/spec/unit/rom/commands/pre_and_post_processors_spec.rb +336 -0
  112. data/spec/unit/rom/commands/result_spec.rb +1 -1
  113. data/spec/unit/rom/commands_spec.rb +26 -3
  114. data/spec/unit/rom/configuration_spec.rb +1 -1
  115. data/spec/unit/rom/container_spec.rb +15 -5
  116. data/spec/unit/rom/create_container_spec.rb +1 -1
  117. data/spec/unit/rom/enumerable_dataset_spec.rb +15 -0
  118. data/spec/unit/rom/gateway_spec.rb +1 -1
  119. data/spec/unit/rom/mapper_registry_spec.rb +1 -1
  120. data/spec/unit/rom/memory/commands_spec.rb +1 -1
  121. data/spec/unit/rom/memory/dataset_spec.rb +1 -1
  122. data/spec/unit/rom/memory/{repository_spec.rb → gateway_spec.rb} +1 -1
  123. data/spec/unit/rom/memory/inheritance_spec.rb +32 -0
  124. data/spec/unit/rom/memory/relation_spec.rb +15 -3
  125. data/spec/unit/rom/memory/storage_spec.rb +1 -1
  126. data/spec/unit/rom/plugin_spec.rb +1 -1
  127. data/spec/unit/rom/plugins/command/schema_spec.rb +5 -5
  128. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +1 -1
  129. data/spec/unit/rom/registry_spec.rb +86 -0
  130. data/spec/unit/rom/relation/attribute_reader_spec.rb +17 -0
  131. data/spec/unit/rom/relation/call_spec.rb +51 -0
  132. data/spec/unit/rom/relation/composite_spec.rb +1 -1
  133. data/spec/unit/rom/relation/graph_spec.rb +1 -1
  134. data/spec/unit/rom/relation/lazy/combine_spec.rb +1 -1
  135. data/spec/unit/rom/relation/lazy_spec.rb +1 -1
  136. data/spec/unit/rom/relation/loaded_spec.rb +1 -1
  137. data/spec/unit/rom/relation/schema_spec.rb +50 -6
  138. data/spec/unit/rom/relation/view_spec.rb +122 -0
  139. data/spec/unit/rom/relation_spec.rb +20 -5
  140. data/spec/unit/rom/schema/accessing_attributes_spec.rb +52 -0
  141. data/spec/unit/rom/schema/append_spec.rb +17 -0
  142. data/spec/unit/rom/schema/exclude_spec.rb +15 -0
  143. data/spec/unit/rom/schema/finalize_spec.rb +59 -0
  144. data/spec/unit/rom/schema/key_predicate_spec.rb +15 -0
  145. data/spec/unit/rom/schema/merge_spec.rb +17 -0
  146. data/spec/unit/rom/schema/prefix_spec.rb +16 -0
  147. data/spec/unit/rom/schema/project_spec.rb +15 -0
  148. data/spec/unit/rom/schema/rename_spec.rb +22 -0
  149. data/spec/unit/rom/schema/type_spec.rb +49 -0
  150. data/spec/unit/rom/schema/uniq_spec.rb +21 -0
  151. data/spec/unit/rom/schema/wrap_spec.rb +17 -0
  152. data/spec/unit/rom/schema_spec.rb +2 -2
  153. metadata +79 -17
  154. data/lib/rom/plugins/relation/view/dsl.rb +0 -32
  155. data/lib/rom/plugins/relation/view.rb +0 -95
  156. data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
data/lib/rom/schema.rb CHANGED
@@ -1,16 +1,43 @@
1
1
  require 'dry-equalizer'
2
2
 
3
- require 'rom/support/constants'
3
+ require 'rom/schema/attribute'
4
4
  require 'rom/schema/dsl'
5
5
  require 'rom/association_set'
6
6
 
7
7
  module ROM
8
8
  # Relation schema
9
9
  #
10
+ # Schemas hold detailed information about relation tuples, including their
11
+ # primitive types (String, Integer, Hash, etc. or custom classes), as well as
12
+ # various meta information like primary/foreign key and literally any other
13
+ # information that a given database adapter may need.
14
+ #
15
+ # Adapters can extend this class and it can be used in adapter-specific relations.
16
+ # In example rom-sql extends schema with Association DSL and many additional
17
+ # SQL-specific APIs in schema types.
18
+ #
19
+ # Schemas are used for projecting canonical relations into other relations and
20
+ # every relation object maintains its schema. This means that we always have
21
+ # all information about relation tuples, even when a relation was projected and
22
+ # diverged from its canonical form.
23
+ #
24
+ # Furthermore schema attributes know their source relations, which makes it
25
+ # possible to merge schemas from multiple relations and maintain information
26
+ # about the source relations. In example when two relations are joined, their
27
+ # schemas are merged, and we know which attributes belong to which relation.
28
+ #
10
29
  # @api public
11
30
  class Schema
12
31
  EMPTY_ASSOCIATION_SET = AssociationSet.new(EMPTY_HASH).freeze
13
32
 
33
+ DEFAULT_INFERRER = proc { [EMPTY_ARRAY, EMPTY_ARRAY].freeze }
34
+
35
+ MissingAttributesError = Class.new(StandardError) do
36
+ def initialize(name, attributes)
37
+ super("missing attributes in #{name.inspect} schema: #{attributes.map(&:inspect).join(', ')}")
38
+ end
39
+ end
40
+
14
41
  include Dry::Equalizer(:name, :attributes, :associations)
15
42
  include Enumerable
16
43
 
@@ -19,7 +46,7 @@ module ROM
19
46
  attr_reader :name
20
47
 
21
48
  # @!attribute [r] attributes
22
- # @return [Hash] The hash with schema attribute types
49
+ # @return [Array] Array with schema attributes
23
50
  attr_reader :attributes
24
51
 
25
52
  # @!attribute [r] associations
@@ -30,43 +57,246 @@ module ROM
30
57
  # @return [#call] An optional inferrer object used in `finalize!`
31
58
  attr_reader :inferrer
32
59
 
33
- # @!attribute [r] primary_key
34
- # @return [Array<Dry::Types::Definition] Primary key array
35
- attr_reader :primary_key
60
+ # @api private
61
+ attr_reader :options
62
+
63
+ # @api private
64
+ attr_reader :relations
36
65
 
37
- alias_method :to_h, :attributes
66
+ alias_method :to_ary, :attributes
67
+
68
+ # Define a relation schema from plain rom types
69
+ #
70
+ # Resulting schema will decorate plain rom types with adapter-specific types
71
+ # By default `Schema::Attribute` will be used
72
+ #
73
+ # @param [Relation::Name, Symbol] name The schema name, typically ROM::Relation::Name
74
+ #
75
+ # @return [Schema]
76
+ #
77
+ # @api public
78
+ def self.define(name, attr_class: Attribute, attributes: EMPTY_ARRAY, associations: EMPTY_ASSOCIATION_SET, inferrer: DEFAULT_INFERRER)
79
+ new(
80
+ name,
81
+ attributes: attributes(attributes, attr_class),
82
+ associations: associations,
83
+ inferrer: inferrer,
84
+ attr_class: attr_class
85
+ )
86
+ end
38
87
 
39
88
  # @api private
40
- def initialize(name, attributes, inferrer: nil, associations: EMPTY_ASSOCIATION_SET)
89
+ def self.attributes(attributes, attr_class)
90
+ attributes.map { |type| attr_class.new(type) }
91
+ end
92
+
93
+ # @api private
94
+ def initialize(name, options)
41
95
  @name = name
42
- @attributes = attributes
43
- @associations = associations
44
- @inferrer = inferrer
96
+ @options = options
97
+ @attributes = options[:attributes] || EMPTY_ARRAY
98
+ @associations = options[:associations]
99
+ @inferrer = options[:inferrer] || DEFAULT_INFERRER
100
+ @relations = options[:relations] || EMPTY_HASH
101
+ end
102
+
103
+ # Abstract method for creating a new relation based on schema definition
104
+ #
105
+ # This can be used by views to generate a new relation automatically.
106
+ # In example a schema can project a relation, join any additional relations
107
+ # if it uncludes attributes from other relations etc.
108
+ #
109
+ # Default implementation is a no-op and it simply returns back untouched relation
110
+ #
111
+ # @param [Relation]
112
+ #
113
+ # @return [Relation]
114
+ #
115
+ # @api public
116
+ def call(relation)
117
+ relation
45
118
  end
46
119
 
47
120
  # Iterate over schema's attributes
48
121
  #
49
- # @yield [Dry::Data::Type]
122
+ # @yield [Schema::Attribute]
50
123
  #
51
124
  # @api public
52
125
  def each(&block)
53
- attributes.each_value(&block)
126
+ attributes.each(&block)
127
+ end
128
+
129
+ # Check if schema has any attributes
130
+ #
131
+ # @return [TrueClass, FalseClass]
132
+ #
133
+ # @api public
134
+ def empty?
135
+ attributes.size == 0
136
+ end
137
+
138
+ # Coerce schema into a <AttributeName=>Attribute> Hash
139
+ #
140
+ # @return [Hash]
141
+ #
142
+ # @api public
143
+ def to_h
144
+ each_with_object({}) { |attr, h| h[attr.name] = attr }
54
145
  end
55
146
 
56
147
  # Return attribute
57
148
  #
149
+ # @param [Symbol] key The attribute name
150
+ # @param [Symbol, Relation::Name] src The source relation (for merged schemas)
151
+ #
152
+ # @raise KeyError
153
+ #
154
+ # @api public
155
+ def [](key, src = name.to_sym)
156
+ attr =
157
+ if count_index[key].equal?(1)
158
+ name_index[key]
159
+ else
160
+ source_index[src][key]
161
+ end
162
+
163
+ unless attr
164
+ raise(KeyError, "#{key.inspect} attribute doesn't exist in #{src} schema")
165
+ end
166
+
167
+ attr
168
+ end
169
+
170
+ # Project a schema to include only specified attributes
171
+ #
172
+ # @param [*Array<Symbol, Schema::Attribute>] names Attribute names
173
+ #
174
+ # @return [Schema]
175
+ #
176
+ # @api public
177
+ def project(*names)
178
+ new(names.map { |name| name.is_a?(Symbol) ? self[name] : name })
179
+ end
180
+
181
+ # Exclude provided attributes from a schema
182
+ #
183
+ # @param [*Array] names Attribute names
184
+ #
185
+ # @return [Schema]
186
+ #
187
+ # @api public
188
+ def exclude(*names)
189
+ project(*(map(&:name) - names))
190
+ end
191
+
192
+ # Project a schema with renamed attributes
193
+ #
194
+ # @param [Hash] mapping The attribute mappings
195
+ #
196
+ # @return [Schema]
197
+ #
198
+ # @api public
199
+ def rename(mapping)
200
+ new_attributes = map do |attr|
201
+ alias_name = mapping[attr.name]
202
+ alias_name ? attr.aliased(alias_name) : attr
203
+ end
204
+
205
+ new(new_attributes)
206
+ end
207
+
208
+ # Project a schema with renamed attributes using provided prefix
209
+ #
210
+ # @param [Symbol] prefix The name of the prefix
211
+ #
212
+ # @return [Schema]
213
+ #
214
+ # @api public
215
+ def prefix(prefix)
216
+ new(map { |attr| attr.prefixed(prefix) })
217
+ end
218
+
219
+ # Return new schema with all attributes marked as prefixed and wrapped
220
+ #
221
+ # This is useful when relations are joined and the right side should be marked
222
+ # as wrapped
223
+ #
224
+ # @param [Symbol] prefix The prefix used for aliasing wrapped attributes
225
+ #
226
+ # @return [Schema]
227
+ #
58
228
  # @api public
59
- def [](name)
60
- attributes.fetch(name)
229
+ def wrap(prefix = name.dataset)
230
+ new(map { |attr| attr.wrapped(prefix) })
61
231
  end
62
232
 
63
233
  # Return FK attribute for a given relation name
64
234
  #
65
- # @return [Dry::Types::Definition]
235
+ # @return [Schema::Attribute]
66
236
  #
67
237
  # @api public
68
238
  def foreign_key(relation)
69
- detect { |attr| attr.meta[:foreign_key] && attr.meta[:relation] == relation }
239
+ detect { |attr| attr.foreign_key? && attr.target == relation }
240
+ end
241
+
242
+ # Return primary key attributes
243
+ #
244
+ # @return [Array<Schema::Attribute>]
245
+ #
246
+ # @api public
247
+ def primary_key
248
+ select(&:primary_key?)
249
+ end
250
+
251
+ # Merge with another schema
252
+ #
253
+ # @param [Schema] other Other schema
254
+ #
255
+ # @return [Schema]
256
+ #
257
+ # @api public
258
+ def merge(other)
259
+ append(*other)
260
+ end
261
+ alias_method :+, :merge
262
+
263
+ # Append more attributes to the schema
264
+ #
265
+ # This returns a new schema instance
266
+ #
267
+ # @param [*Array<Schema::Attribute>]
268
+ #
269
+ # @return [Schema]
270
+ #
271
+ # @api public
272
+ def append(*new_attributes)
273
+ new(attributes + new_attributes)
274
+ end
275
+
276
+ # Return a new schema with uniq attributes
277
+ #
278
+ # @param [*Array<Schema::Attribute>]
279
+ #
280
+ # @return [Schema]
281
+ #
282
+ # @api public
283
+ def uniq(&block)
284
+ if block
285
+ new(attributes.uniq(&block))
286
+ else
287
+ new(attributes.uniq(&:name))
288
+ end
289
+ end
290
+
291
+ # Return if a schema includes an attribute with the given name
292
+ #
293
+ # @param [Symbol] name The name of the attribute
294
+ #
295
+ # @return [Boolean]
296
+ #
297
+ # @api public
298
+ def key?(name)
299
+ ! attributes.detect { |attr| attr.name == name }.nil?
70
300
  end
71
301
 
72
302
  # This hook is called when relation is being build during container finalization
@@ -77,13 +307,101 @@ module ROM
77
307
  # @return [self]
78
308
  #
79
309
  # @api private
80
- def finalize!(gateway = nil, &block)
310
+ def finalize!(gateway: nil, relations: nil, &block)
81
311
  return self if frozen?
82
312
 
83
- @attributes = inferrer.call(name.dataset, gateway) if inferrer
84
- @primary_key = select { |attr| attr.meta[:primary_key] == true }
313
+ inferred, missing = inferrer.call(name, gateway)
314
+
315
+ attr_names = map(&:name)
316
+ inferred_attrs = self.class.attributes(inferred, attr_class).
317
+ reject { |attr| attr_names.include?(attr.name) }
318
+
319
+ attributes.concat(inferred_attrs)
320
+
321
+ missing_attributes = missing - map(&:name)
322
+
323
+ if missing_attributes.size > 0
324
+ raise MissingAttributesError.new(name, missing_attributes)
325
+ end
326
+
85
327
  block.call if block
328
+
329
+ count_index
330
+ name_index
331
+ source_index
332
+
86
333
  freeze
87
334
  end
335
+
336
+ # Return coercion function using attribute read types
337
+ #
338
+ # This is used for `output_schema` in relations
339
+ #
340
+ # @return [Dry::Types::Hash]
341
+ #
342
+ # @api private
343
+ def to_output_hash
344
+ Types::Coercible::Hash.schema(
345
+ map { |attr| [attr.name, attr.to_read_type] }.to_h
346
+ )
347
+ end
348
+
349
+ # Return coercion function using attribute types
350
+ #
351
+ # This is used for `input_schema` in relations, typically commands use it
352
+ # for processing input
353
+ #
354
+ # @return [Dry::Types::Hash]
355
+ #
356
+ # @api private
357
+ def to_input_hash
358
+ Types::Coercible::Hash.schema(
359
+ map { |attr| [attr.name, attr] }.to_h
360
+ )
361
+ end
362
+
363
+ # Return a new schema with new options
364
+ #
365
+ # @example
366
+ # schema.with(inferrer: my_inferrer)
367
+ #
368
+ # @param [Hash] new_options
369
+ #
370
+ # @return [Schema]
371
+ #
372
+ # @api public
373
+ def with(new_options)
374
+ self.class.new(name, options.merge(new_options))
375
+ end
376
+
377
+ private
378
+
379
+ # @api private
380
+ def count_index
381
+ @count_index ||= map(&:name).map { |name| [name, count { |attr| attr.name == name }] }.to_h
382
+ end
383
+
384
+ # @api private
385
+ def name_index
386
+ @name_index ||= map { |attr| [attr.name, attr] }.to_h
387
+ end
388
+
389
+ # @api private
390
+ def source_index
391
+ @source_index ||= select(&:source).
392
+ group_by(&:source).
393
+ map { |src, grp| [src.to_sym, grp.map { |attr| [attr.name, attr] }.to_h] }.
394
+ to_h
395
+ end
396
+
397
+ # @api private
398
+ def attr_class
399
+ options.fetch(:attr_class)
400
+ end
401
+
402
+ # @api private
403
+ def new(attributes)
404
+ self.class.new(name, options.merge(attributes: attributes))
405
+ end
88
406
  end
89
407
  end
@@ -1,34 +1,37 @@
1
1
  require 'pathname'
2
2
 
3
- require 'rom/support/constants'
4
- require 'rom/support/inflector'
5
- require 'rom/support/options'
3
+ require 'dry/core/inflector'
6
4
 
5
+ require 'rom/types'
6
+ require 'rom/initializer'
7
7
  require 'rom/setup/auto_registration_strategies/no_namespace'
8
8
  require 'rom/setup/auto_registration_strategies/with_namespace'
9
9
  require 'rom/setup/auto_registration_strategies/custom_namespace'
10
10
 
11
11
  module ROM
12
12
  class AutoRegistration
13
- include Options
13
+ extend Initializer
14
14
 
15
- option :namespace, reader: true, type: [TrueClass, FalseClass, String], default: true
15
+ NamespaceType = Types::Strict::Bool | Types::Strict::String
16
+ PathnameType = Types.Constructor(Pathname, &Kernel.method(:Pathname))
16
17
 
17
- option :component_dirs, reader: true, type: ::Hash, default: {
18
+ param :directory, type: PathnameType
19
+
20
+ option :namespace, reader: true, type: NamespaceType, default: proc { true }
21
+
22
+ option :component_dirs, reader: true, type: Types::Strict::Hash, default: proc { {
18
23
  relations: :relations,
19
24
  mappers: :mappers,
20
25
  commands: :commands
21
- }
26
+ } }
22
27
 
23
- attr_reader :globs, :directory
24
-
25
- def initialize(directory, options = EMPTY_HASH)
26
- super
27
- @directory = Pathname(directory)
28
- @globs = Hash[component_dirs.map { |component, directory|
29
- [component, @directory.join("#{directory}/**/*.rb")]
30
- }]
31
- end
28
+ option :globs, reader: true, default: -> r {
29
+ Hash[
30
+ component_dirs.map { |component, directory|
31
+ [component, r.directory.join("#{directory}/**/*.rb")]
32
+ }
33
+ ]
34
+ }
32
35
 
33
36
  def relations
34
37
  load_entities(:relations)
@@ -62,7 +65,7 @@ module ROM
62
65
  file: file, directory: directory, entity: component_dirs.fetch(entity)
63
66
  ).call
64
67
  end
65
- Inflector.constantize(klass_name)
68
+ Dry::Core::Inflector.constantize(klass_name)
66
69
  end
67
70
  end
68
71
  end
@@ -1,11 +1,16 @@
1
+ require 'rom/types'
2
+ require 'rom/initializer'
3
+
1
4
  module ROM
2
5
  module AutoRegistrationStrategies
3
6
  class Base
4
- include Options
7
+ extend Initializer
8
+
9
+ PathnameType = Types.Definition(Pathname).constrained(type: Pathname)
5
10
 
6
- option :file, reader: true, type: String
11
+ option :file, reader: true, type: Types::Strict::String
7
12
 
8
- EXTENSION_REGEX = /\.rb$/.freeze
13
+ EXTENSION_REGEX = /\.rb\z/.freeze
9
14
  end
10
15
  end
11
16
  end
@@ -1,15 +1,16 @@
1
1
  require 'pathname'
2
2
 
3
- require 'rom/support/inflector'
3
+ require 'dry/core/inflector'
4
+ require 'rom/types'
4
5
  require 'rom/setup/auto_registration_strategies/base'
5
6
 
6
7
  module ROM
7
8
  module AutoRegistrationStrategies
8
9
  class CustomNamespace < Base
9
- option :namespace, reader: true, type: String
10
+ option :namespace, reader: true, type: Types::Strict::String
10
11
 
11
12
  def call
12
- "#{namespace}::#{Inflector.camelize(filename)}"
13
+ "#{namespace}::#{Dry::Core::Inflector.camelize(filename)}"
13
14
  end
14
15
 
15
16
  private
@@ -1,16 +1,17 @@
1
1
  require 'pathname'
2
2
 
3
- require 'rom/support/inflector'
3
+ require 'dry/core/inflector'
4
+ require 'rom/types'
4
5
  require 'rom/setup/auto_registration_strategies/base'
5
6
 
6
7
  module ROM
7
8
  module AutoRegistrationStrategies
8
9
  class NoNamespace < Base
9
- option :directory, reader: true, type: Pathname
10
- option :entity, reader: true, type: Symbol
10
+ option :directory, reader: true, type: PathnameType
11
+ option :entity, reader: true, type: Types::Strict::Symbol
11
12
 
12
13
  def call
13
- Inflector.camelize(
14
+ Dry::Core::Inflector.camelize(
14
15
  file.sub(/^#{directory}\/#{entity}\//, '').sub(EXTENSION_REGEX, '')
15
16
  )
16
17
  end
@@ -1,15 +1,15 @@
1
1
  require 'pathname'
2
2
 
3
- require 'rom/support/inflector'
3
+ require 'dry/core/inflector'
4
4
  require 'rom/setup/auto_registration_strategies/base'
5
5
 
6
6
  module ROM
7
7
  module AutoRegistrationStrategies
8
8
  class WithNamespace < Base
9
- option :directory, reader: true, type: Pathname
9
+ option :directory, reader: true, type: PathnameType
10
10
 
11
11
  def call
12
- Inflector.camelize(
12
+ Dry::Core::Inflector.camelize(
13
13
  file.sub(/^#{directory.dirname}\//, '').sub(EXTENSION_REGEX, '')
14
14
  )
15
15
  end
@@ -1,4 +1,4 @@
1
- require 'rom/support/registry'
1
+ require 'rom/registry'
2
2
  require 'rom/command_registry'
3
3
 
4
4
  module ROM
@@ -1,4 +1,4 @@
1
- require 'rom/support/registry'
1
+ require 'rom/registry'
2
2
 
3
3
  module ROM
4
4
  class Finalize
@@ -50,10 +50,12 @@ module ROM
50
50
  gateway = @gateways.fetch(klass.gateway)
51
51
  ds_proc = klass.dataset_proc || -> _ { self }
52
52
 
53
- klass.schema.finalize!(gateway) if klass.schema
53
+ klass.schema(infer: true) unless klass.schema
54
+ schema = klass.schema.finalize!(gateway: gateway, relations: registry)
55
+
54
56
  dataset = gateway.dataset(klass.dataset).instance_exec(klass, &ds_proc)
55
57
 
56
- klass.new(dataset, __registry__: registry)
58
+ klass.new(dataset, __registry__: registry, schema: schema.with(relations: registry))
57
59
  end
58
60
  end
59
61
  end
@@ -1,7 +1,7 @@
1
1
  require 'rom/relation'
2
2
  require 'rom/command'
3
3
 
4
- require 'rom/support/registry'
4
+ require 'rom/registry'
5
5
  require 'rom/command_registry'
6
6
  require 'rom/mapper_registry'
7
7
 
@@ -0,0 +1,24 @@
1
+ module ROM
2
+ # @api private
3
+ class Transaction
4
+ # @api private
5
+ Rollback = Class.new(StandardError)
6
+
7
+ # @api private
8
+ def run(opts = EMPTY_HASH)
9
+ yield(self)
10
+ rescue Rollback
11
+ # noop
12
+ end
13
+
14
+ # Unconditionally roll back the current transaction
15
+ #
16
+ # @api public
17
+ def rollback!
18
+ raise Rollback
19
+ end
20
+
21
+ # @api private
22
+ NoOp = Transaction.new.freeze
23
+ end
24
+ end
data/lib/rom/types.rb CHANGED
@@ -9,9 +9,17 @@ module ROM
9
9
  super
10
10
  end
11
11
 
12
+ def self.Definition(primitive)
13
+ Dry::Types::Definition.new(primitive)
14
+ end
15
+
16
+ def self.Constructor(primitive, &block)
17
+ Types.Definition(primitive).constructor(&block)
18
+ end
19
+
12
20
  module Methods
13
21
  def ForeignKey(relation, type = Types::Int)
14
- type.meta(foreign_key: true, relation: relation)
22
+ type.meta(foreign_key: true, target: relation)
15
23
  end
16
24
  end
17
25
  end
data/lib/rom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '2.0.2'.freeze
2
+ VERSION = '3.0.0'.freeze
3
3
  end
data/lib/rom.rb CHANGED
@@ -1,16 +1,12 @@
1
1
  require 'dry-equalizer'
2
+ require 'dry/core/constants'
2
3
 
3
- require 'rom-support'
4
4
  require 'rom/version'
5
5
  require 'rom/constants'
6
6
 
7
- # internal ROM support lib
8
- require 'rom/support/inflector'
9
- require 'rom/support/registry'
10
- require 'rom/support/options'
11
- require 'rom/support/class_macros'
12
- require 'rom/support/class_builder'
13
- require 'rom/support/inheritance_hook'
7
+ module ROM
8
+ include Dry::Core::Constants
9
+ end
14
10
 
15
11
  # core parts
16
12
  require 'rom/configuration_plugin'
data/rom.gemspec CHANGED
@@ -17,10 +17,11 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
19
19
  gem.add_runtime_dependency 'dry-equalizer', '~> 0.2'
20
- gem.add_runtime_dependency 'dry-types', '~> 0.8'
21
- gem.add_runtime_dependency 'rom-support', '~> 2.0'
22
- gem.add_runtime_dependency 'rom-mapper', '~> 0.4.0'
20
+ gem.add_runtime_dependency 'dry-types', '~> 0.9', '>= 0.9.4'
21
+ gem.add_runtime_dependency 'dry-core', '~> 0.2', '>= 0.2.3'
22
+ gem.add_runtime_dependency 'dry-initializer', '~> 0.10', '>= 0.10.2'
23
+ gem.add_runtime_dependency 'rom-mapper', '~> 0.5'
23
24
 
24
25
  gem.add_development_dependency 'rake', '~> 10.3'
25
- gem.add_development_dependency 'rspec', '~> 3.3'
26
+ gem.add_development_dependency 'rspec', '~> 3.5'
26
27
  end