class ROM::Attribute

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.

@api public

Constants

META_OPTIONS

Public Instance Methods

[](value = Undefined) click to toggle source

@api private

# File lib/rom/attribute.rb, line 62
def [](value = Undefined)
  type[value]
end
aliased(name) click to toggle source

Return new attribute type with provided alias

@example

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

@param [Symbol] name The alias

@return [Attribute]

@api public

# File lib/rom/attribute.rb, line 234
def aliased(name)
  with(alias: name)
end
Also aliased as: as
aliased?() click to toggle source

Return true if this attribute has a configured alias

@example

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

@return [TrueClass,FalseClass]

@api public

# File lib/rom/attribute.rb, line 133
def aliased?
  !self.alias.nil?
end
as(name)
Alias for: aliased
eql?(other) click to toggle source

Check if the attribute type is equal to another

@param [Dry::Type, Attribute] other

@return [TrueClass,FalseClass]

@api public

Calls superclass method
# File lib/rom/attribute.rb, line 332
def eql?(other)
  other.is_a?(self.class) ? super : type.eql?(other)
end
foreign_key?() click to toggle source

Return true if this attribute type is a foreign key

@example

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

@return [TrueClass,FalseClass]

@api public

# File lib/rom/attribute.rb, line 110
def foreign_key?
  meta[:foreign_key].equal?(true)
end
inspect() click to toggle source

Return string representation of the attribute type

@return [String]

@api public

# 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
Also aliased as: pretty_inspect
key() click to toggle source

Return tuple key

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

@example

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

@return [Symbol]

@api public

# File lib/rom/attribute.rb, line 204
def key
  self.alias || name
end
meta(opts = nil) click to toggle source

Return attribute type with additional meta information

Return meta information hash if no opts are provided

@param [Hash] opts The meta options

@return [Attribute]

@api public

# 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_ast() click to toggle source

@api private

# 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
optional() click to toggle source

Return nullable attribute

@return [Attribute]

@api public

Calls superclass method
# 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) click to toggle source

Return new attribute type with an alias using provided prefix

@example

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

@param [Symbol] prefix The prefix (defaults to source.dataset)

@return [Attribute]

@api public

# File lib/rom/attribute.rb, line 270
def prefixed(prefix = source.dataset)
  aliased(:"#{prefix}_#{name}")
end
pretty_inspect()
Alias for: inspect
primary_key?() click to toggle source

Return true if this attribute type is a primary key

@example

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

@return [TrueClass,FalseClass]

@api public

# File lib/rom/attribute.rb, line 87
def primary_key?
  meta[:primary_key].equal?(true)
end
read?() click to toggle source

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

@return [TrueClass, FalseClass]

@api private

# File lib/rom/attribute.rb, line 342
def read?
  !meta[:read].nil?
end
respond_to_missing?(name, include_private = false) click to toggle source

@api private

Calls superclass method
# File lib/rom/attribute.rb, line 375
def respond_to_missing?(name, include_private = false)
  type.respond_to?(name) || super
end
source() click to toggle source

Return source relation of this attribute type

@example

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

@return [Symbol, Relation::Name]

@api public

# File lib/rom/attribute.rb, line 156
def source
  meta[:source]
end
target() click to toggle source

Return target relation of this attribute type

@example

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

@return [NilClass, Symbol, Relation::Name]

@api public

# File lib/rom/attribute.rb, line 179
def target
  meta[:target]
end
to_ast() click to toggle source

Return AST for the type

@return [Array]

@api public

# File lib/rom/attribute.rb, line 384
def to_ast
  [:attribute, [name, type.to_ast(meta: false), meta_options_ast]]
end
to_read_ast() click to toggle source

Return AST for the read type

@return [Array]

@api public

# 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_type() click to toggle source

Return read type

@return [Dry::Types::Type]

@api private

# File lib/rom/attribute.rb, line 351
def to_read_type
  read? ? meta[:read] : type
end
to_write_type() click to toggle source

Return write type

@return [Dry::Types::Type]

@api private

# File lib/rom/attribute.rb, line 360
def to_write_type
  type
end
wrapped(name = source.dataset) click to toggle source

Return attribute type wrapped for the specified relation name

@param [Symbol] name The name of the source relation (defaults to source.dataset)

@return [Attribute]

@api public

# File lib/rom/attribute.rb, line 292
def wrapped(name = source.dataset)
  prefixed(name).meta(wrapped: true)
end
wrapped?() click to toggle source

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.

@api public

# File lib/rom/attribute.rb, line 281
def wrapped?
  meta[:wrapped].equal?(true)
end

Private Instance Methods

method_missing(meth, *args, &block) click to toggle source

@api private

Calls superclass method
# 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