Class: ROM::Relation
- Inherits:
-
Object
- Object
- ROM::Relation
- Extended by:
- Dry::Core::ClassAttributes, AutoCurry, Initializer, ClassInterface
- Includes:
- Memoizable, Pipeline, Commands, Materializable
- Defined in:
- lib/rom/relation.rb,
lib/rom/relation/name.rb,
lib/rom/relation/wrap.rb,
lib/rom/relation/graph.rb,
lib/rom/relation/loaded.rb,
lib/rom/relation/curried.rb,
lib/rom/relation/combined.rb,
lib/rom/relation/commands.rb,
lib/rom/relation/view_dsl.rb,
lib/rom/relation/composite.rb,
lib/rom/relation/materializable.rb,
lib/rom/relation/class_interface.rb
Overview
Base relation class
Relation is a proxy for the dataset object provided by the gateway. It can forward methods to the dataset, which is why the “native” interface of the underlying gateway is available in the relation
Individual adapters sets up their relation classes and provide different APIs depending on their persistence backend.
Direct Known Subclasses
Defined Under Namespace
Modules: ClassInterface, Commands, Materializable Classes: Combined, Composite, Curried, Graph, Loaded, Name, ViewDSL, Wrap
Constant Summary collapse
- NOOP_OUTPUT_SCHEMA =
Default no-op output schema which is called in ‘Relation#each`
-> tuple { tuple }.freeze
Constants included from ClassInterface
ClassInterface::DEFAULT_DATASET_PROC, ClassInterface::INVALID_RELATIONS_NAMES
Constants included from Memoizable
Instance Attribute Summary collapse
-
#auto_map ⇒ TrueClass, FalseClass
readonly
private
Whether or not a relation and its compositions should be auto-mapped.
-
#auto_struct ⇒ TrueClass, FalseClass
readonly
private
Whether or not tuples should be auto-mapped to structs.
-
#commands ⇒ CommandRegistry
readonly
private
Command registry.
-
#dataset ⇒ Object
readonly
Dataset used by the relation provided by relation’s gateway.
-
#input_schema ⇒ Object#[]
readonly
private
Tuple processing function, uses schema or defaults to Hash[].
-
#mappers ⇒ MapperRegistry
readonly
An optional mapper registry (empty by default).
-
#meta ⇒ Hash
readonly
private
Meta data stored in a hash.
-
#name ⇒ Object
readonly
The relation name.
-
#output_schema ⇒ Object#[]
readonly
private
Tuple processing function, uses schema or defaults to NOOP_OUTPUT_SCHEMA.
-
#schema ⇒ Schema
readonly
Relation schema, defaults to class-level canonical schema (if it was defined) and sets an empty one as the fallback.
-
#struct_namespace(ns) ⇒ Relation
readonly
Return a new relation configured with the provided struct namespace.
Attributes included from ClassInterface
Attributes included from Memoizable
Class Method Summary collapse
-
.auto_map ⇒ Object
Whether or not a relation and its compositions should be auto-mapped.
-
.auto_struct ⇒ Object
Whether or not tuples should be auto-mapped to structs.
-
.gateway ⇒ Object
Manage the gateway.
-
.struct_namespace ⇒ Object
Get or set a namespace for auto-generated struct classes.
Instance Method Summary collapse
-
#[](name) ⇒ Attribute
Return schema attribute.
-
#adapter ⇒ Symbol
private
The wrapped relation’s adapter identifier ie :sql or :http.
-
#as(aliaz) ⇒ Relation
Return a new relation with an aliased name.
-
#associations ⇒ AssociationSet
Return schema’s association set (empty by default).
- #attr_ast ⇒ Object private
- #auto_map? ⇒ Boolean private
- #auto_struct? ⇒ Boolean private
-
#call ⇒ Relation::Loaded
Loads a relation.
-
#combine(*associations) ⇒ Relation
Combine with other relations.
-
#combine_with(*others) ⇒ Relation::Graph
Composes with other relations.
-
#curried? ⇒ false
private
Returns if this relation is curried.
-
#each {|Hash| ... } ⇒ Enumerator
Yields relation tuples.
-
#eager_load(assoc) ⇒ Relation
Return a graph node prepared by the given association.
-
#foreign_key(name) ⇒ Symbol
private
Return a foreign key name for the provided relation name.
-
#gateway ⇒ Symbol
private
Return name of the source gateway of this relation.
-
#graph? ⇒ false
private
Returns if this relation is a graph.
-
#map_to(klass, **opts) ⇒ Relation::Composite
Return a new relation that will map its tuples to instance of the provided class.
-
#map_with(*names, **opts) ⇒ Relation
Maps the wrapped relation with other mappers available in the registry.
- #mapper ⇒ Object private
- #meta_ast ⇒ Object private
-
#new(dataset, new_opts = EMPTY_HASH) ⇒ Object
Return a new relation with provided dataset and additional options.
-
#node(name) ⇒ Relation
Create a graph node for a given association identifier.
- #nodes(*args) ⇒ Object private
-
#preload_assoc(assoc, other) ⇒ Relation::Curried
private
Preload other relation via association.
-
#schema? ⇒ TrueClass, FalseClass
private
Returns true if a relation has schema defined.
-
#schemas ⇒ Hash<Symbol=>Schema>
Return all registered relation schemas.
-
#to_a ⇒ Array<Hash>
Materializes a relation into an array.
-
#to_ast ⇒ Array
Returns AST for the wrapped relation.
-
#with(opts) ⇒ Relation
Returns a new instance with the same dataset but new options.
-
#wrap(*names) ⇒ Wrap
Wrap other relations using association names.
-
#wrap? ⇒ false
private
Return if this is a wrap relation.
-
#wrap_around(*others) ⇒ Relation::Wrap
Wrap around other relations.
Methods included from Initializer
Methods included from ClassInterface
curried, default_name, default_schema, forward, relation_name, set_schema!, use, view, view_methods
Methods included from Notifications::Listener
Methods included from AutoCurry
auto_curried_methods, auto_curry, auto_curry_busy?, auto_curry_guard, extended
Methods included from Pipeline::Operator
Methods included from Materializable
Methods included from Memoizable
Methods included from Commands
Instance Attribute Details
#auto_map ⇒ TrueClass, FalseClass (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns Whether or not a relation and its compositions should be auto-mapped.
165 |
# File 'lib/rom/relation.rb', line 165 option :auto_map, default: -> { self.class.auto_map } |
#auto_struct ⇒ TrueClass, FalseClass (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns Whether or not tuples should be auto-mapped to structs.
170 |
# File 'lib/rom/relation.rb', line 170 option :auto_struct, default: -> { self.class.auto_struct } |
#commands ⇒ CommandRegistry (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns Command registry.
184 |
# File 'lib/rom/relation.rb', line 184 option :commands, default: -> { CommandRegistry.new({}, relation_name: name.relation) } |
#dataset ⇒ Object (readonly)
Returns dataset used by the relation provided by relation’s gateway.
136 |
# File 'lib/rom/relation.rb', line 136 param :dataset |
#input_schema ⇒ Object#[] (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns tuple processing function, uses schema or defaults to Hash[].
153 |
# File 'lib/rom/relation.rb', line 153 option :input_schema, default: -> { schema.to_input_hash } |
#mappers ⇒ MapperRegistry (readonly)
Returns an optional mapper registry (empty by default).
179 |
# File 'lib/rom/relation.rb', line 179 option :mappers, default: -> { MapperRegistry.new } |
#meta ⇒ Hash (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns Meta data stored in a hash.
189 |
# File 'lib/rom/relation.rb', line 189 option :meta, reader: true, default: -> { EMPTY_HASH } |
#name ⇒ Object (readonly)
Returns The relation name.
148 |
# File 'lib/rom/relation.rb', line 148 option :name, default: -> { self.class.schema ? self.class.schema.name : self.class.default_name } |
#output_schema ⇒ Object#[] (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns tuple processing function, uses schema or defaults to NOOP_OUTPUT_SCHEMA.
158 159 160 |
# File 'lib/rom/relation.rb', line 158 option :output_schema, default: -> { schema.any?(&:read?) ? schema.to_output_hash : NOOP_OUTPUT_SCHEMA } |
#schema ⇒ Schema (readonly)
Returns relation schema, defaults to class-level canonical schema (if it was defined) and sets an empty one as the fallback.
143 |
# File 'lib/rom/relation.rb', line 143 option :schema, default: -> { self.class.schema || self.class.default_schema } |
#struct_namespace(ns) ⇒ Relation (readonly)
Return a new relation configured with the provided struct namespace
175 |
# File 'lib/rom/relation.rb', line 175 option :struct_namespace, reader: false, default: -> { self.class.struct_namespace } |
Class Method Details
.auto_map ⇒ Boolean .auto_map(value) ⇒ Object
Whether or not a relation and its compositions should be auto-mapped
83 |
# File 'lib/rom/relation.rb', line 83 defines :auto_map |
.auto_struct ⇒ Boolean .auto_struct(value) ⇒ Object
Whether or not tuples should be auto-mapped to structs
94 |
# File 'lib/rom/relation.rb', line 94 defines :auto_struct |
.gateway ⇒ Symbol .gateway(gateway_key) ⇒ Object
Manage the gateway
72 |
# File 'lib/rom/relation.rb', line 72 defines :gateway |
.struct_namespace ⇒ Module .struct_namespace(namespace) ⇒ Object
Get or set a namespace for auto-generated struct classes. By default, new struct classes are created within ROM::Struct
@example using custom namespace
class Users < ROM::Relation[:sql]
struct_namespace Entities
end
users.by_pk(1).one! # => #<Entities::User id=1 name="Jane Doe">
113 |
# File 'lib/rom/relation.rb', line 113 defines :struct_namespace |
Instance Method Details
#[](name) ⇒ Attribute
Return schema attribute
205 206 207 |
# File 'lib/rom/relation.rb', line 205 def [](name) schema[name] end |
#adapter ⇒ Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns The wrapped relation’s adapter identifier ie :sql or :http.
557 558 559 |
# File 'lib/rom/relation.rb', line 557 def adapter self.class.adapter end |
#as(aliaz) ⇒ Relation
Return a new relation with an aliased name
550 551 552 |
# File 'lib/rom/relation.rb', line 550 def as(aliaz) with(name: name.as(aliaz)) end |
#associations ⇒ AssociationSet
Return schema’s association set (empty by default)
448 449 450 |
# File 'lib/rom/relation.rb', line 448 def associations schema.associations end |
#attr_ast ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
462 463 464 |
# File 'lib/rom/relation.rb', line 462 def attr_ast schema.map { |t| t.to_read_ast } end |
#auto_map? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
474 475 476 |
# File 'lib/rom/relation.rb', line 474 def auto_map? (auto_map || auto_struct) && ![:combine_type] end |
#auto_struct? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
479 480 481 |
# File 'lib/rom/relation.rb', line 479 def auto_struct? auto_struct && ![:combine_type] end |
#call ⇒ Relation::Loaded
Loads a relation
340 341 342 |
# File 'lib/rom/relation.rb', line 340 def call Loaded.new(self) end |
#combine(*associations) ⇒ Relation
Combine with other relations
240 241 242 |
# File 'lib/rom/relation.rb', line 240 def combine(*args) combine_with(*nodes(*args)) end |
#combine_with(*others) ⇒ Relation::Graph
Composes with other relations
251 252 253 |
# File 'lib/rom/relation.rb', line 251 def combine_with(*others) Combined.new(self, others) end |
#curried? ⇒ false
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns if this relation is curried
358 359 360 |
# File 'lib/rom/relation.rb', line 358 def curried? false end |
#each {|Hash| ... } ⇒ Enumerator
Yields relation tuples
Every tuple is processed through Relation#output_schema, it’s a no-op by default
218 219 220 221 222 223 224 225 226 |
# File 'lib/rom/relation.rb', line 218 def each return to_enum unless block_given? if auto_struct? mapper.(dataset.map { |tuple| output_schema[tuple] }).each { |struct| yield(struct) } else dataset.each { |tuple| yield(output_schema[tuple]) } end end |
#eager_load(assoc) ⇒ Relation
Return a graph node prepared by the given association
289 290 291 292 293 294 295 296 297 |
# File 'lib/rom/relation.rb', line 289 def eager_load(assoc) relation = assoc.prepare(self) if assoc.override? relation.(assoc) else relation.preload_assoc(assoc) end end |
#foreign_key(name) ⇒ Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return a foreign key name for the provided relation name
588 589 590 591 592 593 594 595 596 |
# File 'lib/rom/relation.rb', line 588 def foreign_key(name) attr = schema.foreign_key(name.dataset) if attr attr.name else :"#{Dry::Core::Inflector.singularize(name.dataset)}_id" end end |
#gateway ⇒ Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return name of the source gateway of this relation
566 567 568 |
# File 'lib/rom/relation.rb', line 566 def gateway self.class.gateway end |
#graph? ⇒ false
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns if this relation is a graph
367 368 369 |
# File 'lib/rom/relation.rb', line 367 def graph? false end |
#map_to(klass, **opts) ⇒ Relation::Composite
Return a new relation that will map its tuples to instance of the provided class
536 537 538 |
# File 'lib/rom/relation.rb', line 536 def map_to(klass, **opts) with(opts.merge(auto_struct: true, meta: { model: klass })) end |
#map_with(model) ⇒ Relation #map_with(*mappers) ⇒ Relation #map_with(*mappers, auto_map: true) ⇒ Relation
Maps the wrapped relation with other mappers available in the registry
522 523 524 |
# File 'lib/rom/relation.rb', line 522 def map_with(*names, **opts) super(*names).with(opts) end |
#mapper ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
484 485 486 |
# File 'lib/rom/relation.rb', line 484 def mapper mappers[to_ast] end |
#meta_ast ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
467 468 469 470 471 |
# File 'lib/rom/relation.rb', line 467 def = self..merge(dataset: name.dataset, alias: name.aliaz, struct_namespace: [:struct_namespace]) [:model] = false unless auto_struct? || [:model] end |
#new(dataset, new_opts = EMPTY_HASH) ⇒ Object
Return a new relation with provided dataset and additional options
Use this method whenever you need to use dataset API to get a new dataset and you want to return a relation back. Typically relation API should be enough though. If you find yourself using this method, it might be worth to consider reporting an issue that some dataset functionality is not available through relation API.
407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/rom/relation.rb', line 407 def new(dataset, new_opts = EMPTY_HASH) opts = if new_opts.empty? elsif new_opts.key?(:schema) .merge(new_opts).reject { |k, _| k == :input_schema || k == :output_schema } else .merge(new_opts) end self.class.new(dataset, opts) end |
#node(name) ⇒ Relation
Create a graph node for a given association identifier
276 277 278 279 280 |
# File 'lib/rom/relation.rb', line 276 def node(name) assoc = associations[name] other = assoc.node other.eager_load(assoc) end |
#nodes(*args) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/rom/relation.rb', line 256 def nodes(*args) args.reduce([]) do |acc, arg| case arg when Symbol acc << node(arg) when Hash acc.concat(arg.map { |name, opts| node(name).combine(opts) }) when Array acc.concat(arg.map { |opts| nodes(opts) }.reduce(:concat)) end end end |
#preload_assoc(assoc, other) ⇒ Relation::Curried
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Preload other relation via association
This is used internally when relations are composed
306 307 308 |
# File 'lib/rom/relation.rb', line 306 def preload_assoc(assoc, other) assoc.preload(self, other) end |
#schema? ⇒ TrueClass, FalseClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns true if a relation has schema defined
385 386 387 |
# File 'lib/rom/relation.rb', line 385 def schema? ! schema.empty? end |
#schemas ⇒ Hash<Symbol=>Schema>
Return all registered relation schemas
This holds all schemas defined via ‘view` DSL
577 578 579 |
# File 'lib/rom/relation.rb', line 577 def schemas self.class.schemas end |
#to_a ⇒ Array<Hash>
Materializes a relation into an array
349 350 351 |
# File 'lib/rom/relation.rb', line 349 def to_a to_enum.to_a end |
#to_ast ⇒ Array
Returns AST for the wrapped relation
457 458 459 |
# File 'lib/rom/relation.rb', line 457 def to_ast [:relation, [name.relation, attr_ast, ]] end |
#with(opts) ⇒ Relation
Returns a new instance with the same dataset but new options
432 433 434 435 436 437 438 439 440 441 |
# File 'lib/rom/relation.rb', line 432 def with(opts) = if opts.key?(:meta) opts.merge(meta: .merge(opts[:meta])) else opts end new(dataset, .merge()) end |
#wrap(*names) ⇒ Wrap
Wrap other relations using association names
320 321 322 |
# File 'lib/rom/relation.rb', line 320 def wrap(*names) wrap_around(*names.map { |n| associations[n].wrap }) end |
#wrap? ⇒ false
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return if this is a wrap relation
376 377 378 |
# File 'lib/rom/relation.rb', line 376 def wrap? false end |
#wrap_around(*others) ⇒ Relation::Wrap
Wrap around other relations
331 332 333 |
# File 'lib/rom/relation.rb', line 331 def wrap_around(*others) wrap_class.new(self, others) end |