rom 5.4.2 → 6.0.0.alpha1
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/CHANGELOG.md +58 -71
- data/LICENSE +1 -1
- data/README.md +7 -6
- data/lib/rom/array_dataset.rb +46 -0
- data/lib/rom/associations/abstract.rb +217 -0
- data/lib/rom/associations/definitions/abstract.rb +150 -0
- data/lib/rom/associations/definitions/many_to_many.rb +29 -0
- data/lib/rom/associations/definitions/many_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_many.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +14 -0
- data/lib/rom/associations/definitions.rb +7 -0
- data/lib/rom/associations/many_to_many.rb +128 -0
- data/lib/rom/associations/many_to_one.rb +65 -0
- data/lib/rom/associations/one_to_many.rb +65 -0
- data/lib/rom/associations/one_to_one.rb +13 -0
- data/lib/rom/associations/one_to_one_through.rb +13 -0
- data/lib/rom/associations/through_identifier.rb +41 -0
- data/lib/rom/attribute.rb +425 -0
- data/lib/rom/auto_curry.rb +70 -0
- data/lib/rom/cache.rb +87 -0
- data/lib/rom/changeset/associated.rb +110 -0
- data/lib/rom/changeset/create.rb +18 -0
- data/lib/rom/changeset/delete.rb +15 -0
- data/lib/rom/changeset/extensions/relation.rb +26 -0
- data/lib/rom/changeset/pipe.rb +81 -0
- data/lib/rom/changeset/pipe_registry.rb +27 -0
- data/lib/rom/changeset/stateful.rb +285 -0
- data/lib/rom/changeset/update.rb +81 -0
- data/lib/rom/changeset.rb +185 -0
- data/lib/rom/command.rb +351 -0
- data/lib/rom/command_compiler.rb +201 -0
- data/lib/rom/command_proxy.rb +36 -0
- data/lib/rom/commands/class_interface.rb +236 -0
- data/lib/rom/commands/composite.rb +55 -0
- data/lib/rom/commands/create.rb +15 -0
- data/lib/rom/commands/delete.rb +16 -0
- data/lib/rom/commands/graph/class_interface.rb +64 -0
- data/lib/rom/commands/graph/input_evaluator.rb +94 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/lazy/create.rb +35 -0
- data/lib/rom/commands/lazy/delete.rb +39 -0
- data/lib/rom/commands/lazy/update.rb +46 -0
- data/lib/rom/commands/lazy.rb +106 -0
- data/lib/rom/commands/update.rb +16 -0
- data/lib/rom/commands.rb +5 -0
- data/lib/rom/compat/auto_registration.rb +115 -0
- data/lib/rom/compat/auto_registration_strategies/base.rb +29 -0
- data/lib/rom/compat/auto_registration_strategies/custom_namespace.rb +84 -0
- data/lib/rom/compat/auto_registration_strategies/no_namespace.rb +33 -0
- data/lib/rom/compat/auto_registration_strategies/with_namespace.rb +29 -0
- data/lib/rom/compat/command.rb +74 -0
- data/lib/rom/compat/components/dsl/schema.rb +130 -0
- data/lib/rom/compat/components.rb +91 -0
- data/lib/rom/compat/global.rb +17 -0
- data/lib/rom/compat/mapper.rb +22 -0
- data/lib/rom/compat/registries.rb +47 -0
- data/lib/rom/compat/relation.rb +40 -0
- data/lib/rom/compat/schema/dsl.rb +260 -0
- data/lib/rom/compat/setting_proxy.rb +44 -0
- data/lib/rom/compat/setup.rb +151 -0
- data/lib/rom/compat/transformer.rb +49 -0
- data/lib/rom/compat.rb +22 -0
- data/lib/rom/components/association.rb +26 -0
- data/lib/rom/components/command.rb +24 -0
- data/lib/rom/components/core.rb +148 -0
- data/lib/rom/components/dataset.rb +60 -0
- data/lib/rom/components/dsl/association.rb +47 -0
- data/lib/rom/components/dsl/command.rb +60 -0
- data/lib/rom/components/dsl/core.rb +126 -0
- data/lib/rom/components/dsl/dataset.rb +33 -0
- data/lib/rom/components/dsl/gateway.rb +14 -0
- data/lib/rom/components/dsl/mapper.rb +70 -0
- data/lib/rom/components/dsl/relation.rb +49 -0
- data/lib/rom/components/dsl/schema.rb +150 -0
- data/lib/rom/components/dsl/view.rb +82 -0
- data/lib/rom/components/dsl.rb +255 -0
- data/lib/rom/components/gateway.rb +50 -0
- data/lib/rom/components/mapper.rb +29 -0
- data/lib/rom/components/provider.rb +160 -0
- data/lib/rom/components/registry.rb +154 -0
- data/lib/rom/components/relation.rb +41 -0
- data/lib/rom/components/schema.rb +61 -0
- data/lib/rom/components/view.rb +55 -0
- data/lib/rom/components.rb +55 -0
- data/lib/rom/configuration_dsl.rb +4 -0
- data/lib/rom/constants.rb +135 -0
- data/lib/rom/container.rb +182 -0
- data/lib/rom/core.rb +125 -0
- data/lib/rom/data_proxy.rb +97 -0
- data/lib/rom/enumerable_dataset.rb +70 -0
- data/lib/rom/gateway.rb +232 -0
- data/lib/rom/global.rb +56 -0
- data/lib/rom/header/attribute.rb +190 -0
- data/lib/rom/header.rb +198 -0
- data/lib/rom/inferrer.rb +55 -0
- data/lib/rom/initializer.rb +80 -0
- data/lib/rom/lint/enumerable_dataset.rb +56 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +79 -0
- data/lib/rom/lint/spec.rb +22 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/loader.rb +161 -0
- data/lib/rom/mapper/attribute_dsl.rb +480 -0
- data/lib/rom/mapper/dsl.rb +107 -0
- data/lib/rom/mapper/model_dsl.rb +61 -0
- data/lib/rom/mapper.rb +99 -0
- data/lib/rom/mapper_compiler.rb +84 -0
- data/lib/rom/memory/associations/many_to_many.rb +12 -0
- data/lib/rom/memory/associations/many_to_one.rb +12 -0
- data/lib/rom/memory/associations/one_to_many.rb +12 -0
- data/lib/rom/memory/associations/one_to_one.rb +12 -0
- data/lib/rom/memory/associations.rb +6 -0
- data/lib/rom/memory/commands.rb +60 -0
- data/lib/rom/memory/dataset.rb +127 -0
- data/lib/rom/memory/gateway.rb +66 -0
- data/lib/rom/memory/mapper_compiler.rb +10 -0
- data/lib/rom/memory/relation.rb +91 -0
- data/lib/rom/memory/schema.rb +32 -0
- data/lib/rom/memory/storage.rb +61 -0
- data/lib/rom/memory/types.rb +11 -0
- data/lib/rom/memory.rb +7 -0
- data/lib/rom/model_builder.rb +103 -0
- data/lib/rom/open_struct.rb +112 -0
- data/lib/rom/pipeline.rb +111 -0
- data/lib/rom/plugin.rb +130 -0
- data/lib/rom/plugins/class_methods.rb +37 -0
- data/lib/rom/plugins/command/schema.rb +45 -0
- data/lib/rom/plugins/command/timestamps.rb +149 -0
- data/lib/rom/plugins/dsl.rb +53 -0
- data/lib/rom/plugins/relation/changeset.rb +97 -0
- data/lib/rom/plugins/relation/instrumentation.rb +66 -0
- data/lib/rom/plugins/relation/registry_reader.rb +36 -0
- data/lib/rom/plugins/schema/timestamps.rb +59 -0
- data/lib/rom/plugins.rb +100 -0
- data/lib/rom/processor/composer.rb +37 -0
- data/lib/rom/processor/transformer.rb +415 -0
- data/lib/rom/processor.rb +30 -0
- data/lib/rom/registries/associations.rb +26 -0
- data/lib/rom/registries/commands.rb +11 -0
- data/lib/rom/registries/container.rb +12 -0
- data/lib/rom/registries/datasets.rb +21 -0
- data/lib/rom/registries/gateways.rb +8 -0
- data/lib/rom/registries/mappers.rb +21 -0
- data/lib/rom/registries/nestable.rb +32 -0
- data/lib/rom/registries/relations.rb +8 -0
- data/lib/rom/registries/root.rb +203 -0
- data/lib/rom/registries/schemas.rb +44 -0
- data/lib/rom/registries/views.rb +11 -0
- data/lib/rom/relation/class_interface.rb +61 -0
- data/lib/rom/relation/combined.rb +160 -0
- data/lib/rom/relation/commands.rb +65 -0
- data/lib/rom/relation/composite.rb +53 -0
- data/lib/rom/relation/curried.rb +129 -0
- data/lib/rom/relation/graph.rb +107 -0
- data/lib/rom/relation/loaded.rb +136 -0
- data/lib/rom/relation/materializable.rb +62 -0
- data/lib/rom/relation/name.rb +122 -0
- data/lib/rom/relation/wrap.rb +64 -0
- data/lib/rom/relation.rb +625 -0
- data/lib/rom/repository/class_interface.rb +162 -0
- data/lib/rom/repository/relation_reader.rb +48 -0
- data/lib/rom/repository/root.rb +75 -0
- data/lib/rom/repository/session.rb +60 -0
- data/lib/rom/repository.rb +179 -0
- data/lib/rom/schema/associations_dsl.rb +222 -0
- data/lib/rom/schema/inferrer.rb +106 -0
- data/lib/rom/schema.rb +471 -0
- data/lib/rom/settings.rb +141 -0
- data/lib/rom/setup.rb +297 -0
- data/lib/rom/struct.rb +99 -0
- data/lib/rom/struct_compiler.rb +114 -0
- data/lib/rom/support/configurable.rb +213 -0
- data/lib/rom/support/inflector.rb +31 -0
- data/lib/rom/support/memoizable.rb +61 -0
- data/lib/rom/support/notifications.rb +238 -0
- data/lib/rom/transaction.rb +26 -0
- data/lib/rom/transformer.rb +46 -0
- data/lib/rom/types.rb +74 -0
- data/lib/rom/version.rb +1 -1
- data/lib/rom-changeset.rb +4 -0
- data/lib/rom-core.rb +3 -0
- data/lib/rom-repository.rb +4 -0
- data/lib/rom.rb +3 -3
- metadata +302 -23
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "core"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Components
|
7
|
+
module DSL
|
8
|
+
# Setup DSL-specific relation extensions
|
9
|
+
#
|
10
|
+
# @private
|
11
|
+
class Relation < Core
|
12
|
+
key :relations
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
def call
|
16
|
+
super(constant: constant, config: constant.config.component)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
memoize def constant
|
21
|
+
build_class do |dsl|
|
22
|
+
config.component.adapter = dsl.adapter if dsl.adapter
|
23
|
+
|
24
|
+
class_exec(&dsl.block) if dsl.block
|
25
|
+
|
26
|
+
if (schema_dataset = components.schemas.first&.config&.dataset)
|
27
|
+
config.component.dataset = schema_dataset
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @api private
|
33
|
+
memoize def class_name
|
34
|
+
class_name_inferrer[
|
35
|
+
config.id,
|
36
|
+
type: :relation,
|
37
|
+
inflector: inflector,
|
38
|
+
class_namespace: provider.class_namespace
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def class_parent
|
44
|
+
ROM::Relation[adapter]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/schema"
|
4
|
+
require "rom/attribute"
|
5
|
+
|
6
|
+
require_relative "core"
|
7
|
+
|
8
|
+
module ROM
|
9
|
+
module Components
|
10
|
+
module DSL
|
11
|
+
# @private
|
12
|
+
class Schema < Core
|
13
|
+
key :schemas
|
14
|
+
|
15
|
+
option :attributes, default: -> { EMPTY_HASH.dup }
|
16
|
+
|
17
|
+
# Defines a relation attribute with its type and options.
|
18
|
+
#
|
19
|
+
# When only options are given, type is left as nil. It makes
|
20
|
+
# sense when it is used alongside a schema inferrer, which will
|
21
|
+
# populate the type.
|
22
|
+
#
|
23
|
+
# @see Components::DSL#schema
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def attribute(name, type_or_options, options = EMPTY_HASH)
|
27
|
+
if attributes.key?(name)
|
28
|
+
raise(AttributeAlreadyDefinedError, "Attribute #{name.inspect} already defined")
|
29
|
+
end
|
30
|
+
|
31
|
+
build_attribute_info(name, type_or_options, options).tap do |attr_info|
|
32
|
+
attributes[name] = attr_info
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Specify which key(s) should be the primary key
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def primary_key(*names)
|
40
|
+
names.each do |name|
|
41
|
+
attributes[name][:type] = attributes[name][:type].meta(primary_key: true)
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
# @api private
|
47
|
+
def call
|
48
|
+
# Evaluate block only if it's not a schema defined by Relation.view DSL
|
49
|
+
instance_eval(&block) if block && !config.view
|
50
|
+
|
51
|
+
enabled_plugins.each_value do |plugin|
|
52
|
+
plugin.apply unless plugin.applied?
|
53
|
+
end
|
54
|
+
|
55
|
+
configure
|
56
|
+
|
57
|
+
components.add(key, config: config, block: config.view ? block : nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
# rubocop:disable Metrics/AbcSize
|
62
|
+
def configure
|
63
|
+
config.update(attributes: attributes.values)
|
64
|
+
|
65
|
+
# TODO: make this simpler
|
66
|
+
config.update(
|
67
|
+
relation: relation_id,
|
68
|
+
inferrer: config.inferrer.with(enabled: config.infer)
|
69
|
+
)
|
70
|
+
|
71
|
+
if !view? && relation?
|
72
|
+
config.join!({namespace: relation_id}, :right) if config.id != relation_id
|
73
|
+
|
74
|
+
provider.config.component.update(dataset: config.dataset) if config.dataset
|
75
|
+
provider.config.component.update(id: config.as) if config.as
|
76
|
+
end
|
77
|
+
|
78
|
+
provider.config.schema.infer = config.infer
|
79
|
+
|
80
|
+
super
|
81
|
+
end
|
82
|
+
# rubocop:enable Metrics/AbcSize
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Builds a representation of the information needed to create an
|
87
|
+
# attribute. It returns a hash with `:type` and `:options` keys.
|
88
|
+
#
|
89
|
+
# @return [Hash]
|
90
|
+
#
|
91
|
+
# @see [Schema.build_attribute_info]
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
def build_attribute_info(name, type_or_options, options = EMPTY_HASH)
|
95
|
+
type, options = if type_or_options.is_a?(::Hash)
|
96
|
+
[nil, type_or_options]
|
97
|
+
else
|
98
|
+
[build_type(type_or_options, options), options]
|
99
|
+
end
|
100
|
+
ROM::Schema.build_attribute_info(type, **options, name: name)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Builds a type instance from base type and meta options
|
104
|
+
#
|
105
|
+
# @return [Dry::Types::Type] Type instance
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
def build_type(type, options = EMPTY_HASH)
|
109
|
+
meta = ROM::Attribute::META_OPTIONS
|
110
|
+
.map { |opt| [opt, options[opt]] if options.key?(opt) }
|
111
|
+
.compact
|
112
|
+
.to_h
|
113
|
+
|
114
|
+
# TODO: this should be probably moved to rom/compat
|
115
|
+
source = ROM::Relation::Name[relation_id, config.dataset]
|
116
|
+
|
117
|
+
base =
|
118
|
+
if options[:read]
|
119
|
+
type.meta(source: source, read: options[:read])
|
120
|
+
elsif type.optional? && type.meta[:read]
|
121
|
+
type.meta(source: source, read: type.meta[:read].optional)
|
122
|
+
else
|
123
|
+
type.meta(source: source)
|
124
|
+
end
|
125
|
+
|
126
|
+
if meta.empty?
|
127
|
+
base
|
128
|
+
else
|
129
|
+
base.meta(meta)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# @api private
|
134
|
+
def relation_id
|
135
|
+
relation? ? provider.config.component.id : config.id
|
136
|
+
end
|
137
|
+
|
138
|
+
# @api private
|
139
|
+
def relation?
|
140
|
+
provider.config.component.type == :relation
|
141
|
+
end
|
142
|
+
|
143
|
+
# @api private
|
144
|
+
def view?
|
145
|
+
config.view.equal?(true)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "core"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Components
|
7
|
+
module DSL
|
8
|
+
# @api private
|
9
|
+
class View < Core
|
10
|
+
key :views
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
attr_reader :schema_block
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
attr_reader :relation_block
|
17
|
+
|
18
|
+
# @see Components::DSL#view
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
def schema(&block)
|
22
|
+
@schema_block = block
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
# @see Components::DSL#view
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def relation(&block)
|
30
|
+
@relation_block = block
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def call
|
36
|
+
# Nest view under relation ns
|
37
|
+
config.join!({namespace: relation_id}, :right)
|
38
|
+
|
39
|
+
if args.empty? && block.arity.positive?
|
40
|
+
raise ArgumentError, "schema attribute names must be provided as the second argument"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Capture schema and relation blocks if there are no args
|
44
|
+
# otherwise assume args is a list of attributes to project
|
45
|
+
if args.empty? && block
|
46
|
+
instance_eval(&block)
|
47
|
+
else
|
48
|
+
schema { schema.project(*args.first) }
|
49
|
+
end
|
50
|
+
|
51
|
+
provider.schema(
|
52
|
+
id: config.id,
|
53
|
+
namespace: relation_id,
|
54
|
+
relation: relation_id,
|
55
|
+
view: true,
|
56
|
+
&schema_block
|
57
|
+
)
|
58
|
+
|
59
|
+
components.add(
|
60
|
+
key,
|
61
|
+
config: config,
|
62
|
+
relation_id: relation_id,
|
63
|
+
# Default to the block because we assume the schema was set based on args
|
64
|
+
relation_block: relation_block || block
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
def args
|
72
|
+
config.args
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def relation_id
|
77
|
+
provider.config.component.id
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/relation/name"
|
4
|
+
|
5
|
+
require "rom/components/dsl/gateway"
|
6
|
+
require "rom/components/dsl/dataset"
|
7
|
+
require "rom/components/dsl/schema"
|
8
|
+
require "rom/components/dsl/relation"
|
9
|
+
require "rom/components/dsl/view"
|
10
|
+
require "rom/components/dsl/association"
|
11
|
+
require "rom/components/dsl/command"
|
12
|
+
require "rom/components/dsl/mapper"
|
13
|
+
|
14
|
+
module ROM
|
15
|
+
# This extends Configuration class with the DSL methods
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
module Components
|
19
|
+
module DSL
|
20
|
+
# Set or get custom dataset block
|
21
|
+
#
|
22
|
+
# This block will be evaluated when a relation is instantiated and registered
|
23
|
+
# in a relation registry.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# class Users < ROM::Relation[:memory]
|
27
|
+
# dataset { sort_by(:id) }
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def dataset(id = nil, **options, &block)
|
32
|
+
__dsl__(DSL::Dataset, id: id, **options, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Specify a relation schema
|
36
|
+
#
|
37
|
+
# With a schema defined commands will set up a type-safe input handler automatically
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# class Users < ROM::Relation[:sql]
|
41
|
+
# schema do
|
42
|
+
# attribute :id, Types::Serial
|
43
|
+
# attribute :name, Types::String
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # access schema from a finalized relation
|
48
|
+
# users.schema
|
49
|
+
#
|
50
|
+
# @return [Schema]
|
51
|
+
#
|
52
|
+
# @param [Symbol] dataset An optional dataset name
|
53
|
+
# @param [Boolean] infer Whether to do an automatic schema inferring
|
54
|
+
# @param [Boolean, Symbol] view Whether this is a view schema
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def schema(id = nil, **options, &block)
|
58
|
+
__dsl__(DSL::Schema, id: id, dataset: id, **options, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Relation definition DSL
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# setup.relation(:users) do
|
65
|
+
# def names
|
66
|
+
# project(:name)
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def relation(id, dataset: id, **options, &block)
|
72
|
+
__dsl__(DSL::Relation, id: id, dataset: dataset, **options, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Define a relation view with a specific schema
|
76
|
+
#
|
77
|
+
# This method should only be used in cases where a given adapter doesn't
|
78
|
+
# support automatic schema projection at run-time.
|
79
|
+
#
|
80
|
+
# @overload view(name, schema, &block)
|
81
|
+
# @example View with the canonical schema
|
82
|
+
# class Users < ROM::Relation[:sql]
|
83
|
+
# view(:listing, schema) do
|
84
|
+
# order(:name)
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# @example View with a projected schema
|
89
|
+
# class Users < ROM::Relation[:sql]
|
90
|
+
# view(:listing, schema.project(:id, :name)) do
|
91
|
+
# order(:name)
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @overload view(name, &block)
|
96
|
+
# @example View with the canonical schema and arguments
|
97
|
+
# class Users < ROM::Relation[:sql]
|
98
|
+
# view(:by_name) do |name|
|
99
|
+
# where(name: name)
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# @example View with projected schema and arguments
|
104
|
+
# class Users < ROM::Relation[:sql]
|
105
|
+
# view(:by_name) do
|
106
|
+
# schema { project(:id, :name) }
|
107
|
+
# relation { |name| where(name: name) }
|
108
|
+
# end
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# @example View with a schema extended with foreign attributes
|
112
|
+
# class Users < ROM::Relation[:sql]
|
113
|
+
# view(:index) do
|
114
|
+
# schema { append(relations[:tasks][:title]) }
|
115
|
+
# relation { |name| where(name: name) }
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# @return [Symbol] view method name
|
120
|
+
#
|
121
|
+
# @api public
|
122
|
+
def view(id, *args, &block)
|
123
|
+
__dsl__(DSL::View, id: id, args: args, &block)
|
124
|
+
id
|
125
|
+
end
|
126
|
+
|
127
|
+
# Define associations for a relation
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# class Users < ROM::Relation[:sql]
|
131
|
+
# associations do
|
132
|
+
# has_many :tasks
|
133
|
+
# has_many :posts
|
134
|
+
# has_many :posts, as: :priority_posts, view: :prioritized
|
135
|
+
# belongs_to :account
|
136
|
+
# end
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# class Posts < ROM::Relation[:sql]
|
140
|
+
# associations do
|
141
|
+
# belongs_to :users, as: :author
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# view(:prioritized) do
|
145
|
+
# where { priority <= 3 }
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# @return [Array<Components::Association>]
|
150
|
+
#
|
151
|
+
# @api public
|
152
|
+
def associations(source: config.component.id, namespace: source, **options, &block)
|
153
|
+
__dsl__(DSL::Association, source: source, namespace: namespace, **options, &block)
|
154
|
+
components.associations
|
155
|
+
end
|
156
|
+
|
157
|
+
# Command definition DSL
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# setup.commands(:users) do
|
161
|
+
# define(:create) do
|
162
|
+
# input NewUserParams
|
163
|
+
# result :one
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# define(:update) do
|
167
|
+
# input UserParams
|
168
|
+
# result :many
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# define(:delete) do
|
172
|
+
# result :many
|
173
|
+
# end
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# @api public
|
177
|
+
def commands(namespace, **options, &block)
|
178
|
+
__dsl__(DSL::Command, namespace: namespace, relation: namespace, **options, &block)
|
179
|
+
components.commands
|
180
|
+
end
|
181
|
+
|
182
|
+
# Mapper definition DSL
|
183
|
+
#
|
184
|
+
# @api public
|
185
|
+
def mappers(namespace = nil, **options, &block)
|
186
|
+
__dsl__(DSL::Mapper, namespace: namespace, relation: namespace, **options, &block)
|
187
|
+
components.mappers
|
188
|
+
end
|
189
|
+
|
190
|
+
# Configures a plugin for a specific adapter to be enabled for all relations
|
191
|
+
#
|
192
|
+
# @example
|
193
|
+
# setup = ROM::Setup.new(:sql, 'sqlite::memory')
|
194
|
+
#
|
195
|
+
# setup.plugin(:sql, relations: :instrumentation) do |p|
|
196
|
+
# p.notifications = MyNotificationsBackend
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# setup.plugin(:sql, relations: :pagination)
|
200
|
+
#
|
201
|
+
# @param [Symbol] adapter The adapter identifier
|
202
|
+
# @param [Hash<Symbol=>Symbol>] spec Component identifier => plugin identifier
|
203
|
+
#
|
204
|
+
# @return [Plugin]
|
205
|
+
#
|
206
|
+
# @api public
|
207
|
+
def plugin(*args, &block)
|
208
|
+
case args.size
|
209
|
+
when 2
|
210
|
+
adapter, spec = args
|
211
|
+
type, name = spec.flatten(1)
|
212
|
+
|
213
|
+
# TODO: plugin types are singularized, so this is not consistent
|
214
|
+
# with the configuration DSL for plugins that uses plural
|
215
|
+
# names of the components - this should be unified
|
216
|
+
plugin = ROM
|
217
|
+
.plugins[Inflector.singularize(type)].adapter(adapter).fetch(name)
|
218
|
+
.configure(&block)
|
219
|
+
|
220
|
+
config.component.plugins << plugin
|
221
|
+
|
222
|
+
plugin
|
223
|
+
when 1
|
224
|
+
plugin(self.adapter, *args)
|
225
|
+
else
|
226
|
+
raise ArgumentError, "+plugin+ accepts either 1 or 2 arguments (#{args.size} given)"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# @api public
|
231
|
+
def gateway(id, **options, &block)
|
232
|
+
__dsl__(DSL::Gateway, id: id, **options, &block)
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
# @api private
|
238
|
+
def __dsl__(klass, type: klass.type, **options, &block)
|
239
|
+
type_config = config[type].join(options, :right).inherit!(config.component)
|
240
|
+
|
241
|
+
if klass.nested && block
|
242
|
+
dsl = klass.new(provider: self, config: type_config)
|
243
|
+
dsl.enable_plugins
|
244
|
+
dsl.configure
|
245
|
+
dsl.instance_eval(&block)
|
246
|
+
dsl
|
247
|
+
else
|
248
|
+
dsl = klass.new(provider: self, config: type_config, block: block)
|
249
|
+
dsl.enable_plugins
|
250
|
+
dsl.()
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/open_struct"
|
4
|
+
require_relative "core"
|
5
|
+
|
6
|
+
module ROM
|
7
|
+
module Components
|
8
|
+
# @api public
|
9
|
+
class Gateway < Core
|
10
|
+
# @api public
|
11
|
+
def build
|
12
|
+
gateway = adapter.is_a?(ROM::Gateway) ? adapter : setup
|
13
|
+
|
14
|
+
# TODO: once Gateway is unified with the rest of component types, this
|
15
|
+
# won't be needed as it'll happen automatically when inheriting
|
16
|
+
# config settings
|
17
|
+
gateway_config.plugins.concat(gateway.class.config.component.plugins)
|
18
|
+
|
19
|
+
gateway.instance_variable_set("@config", gateway_config)
|
20
|
+
gateway.use_logger(config.logger) if config.logger
|
21
|
+
|
22
|
+
gateway
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def adapter
|
27
|
+
config.adapter
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# @api private
|
33
|
+
def setup
|
34
|
+
if config.args.empty?
|
35
|
+
ROM::Gateway.setup(adapter, **config)
|
36
|
+
else
|
37
|
+
ROM::Gateway.setup(adapter, *config.args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
def gateway_config
|
43
|
+
hash = config.to_h
|
44
|
+
keys = hash.keys - %i[type namespace opts]
|
45
|
+
|
46
|
+
ROM::OpenStruct.new(**keys.zip(hash.values_at(*keys)).to_h, **config.opts)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "core"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Components
|
7
|
+
# @api public
|
8
|
+
class Mapper < Core
|
9
|
+
# @!attribute [r] constant
|
10
|
+
# @return [Class] Component's target class
|
11
|
+
option :constant, type: Types.Interface(:new), optional: true
|
12
|
+
|
13
|
+
# @!attribute [r] object
|
14
|
+
# @return [Class] Pre-initialized object that should be used instead of the constant
|
15
|
+
# @api public
|
16
|
+
option :object, optional: true
|
17
|
+
|
18
|
+
# @api public
|
19
|
+
def build
|
20
|
+
object || constant.build
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api public
|
24
|
+
def relation
|
25
|
+
config.relation
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|