module Engine2::Model

Attributes

after_destroy_processors[R]
after_load_processors[R]
after_save_processors[R]
before_destroy_processors[R]
before_save_processors[R]
dummies[R]
many_to_many_associations[R]
many_to_one_associations[R]
one_to_many_associations[R]
scheme_args[R]
scheme_name[R]
validation_in_transaction[R]

Public Class Methods

extended(cls) click to toggle source
# File lib/engine2/model.rb, line 11
def self.extended cls
    models = cls.db.models
    raise E2Error.new("Model '#{cls.name}' already defined") if models[cls.name.to_sym]
    models[cls.name.to_sym] = cls

    cls.instance_eval do
        @many_to_one_associations = association_reflections.select{|n, a| a[:type] == :many_to_one}
        @one_to_many_associations = association_reflections.select{|n, a| a[:type] == :one_to_many}
        @many_to_many_associations = association_reflections.select{|n, a| a[:type] == :many_to_many}
        # @one_to_one_associations = association_reflections.select{|n, a| a[:type] == :one_to_one}
        @validation_in_transaction = nil
        @after_load_processors = nil
        @before_save_processors = nil
        @after_save_processors = nil
        @around_save_processors = nil
        @before_destroy_processors = nil
        @after_destroy_processors = nil
        @type_info_synchronized = nil
        @model_icon = :"list"
        @model_route = cls.name.to_sym
    end
    cls.setup_schema
end

Public Instance Methods

find_type_info(name) click to toggle source
# File lib/engine2/model.rb, line 115
def find_type_info name
    model = self
    info = case name
    when Symbol
        model.type_info[name]
    when Sequel::SQL::QualifiedIdentifier
        assoc = model.many_to_one_associations[name.table] || model.many_to_many_associations[name.table]
        raise E2Error.new("Association #{name.table} not found for model #{model}") unless assoc
        assoc.associated_class.type_info[name.column]
    else
        raise E2Error.new("Unknown type info key: #{name} in model #{model}")
    end

    raise E2Error.new("Type info not found for '#{name}' in model '#{model}'") unless info
    info
end
install_processors(processors) click to toggle source
# File lib/engine2/model.rb, line 35
def install_processors processors
    hash = {}
    type_info.each_pair do |name, info|
        proc = processors[info[:type]]
        hash[name] = proc if proc
    end
    hash.empty? ? nil : hash
end
model_icon(icn = nil) click to toggle source
# File lib/engine2/model.rb, line 185
def model_icon icn = nil
    icn ? @model_icon = icn : @model_icon
end
model_route(rt = nil) click to toggle source
# File lib/engine2/model.rb, line 189
def model_route rt = nil
    rt ? @model_route = rt : @model_route
end
resolve_dependencies() click to toggle source
# File lib/engine2/model.rb, line 144
def resolve_dependencies
    resolved = {}
    @type_info.each_pair do |name, info|
        @validation_in_transaction ||= info[:transaction]
        resolve_dependency(name, resolved)
    end
    @type_info = resolved
end
resolve_dependency(name, resolved, seen = []) click to toggle source
# File lib/engine2/model.rb, line 153
def resolve_dependency name, resolved, seen = []
    seen << name
    deps = @type_info[name][:depends]
    deps.each do |e|
        if !resolved[e]
            raise E2Error.new("Circular dependency for field '#{name}' in model '#{self}'") if seen.include?(e)
            resolve_dependency(e, resolved, seen)
        end
    end if deps
    resolved[name] = @type_info[name]
end
scheme(s_name = :default, opts = nil, &blk) click to toggle source
# File lib/engine2/model.rb, line 179
def scheme s_name = :default, opts = nil, &blk
    @scheme_name = s_name
    @scheme_args = [model_route, self, opts]
    SCHEMES::define_scheme model_route, &blk
end
setup_schema() click to toggle source
# File lib/engine2/model.rb, line 44
def setup_schema
    @type_info = {}
    @dummies = []

    type_info do
        schema = @model.db_schema
        @model.primary_keys.each{|pk| (schema[pk]||={})[:primary_key] = true} if @model.primary_key

        schema.each_pair do |name, db_info|
            @info[name] = {}

            case db_info[:type]
            when :integer
                integer_field name
            when :string
                string_field name, case db_info[:db_type]
                when 'text', 'character varying'
                    100
                else
                    Integer(db_info[:column_size] || db_info[:db_type][/\((\d+)\)/, 1])
                end
            when :time
                time_field name, LOCS[:default_time_format], LOCS[:default_time_model_format]
            when :date
                date_field name, LOCS[:default_date_format], LOCS[:default_date_model_format]
            when :datetime
                datetime_field name, LOCS[:default_date_format], LOCS[:default_time_format], LOCS[:default_date_model_format], LOCS[:default_time_model_format]
            when :decimal
                size, scale = db_info[:column_size], db_info[:scale].to_i
                unless size && scale
                    db_info[:db_type] =~ /decimal\((\d+),(\d+)\)/i
                    size, scale = $1.to_i, $2.to_i
                    raise E2Error.new("Cannot parse decimal type for #{db_info}") unless size || scale
                end
                decimal_field name, size, scale
            when :blob
                blob_field name, 100000
            when :boolean
                boolean_field name
            when nil
                # ignore nil type
            else
                p db_info
                raise E2Error.new("Unknown column type: #{db_info[:type].inspect} for #{name}")
            end

            required name if !db_info[:allow_null]
            primary_key name if db_info[:primary_key]
            sequence name, "SEQ_#{@model.table_name}.nextVal" if db_info[:primary_key] && !db_info[:allow_null] && !db_info[:auto_increment] && !@model.natural_key
            default name, db_info[:ruby_default] if db_info[:ruby_default]
        end

        unique *@model.primary_keys if @model.natural_key && @model.db.adapter_scheme # uri ?

        @model.many_to_one_associations.each do |aname, assoc|
            many_to_one_field aname
            decode assoc[:keys].first
        end
    end
end
synchronize_type_info() click to toggle source
# File lib/engine2/model.rb, line 132
def synchronize_type_info
    resolve_dependencies
    verify_associations
    @after_load_processors = install_processors(AfterLoadProcessors)
    @before_save_processors = install_processors(BeforeSaveProcessors)
    @after_save_processors = install_processors(AfterSaveProcessors)
    @around_save_processors = {}
    @before_destroy_processors = install_processors(BeforeDestroyProcessors)
    @after_destroy_processors = install_processors(AfterDestroyProcessors)
    @type_info_synchronized = true
end
type_info(&blk) click to toggle source
# File lib/engine2/model.rb, line 105
def type_info &blk
    if blk
        raise E2Error.new("type_info already called for model #{self}") if @type_info_synchronized
        TypeInfo.new(self).instance_eval(&blk)
        nil
    else
        @type_info
    end
end
verify_associations() click to toggle source
# File lib/engine2/model.rb, line 165
def verify_associations
    one_to_many_associations.each do |name, assoc|
        other = assoc.associated_class
        other_type_info = other.type_info
        if other_keys = assoc[:keys]
            other_keys.each do |key|
                raise E2Error.new("No key '#{key}' found in model '#{other}' being related from #{self}") unless other_type_info[key]
            end
        end
    end
end