Module: Spider::Model

Defined in:
lib/spiderfw/model/model.rb,
lib/spiderfw/model/sync.rb,
lib/spiderfw/model/type.rb,
lib/spiderfw/model/query.rb,
lib/spiderfw/model/element.rb,
lib/spiderfw/model/request.rb,
lib/spiderfw/model/storage.rb,
lib/spiderfw/model/junction.rb,
lib/spiderfw/model/condition.rb,
lib/spiderfw/model/query_set.rb,
lib/spiderfw/model/base_model.rb,
lib/spiderfw/model/model_hash.rb,
lib/spiderfw/model/mixins/list.rb,
lib/spiderfw/model/mixins/tree.rb,
lib/spiderfw/model/proxy_model.rb,
lib/spiderfw/model/query_funcs.rb,
lib/spiderfw/model/inline_model.rb,
lib/spiderfw/model/unit_of_work.rb,
lib/spiderfw/model/active_record.rb,
lib/spiderfw/model/mixins/mixins.rb,
lib/spiderfw/model/storage/db/db.rb,
lib/spiderfw/model/mappers/mapper.rb,
lib/spiderfw/model/storage/schema.rb,
lib/spiderfw/model/identity_mapper.rb,
lib/spiderfw/model/mappers/mappers.rb,
lib/spiderfw/model/mixins/converted.rb,
lib/spiderfw/model/mixins/versioned.rb,
lib/spiderfw/model/mappers/db_mapper.rb,
lib/spiderfw/model/integrated_element.rb,
lib/spiderfw/model/mappers/hash_mapper.rb,
lib/spiderfw/model/mixins/synchronized.rb,
lib/spiderfw/model/mappers/proxy_mapper.rb,
lib/spiderfw/model/mixins/state_machine.rb,
lib/spiderfw/model/storage/base_storage.rb,
lib/spiderfw/model/storage/db/db_schema.rb,
lib/spiderfw/model/storage/db/reflector.rb,
lib/spiderfw/model/storage/null_storage.rb,
lib/spiderfw/model/storage/db/db_storage.rb,
lib/spiderfw/model/extended_models/managed.rb,
lib/spiderfw/model/mappers/document_mapper.rb,
lib/spiderfw/model/storage/connection_pool.rb,
lib/spiderfw/model/storage/db/db_connector.rb,
lib/spiderfw/model/storage/db/adapters/mssql.rb,
lib/spiderfw/model/storage/db/adapters/mysql.rb,
lib/spiderfw/model/storage/document/document.rb,
lib/spiderfw/model/storage/db/adapters/oracle.rb,
lib/spiderfw/model/storage/db/adapters/sqlite.rb,
lib/spiderfw/model/storage/db/connectors/jdbc.rb,
lib/spiderfw/model/storage/db/connectors/oci8.rb,
lib/spiderfw/model/storage/db/connectors/odbc.rb,
lib/spiderfw/model/storage/db/connectors/jdbc_oracle.rb,
lib/spiderfw/model/storage/db/dialects/no_total_rows.rb,
lib/spiderfw/model/storage/document/adapters/mongodb.rb,
lib/spiderfw/model/storage/document/document_storage.rb

Overview

Spider::Model is the namespace containing all data-related classes and modules.

In addition, it implements some helper methods.

See BaseModel for the base class that must be subclassed by app’s models.

Defined Under Namespace

Modules: ActiveRecordModel, ConditionMixin, Converted, Junction, List, MapperIncludeModule, Mappers, Mixins, StateMachine, Storage, Synchronized, Tree, VersionModel, Versioned Classes: BaseModel, Condition, ConditionContext, Element, FormatError, IdentityMapper, IdentityMapperException, InlineModel, IntegratedElement, Managed, Mapper, MapperElementError, MapperError, MapperTask, ModelException, ModelHash, ProxyModel, Query, QuerySet, Request, SortTask, Sorter, Sync, Type, TypeError, UnitOfWork

Constant Summary collapse

RequiredError =

A required element has no value

MapperElementError.create_subclass(_("Element %s is required"))
NotUniqueError =

An uniqueness constraint has been violated.

MapperElementError.create_subclass(_("Another item with the same %s is already present"))

Class Method Summary collapse

Class Method Details

.ar_modelsObject



299
300
301
# File 'lib/spiderfw/model/active_record.rb', line 299

def self.ar_models
    @ar_models
end

.base_type(klass) ⇒ Class

Returns the base type corresponding to a class.

For BaseModels, the class itself will be returned; otherwise, will walk superclasses and DataType info until one of the base_types is found.



36
37
38
39
40
41
42
# File 'lib/spiderfw/model/model.rb', line 36

def self.base_type(klass)
    k = klass
    while (k && !base_types.include?(k))
        k = simplify_type(k)
    end
    return k
end

.base_typesArray

Returns a list of the base types, which must be handled by all mappers.

String, Spider::DataTypes::Text, Fixnum, Float, BigDecimal, Date, DateTime, Spider::DataTypes::Bool.

These types must be handled by all mappers.



25
26
27
# File 'lib/spiderfw/model/model.rb', line 25

def self.base_types
    @base_types
end

.create_ar_classes(ar, container) ⇒ Object



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/spiderfw/model/active_record.rb', line 303

def self.create_ar_classes(ar, container)
    @ar_models ||= []
    return if ar.spider_model
    name = ar.name.split(':')[-1]
    if (container.const_defined?(name))
        current = container.const_get(name)
    end
    unless current
        mod = Class.new(Spider::Model::BaseModel)
        container.const_set(name, mod)
    else
        mod = current
    end
    unless mod.is_a?(ActiveRecordModel)
        mod.instance_eval do
            include ActiveRecordModel
        end
    end
    mod.ar_defined = true unless current
    mod.ar = ar
    ar.spider_model = mod
    ar.reflections.each do |name, reflection|
        begin 
            create_ar_classes(reflection.klass, container) unless reflection.klass.spider_model
            through = reflection.through_reflection.klass
            create_ar_classes(through, container) if through && !through.spider_model
        rescue NameError
        end
    end
    @ar_models << mod
end

.get(model, val = nil, set_loaded = false) ⇒ BaseModel

Retrieves an object corresponding to gived values from the IdentityMapper, or puts it there if not found.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/spiderfw/model/model.rb', line 80

def self.get(model, val=nil, set_loaded=false)
    if (val && !val.is_a?(Hash))
        if (model.primary_keys.length == 1)
            val = {model.primary_keys[0].name => val}
        else
            raise ModelException, "Can't get without primary keys"
        end
    end
    if identity_mapper
        return identity_mapper.get(model, val, set_loaded)
    else
        return model.new(val)
    end
end

.identity_mapperIdentityMapper



109
110
111
# File 'lib/spiderfw/model/model.rb', line 109

def self.identity_mapper
    Spider.current[:identity_mapper]
end

.identity_mapper=(im) ⇒ IdentityMapper



115
116
117
# File 'lib/spiderfw/model/model.rb', line 115

def self.identity_mapper=(im)
    Spider.current[:identity_mapper] = im
end

.in_unit(&proc) ⇒ void

This method returns an undefined value.

Executes a block inside a Unit Of Work and Identity Mapper



221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/spiderfw/model/model.rb', line 221

def self.in_unit(&proc)
    uow = self.unit_of_work
    self.start_unit_of_work unless uow
    self.with_identity_mapper do
        begin
            yield Spider::Model.unit_of_work
        
            self.unit_of_work.commit unless uow
        ensure
            self.stop_unit_of_work unless uow
        end
    end
    
end

.load_fixtures(file, truncate = false) ⇒ Object

Load YAML data to the storage



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/spiderfw/model/model.rb', line 289

def self.load_fixtures(file, truncate=false)
    if (file =~ /\.([^\.]+)$/)
        extension = $1
    else
        raise ArgumentError, "Can't determine type of fixtures file #{file}"
    end
    data = {}
    case extension
    when 'yml'
        require 'yaml'
        data = YAML.load_file(file)
    end
     # Ruby 1.9: steps are not needed with ordered hashes
    data = [data] unless data.is_a?(Array)
    loaded = []
    data.each do |step|
        step.each do |mod_name, mod_data|
            mod = const_get_full(mod_name)
            mod.mapper.truncate! if truncate
            mod_data.each do |row|
                h = {}
                row.each do |k, v|
                    if v.is_a?(String)
                        if v[0..1] == '@@'
                            v = v[1..-1]
                        elsif v[0].chr == '@'
                            v = eval(v[1..-1].to_s)
                        end
                    end
                    h[k] = v
                end
                obj = mod.new(h)
                obj.insert
                loaded << obj
            end
        end
    end
    loaded
end

.no_context(&proc) ⇒ UnitOfWork

Executes a block without Identity Mapper and Unit Of Work



193
194
195
196
197
198
199
200
201
202
# File 'lib/spiderfw/model/model.rb', line 193

def self.no_context(&proc)
    uow = self.unit_of_work
    self.unit_of_work = nil
    im = self.identity_mapper            
    self.identity_mapper = nil
    yield
    self.identity_mapper = im
    self.unit_of_work = uow
    
end

.no_identity_mapper(&proc) ⇒ IdentityMapper

Executes a block without Identity Mapper



183
184
185
186
187
188
# File 'lib/spiderfw/model/model.rb', line 183

def self.no_identity_mapper(&proc)
    im = self.identity_mapper
    self.identity_mapper = nil
    yield
    self.identity_mapper = im
end

.no_unit_of_work(&proc) ⇒ UnitOfWork

Executes a block without running in Unit Of Work



168
169
170
171
172
173
# File 'lib/spiderfw/model/model.rb', line 168

def self.no_unit_of_work(&proc)
    uow = self.unit_of_work
    self.unit_of_work = nil
    yield
    self.unit_of_work = uow
end

.put(obj, check = false) ⇒ BaseModel

Puts an object into the IdentityMapper



100
101
102
103
104
105
106
# File 'lib/spiderfw/model/model.rb', line 100

def self.put(obj, check=false)
    if (identity_mapper)
        return identity_mapper.put(obj, check)
    else
        return obj
    end
end

.ruby_type(klass) ⇒ Class



46
47
48
49
50
51
52
53
54
55
# File 'lib/spiderfw/model/model.rb', line 46

def self.ruby_type(klass)
    map_types = {
        Spider::DataTypes::Text => String,
        Spider::DataTypes::Bool => FalseClass,
        Spider::DataTypes::Binary => String,
        Spider::DataTypes::FilePath => String
    }
    return map_types[klass] if map_types[klass]
    return klass
end

.simplify_type(klass) ⇒ Class

An iteration in the search for base type.



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/spiderfw/model/model.rb', line 61

def self.simplify_type(klass)
    map_types = {
        
    }
    return klass if base_types.include?(klass)
    return klass if klass <= Spider::Model::BaseModel
    return t if t = map_types[klass]
    return klass.maps_to if klass.subclass_of?(Spider::DataType) && klass.maps_to
    return klass.superclass if klass.superclass
    return nil
end

.sort(models, options = {}) ⇒ Array

Sorts an Array of models, placing subclasses before superclasses.

If :association_dependencies is true, models having an association to another model will be placed after the associated model.

This can be used to insert a dump of data, ensuring later models only depend on already inserted objects.



378
379
380
381
382
383
384
# File 'lib/spiderfw/model/model.rb', line 378

def self.sort(models, options={})
    options = {
        :association_dependencies => true
    }.merge(options)
    sorter = Sorter.new(models, options)
    sorter.sort
end

.start_unit_of_workUnitOfWork

Starts a new Unit Of Work



121
122
123
124
# File 'lib/spiderfw/model/model.rb', line 121

def self.start_unit_of_work
    uow = UnitOfWork.new
    uow.start
end

.stop_unit_of_workvoid

This method returns an undefined value.

Stops the current Unit Of Work



128
129
130
# File 'lib/spiderfw/model/model.rb', line 128

def self.stop_unit_of_work
    Spider.current[:unit_of_work].stop
end

.sync_schema(model_or_app, force = false, options = {}) ⇒ void

This method returns an undefined value.

Syncs the schema for a model, or for all models within an app, with the storage.



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/spiderfw/model/model.rb', line 243

def self.sync_schema(model_or_app, force=false, options={})
    
    # FIXME: this is clearly db specific. Move somewhere else.
    models = []
    mod = const_get_full(model_or_app)
    if (mod.is_a?(Module) && mod.include?(Spider::App))
        mod.models.each { |m| models << m }
    elsif (mod.subclass_of?(Spider::Model::BaseModel))
        models << mod
    end
    storages = []
    tables = []
    models.each do |m|
        unless (options[:no_sync])
            Spider::Logger.debug("SYNCING #{m}")
            m.mapper.sync_schema(force, options) if m.mapper.respond_to?(:sync_schema)
        m.after_sync if m.respond_to?(:after_sync)  
    end
        if (options[:drop_tables] && m.mapper.respond_to?(:schema))
            storages << m.mapper.storage unless storages.include?(m.mapper.storage)
            tables += m.mapper.schema.get_schemas.keys
        end
    end
    if (options[:drop_tables])
        dt = options[:drop_tables]
        tables.flatten
        storage_tables = {}
        storages.each do |s|
            s.list_tables.each do |t|
                storage_tables[t] = s
            end
        end
        tables_to_drop = []
        storage_tables.each do |table_name, storage|
            if !tables.include?(table_name) && (dt == true || table_name.index(dt) == 0)
                tables_to_drop << table_name
            end
        end
        raise Spider::Model::Mappers::SchemaSyncUnsafeConversion.new(tables_to_drop) unless tables_to_drop.empty?
        tables_to_drop.each{ |t| storage.drop_table(t) }
    end
end

.unit_of_work(&proc) ⇒ UnitOfWork



136
137
138
139
140
141
142
143
144
# File 'lib/spiderfw/model/model.rb', line 136

def self.unit_of_work(&proc)
    uow = Spider.current[:unit_of_work]
    if !uow
        if proc
            uow = UnitOfWork.new(&proc)
        end
    end
    return uow
end

.unit_of_work=(uow) ⇒ UnitOfWork

Sets the UnitOfWork to use for the current request



149
150
151
# File 'lib/spiderfw/model/model.rb', line 149

def self.unit_of_work=(uow)
    Spider.current[:unit_of_work] = uow
end

.unit_of_work_running?bool



176
177
178
# File 'lib/spiderfw/model/model.rb', line 176

def self.unit_of_work_running?
    self.unit_of_work && self.unit_of_work.running?
end

.with_identity_mapper(&proc) ⇒ IdentityMapper

Executes a block in the context of the current IdentityMapper, if one is active. If no IdentityMapper is running, the code is executed inside a new Identity Mapper



208
209
210
211
212
213
214
215
216
# File 'lib/spiderfw/model/model.rb', line 208

def self.with_identity_mapper(&proc)
    if identity_mapper
        yield identity_mapper
    else
        IdentityMapper.new do |im|
            yield im
        end
    end
end

.with_unit_of_work(&proc) ⇒ UnitOfWork

Executes a block inside a new Unit Of Work

Note: you should almost always use in_unit instead, since a Unit Of Work without an Identity Mapper can be problematic.



159
160
161
162
163
# File 'lib/spiderfw/model/model.rb', line 159

def self.with_unit_of_work(&proc)
    with_identity_mapper do
        return unit_of_work(&proc)
    end
end