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:

[View source]

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:

[View source]

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

[View source]

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

[View source]

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

[View source]

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

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

#resolve_dependenciesObject

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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