Class: ROM::Attribute

Inherits:
Object
  • Object
show all
Extended by:
Initializer
Includes:
Memoizable
Defined in:
lib/rom/attribute.rb

Overview

Schema attributes provide meta information about types and an API for additional operations. This class can be extended by adapters to provide database-specific features. In example rom-sql provides SQL::Attribute with more features like creating SQL expressions for queries.

Schema attributes are accessible through canonical relation schemas and instance-level schemas.

Constant Summary collapse

META_OPTIONS =
%i[primary_key foreign_key source target relation].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object (private)

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.


410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/rom/attribute.rb', line 410

def method_missing(meth, *args, &block)
  if type.respond_to?(meth)
    response = type.__send__(meth, *args, &block)

    if response.is_a?(type.class)
      self.class.new(response, **options)
    else
      response
    end
  else
    super
  end
end

Instance Attribute Details

#__memoized__Object (readonly) Originally defined in module Memoizable

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.

#nameSymbol (readonly)

Return the canonical name of this attribute name

This always returns the name that is used in the datastore, even when an attribute is aliased

Examples:

class Users < ROM::Relation[:memory]
  schema do
    attribute :user_id, Types::Integer, alias: :id
    attribute :email, Types::String
  end
end

users[:user_id].name
# => :user_id

users[:email].name
# => :email

Returns:

  • (Symbol)

55
# File 'lib/rom/attribute.rb', line 55

option :name, optional: true, type: Types::Strict::Symbol

#typeSymbol? (readonly)

Returns Alias to use instead of attribute name.

Returns:

  • (Symbol, nil)

    Alias to use instead of attribute name


29
# File 'lib/rom/attribute.rb', line 29

param :type

Instance Method Details

#[](value = Undefined) ⇒ 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.


62
63
64
# File 'lib/rom/attribute.rb', line 62

def [](value = Undefined)
  type[value]
end

#aliased(name) ⇒ Attribute Also known as: as

Return new attribute type with provided alias

Examples:

class Tasks < ROM::Relation[:memory]
  schema do
    attribute :user_id, Types::Integer
    attribute :name, Types::String
  end
end

aliased_user_id = Users.schema[:user_id].aliased(:id)

aliased_user_id.aliased?
# => true

aliased_user_id.name
# => :user_id

aliased_user_id.alias
# => :id

Parameters:

  • name (Symbol)

    The alias

Returns:


234
235
236
# File 'lib/rom/attribute.rb', line 234

def aliased(name)
  with(alias: name)
end

#aliased?TrueClass, FalseClass

Return true if this attribute has a configured alias

Examples:

class Tasks < ROM::Relation[:memory]
  schema do
    attribute :user_id, Types::Integer, alias: :id
    attribute :name, Types::String
  end
end

Users.schema[:user_id].aliased?
# => true

Users.schema[:name].aliased?
# => false

Returns:

  • (TrueClass, FalseClass)

133
134
135
# File 'lib/rom/attribute.rb', line 133

def aliased?
  !self.alias.nil?
end

#eql?(other) ⇒ TrueClass, FalseClass

Check if the attribute type is equal to another

Parameters:

Returns:

  • (TrueClass, FalseClass)

332
333
334
# File 'lib/rom/attribute.rb', line 332

def eql?(other)
  other.is_a?(self.class) ? super : type.eql?(other)
end

#foreign_key?TrueClass, FalseClass

Return true if this attribute type is a foreign key

Examples:

class Tasks < ROM::Relation[:memory]
  schema do
    attribute :id, Types::Integer
    attribute :user_id, Types.ForeignKey(:users)
  end
end

Users.schema[:user_id].foreign_key?
# => true

Users.schema[:id].foreign_key?
# => false

Returns:

  • (TrueClass, FalseClass)

110
111
112
# File 'lib/rom/attribute.rb', line 110

def foreign_key?
  meta[:foreign_key].equal?(true)
end

#inspectString Also known as: pretty_inspect

Return string representation of the attribute type

Returns:

  • (String)

318
319
320
321
322
# File 'lib/rom/attribute.rb', line 318

def inspect
  opts = options.reject { |k| %i[type name].include?(k) }
  meta_and_opts = meta.merge(opts).map { |k, v| "#{k}=#{v.inspect}" }
  %(#<#{self.class}[#{type.name}] name=#{name.inspect} #{meta_and_opts.join(" ")}>)
end

#keySymbol

Return tuple key

When schemas are projected with aliased attributes, we need a simple access to tuple keys

Examples:

class Tasks < ROM::Relation[:memory]
  schema do
    attribute :user_id, Types::Integer, alias: :id
    attribute :name, Types::String
  end
end

Users.schema[:id].key
# :id

Users.schema.project(Users.schema[:id].aliased(:user_id)).key
# :user_id

Returns:

  • (Symbol)

204
205
206
# File 'lib/rom/attribute.rb', line 204

def key
  self.alias || name
end

#meta(opts = nil) ⇒ Attribute

Return attribute type with additional meta information

Return meta information hash if no opts are provided

Parameters:

  • opts (Hash) (defaults to: nil)

    The meta options

Returns:


305
306
307
308
309
310
311
# File 'lib/rom/attribute.rb', line 305

def meta(opts = nil)
  if opts
    self.class.new(type.meta(opts), **options)
  else
    type.meta
  end
end

#meta_options_astObject

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.


398
399
400
401
402
403
# File 'lib/rom/attribute.rb', line 398

def meta_options_ast
  keys = %i[wrapped primary_key alias]
  ast = meta.merge(options).select { |k, _| keys.include?(k) }
  ast[:source] = source.to_sym if source
  ast
end

#optionalAttribute

Return nullable attribute

Returns:


369
370
371
372
# File 'lib/rom/attribute.rb', line 369

def optional
  sum = self.class.new(super, **options)
  read? ? sum.meta(read: meta[:read].optional) : sum
end

#prefixed(prefix = source.dataset) ⇒ Attribute

Return new attribute type with an alias using provided prefix

Examples:

class Users < ROM::Relation[:memory]
  schema do
    attribute :id, Types::Integer
    attribute :name, Types::String
  end
end

prefixed_id = Users.schema[:id].prefixed

prefixed_id.aliased?
# => true

prefixed_id.name
# => :id

prefixed_id.alias
# => :users_id

prefixed_id = Users.schema[:id].prefixed(:user)

prefixed_id.alias
# => :user_id

Parameters:

  • prefix (Symbol) (defaults to: source.dataset)

    The prefix (defaults to source.dataset)

Returns:


270
271
272
# File 'lib/rom/attribute.rb', line 270

def prefixed(prefix = source.dataset)
  aliased(:"#{prefix}_#{name}")
end

#primary_key?TrueClass, FalseClass

Return true if this attribute type is a primary key

Examples:

class Users < ROM::Relation[:memory]
  schema do
    attribute :id, Types::Integer
    attribute :name, Types::String

    primary_key :id
  end
end

Users.schema[:id].primary_key?
# => true

Users.schema[:name].primary_key?
# => false

Returns:

  • (TrueClass, FalseClass)

87
88
89
# File 'lib/rom/attribute.rb', line 87

def primary_key?
  meta[:primary_key].equal?(true)
end

#read?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.

Return if this attribute type has additional attribute type for reading tuple values

Returns:

  • (TrueClass, FalseClass)

342
343
344
# File 'lib/rom/attribute.rb', line 342

def read?
  !meta[:read].nil?
end

#respond_to_missing?(name, include_private = false) ⇒ 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.

Returns:

  • (Boolean)

375
376
377
# File 'lib/rom/attribute.rb', line 375

def respond_to_missing?(name, include_private = false)
  type.respond_to?(name) || super
end

#sourceSymbol, Relation::Name

Return source relation of this attribute type

Examples:

class Tasks < ROM::Relation[:memory]
  schema do
    attribute :id, Types::Integer
    attribute :user_id, Types.ForeignKey(:users)
  end
end

Users.schema[:id].source
# => :tasks

Users.schema[:user_id].source
# => :tasks

Returns:


156
157
158
# File 'lib/rom/attribute.rb', line 156

def source
  meta[:source]
end

#targetNilClass, ...

Return target relation of this attribute type

Examples:

class Tasks < ROM::Relation[:memory]
  schema do
    attribute :id, Types::Integer
    attribute :user_id, Types.ForeignKey(:users)
  end
end

Users.schema[:id].target
# => nil

Users.schema[:user_id].target
# => :users

Returns:


179
180
181
# File 'lib/rom/attribute.rb', line 179

def target
  meta[:target]
end

#to_astArray

Return AST for the type

Returns:

  • (Array)

384
385
386
# File 'lib/rom/attribute.rb', line 384

def to_ast
  [:attribute, [name, type.to_ast(meta: false), meta_options_ast]]
end

#to_read_astArray

Return AST for the read type

Returns:

  • (Array)

393
394
395
# File 'lib/rom/attribute.rb', line 393

def to_read_ast
  [:attribute, [name, to_read_type.to_ast(meta: false), meta_options_ast]]
end

#to_read_typeDry::Types::Type

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 read type

Returns:

  • (Dry::Types::Type)

351
352
353
# File 'lib/rom/attribute.rb', line 351

def to_read_type
  read? ? meta[:read] : type
end

#to_write_typeDry::Types::Type

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 write type

Returns:

  • (Dry::Types::Type)

360
361
362
# File 'lib/rom/attribute.rb', line 360

def to_write_type
  type
end

#wrapped(name = source.dataset) ⇒ Attribute

Return attribute type wrapped for the specified relation name

Parameters:

  • name (Symbol) (defaults to: source.dataset)

    The name of the source relation (defaults to source.dataset)

Returns:


292
293
294
# File 'lib/rom/attribute.rb', line 292

def wrapped(name = source.dataset)
  prefixed(name).meta(wrapped: true)
end

#wrapped?Boolean

Return if the attribute type is from a wrapped relation

Wrapped attributes are used when two schemas from different relations are merged together. This way we can identify them easily and handle correctly in places like auto-mapping.

Returns:

  • (Boolean)

281
282
283
# File 'lib/rom/attribute.rb', line 281

def wrapped?
  meta[:wrapped].equal?(true)
end