module Swift
# A relation (instance) definition.
#
# @example A user scheme.
# class User < Swift::Scheme
# store :users
# attribute :id, Swift::Type::Integer, serial: true, key: true
# attribute :name, Swift::Type::String
# attribute :email, Swift::Type::String
# attribute :updated_at, Swift::Type::Time
# end # User
#
# @todo Tuple should be renamed tuples (plural?)
class Scheme
attr_accessor :tuple
alias_method :scheme, :class
# @example
# User.new(
# name: 'Apple Arthurton',
# email: 'apple@arthurton.local',
# updated_at: Time.now
# )
# @param [Hash] options Create relation and set attributes. {name: value}
def initialize options = {}
@tuple = scheme.header.new_tuple
options.each{|k, v| send(:"#{k}=", v)}
end
# @example
# apple = User.create(
# name: 'Apple Arthurton',
# email: 'apple@arthurton.local',
# updated_at: Time.now
# )
# apple.update(name: 'Arthur Appleton')
#
# @param [Hash] options Update attributes. {name: value}
def update options = {}
options.each{|k, v| send(:"#{k}=", v)}
Swift.db.update(scheme, self)
end
# @example
# apple = User.create(
# name: 'Apple Arthurton',
# email: 'apple@arthurton.local',
# updated_at: Time.now
# )
# apple.destroy
def destroy
Swift.db.destroy(scheme, self)
end
class << self
# Attribute set.
#
# @return [Swift::Header]
attr_accessor :header
def inherited klass
klass.header = Header.new
klass.header.push(*header) if header
Swift.schema.push(klass) if klass.name
end
def load tuple
scheme = allocate
scheme.tuple = tuple
scheme
end
# Define a new attribute for this scheme.
#
# @see Swift::Attribute#new
def attribute name, type, options = {}
header.push(attribute = type.new(self, name, options))
(class << self; self end).send(:define_method, name, lambda{ attribute })
end
# Define the store (table).
#
# @param [Symbol] name Storage name.
# @return [Symbol]
def store name = nil
name ? @store = name : @store
end
# Create (insert).
#
# @example
# apple = User.create(
# name: 'Apple Arthurton',
# email: 'apple@arthurton.local',
# updated_at: Time.now
# )
#
# @param [Hash] options Create with attributes. {name: value}
def create options = {}
Swift.db.create(self, options)
end
# Select by id(s).
#
# @example Single key.
# User.get(id: 12)
# @example Complex primary key.
# UserAddress.get(user_id: 12, address_id: 15)
#
# @param [Hash] keys Hash of id(s) {id_name: value}.
# @return [Swift::Scheme, nil]
def get keys
Swift.db.get(self, keys)
end
# Select one or more.
#
# @example All.
# User.all
# @example All with conditions and binds.
# User.all(':name = ? and :age > ?', 'Apple Arthurton', 32)
# @example Block form iterator.
# User.all(':age > ?', 32) do |user|
# puts user.name
# end
#
# @param [String] conditions Optional SQL 'where' fragment.
# @param [Object, ...] *binds Optional bind values that accompany conditions SQL fragment.
# @param [Proc] &block Optional 'each' iterator block.
# @return [Swift::Result]
def all conditions = '', *binds, &block
Swift.db.all(self, conditions, *binds, &block)
end
# Select one.
#
# @example First.
# User.first
# @example First with conditions and binds.
# User.first(':name = ? and :age > ?', 'Apple Arthurton', 32)
# @example Block form iterator.
# User.first(User, 'age > ?', 32) do |user|
# puts user.name
# end
#
# @param [String] conditions Optional SQL 'where' fragment.
# @param [Object, ...] *binds Optional bind values that accompany conditions SQL fragment.
# @param [Proc] &block Optional 'each' iterator block.
# @return [Swift::Scheme, nil]
def first conditions = '', *binds, &block
Swift.db.first(self, conditions, *binds, &block)
end
end
end # Scheme
end # Swift