class Axiom::Relation::Header

A set of attributes that correspond to values in each tuple

Constants

EMPTY

Represent an empty set of attributes

Attributes

keys[R]

The header keys

@return [Keys]

@api private

to_ary[R]

Convert the Header into an Array

@example

array = header.to_ary

@return [Array]

@api public

Public Class Methods

coerce(object, options = EMPTY_HASH) { |attribute| ... } click to toggle source

Coerce an Array-like object into a Header

@param [Header, to_ary] object

the header or attributes

@param [Hash] options

@yield [attribute]

@yieldparam [Attribute, Array] attribute

@return [Header]

@api private

# File lib/axiom/relation/header.rb, line 49
def self.coerce(object, options = EMPTY_HASH)
  if object.kind_of?(self)
    object
  else
    # Find the attribute with the block if possible, then fallback
    # to the default coercion method.
    block = lambda do |attribute|
      coerce_attribute(block_given? && yield(attribute) || attribute)
    end
    new(Array(object).map(&block), options)
  end
end
new(attributes = EMPTY_ARRAY, *) click to toggle source

Instantiate a Header

@example

header = Header.new(attributes)

@param [Array<Attribute>] attributes

optional attributes

@param [Hash] _options

@return [Header]

@api public

Calls superclass method
# File lib/axiom/relation/header.rb, line 74
def self.new(attributes = EMPTY_ARRAY, *)
  assert_unique_names(attributes.map(&:name))
  super
end
new(attributes, options = EMPTY_HASH) click to toggle source

Initialize a Header

@example

header = Header.new(attributes, keys: [[:id]])

@param [Array] attributes

@param [Hash] options

@return [undefined]

@api public

# File lib/axiom/relation/header.rb, line 136
def initialize(attributes, options = EMPTY_HASH)
  @to_ary        = self.class.freezer.call(attributes)
  @attribute_for = Hash[@to_ary.map(&:name).zip(@to_ary)]
  @keys          = coerce_keys(options.fetch(:keys, EMPTY_ARRAY))
end

Private Class Methods

assert_unique_names(names) click to toggle source

Assert the names are unique

@param [Array<Symbol>] names

@return [undefined]

@raise [DuplicateNameError]

raised if the names are not unique

@api private

# File lib/axiom/relation/header.rb, line 100
def self.assert_unique_names(names)
  duplicates = duplicate_names(names)
  if duplicates
    fail DuplicateNameError, "duplicate names: #{duplicates}"
  end
end
coerce_attribute(attribute) click to toggle source

Coerce the attribute into an Attribute

@param [Object] attribute

@return [Attribute]

@api private

# File lib/axiom/relation/header.rb, line 86
def self.coerce_attribute(attribute)
  Attribute.coerce(attribute)
end
duplicate_names(names) click to toggle source

Returns the duplicate names, if any

@param [Array<Symbol>] names

@return [Array<Symbol>]

returns an array of duplicate names

@return [nil]

returns nil if there are no duplicate names

@api private

# File lib/axiom/relation/header.rb, line 118
def self.duplicate_names(names)
  names.select { |name| names.count(name) > 1 }.uniq!
end

Public Instance Methods

context(&block) click to toggle source

Evaluate a block within the context of the header

@yield [context]

@yieldparam [Evaluator::Context] context

@yieldreturn [Evaluator::Context]

@return [Header]

@api private

# File lib/axiom/relation/header.rb, line 303
def context(&block)
  Evaluator::Context.new(self, &block)
end
difference(other) click to toggle source

Return the difference of the header with another header

The original keys from the header are reused because a difference does not affect key constraints.

@example

difference = header.difference(other)

@param [Header] other

@return [Header]

@api public

# File lib/axiom/relation/header.rb, line 287
def difference(other)
  other = coerce(other)
  new(to_ary - other, keys: keys - other.keys)
end
each() { |attribute| ... } click to toggle source

Iterate over each attribute in the header

@example

header = Header.new(attributes)
header.each { |attribute| ... }

@yield [attribute]

@yieldparam [Attribute] attribute

each attribute in the header

@return [self]

@api public

# File lib/axiom/relation/header.rb, line 156
def each
  return to_enum unless block_given?
  to_ary.each { |attribute| yield attribute }
  self
end
empty?() click to toggle source

Test if there are no attributes

@example

header.empty?  # => true or false

@return [Boolean]

@api public

# File lib/axiom/relation/header.rb, line 324
def empty?
  to_ary.empty?
end
extend(attributes) click to toggle source

Return a header with the new attributes added

The original keys from the header are reused because an extension does not affect key constraints.

@example

extended = header.extend(attributes)

@param [#to_ary] attributes

the attributes to add to the header

@return [Header]

@api public

# File lib/axiom/relation/header.rb, line 214
def extend(attributes)
  new(to_ary + coerce(attributes), keys: keys)
end
fetch(name) click to toggle source

Lookup an attribute in the header given a name

@example

attribute = header.call(:id)

@param [Attribute, to_ary, to_sym] name

@return [Attribute]

the attribute when the name is known

@api public

# File lib/axiom/relation/header.rb, line 173
def fetch(name)
  @attribute_for.fetch(Attribute.name_from(name)) do |attribute_name|
    fail(
      UnknownAttributeError,
      "the attribute #{attribute_name} is unknown"
    )
  end
end
intersect(other) click to toggle source

Return the intersection of the header with another header

The unique keys from the headers become the new keys because an intersection strengthens key constraints.

@example

intersection = header.intersect(other)

@param [Header] other

@return [Header]

@api public

# File lib/axiom/relation/header.rb, line 250
def intersect(other)
  other      = coerce(other)
  attributes = to_ary & other
  new(attributes, keys: (keys | other.keys).project(attributes))
end
project(attributes) click to toggle source

Return a header with only the attributes specified

The unique keys intersected with the attributes become the new keys because a projection strengthens key constraints.

@example

projected = header.project(attributes)

@param [#map] attributes

the attributes to keep in the header

@return [Header]

@api public

# File lib/axiom/relation/header.rb, line 196
def project(attributes)
  coerce(attributes, keys: keys.project(attributes))
end
rename(aliases) click to toggle source

Return a header with the attributes renamed

The attributes in the original keys are renamed, but a rename does not otherwise affect the key constraints.

@example

renamed = header.rename(aliases)

@param [Aliases] aliases

the old and new attribute names

@return [Header]

@api public

# File lib/axiom/relation/header.rb, line 232
def rename(aliases)
  aliases = Algebra::Rename::Aliases.coerce(self, aliases)
  new(map(&aliases.method(:[])), keys: keys.rename(aliases))
end
size() click to toggle source

The number of attributes

@return [Integer]

@api public

# File lib/axiom/relation/header.rb, line 312
def size
  to_ary.size
end
union(other) click to toggle source

Return the union of the header with another header

The common keys from the headers become the new keys because a union weakens key constraints.

@example

union = header.union(other)

@param [Header] other

@return [Header]

@api public

# File lib/axiom/relation/header.rb, line 269
def union(other)
  other = coerce(other)
  new(to_ary | other, keys: keys & other.keys)
end

Private Instance Methods

coerce(*args) click to toggle source

Coerce the object into a Header

@param [Array] args

@return [Header]

@api private

# File lib/axiom/relation/header.rb, line 359
def coerce(*args)
  self.class.coerce(*args, &@attribute_for.method(:[]))
end
coerce_keys(keys) click to toggle source

Coerce the keys into an Array of Headers

@return [Array]

@return [Array<Header>]

@api private

# File lib/axiom/relation/header.rb, line 348
def coerce_keys(keys)
  Keys.coerce(keys) { |attributes| coerce(attributes) }
end
new(*args) click to toggle source

Utility method to instantiate a Header

@param [Array] args

@return [Header]

@api private

# File lib/axiom/relation/header.rb, line 337
def new(*args)
  self.class.new(*args)
end