Class: ROM::Attribute

Inherits:
Object
  • Object
show all
Extended by:
Initializer
Includes:
Memoizable
Defined in:
core/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.



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

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)


53
# File 'core/lib/rom/attribute.rb', line 53

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



27
# File 'core/lib/rom/attribute.rb', line 27

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.



60
61
62
# File 'core/lib/rom/attribute.rb', line 60

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:



232
233
234
# File 'core/lib/rom/attribute.rb', line 232

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)


131
132
133
# File 'core/lib/rom/attribute.rb', line 131

def aliased?
  !self.alias.nil?
end

#eql?(other) ⇒ TrueClass, FalseClass

Check if the attribute type is equal to another

Parameters:

Returns:

  • (TrueClass, FalseClass)


330
331
332
# File 'core/lib/rom/attribute.rb', line 330

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)


108
109
110
# File 'core/lib/rom/attribute.rb', line 108

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

#inspectString Also known as: pretty_inspect

Return string representation of the attribute type

Returns:

  • (String)


316
317
318
319
320
# File 'core/lib/rom/attribute.rb', line 316

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)


202
203
204
# File 'core/lib/rom/attribute.rb', line 202

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:



303
304
305
306
307
308
309
# File 'core/lib/rom/attribute.rb', line 303

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.



396
397
398
399
400
401
# File 'core/lib/rom/attribute.rb', line 396

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:



367
368
369
370
# File 'core/lib/rom/attribute.rb', line 367

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:



268
269
270
# File 'core/lib/rom/attribute.rb', line 268

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)


85
86
87
# File 'core/lib/rom/attribute.rb', line 85

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)


340
341
342
# File 'core/lib/rom/attribute.rb', line 340

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)


373
374
375
# File 'core/lib/rom/attribute.rb', line 373

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:



154
155
156
# File 'core/lib/rom/attribute.rb', line 154

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:



177
178
179
# File 'core/lib/rom/attribute.rb', line 177

def target
  meta[:target]
end

#to_astArray

Return AST for the type

Returns:

  • (Array)


382
383
384
# File 'core/lib/rom/attribute.rb', line 382

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)


391
392
393
# File 'core/lib/rom/attribute.rb', line 391

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)


349
350
351
# File 'core/lib/rom/attribute.rb', line 349

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)


358
359
360
# File 'core/lib/rom/attribute.rb', line 358

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:



290
291
292
# File 'core/lib/rom/attribute.rb', line 290

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)


279
280
281
# File 'core/lib/rom/attribute.rb', line 279

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