Module: Engine2::Model

Included in:
E2Files
Defined in:
lib/engine2/model.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#after_destroy_processorsObject (readonly)

Returns the value of attribute after_destroy_processors.



8
9
10
# File 'lib/engine2/model.rb', line 8

def after_destroy_processors
  @after_destroy_processors
end

#after_load_processorsObject (readonly)

Returns the value of attribute after_load_processors.



8
9
10
# File 'lib/engine2/model.rb', line 8

def after_load_processors
  @after_load_processors
end

#after_save_processorsObject (readonly)

Returns the value of attribute after_save_processors.



8
9
10
# File 'lib/engine2/model.rb', line 8

def after_save_processors
  @after_save_processors
end

#before_destroy_processorsObject (readonly)

Returns the value of attribute before_destroy_processors.



8
9
10
# File 'lib/engine2/model.rb', line 8

def before_destroy_processors
  @before_destroy_processors
end

#before_save_processorsObject (readonly)

Returns the value of attribute before_save_processors.



8
9
10
# File 'lib/engine2/model.rb', line 8

def before_save_processors
  @before_save_processors
end

#dummiesObject (readonly)

Returns the value of attribute dummies.



6
7
8
# File 'lib/engine2/model.rb', line 6

def dummies
  @dummies
end

#many_to_many_associationsObject (readonly)

, :one_to_one_associations



7
8
9
# File 'lib/engine2/model.rb', line 7

def many_to_many_associations
  @many_to_many_associations
end

#many_to_one_associationsObject (readonly)

, :one_to_one_associations



7
8
9
# File 'lib/engine2/model.rb', line 7

def many_to_one_associations
  @many_to_one_associations
end

#one_to_many_associationsObject (readonly)

, :one_to_one_associations



7
8
9
# File 'lib/engine2/model.rb', line 7

def one_to_many_associations
  @one_to_many_associations
end

#scheme_argsObject (readonly)

Returns the value of attribute scheme_args.



177
178
179
# File 'lib/engine2/model.rb', line 177

def scheme_args
  @scheme_args
end

#scheme_nameObject (readonly)

Returns the value of attribute scheme_name.



177
178
179
# File 'lib/engine2/model.rb', line 177

def scheme_name
  @scheme_name
end

#validation_in_transactionObject (readonly)

Returns the value of attribute validation_in_transaction.



9
10
11
# File 'lib/engine2/model.rb', line 9

def validation_in_transaction
  @validation_in_transaction
end

Class Method Details

.extended(cls) ⇒ Object

Raises:



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 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

Instance Method Details

#find_type_info(name) ⇒ Object

Raises:



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 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) ⇒ Object



35
36
37
38
39
40
41
42
# 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) ⇒ Object



185
186
187
# File 'lib/engine2/model.rb', line 185

def model_icon icn = nil
    icn ? @model_icon = icn : @model_icon
end

#model_route(rt = nil) ⇒ Object



189
190
191
# File 'lib/engine2/model.rb', line 189

def model_route rt = nil
    rt ? @model_route = rt : @model_route
end

#resolve_dependenciesObject



144
145
146
147
148
149
150
151
# 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 = []) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
# 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) ⇒ Object



179
180
181
182
183
# 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_schemaObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# 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_infoObject



132
133
134
135
136
137
138
139
140
141
142
# 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) ⇒ Object



105
106
107
108
109
110
111
112
113
# 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_associationsObject



165
166
167
168
169
170
171
172
173
174
175
# 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