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 ⇒ true, false
readonly
private
Whether or not a relation and its compositions should be auto-mapped.
-
#auto_struct ⇒ true, false
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
Return a new relation that will map its tuples to instances of the provided class.
-
#map_with(*names, **opts) ⇒ Relation::Composite
Maps relation with custom mappers available in the registry.
- #mapper ⇒ Object private
- #meta_ast ⇒ Object private
-
#new(dataset, **new_opts) ⇒ 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, 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 ⇒ true, false (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.
167 |
# File 'lib/rom/relation.rb', line 167 option :auto_map, default: -> { self.class.auto_map } |
#auto_struct ⇒ true, false (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.
172 |
# File 'lib/rom/relation.rb', line 172 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.
186 |
# File 'lib/rom/relation.rb', line 186 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[].
154 |
# File 'lib/rom/relation.rb', line 154 option :input_schema, default: -> { schema.to_input_hash } |
#mappers ⇒ MapperRegistry (readonly)
Returns an optional mapper registry (empty by default).
181 |
# File 'lib/rom/relation.rb', line 181 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.
191 |
# File 'lib/rom/relation.rb', line 191 option :meta, reader: true, default: -> { EMPTY_HASH } |
#name ⇒ Object (readonly)
Returns The relation name.
147 148 149 |
# File 'lib/rom/relation.rb', line 147 option :name, default: lambda { 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.
159 160 161 |
# File 'lib/rom/relation.rb', line 159 option :output_schema, default: lambda { 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
177 |
# File 'lib/rom/relation.rb', line 177 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
209 |
# File 'lib/rom/relation.rb', line 209 def [](name) = schema[name] |
#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.
528 |
# File 'lib/rom/relation.rb', line 528 def adapter = self.class.adapter |
#as(aliaz) ⇒ Relation
Return a new relation with an aliased name
523 |
# File 'lib/rom/relation.rb', line 523 def as(aliaz) = with(name: name.as(aliaz)) |
#associations ⇒ AssociationSet
Return schema’s association set (empty by default)
442 |
# File 'lib/rom/relation.rb', line 442 def associations = schema.associations |
#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.
452 |
# File 'lib/rom/relation.rb', line 452 def attr_ast = schema.map(&:to_read_ast) |
#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.
463 |
# File 'lib/rom/relation.rb', line 463 def auto_map? = (auto_map || auto_struct) && ![:combine_type] |
#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.
466 |
# File 'lib/rom/relation.rb', line 466 def auto_struct? = auto_struct && ![:combine_type] |
#call ⇒ Relation::Loaded
Loads a relation
346 |
# File 'lib/rom/relation.rb', line 346 def call = Loaded.new(self) |
#combine(*associations) ⇒ Relation #combine(*associations, **nested_associations) ⇒ Relation #combine(associations) ⇒ Relation
Combine with other relations using configured associations
254 |
# File 'lib/rom/relation.rb', line 254 def combine(*args) = combine_with(*nodes(*args)) |
#combine_with(*others) ⇒ Relation::Graph
Composes with other relations
263 |
# File 'lib/rom/relation.rb', line 263 def combine_with(*others) = Combined.new(self, others) |
#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
360 |
# File 'lib/rom/relation.rb', line 360 def curried? = false |
#each {|Hash| ... } ⇒ Enumerator
Yields relation tuples
Every tuple is processed through Relation#output_schema, it’s a no-op by default
220 221 222 223 224 225 226 227 228 |
# File 'lib/rom/relation.rb', line 220 def each(&) return to_enum unless block_given? if auto_map? mapper.(dataset.map { |tuple| output_schema[tuple] }).each(&) else dataset.each { |tuple| yield(output_schema[tuple]) } end end |
#eager_load(assoc) ⇒ Relation
Return a graph node prepared by the given association
299 300 301 302 303 304 305 306 307 |
# File 'lib/rom/relation.rb', line 299 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
553 554 555 556 557 558 559 560 561 |
# File 'lib/rom/relation.rb', line 553 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
535 |
# File 'lib/rom/relation.rb', line 535 def gateway = self.class.gateway |
#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 |
# File 'lib/rom/relation.rb', line 367 def graph? = false |
#map_to(klass, **opts) ⇒ Relation
Return a new relation that will map its tuples to instances of the provided class
509 510 511 |
# File 'lib/rom/relation.rb', line 509 def map_to(klass, **opts) with(opts.merge(auto_map: false, auto_struct: true, meta: { model: klass })) end |
#map_with(*mappers) ⇒ Relation::Composite #map_with(*mappers, auto_map: true) ⇒ Relation::Composite
Maps relation with custom mappers available in the registry
When ‘auto_map` is enabled, your mappers will be applied after performing default auto-mapping. This means that you can compose complex relations and have them auto-mapped, and use much simpler custom mappers to adjust resulting data according to your requirements.
497 |
# File 'lib/rom/relation.rb', line 497 def map_with(*names, **opts) = super(*names).with(opts) |
#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.
469 |
# File 'lib/rom/relation.rb', line 469 def mapper = mappers[to_ast] |
#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.
455 456 457 458 459 460 |
# File 'lib/rom/relation.rb', line 455 def = self..merge(dataset: name.dataset, alias: name.aliaz, struct_namespace: [:struct_namespace]) [:model] = false unless auto_struct? || [:model] end |
#new(dataset, **new_opts) ⇒ 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.
401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/rom/relation.rb', line 401 def new(dataset, **new_opts) opts = if new_opts.empty? elsif new_opts.key?(:schema) .merge(new_opts).except(:input_schema, :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
286 287 288 289 290 |
# File 'lib/rom/relation.rb', line 286 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.
266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/rom/relation.rb', line 266 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
316 |
# File 'lib/rom/relation.rb', line 316 def preload_assoc(assoc, other) = assoc.preload(self, other) |
#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
381 |
# File 'lib/rom/relation.rb', line 381 def schema? = !schema.empty? |
#schemas ⇒ Hash<Symbol=>Schema>
Return all registered relation schemas
This holds all schemas defined via ‘view` DSL
544 |
# File 'lib/rom/relation.rb', line 544 def schemas = self.class.schemas |
#to_a ⇒ Array<Hash>
Materializes a relation into an array
353 |
# File 'lib/rom/relation.rb', line 353 def to_a = to_enum.to_a |
#to_ast ⇒ Array
Returns AST for the wrapped relation
449 |
# File 'lib/rom/relation.rb', line 449 def to_ast = [:relation, [name.relation, attr_ast, ]] |
#with(opts) ⇒ Relation
Returns a new instance with the same dataset but new options
426 427 428 429 430 431 432 433 434 435 |
# File 'lib/rom/relation.rb', line 426 def with(opts) = if opts.key?(:meta) opts.merge(meta: .merge(opts[:meta])) else opts end new(dataset, **, **) end |
#wrap(*names) ⇒ Wrap
Wrap other relations using association names
328 329 330 |
# File 'lib/rom/relation.rb', line 328 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
374 |
# File 'lib/rom/relation.rb', line 374 def wrap? = false |
#wrap_around(*others) ⇒ Relation::Wrap
Wrap around other relations
339 |
# File 'lib/rom/relation.rb', line 339 def wrap_around(*others) = wrap_class.new(self, others) |