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(*args) ⇒ Relation
Combine with other relations using configured associations.
-
#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, mapper_registry, 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.
164 |
# File 'lib/rom/relation.rb', line 164 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.
169 |
# File 'lib/rom/relation.rb', line 169 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.
183 |
# File 'lib/rom/relation.rb', line 183 option :commands, default: -> { CommandRegistry.new({}, relation_name: name.relation) } |
#dataset ⇒ Object (readonly)
Returns dataset used by the relation provided by relation’s gateway.
135 |
# File 'lib/rom/relation.rb', line 135 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[].
152 |
# File 'lib/rom/relation.rb', line 152 option :input_schema, default: -> { schema.to_input_hash } |
#mappers ⇒ MapperRegistry (readonly)
Returns an optional mapper registry (empty by default).
178 |
# File 'lib/rom/relation.rb', line 178 option :mappers, default: -> { self.class.mapper_registry } |
#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.
188 |
# File 'lib/rom/relation.rb', line 188 option :meta, reader: true, default: -> { EMPTY_HASH } |
#name ⇒ Object (readonly)
Returns The relation name.
147 |
# File 'lib/rom/relation.rb', line 147 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.
157 158 159 |
# File 'lib/rom/relation.rb', line 157 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.
142 |
# File 'lib/rom/relation.rb', line 142 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
174 |
# File 'lib/rom/relation.rb', line 174 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
82 |
# File 'lib/rom/relation.rb', line 82 defines :auto_map |
.auto_struct ⇒ Boolean .auto_struct(value) ⇒ Object
Whether or not tuples should be auto-mapped to structs
93 |
# File 'lib/rom/relation.rb', line 93 defines :auto_struct |
.gateway ⇒ Symbol .gateway(gateway_key) ⇒ Object
Manage the gateway
71 |
# File 'lib/rom/relation.rb', line 71 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">
112 |
# File 'lib/rom/relation.rb', line 112 defines :struct_namespace |
Instance Method Details
#[](name) ⇒ Attribute
Return schema attribute
204 205 206 |
# File 'lib/rom/relation.rb', line 204 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.
568 569 570 |
# File 'lib/rom/relation.rb', line 568 def adapter self.class.adapter end |
#as(aliaz) ⇒ Relation
Return a new relation with an aliased name
561 562 563 |
# File 'lib/rom/relation.rb', line 561 def as(aliaz) with(name: name.as(aliaz)) end |
#associations ⇒ AssociationSet
Return schema’s association set (empty by default)
459 460 461 |
# File 'lib/rom/relation.rb', line 459 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.
473 474 475 |
# File 'lib/rom/relation.rb', line 473 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.
485 486 487 |
# File 'lib/rom/relation.rb', line 485 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.
490 491 492 |
# File 'lib/rom/relation.rb', line 490 def auto_struct? auto_struct && ![:combine_type] end |
#call ⇒ Relation::Loaded
Loads a relation
351 352 353 |
# File 'lib/rom/relation.rb', line 351 def call Loaded.new(self) end |
#combine(*associations) ⇒ Relation #combine(*associations, **nested_associations) ⇒ Relation #combine(associations) ⇒ Relation
Combine with other relations using configured associations
251 252 253 |
# File 'lib/rom/relation.rb', line 251 def combine(*args) combine_with(*nodes(*args)) end |
#combine_with(*others) ⇒ Relation::Graph
Composes with other relations
262 263 264 |
# File 'lib/rom/relation.rb', line 262 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
369 370 371 |
# File 'lib/rom/relation.rb', line 369 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
217 218 219 220 221 222 223 224 225 |
# File 'lib/rom/relation.rb', line 217 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
300 301 302 303 304 305 306 307 308 |
# File 'lib/rom/relation.rb', line 300 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
599 600 601 602 603 604 605 606 607 |
# File 'lib/rom/relation.rb', line 599 def foreign_key(name) attr = schema.foreign_key(name.dataset) if attr attr.name else :"#{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
577 578 579 |
# File 'lib/rom/relation.rb', line 577 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
378 379 380 |
# File 'lib/rom/relation.rb', line 378 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
547 548 549 |
# File 'lib/rom/relation.rb', line 547 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
533 534 535 |
# File 'lib/rom/relation.rb', line 533 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.
495 496 497 |
# File 'lib/rom/relation.rb', line 495 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.
478 479 480 481 482 |
# File 'lib/rom/relation.rb', line 478 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.
418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/rom/relation.rb', line 418 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
287 288 289 290 291 |
# File 'lib/rom/relation.rb', line 287 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.
267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/rom/relation.rb', line 267 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
317 318 319 |
# File 'lib/rom/relation.rb', line 317 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
396 397 398 |
# File 'lib/rom/relation.rb', line 396 def schema? ! schema.empty? end |
#schemas ⇒ Hash<Symbol=>Schema>
Return all registered relation schemas
This holds all schemas defined via ‘view` DSL
588 589 590 |
# File 'lib/rom/relation.rb', line 588 def schemas self.class.schemas end |
#to_a ⇒ Array<Hash>
Materializes a relation into an array
360 361 362 |
# File 'lib/rom/relation.rb', line 360 def to_a to_enum.to_a end |
#to_ast ⇒ Array
Returns AST for the wrapped relation
468 469 470 |
# File 'lib/rom/relation.rb', line 468 def to_ast [:relation, [name.relation, attr_ast, ]] end |
#with(opts) ⇒ Relation
Returns a new instance with the same dataset but new options
443 444 445 446 447 448 449 450 451 452 |
# File 'lib/rom/relation.rb', line 443 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
331 332 333 |
# File 'lib/rom/relation.rb', line 331 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
387 388 389 |
# File 'lib/rom/relation.rb', line 387 def wrap? false end |
#wrap_around(*others) ⇒ Relation::Wrap
Wrap around other relations
342 343 344 |
# File 'lib/rom/relation.rb', line 342 def wrap_around(*others) wrap_class.new(self, others) end |