rom 2.0.2 → 3.0.0.beta1
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/CHANGELOG.md +34 -1
- data/Gemfile +16 -2
- data/Rakefile +7 -2
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +11 -5
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/command.rb +70 -41
- data/lib/rom/command_registry.rb +7 -18
- data/lib/rom/commands/class_interface.rb +7 -6
- data/lib/rom/commands/composite.rb +0 -1
- data/lib/rom/commands/graph.rb +7 -15
- data/lib/rom/commands/lazy/update.rb +1 -1
- data/lib/rom/configuration_dsl/command.rb +6 -8
- data/lib/rom/configuration_dsl/mapper.rb +2 -3
- data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -1
- data/lib/rom/configuration_dsl/relation.rb +4 -4
- data/lib/rom/configuration_dsl.rb +0 -4
- data/lib/rom/constants.rb +1 -1
- data/lib/rom/container.rb +0 -2
- data/lib/rom/create_container.rb +0 -2
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/gateway.rb +23 -6
- data/lib/rom/global/plugin_dsl.rb +0 -2
- data/lib/rom/global.rb +0 -2
- data/lib/rom/initializer.rb +26 -0
- data/lib/rom/lint/gateway.rb +17 -0
- data/lib/rom/mapper_registry.rb +1 -1
- data/lib/rom/memory/commands.rb +0 -2
- data/lib/rom/memory/dataset.rb +1 -2
- data/lib/rom/memory/relation.rb +14 -1
- data/lib/rom/memory/schema.rb +13 -0
- data/lib/rom/plugin_registry.rb +1 -1
- data/lib/rom/plugins/configuration/configuration_dsl.rb +6 -2
- data/lib/rom/plugins/relation/key_inference.rb +4 -2
- data/lib/rom/plugins/relation/registry_reader.rb +5 -1
- data/lib/rom/registry.rb +50 -0
- data/lib/rom/relation/class_interface.rb +94 -26
- data/lib/rom/relation/curried.rb +15 -15
- data/lib/rom/relation/view_dsl.rb +31 -0
- data/lib/rom/relation.rb +49 -34
- data/lib/rom/schema/dsl.rb +7 -9
- data/lib/rom/schema/type.rb +115 -0
- data/lib/rom/schema.rb +218 -18
- data/lib/rom/setup/auto_registration.rb +20 -17
- data/lib/rom/setup/auto_registration_strategies/base.rb +8 -3
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +4 -3
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +5 -4
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +3 -3
- data/lib/rom/setup/finalize/finalize_commands.rb +1 -1
- data/lib/rom/setup/finalize/finalize_mappers.rb +1 -1
- data/lib/rom/setup/finalize/finalize_relations.rb +3 -1
- data/lib/rom/setup/finalize.rb +1 -1
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +9 -1
- data/lib/rom/version.rb +1 -1
- data/lib/rom.rb +4 -8
- data/rom.gemspec +4 -3
- data/spec/integration/command_registry_spec.rb +1 -14
- data/spec/integration/commands/create_spec.rb +5 -25
- data/spec/integration/commands/delete_spec.rb +1 -1
- data/spec/integration/commands/error_handling_spec.rb +1 -1
- data/spec/integration/commands/graph_spec.rb +20 -14
- data/spec/integration/commands/update_spec.rb +4 -27
- data/spec/integration/commands_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/extending_relations_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/setting_logger_spec.rb +2 -2
- data/spec/integration/mappers/combine_spec.rb +1 -1
- data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
- data/spec/integration/mappers/definition_dsl_spec.rb +1 -1
- data/spec/integration/mappers/embedded_spec.rb +1 -1
- data/spec/integration/mappers/exclude_spec.rb +1 -1
- data/spec/integration/mappers/fold_spec.rb +1 -1
- data/spec/integration/mappers/group_spec.rb +1 -1
- data/spec/integration/mappers/overwrite_attributes_value_spec.rb +1 -1
- data/spec/integration/mappers/prefix_separator_spec.rb +1 -1
- data/spec/integration/mappers/prefix_spec.rb +1 -1
- data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/registering_custom_mappers_spec.rb +1 -1
- data/spec/integration/mappers/renaming_attributes_spec.rb +1 -1
- data/spec/integration/mappers/reusing_mappers_spec.rb +1 -1
- data/spec/integration/mappers/step_spec.rb +1 -1
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/unfold_spec.rb +1 -1
- data/spec/integration/mappers/ungroup_spec.rb +1 -1
- data/spec/integration/mappers/unwrap_spec.rb +2 -2
- data/spec/integration/mappers/wrap_spec.rb +1 -1
- data/spec/integration/memory/commands/create_spec.rb +1 -1
- data/spec/integration/memory/commands/delete_spec.rb +1 -1
- data/spec/integration/memory/commands/update_spec.rb +1 -1
- data/spec/integration/multi_env_spec.rb +1 -1
- data/spec/integration/multi_repo_spec.rb +1 -1
- data/spec/integration/relations/default_dataset_spec.rb +1 -1
- data/spec/integration/relations/reading_spec.rb +1 -1
- data/spec/integration/relations/registry_dsl_spec.rb +1 -1
- data/spec/integration/setup_spec.rb +10 -4
- data/spec/shared/command_graph.rb +8 -4
- data/spec/shared/enumerable_dataset.rb +1 -1
- data/spec/spec_helper.rb +7 -9
- data/spec/support/schema.rb +14 -0
- data/spec/unit/rom/array_dataset_spec.rb +59 -0
- data/spec/unit/rom/association_set_spec.rb +4 -0
- data/spec/unit/rom/auto_curry_spec.rb +63 -0
- data/spec/unit/rom/commands/graph_spec.rb +12 -11
- data/spec/unit/rom/commands/lazy_spec.rb +8 -5
- data/spec/unit/rom/commands/pre_and_post_processors_spec.rb +269 -0
- data/spec/unit/rom/commands/result_spec.rb +1 -1
- data/spec/unit/rom/commands_spec.rb +9 -3
- data/spec/unit/rom/configuration_spec.rb +1 -1
- data/spec/unit/rom/container_spec.rb +11 -5
- data/spec/unit/rom/create_container_spec.rb +1 -1
- data/spec/unit/rom/enumerable_dataset_spec.rb +15 -0
- data/spec/unit/rom/gateway_spec.rb +1 -1
- data/spec/unit/rom/mapper_registry_spec.rb +1 -1
- data/spec/unit/rom/memory/commands_spec.rb +1 -1
- data/spec/unit/rom/memory/dataset_spec.rb +1 -1
- data/spec/unit/rom/memory/{repository_spec.rb → gateway_spec.rb} +1 -1
- data/spec/unit/rom/memory/inheritance_spec.rb +32 -0
- data/spec/unit/rom/memory/relation_spec.rb +15 -3
- data/spec/unit/rom/memory/storage_spec.rb +1 -1
- data/spec/unit/rom/plugin_spec.rb +1 -1
- data/spec/unit/rom/plugins/relation/key_inference_spec.rb +1 -1
- data/spec/unit/rom/registry_spec.rb +86 -0
- data/spec/unit/rom/relation/attribute_reader_spec.rb +17 -0
- data/spec/unit/rom/relation/composite_spec.rb +1 -1
- data/spec/unit/rom/relation/graph_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy/combine_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy_spec.rb +1 -1
- data/spec/unit/rom/relation/loaded_spec.rb +1 -1
- data/spec/unit/rom/relation/schema_spec.rb +10 -6
- data/spec/unit/rom/relation/view_spec.rb +112 -0
- data/spec/unit/rom/relation_spec.rb +16 -2
- data/spec/unit/rom/schema/accessing_attributes_spec.rb +52 -0
- data/spec/unit/rom/schema/exclude_spec.rb +15 -0
- data/spec/unit/rom/schema/finalize_spec.rb +59 -0
- data/spec/unit/rom/schema/key_predicate_spec.rb +15 -0
- data/spec/unit/rom/schema/merge_spec.rb +17 -0
- data/spec/unit/rom/schema/prefix_spec.rb +16 -0
- data/spec/unit/rom/schema/project_spec.rb +15 -0
- data/spec/unit/rom/schema/rename_spec.rb +22 -0
- data/spec/unit/rom/schema/type_spec.rb +49 -0
- data/spec/unit/rom/schema/wrap_spec.rb +17 -0
- data/spec/unit/rom/schema_spec.rb +2 -2
- metadata +69 -17
- data/lib/rom/plugins/relation/view/dsl.rb +0 -32
- data/lib/rom/plugins/relation/view.rb +0 -95
- data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
@@ -1,13 +1,20 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'dry/core/inflector'
|
4
|
+
require 'dry/core/constants'
|
5
|
+
require 'dry/core/class_attributes'
|
6
|
+
|
7
|
+
require 'rom/auto_curry'
|
4
8
|
require 'rom/relation/curried'
|
5
9
|
require 'rom/relation/name'
|
10
|
+
require 'rom/relation/view_dsl'
|
6
11
|
require 'rom/schema'
|
7
12
|
|
8
13
|
module ROM
|
9
14
|
class Relation
|
10
15
|
module ClassInterface
|
16
|
+
include Dry::Core::Constants
|
17
|
+
|
11
18
|
# Register adapter relation subclasses during setup phase
|
12
19
|
#
|
13
20
|
# In adition those subclasses are extended with an interface for accessing
|
@@ -17,14 +24,14 @@ module ROM
|
|
17
24
|
def inherited(klass)
|
18
25
|
super
|
19
26
|
|
20
|
-
klass.extend ClassMacros
|
21
|
-
klass.defines :adapter
|
22
|
-
|
23
27
|
if respond_to?(:adapter) && adapter.nil?
|
24
28
|
raise MissingAdapterIdentifierError,
|
25
|
-
|
29
|
+
"relation class +#{self}+ is missing the adapter identifier"
|
26
30
|
end
|
27
31
|
|
32
|
+
klass.extend Dry::Core::ClassAttributes
|
33
|
+
klass.defines :adapter, :schema_class
|
34
|
+
|
28
35
|
# Extend with functionality required by adapters *only* if this is a direct
|
29
36
|
# descendant of an adapter-specific relation subclass
|
30
37
|
return unless respond_to?(:adapter) && klass.superclass == ROM::Relation[adapter]
|
@@ -32,22 +39,30 @@ module ROM
|
|
32
39
|
klass.class_eval do
|
33
40
|
use :registry_reader
|
34
41
|
|
35
|
-
defines :gateway, :dataset, :dataset_proc, :register_as,
|
42
|
+
defines :gateway, :dataset, :dataset_proc, :register_as,
|
43
|
+
:schema_dsl, :schema_inferrer
|
36
44
|
|
37
45
|
gateway :default
|
38
46
|
schema_dsl Schema::DSL
|
47
|
+
schema_class Schema
|
39
48
|
schema_inferrer nil
|
40
49
|
|
41
50
|
dataset default_name
|
42
51
|
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
# skip defining :name option if it's a class that already has this method
|
53
|
+
# which can happen when an adapter's relation class inherits from another
|
54
|
+
# adapter's relation class (ie YAML::Relation < Memory::Relation)
|
55
|
+
unless instance_methods.include?(:name)
|
56
|
+
# Relation's dataset name
|
57
|
+
#
|
58
|
+
# In example a table name in an SQL database
|
59
|
+
#
|
60
|
+
# @return [Symbol]
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
option :name, reader: true, optional: true,
|
64
|
+
default: -> r { Name.new(r.class.register_as, r.class.dataset) }
|
65
|
+
end
|
51
66
|
|
52
67
|
# Set dataset name
|
53
68
|
#
|
@@ -95,12 +110,6 @@ module ROM
|
|
95
110
|
end
|
96
111
|
end
|
97
112
|
|
98
|
-
# @api private
|
99
|
-
def initialize(dataset, options = EMPTY_HASH)
|
100
|
-
@name = Name.new(self.class.register_as, self.class.dataset)
|
101
|
-
super
|
102
|
-
end
|
103
|
-
|
104
113
|
# Return name of the source gateway of this relation
|
105
114
|
#
|
106
115
|
# @return [Symbol]
|
@@ -160,12 +169,62 @@ module ROM
|
|
160
169
|
|
161
170
|
name = Name[register_as, self.dataset]
|
162
171
|
inferrer = infer ? schema_inferrer : nil
|
163
|
-
dsl = schema_dsl.new(name, inferrer, &block)
|
172
|
+
dsl = schema_dsl.new(name, schema_class: schema_class, inferrer: inferrer, &block)
|
164
173
|
|
165
174
|
@schema = dsl.call
|
166
175
|
end
|
167
176
|
end
|
168
177
|
|
178
|
+
# Define a relation view with a specific header
|
179
|
+
#
|
180
|
+
# With headers defined all the mappers will be inferred automatically
|
181
|
+
#
|
182
|
+
# @example
|
183
|
+
# class Users < ROM::Relation[:sql]
|
184
|
+
# view(:by_name, [:id, :name]) do |name|
|
185
|
+
# where(name: name)
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# view(:listing, [:id, :name, :email]) do
|
189
|
+
# select(:id, :name, :email).order(:name)
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# @api public
|
194
|
+
def view(*args, &block)
|
195
|
+
if args.size == 1 && block.arity > 0
|
196
|
+
raise ArgumentError, "header must be set as second argument"
|
197
|
+
end
|
198
|
+
|
199
|
+
name, new_schema_fn, relation_block =
|
200
|
+
if args.size == 1
|
201
|
+
ViewDSL.new(*args, schema, &block).call
|
202
|
+
else
|
203
|
+
[*args, block]
|
204
|
+
end
|
205
|
+
|
206
|
+
schemas[name] =
|
207
|
+
if args.size == 2
|
208
|
+
schema.project(*args[1])
|
209
|
+
else
|
210
|
+
new_schema_fn
|
211
|
+
end
|
212
|
+
|
213
|
+
if relation_block.arity > 0
|
214
|
+
auto_curry_guard do
|
215
|
+
define_method(name, &relation_block)
|
216
|
+
|
217
|
+
auto_curry(name) do
|
218
|
+
schemas[name].(self)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
else
|
222
|
+
define_method(name) do
|
223
|
+
schemas[name].(instance_exec(&relation_block))
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
169
228
|
# Dynamically define a method that will forward to the dataset and wrap
|
170
229
|
# response in the relation itself
|
171
230
|
#
|
@@ -179,7 +238,7 @@ module ROM
|
|
179
238
|
methods.each do |method|
|
180
239
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
181
240
|
def #{method}(*args, &block)
|
182
|
-
|
241
|
+
new(dataset.__send__(:#{method}, *args, &block))
|
183
242
|
end
|
184
243
|
RUBY
|
185
244
|
end
|
@@ -203,7 +262,7 @@ module ROM
|
|
203
262
|
# @api private
|
204
263
|
def default_name
|
205
264
|
return unless name
|
206
|
-
Inflector.underscore(name).tr('/', '_').to_sym
|
265
|
+
Dry::Core::Inflector.underscore(name).tr('/', '_').to_sym
|
207
266
|
end
|
208
267
|
|
209
268
|
# @api private
|
@@ -214,16 +273,25 @@ module ROM
|
|
214
273
|
# @api private
|
215
274
|
def view_methods
|
216
275
|
ancestor_methods = ancestors.reject { |klass| klass == self }
|
217
|
-
.map(&:instance_methods).flatten
|
276
|
+
.map(&:instance_methods).flatten(1)
|
218
277
|
|
219
278
|
instance_methods - ancestor_methods + auto_curried_methods
|
220
279
|
end
|
221
280
|
|
281
|
+
# @api private
|
282
|
+
def schemas
|
283
|
+
@schemas ||= {}
|
284
|
+
end
|
285
|
+
|
222
286
|
# Hook to finalize a relation after its instance was created
|
223
287
|
#
|
224
288
|
# @api private
|
225
|
-
def finalize(_container,
|
226
|
-
|
289
|
+
def finalize(_container, relation)
|
290
|
+
schemas = relation.schemas.reduce({}) do |h, (a, e)|
|
291
|
+
h.update(a => e.is_a?(Proc) ? instance_exec(&e) : e)
|
292
|
+
end
|
293
|
+
relation.schemas.update(schemas)
|
294
|
+
relation
|
227
295
|
end
|
228
296
|
end
|
229
297
|
end
|
data/lib/rom/relation/curried.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'rom/
|
2
|
-
|
1
|
+
require 'rom/types'
|
2
|
+
require 'rom/initializer'
|
3
3
|
require 'rom/pipeline'
|
4
4
|
require 'rom/relation/name'
|
5
5
|
require 'rom/relation/materializable'
|
@@ -7,23 +7,23 @@ require 'rom/relation/materializable'
|
|
7
7
|
module ROM
|
8
8
|
class Relation
|
9
9
|
class Curried
|
10
|
-
|
10
|
+
extend Initializer
|
11
11
|
include Materializable
|
12
12
|
include Pipeline
|
13
13
|
|
14
|
-
|
15
|
-
option :arity, type: Integer, reader: true, default: -1
|
16
|
-
option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
|
17
|
-
|
18
|
-
attr_reader :relation
|
14
|
+
param :relation
|
19
15
|
|
20
|
-
|
16
|
+
option :name, optional: true, type: Types::Strict::Symbol
|
17
|
+
option :arity, type: Types::Strict::Int, reader: true, default: proc { -1 }
|
18
|
+
option :curry_args, reader: true, default: proc { EMPTY_ARRAY }
|
21
19
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
# Relation name
|
21
|
+
#
|
22
|
+
# @return [ROM::Relation::Name]
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
def name
|
26
|
+
@name == Dry::Initializer::UNDEFINED ? relation.name : relation.name.with(@name)
|
27
27
|
end
|
28
28
|
|
29
29
|
# Load relation if args match the arity
|
@@ -75,7 +75,7 @@ module ROM
|
|
75
75
|
|
76
76
|
# @api private
|
77
77
|
def __new__(relation, new_opts = EMPTY_HASH)
|
78
|
-
|
78
|
+
self.class.new(relation, new_opts.empty? ? options : options.merge(new_opts))
|
79
79
|
end
|
80
80
|
|
81
81
|
# @api private
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ROM
|
2
|
+
class Relation
|
3
|
+
class ViewDSL
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
attr_reader :relation_block
|
7
|
+
|
8
|
+
attr_reader :new_schema
|
9
|
+
|
10
|
+
def initialize(name, schema, &block)
|
11
|
+
@name = name
|
12
|
+
@schema = schema
|
13
|
+
@new_schema = nil
|
14
|
+
@relation_block = nil
|
15
|
+
instance_eval(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def schema(&block)
|
19
|
+
@new_schema = -> { @schema.instance_exec(&block) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def relation(&block)
|
23
|
+
@relation_block = lambda(&block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
[name, new_schema, relation_block]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/rom/relation.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'rom/initializer'
|
1
2
|
require 'rom/relation/class_interface'
|
2
3
|
|
3
4
|
require 'rom/pipeline'
|
@@ -29,17 +30,31 @@ module ROM
|
|
29
30
|
#
|
30
31
|
# @api public
|
31
32
|
class Relation
|
33
|
+
extend Initializer
|
32
34
|
extend ClassInterface
|
33
35
|
|
34
|
-
include Options
|
35
36
|
include Dry::Equalizer(:dataset)
|
36
37
|
include Materializable
|
37
38
|
include Pipeline
|
38
39
|
|
40
|
+
# @!attribute [r] dataset
|
41
|
+
# @return [Object] dataset used by the relation provided by relation's gateway
|
42
|
+
# @api public
|
43
|
+
param :dataset
|
44
|
+
|
39
45
|
# @!attribute [r] mappers
|
40
46
|
# @return [MapperRegistry] an optional mapper registry (empty by default)
|
41
47
|
option :mappers, reader: true, default: proc { MapperRegistry.new }
|
42
48
|
|
49
|
+
# @!attribute [r] schema
|
50
|
+
# @return [Schema] relation schema, defaults to class-level canonical
|
51
|
+
# schema (if it was defined) and sets an empty one as
|
52
|
+
# the fallback
|
53
|
+
# @api public
|
54
|
+
option :schema, reader: true, optional: true, default: -> relation {
|
55
|
+
relation.class.schema || Schema.define(Dry::Core::Inflector.underscore(relation.class.name || EMPTY_STRING).to_sym)
|
56
|
+
}
|
57
|
+
|
43
58
|
# @!attribute [r] schema_hash
|
44
59
|
# @return [Object#[]] tuple processing function, uses schema or defaults to Hash[]
|
45
60
|
# @api private
|
@@ -47,36 +62,13 @@ module ROM
|
|
47
62
|
relation.schema? ? Types::Coercible::Hash.schema(relation.schema.to_h) : Hash
|
48
63
|
}
|
49
64
|
|
50
|
-
#
|
51
|
-
# @return [AssociationSet] Schema's association set (empty by default)
|
52
|
-
option :associations, reader: true, default: -> rel {
|
53
|
-
rel.schema? ? rel.schema.associations : Schema::EMPTY_ASSOCIATION_SET
|
54
|
-
}
|
55
|
-
|
56
|
-
# @!attribute [r] dataset
|
57
|
-
# @return [Object] dataset used by the relation provided by relation's gateway
|
58
|
-
# @api public
|
59
|
-
attr_reader :dataset
|
60
|
-
|
61
|
-
# @!attribute [r] schema
|
62
|
-
# @return [Schema] returns relation schema object (if defined)
|
63
|
-
# @api public
|
64
|
-
attr_reader :schema
|
65
|
-
|
66
|
-
# Initializes a relation object
|
65
|
+
# Return schema attribute
|
67
66
|
#
|
68
|
-
# @
|
69
|
-
#
|
70
|
-
# @param options [Hash]
|
71
|
-
# @option :mappers [MapperRegistry]
|
72
|
-
# @option :schema_hash [#[]]
|
73
|
-
# @option :associations [AssociationSet]
|
67
|
+
# @return [Schema::Type]
|
74
68
|
#
|
75
69
|
# @api public
|
76
|
-
def
|
77
|
-
|
78
|
-
@schema = self.class.schema
|
79
|
-
super
|
70
|
+
def [](name)
|
71
|
+
schema[name]
|
80
72
|
end
|
81
73
|
|
82
74
|
# Yields relation tuples
|
@@ -143,7 +135,17 @@ module ROM
|
|
143
135
|
#
|
144
136
|
# @api private
|
145
137
|
def schema?
|
146
|
-
! schema.
|
138
|
+
! schema.empty?
|
139
|
+
end
|
140
|
+
|
141
|
+
# Return a new relation with provided dataset and additional options
|
142
|
+
#
|
143
|
+
# @param [Object] dataset
|
144
|
+
# @param [Hash] new_opts Additional options
|
145
|
+
#
|
146
|
+
# @api public
|
147
|
+
def new(dataset, new_opts = EMPTY_HASH)
|
148
|
+
self.class.new(dataset, new_opts.empty? ? options : options.merge(new_opts))
|
147
149
|
end
|
148
150
|
|
149
151
|
# Returns a new instance with the same dataset but new options
|
@@ -154,16 +156,29 @@ module ROM
|
|
154
156
|
#
|
155
157
|
# @api private
|
156
158
|
def with(new_options)
|
157
|
-
|
159
|
+
new(dataset, options.merge(new_options))
|
158
160
|
end
|
159
161
|
|
160
|
-
|
162
|
+
# Return all registered relation schemas
|
163
|
+
#
|
164
|
+
# @return [Hash<Symbol=>Schema>]
|
165
|
+
#
|
166
|
+
# @api public
|
167
|
+
def schemas
|
168
|
+
@schemas ||= self.class.schemas
|
169
|
+
end
|
161
170
|
|
162
|
-
#
|
163
|
-
|
164
|
-
|
171
|
+
# Return schema's association set (empty by default)
|
172
|
+
#
|
173
|
+
# @return [AssociationSet] Schema's association set (empty by default)
|
174
|
+
#
|
175
|
+
# @api public
|
176
|
+
def associations
|
177
|
+
@associations ||= schema.associations
|
165
178
|
end
|
166
179
|
|
180
|
+
private
|
181
|
+
|
167
182
|
# @api private
|
168
183
|
def composite_class
|
169
184
|
Relation::Composite
|
data/lib/rom/schema/dsl.rb
CHANGED
@@ -13,19 +13,17 @@ module ROM
|
|
13
13
|
|
14
14
|
# @api public
|
15
15
|
class DSL < BasicObject
|
16
|
-
attr_reader :
|
16
|
+
attr_reader :relation, :attributes, :inferrer, :schema_class
|
17
17
|
|
18
18
|
# @api private
|
19
|
-
def initialize(
|
20
|
-
@
|
19
|
+
def initialize(relation, schema_class: Schema, inferrer: Schema::DEFAULT_INFERRER, &block)
|
20
|
+
@relation = relation
|
21
21
|
@inferrer = inferrer
|
22
|
-
@
|
22
|
+
@schema_class = schema_class
|
23
|
+
@attributes = {}
|
23
24
|
|
24
25
|
if block
|
25
26
|
instance_exec(&block)
|
26
|
-
elsif inferrer.nil?
|
27
|
-
raise ArgumentError,
|
28
|
-
'You must pass a block to define a schema or set an inferrer for automatic inferring'
|
29
27
|
end
|
30
28
|
end
|
31
29
|
|
@@ -36,7 +34,7 @@ module ROM
|
|
36
34
|
# @api public
|
37
35
|
def attribute(name, type)
|
38
36
|
@attributes ||= {}
|
39
|
-
@attributes[name] = type.meta(name: name)
|
37
|
+
@attributes[name] = type.meta(name: name, source: relation)
|
40
38
|
end
|
41
39
|
|
42
40
|
# Specify which key(s) should be the primary key
|
@@ -51,7 +49,7 @@ module ROM
|
|
51
49
|
|
52
50
|
# @api private
|
53
51
|
def call
|
54
|
-
|
52
|
+
schema_class.define(relation, attributes: attributes.values, inferrer: inferrer)
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'dry/equalizer'
|
3
|
+
require 'dry/types/decorator'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
class Schema
|
7
|
+
class Type
|
8
|
+
include Dry::Equalizer(:type)
|
9
|
+
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
def initialize(type)
|
13
|
+
@type = type
|
14
|
+
end
|
15
|
+
|
16
|
+
# @api public
|
17
|
+
def primary_key?
|
18
|
+
meta[:primary_key].equal?(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api public
|
22
|
+
def foreign_key?
|
23
|
+
meta[:foreign_key].equal?(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api public
|
27
|
+
def aliased?
|
28
|
+
!meta[:alias].nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
# @api public
|
32
|
+
def source
|
33
|
+
meta[:source]
|
34
|
+
end
|
35
|
+
|
36
|
+
# @api public
|
37
|
+
def target
|
38
|
+
meta[:target]
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api public
|
42
|
+
def name
|
43
|
+
meta[:name]
|
44
|
+
end
|
45
|
+
|
46
|
+
# @api public
|
47
|
+
def alias
|
48
|
+
meta[:alias]
|
49
|
+
end
|
50
|
+
|
51
|
+
# @api public
|
52
|
+
def aliased(name)
|
53
|
+
meta(alias: name)
|
54
|
+
end
|
55
|
+
alias_method :as, :aliased
|
56
|
+
|
57
|
+
# @api public
|
58
|
+
def prefixed(prefix = source.dataset)
|
59
|
+
aliased(:"#{prefix}_#{name}")
|
60
|
+
end
|
61
|
+
|
62
|
+
# @api public
|
63
|
+
def wrapped?
|
64
|
+
meta[:wrapped].equal?(true)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api public
|
68
|
+
def wrapped(name = source.dataset)
|
69
|
+
self.class.new(prefixed(name).meta(wrapped: true))
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api public
|
73
|
+
def meta(opts = nil)
|
74
|
+
if opts
|
75
|
+
self.class.new(type.meta(opts))
|
76
|
+
else
|
77
|
+
type.meta
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @api public
|
82
|
+
def inspect
|
83
|
+
%(#<#{self.class}[#{type.name}] #{meta.map { |k, v| "#{k}=#{v.inspect}" }.join(' ')}>)
|
84
|
+
end
|
85
|
+
alias_method :pretty_inspect, :inspect
|
86
|
+
|
87
|
+
# @api public
|
88
|
+
def eql?(other)
|
89
|
+
other.is_a?(self.class) ? super : type.eql?(other)
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
def respond_to_missing?(name, include_private = false)
|
94
|
+
type.respond_to?(name) || super
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# @api private
|
100
|
+
def method_missing(meth, *args, &block)
|
101
|
+
if type.respond_to?(meth)
|
102
|
+
response = type.__send__(meth, *args, &block)
|
103
|
+
|
104
|
+
if response.is_a?(type.class)
|
105
|
+
self.class.new(type)
|
106
|
+
else
|
107
|
+
response
|
108
|
+
end
|
109
|
+
else
|
110
|
+
super
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|