class Audrey

Audrey
build aclasses for collections
This code needs to go at the bottom of this file because the classes being
referenced aren't defined until after the COLLECTIONS hash is used.

Constants

AUDREY_COLLECTION_TO_RUBY
AUDREY_SCALAR_TO_RUBY
RUBY_OBJECT_TO_AUDREY
VERSION

version

Attributes

autopurge[RW]
closers[R]
engine[R]
partition[R]

Public Class Methods

connect(*opts) { |db| ... } click to toggle source
# File lib/audrey.rb, line 131
def self.connect(*opts)
        if block_given?
                begin
                        db = self.new(*opts)
                        
                        db.current do
                                yield db
                        end
                
                # implement db.exit by catching Audrey::Exception::DatabaseExit
                rescue Audrey::Exception::DatabaseExit => e
                        # NOTE: for whatever reason, e.db == db doesn't return true,
                        # even though they're the same object. Using object_id to
                        # bypass that problem.
                        unless e.db.object_id == db.object_id
                                raise e
                        end
                        
                        # return out of this method
                        return nil
                
                # ensure database is closed
                ensure
                        db and db.close
                end
        else
                return self.new(*opts)
        end
end
current_db(opts={}) click to toggle source
# File lib/audrey.rb, line 188
def self.current_db(opts={})
        return @@current_db
end
current_db=(db) click to toggle source
# File lib/audrey.rb, line 205
def self.current_db=(db)
        @@current_db = db
end
explicit_or_current_db(accessor) click to toggle source
# File lib/audrey.rb, line 192
def self.explicit_or_current_db(accessor)
        # $tm.hrm
        
        # explicit accessor was sent
        if accessor
                return accessor
        
        # else return current database
        else
                return @@current_db
        end
end
finalize(id) click to toggle source
# File lib/audrey.rb, line 231
def self.finalize(id)
        # $tm.hrm
        obj = ObjectSpace._id2ref(id)
        obj.close()
end
new(*params) click to toggle source
# File lib/audrey.rb, line 43
def initialize(*params)
        @org_opts = self.class.params_to_opts(*params)
        
        # mode
        # KLUDGE: For now, just always using the mode that was sent with the
        # "new" command. Eventually we'll need to recognize that different
        # partitions will have different modes
        @mode = Audrey::Mode.new(@org_opts['mode'])
        
        # finalizer
        ObjectSpace.define_finalizer(self, proc { self.class.finalize(self.object_id) })
        
        # engine opts
        @engine_opts = {}
        
        # immediate_commit
        if @org_opts.has_key?('immediate_commit')
                @engine_opts['immediate_commit'] = @org_opts['immediate_commit']
        end
        
        # default autopurge
        @autopurge = true
        
        # connect engine
        connect_engine()
end

Private Class Methods

initialize_engine(opts) click to toggle source
# File lib/audrey.rb, line 540
def self.initialize_engine(opts)
        # $tm.hrm
        engine = opts['engine']
        
        # if already an engine, return it
        if engine.is_a?(Audrey::Engine)
                return engine
        end
        
        # if class, return that
        if engine.is_a?(Class) and (engine < Audrey::Engine)
                return engine.new(opts)
        end
end
params_to_opts(*params) click to toggle source
# File lib/audrey.rb, line 562
def self.params_to_opts(*params)
        # $tm.hrm
        # $tm.show params
        
        # if single value and it's a hash, return that
        if (params.length == 1) and params[0].is_a?(Hash)
                return params[0]
        end
        
        # default engine
        default = {'engine'=>'sqlite3'}
        
        # if three, and third is a hash, use that as the options
        if (params.length == 3) and params[2].is_a?(Hash)
                default = default.merge(params.pop)
        end
        
        # if two params, then they are the connection string and the mode
        if (params.length == 2)
                rv = {'connect'=>params[0], 'mode'=>params[1]}
                rv = default.merge(rv)
                return rv
        end
        
        # else invalid input
        raise 'invalid-params-for-initialize'
end

Public Instance Methods

autocommit(opts={}, &block) click to toggle source
# File lib/audrey.rb, line 466
def autocommit(opts={}, &block)
        # $tm.hrm
        opts = {'autocommit'=>true}.merge(opts)
        transaction opts, &block
end
build_array(row) click to toggle source
# File lib/audrey.rb, line 264
def build_array(row)
        node = Audrey::Node::Array.new(self, 'pk'=>row['pk'])
        rv = []
        node.attach_to rv
        return rv
end
changed_objects() { |object_from_row| ... } click to toggle source
# File lib/audrey.rb, line 523
def changed_objects()
        @engine.changed_objects do |row|
                yield self.object_from_row(row)
        end
end
checks_outside_transaction(aclass) click to toggle source
# File lib/audrey.rb, line 423
def checks_outside_transaction(aclass)
        if aclass.respond_to?('has_checks?')
                if (not in_transaction?) and aclass.has_checks?
                        raise 'cannot-create-or-modify-object-that-has-checks-when-not-in-a-transaction'
                end
        end
end
close() click to toggle source
# File lib/audrey.rb, line 244
def close
        # closers
        @closers.keys.each do |k|
                @closers[k].close
                @closers.delete(k)
        end
        
        # purge
        if @engine
                @engine.close 'purge'=>@autopurge
        end
end
connect_engine() click to toggle source
# File lib/audrey.rb, line 77
def connect_engine
        # objects that should be closed before the database is closed
        @closers = {}
        
        # sqlite3
        if @org_opts['engine'] == 'sqlite3'
                require 'audrey/engine/sqlite3'
                @engine = Audrey::Engine::SQLite3.new(@org_opts['connect'], @mode, @engine_opts)
        else
                # @engine = self.class.initialize_engine(opts)
                raise 'not-yet-implemented-non-sqlite-engine'
        end
        
        # default partition to m
        self.partition = 'm'
end
current() { || ... } click to toggle source
# File lib/audrey.rb, line 180
def current
        hold_current = Audrey.current_db
        Audrey.current_db = self
        yield
ensure
        Audrey.current_db = hold_current
end
ensure_object_record(object) click to toggle source
# File lib/audrey.rb, line 306
def ensure_object_record(object)
        # $tm.hrm
        write_check()
        
        # early exit: object already has a audrey object
        if object.respond_to?('audrey')
                return object.audrey.pk
        end
        
        # scalar
        if dfn = Audrey::RUBY_OBJECT_TO_AUDREY[object.class]
                if dfn['nclass']
                        pk = @engine.insert_object(object)
                        node = dfn['nclass'].new(self, 'pk'=>pk)
                        node.attach_to object
                        return pk
                else
                        return @engine.insert_object(object)
                end
        end
end
exit() click to toggle source
# File lib/audrey.rb, line 168
def exit()
        e = Audrey::Exception::DatabaseExit.new(self)
        raise e
end
import_csv(aclass, path, opts={}) click to toggle source
# File lib/audrey.rb, line 411
def import_csv(aclass, path, opts={})
        # $tm.hrm
        return @engine.import_csv(aclass, path, opts)
end
insert_object(object) click to toggle source
# File lib/audrey.rb, line 369
def insert_object(object)
        write_check()
        checks_outside_transaction object.class
        return @engine.insert_object(object)
end
object_from_pk(pk) click to toggle source
# File lib/audrey.rb, line 382
def object_from_pk(pk)
        row = @engine.row_by_pk(pk)
        
        if row
                return object_from_row(row)
        else
                return nil
        end
end
object_from_row(row) click to toggle source
# File lib/audrey.rb, line 335
def object_from_row(row)
        # $tm.hrm
        
        # scalar
        if dfn = Audrey::AUDREY_SCALAR_TO_RUBY[row['aclass']]
                return dfn.call(row['scalar'])
        end
        
        # collection
        if dfn = Audrey::AUDREY_COLLECTION_TO_RUBY[row['aclass']]
                return dfn['nclass'].create_object(self, 'row'=>row)
        end
        
        # custom class
        if Module.const_defined?(row['aclass'])
                clss = Module.const_get(row['aclass'])
                nclass = Audrey::AUDREY_COLLECTION_TO_RUBY[clss.hsa]['nclass']
                node = nclass.new(self, 'row'=>row)
                rv = clss.new('db'=>self, 'node'=>node)
                return rv
        end
        
        # if we get this far then we don't know how to turn the row into an
        # Audrey object
        raise 'unknown-aclass: ' + row['aclass'].to_s
end
partition=(val) click to toggle source
# File lib/audrey.rb, line 113
def partition=(val)
        # $tm.hrm
        
        # set partition
        @partition = val
        @engine.partition = val
        
        # set root
        @root = Audrey::Node::Hash.new(self, 'pk'=>@engine.root_pk)
end
purge() click to toggle source
# File lib/audrey.rb, line 278
def purge
        # $tm.hrm
        @engine.purge
end
q0() click to toggle source
# File lib/audrey.rb, line 399
def q0
        require 'audrey/query/q0'
        return Audrey::Query::Q0.new(self)
end
read_check() click to toggle source
# File lib/audrey.rb, line 290
def read_check
        # $tm.hrm
        @mode.read or raise Audrey::Exception::Permission::Read.new()
end
reset() click to toggle source
# File lib/audrey.rb, line 101
def reset
        close()
        connect_engine()
end
run_checks() click to toggle source
# File lib/audrey.rb, line 479
def run_checks()
        # $tm.hrm
        xeme = Xeme.new()
        
        # loop through records that have been changed
        changed_objects() do |obj|
                if obj.class.has_checks?
                        obj.class.fields.each do |fieldname, dfn|
                                val = obj.audrey[fieldname]
                                
                                # require
                                if dfn.required and val.nil?
                                        xeme.error('required') do |msg|
                                                msg['field'] = fieldname
                                        end
                                
                                # wrong class
                                elsif dfn.aclass and (not val.is_a?(dfn.aclass))
                                        xeme.error('wrong-aclass') do |msg|
                                                msg['field'] = fieldname
                                                msg['aclass'] = dfn.aclass.to_s
                                        end
                                
                                # run checks
                                else
                                        dfn.base_checks xeme, fieldname, val
                                end
                        end
                else
                        obj.audrey.changed = false
                end
        end
        
        # return
        return xeme
end
session_pk() click to toggle source
# File lib/audrey.rb, line 216
def session_pk
        if not instance_variable_defined?(:@session_pk)
                @session_pk = Audrey::Util.uuid
        end
        
        return @session_pk
end
transaction(opts={}) { |tr| ... } click to toggle source
# File lib/audrey.rb, line 438
def transaction(opts={})
        # $tm.hrm
        
        # yield to block and return nil
        if block_given?
                @engine.transaction(opts) do |tr|
                        # yield
                        yield tr
                        
                        # autocommit
                        if opts['autocommit']
                                tr.commit
                        end
                end
        
        # else just return transaction
        else
                raise 'not-yet-implemented-non-block-transaction'
        end
end
write_check() click to toggle source
# File lib/audrey.rb, line 295
def write_check
        @mode.write or raise Audrey::Exception::Permission::Write.new()
end