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,222 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/support/inflector"
|
4
|
+
|
5
|
+
require "rom/associations/definitions"
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
class Schema
|
9
|
+
# Additional schema DSL for definition SQL associations
|
10
|
+
#
|
11
|
+
# This DSL is exposed in `associations do .. end` blocks in schema defintions.
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
class AssociationsDSL < ::BasicObject
|
15
|
+
class << self
|
16
|
+
define_method(:const_missing, ::Object.method(:const_get))
|
17
|
+
end
|
18
|
+
|
19
|
+
include Associations::Definitions
|
20
|
+
|
21
|
+
# @!attribute [r] source
|
22
|
+
# @return [Relation::Name] The source relation
|
23
|
+
attr_reader :source
|
24
|
+
|
25
|
+
# @!attribute [r] inflector
|
26
|
+
# @return [Dry::Inflector] String inflector
|
27
|
+
attr_reader :inflector
|
28
|
+
|
29
|
+
# @!attribute [r] registry
|
30
|
+
# @return [Hash]
|
31
|
+
attr_reader :registry
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
def initialize(source, inflector = Inflector, &block)
|
35
|
+
@source = source
|
36
|
+
@inflector = inflector
|
37
|
+
@registry = {}
|
38
|
+
instance_exec(&block) if block
|
39
|
+
end
|
40
|
+
|
41
|
+
# Establish a one-to-many association
|
42
|
+
#
|
43
|
+
# @example using relation identifier
|
44
|
+
# has_many :tasks
|
45
|
+
#
|
46
|
+
# @example setting custom foreign key name
|
47
|
+
# has_many :tasks, foreign_key: :assignee_id
|
48
|
+
#
|
49
|
+
# @example with a :through option
|
50
|
+
# # this establishes many-to-many association
|
51
|
+
# has_many :tasks, through: :users_tasks
|
52
|
+
#
|
53
|
+
# @example using a custom view which overrides default one
|
54
|
+
# has_many :posts, view: :published, override: true
|
55
|
+
#
|
56
|
+
# @example using aliased association with a custom view
|
57
|
+
# has_many :posts, as: :published_posts, view: :published
|
58
|
+
#
|
59
|
+
# @example using custom target relation
|
60
|
+
# has_many :user_posts, relation: :posts
|
61
|
+
#
|
62
|
+
# @example using custom target relation and an alias
|
63
|
+
# has_many :user_posts, relation: :posts, as: :published, view: :published
|
64
|
+
#
|
65
|
+
# @param [Symbol] target The target relation identifier
|
66
|
+
# @param [Hash] options A hash with additional options
|
67
|
+
#
|
68
|
+
# @return [Associations::OneToMany]
|
69
|
+
#
|
70
|
+
# @see #many_to_many
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def one_to_many(target, **options)
|
74
|
+
if options[:through]
|
75
|
+
many_to_many(target, **options, inflector: inflector)
|
76
|
+
else
|
77
|
+
add(build(OneToMany, target, options))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
alias_method :has_many, :one_to_many
|
81
|
+
|
82
|
+
# Establish a one-to-one association
|
83
|
+
#
|
84
|
+
# @example using relation identifier
|
85
|
+
# one_to_one :addresses, as: :address
|
86
|
+
#
|
87
|
+
# @example with an intermediate join relation
|
88
|
+
# one_to_one :tasks, as: :priority_task, through: :assignments
|
89
|
+
#
|
90
|
+
# @param [Symbol] target The target relation identifier
|
91
|
+
# @param [Hash] options A hash with additional options
|
92
|
+
#
|
93
|
+
# @return [Associations::OneToOne]
|
94
|
+
#
|
95
|
+
# @see #belongs_to
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def one_to_one(target, **options)
|
99
|
+
if options[:through]
|
100
|
+
one_to_one_through(target, **options)
|
101
|
+
else
|
102
|
+
add(build(OneToOne, target, options))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Establish a one-to-one association with a :through option
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# one_to_one_through :users, as: :author, through: :users_posts
|
110
|
+
#
|
111
|
+
# @return [Associations::OneToOneThrough]
|
112
|
+
#
|
113
|
+
# @api public
|
114
|
+
def one_to_one_through(target, **options)
|
115
|
+
add(build(OneToOneThrough, target, options))
|
116
|
+
end
|
117
|
+
|
118
|
+
# Establish a many-to-many association
|
119
|
+
#
|
120
|
+
# @example using relation identifier
|
121
|
+
# many_to_many :tasks, through: :users_tasks
|
122
|
+
#
|
123
|
+
# @param [Symbol] target The target relation identifier
|
124
|
+
# @param [Hash] options A hash with additional options
|
125
|
+
#
|
126
|
+
# @return [Associations::ManyToMany]
|
127
|
+
#
|
128
|
+
# @see #one_to_many
|
129
|
+
#
|
130
|
+
# @api public
|
131
|
+
def many_to_many(target, **options)
|
132
|
+
add(build(ManyToMany, target, options))
|
133
|
+
end
|
134
|
+
|
135
|
+
# Establish a many-to-one association
|
136
|
+
#
|
137
|
+
# @example using relation identifier
|
138
|
+
# many_to_one :users, as: :author
|
139
|
+
#
|
140
|
+
# @param [Symbol] target The target relation identifier
|
141
|
+
# @param [Hash] options A hash with additional options
|
142
|
+
#
|
143
|
+
# @return [Associations::ManyToOne]
|
144
|
+
#
|
145
|
+
# @see #one_to_many
|
146
|
+
#
|
147
|
+
# @api public
|
148
|
+
def many_to_one(target, **options)
|
149
|
+
add(build(ManyToOne, target, options))
|
150
|
+
end
|
151
|
+
|
152
|
+
# Shortcut for many_to_one which sets alias automatically
|
153
|
+
#
|
154
|
+
# @example with an alias (relation identifier is inferred via pluralization)
|
155
|
+
# belongs_to :user
|
156
|
+
#
|
157
|
+
# @example with an explicit alias
|
158
|
+
# belongs_to :users, as: :author
|
159
|
+
#
|
160
|
+
# @see #many_to_one
|
161
|
+
#
|
162
|
+
# @return [Associations::ManyToOne]
|
163
|
+
#
|
164
|
+
# @api public
|
165
|
+
def belongs_to(target, **options)
|
166
|
+
many_to_one(dataset_name(target), as: target, **options)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Shortcut for one_to_one which sets alias automatically
|
170
|
+
#
|
171
|
+
# @example with an alias (relation identifier is inferred via pluralization)
|
172
|
+
# has_one :address
|
173
|
+
#
|
174
|
+
# @example with an explicit alias and a custom view
|
175
|
+
# has_one :posts, as: :priority_post, view: :prioritized
|
176
|
+
#
|
177
|
+
# @see #one_to_one
|
178
|
+
#
|
179
|
+
# @return [Associations::OneToOne]
|
180
|
+
#
|
181
|
+
# @api public
|
182
|
+
def has_one(target, **options)
|
183
|
+
one_to_one(dataset_name(target), as: target, **options)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Return an association set for a schema
|
187
|
+
#
|
188
|
+
# @return [Array<Association::Definition]
|
189
|
+
#
|
190
|
+
# @api private
|
191
|
+
def call
|
192
|
+
registry.values
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
# @api private
|
198
|
+
def build(definition, target, options)
|
199
|
+
definition.new(source, target, **options, inflector: inflector)
|
200
|
+
end
|
201
|
+
|
202
|
+
# @api private
|
203
|
+
def add(association)
|
204
|
+
key = association.as || association.name
|
205
|
+
|
206
|
+
if registry.key?(key)
|
207
|
+
::Kernel.raise(
|
208
|
+
::ArgumentError,
|
209
|
+
"association #{key.inspect} is already defined for #{source.to_sym.inspect} relation"
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
registry[key] = association
|
214
|
+
end
|
215
|
+
|
216
|
+
# @api private
|
217
|
+
def dataset_name(name)
|
218
|
+
inflector.pluralize(name).to_sym
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/class_attributes"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
class Schema
|
7
|
+
# @api private
|
8
|
+
class Inferrer
|
9
|
+
extend Dry::Core::ClassAttributes
|
10
|
+
extend Initializer
|
11
|
+
|
12
|
+
# @!method self.attributes_inferrer
|
13
|
+
# @overload attributes_inferrer
|
14
|
+
# @return [Proc]
|
15
|
+
#
|
16
|
+
# @overload attributes_inferrer(value)
|
17
|
+
# @param value [Proc]
|
18
|
+
# @return [Proc]
|
19
|
+
#
|
20
|
+
# @!method self.attr_class
|
21
|
+
# @overload attr_class
|
22
|
+
# @return [Class(ROM::Attribute)]
|
23
|
+
#
|
24
|
+
# @overload attr_class(value)
|
25
|
+
# @param value [Class(ROM::Attribute)]
|
26
|
+
# @return [Class(ROM::Attribute)]
|
27
|
+
defines :attributes_inferrer, :attr_class
|
28
|
+
|
29
|
+
MissingAttributesError = Class.new(StandardError) do
|
30
|
+
def initialize(name, attributes)
|
31
|
+
super(
|
32
|
+
"Following attributes in #{Relation::Name[name].relation.inspect} schema cannot "\
|
33
|
+
"be inferred and have to be defined explicitly: #{attributes.map(&:inspect).join(", ")}"
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
DEFAULT_ATTRIBUTES = [EMPTY_ARRAY, EMPTY_ARRAY].freeze
|
39
|
+
|
40
|
+
attributes_inferrer -> * { DEFAULT_ATTRIBUTES }
|
41
|
+
|
42
|
+
attr_class Attribute
|
43
|
+
|
44
|
+
include Dry::Equalizer(:options)
|
45
|
+
|
46
|
+
# @!attribute [r] attr_class
|
47
|
+
# @return [Class(ROM::Attribute)]
|
48
|
+
option :attr_class, default: -> { self.class.attr_class }
|
49
|
+
|
50
|
+
# @!attribute [r] enabled
|
51
|
+
# @return [Boolean]
|
52
|
+
option :enabled, default: -> { true }
|
53
|
+
|
54
|
+
alias_method :enabled?, :enabled
|
55
|
+
|
56
|
+
# @!attribute [r] attributes_inferrer
|
57
|
+
# @return [ROM::Schema::AttributesInferrer]
|
58
|
+
option :attributes_inferrer, default: -> { self.class.attributes_inferrer }
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
def call(schema, gateway)
|
62
|
+
if enabled?
|
63
|
+
inferred, missing = attributes_inferrer.(schema, gateway, options)
|
64
|
+
else
|
65
|
+
inferred, missing = DEFAULT_ATTRIBUTES
|
66
|
+
end
|
67
|
+
|
68
|
+
attributes = merge_attributes(schema.attributes, inferred)
|
69
|
+
|
70
|
+
check_all_attributes_defined(schema, attributes, missing)
|
71
|
+
|
72
|
+
{attributes: attributes}
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def check_all_attributes_defined(schema, all_known, not_inferred)
|
77
|
+
not_defined = not_inferred - all_known.map(&:name)
|
78
|
+
|
79
|
+
raise MissingAttributesError.new(schema.name, not_defined) unless not_defined.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
# @api private
|
83
|
+
def merge_attributes(defined, inferred)
|
84
|
+
type_lookup = lambda do |attrs, name|
|
85
|
+
attrs.find { |a| a.name == name }.type
|
86
|
+
end
|
87
|
+
defined_with_type, defined_names =
|
88
|
+
defined.each_with_object([[], []]) do |attr, (attrs, names)|
|
89
|
+
attrs << if attr.type.nil?
|
90
|
+
attr.class.new(
|
91
|
+
type_lookup.(inferred, attr.name),
|
92
|
+
**attr.options
|
93
|
+
)
|
94
|
+
else
|
95
|
+
attr
|
96
|
+
end
|
97
|
+
names << attr.name
|
98
|
+
end
|
99
|
+
|
100
|
+
defined_with_type + inferred.reject do |attr|
|
101
|
+
defined_names.include?(attr.name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|