Class: Spider::Model::QuerySet

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/spiderfw/model/query_set.rb

Overview

The QuerySet expresses represents a Query applied on a Model. It includes Enumerable, and can be accessed as an Array; but, the QuerySet is lazy, and the actual data will be fetched only when actually requested, or when a #load is issued. How much data is fetched and kept in memory can be controlled by setting the #fetch_window and the #keep_window.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, query_or_val = nil) ⇒ QuerySet

Returns a new instance of QuerySet.

Parameters:

  • Class<BaseModel] (Class<BaseModel] model The BaseModel subclass)

    model The BaseModel subclass

  • query_or_val (Query|Array|BaseModel) (defaults to: nil)

    Can be a Query, or data.

    • If a Query is given, the QuerySet will autoload using Query.

    • If data is given, the QuerySet will be static (not autoloading), and the data will be passed to #set_data.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/spiderfw/model/query_set.rb', line 97

def initialize(model, query_or_val=nil)
    @model = model
    model.extend_queryset(self)
    if (model.attributes[:integrated_models])
        model.attributes[:integrated_models].each{ |m, el| m.extend_queryset(self) }
    end
    if (query_or_val.is_a?(Query))
         query = query_or_val 
    else
        data = query_or_val
    end
    @query = query || Query.new
    @objects = []
    @raw_data = []
    @_parent = nil
    @_parent_element = nil
    @index_lookup = {}
    @total_rows = nil
    @fetch_window = nil
    @window_current_start = nil
    @keep_window = 100
    @autoload = query_or_val.is_a?(Query) ? true : false
    @identity_mapper = nil
    @loaded = false
    @loaded_elements = {}
    @fixed = {}
    @append_element = nil
    @loadable = true
    set_data(data) if data
    self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &proc) ⇒ Object

Missing methods will be sent to the query



862
863
864
865
866
867
868
869
# File 'lib/spiderfw/model/query_set.rb', line 862

def method_missing(method, *args, &proc)
    el = @model.elements[method]
    if (el && el.model? && el.reverse)
        return element_queryset(el)
    end
    return @query.send(method, *args, &proc) if @query.respond_to?(method)
    return super
end

Instance Attribute Details

#_no_identity_mapperbool

If bool, on’t put this queryset’s objects into the IdentityMapper

Returns:

  • (bool)


68
69
70
# File 'lib/spiderfw/model/query_set.rb', line 68

def _no_identity_mapper
  @_no_identity_mapper
end

#_no_parentbool

Disables parent setting for this QuerySet

Returns:

  • (bool)


18
19
20
# File 'lib/spiderfw/model/query_set.rb', line 18

def _no_parent
  @_no_parent
end

#_parentBaseModel

BaseModel instance pointing to this QuerySet

Returns:



12
13
14
# File 'lib/spiderfw/model/query_set.rb', line 12

def _parent
  @_parent
end

#_parent_elementElement

Element inside the _parent pointing to this QuerySet.

Returns:



15
16
17
# File 'lib/spiderfw/model/query_set.rb', line 15

def _parent_element
  @_parent_element
end

#append_elementElement

If something that can’t be converted to a @model instance is appended to the QuerySet, and append_element is set, the appended value will be set on the element named append_element of a new instance of @model, which will be appended instead. This is useful for junction models, which function as both types. Example:

cat = Animal.new; tiger = Animal.new;
# Instead of doing
friend = Animal::Friend.new(:animal => cat, :other_animal => tiger)
cat.friends << friend
# since the junction was created setting append_element = :other_animal, one can do
cat.friends << lion

Returns:



62
63
64
# File 'lib/spiderfw/model/query_set.rb', line 62

def append_element
  @append_element
end

#fetch_windowFixnum

How many objects to load at a time. If nil, all the objects returned by the Query will be loaded.

Returns:

  • (Fixnum)


46
47
48
# File 'lib/spiderfw/model/query_set.rb', line 46

def fetch_window
  @fetch_window
end

#keep_windowFixnum

How many objects to keep in memory when advancing the window. If nil, all objects will be kept.

Returns:

  • (Fixnum)


49
50
51
# File 'lib/spiderfw/model/query_set.rb', line 49

def keep_window
  @keep_window
end

#last_queryModel::Query

Set by mapper

Returns:



33
34
35
# File 'lib/spiderfw/model/query_set.rb', line 33

def last_query
  @last_query
end

#loadablebool

If false, prevents the QuerySet from loading.

Returns:

  • (bool)


65
66
67
# File 'lib/spiderfw/model/query_set.rb', line 65

def loadable
  @loadable
end

#loadedbool

Whether the QuerySet has been loaded

Returns:

  • (bool)


42
43
44
# File 'lib/spiderfw/model/query_set.rb', line 42

def loaded
  @loaded
end

#loaded_elementsHash (readonly)

An Hash of autoloaded elements.

Returns:

  • (Hash)


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

def loaded_elements
  @loaded_elements
end

#modelClass<BaseModel]

The BaseModel subclass

Returns:



36
37
38
# File 'lib/spiderfw/model/query_set.rb', line 36

def model
  @model
end

#modifiedbool

Returns True when the QuerySet has been modified after loading.

Returns:

  • (bool)

    True when the QuerySet has been modified after loading



70
71
72
# File 'lib/spiderfw/model/query_set.rb', line 70

def modified
  @modified
end

#objectsArray (readonly)

The actual fetched objects.

Returns:

  • (Array)


27
28
29
# File 'lib/spiderfw/model/query_set.rb', line 27

def objects
  @objects
end

#queryModel::Query

The Query

Returns:



30
31
32
# File 'lib/spiderfw/model/query_set.rb', line 30

def query
  @query
end

#raw_dataHash (readonly)

Raw data returned by the mapper, if requested.

Returns:

  • (Hash)


21
22
23
# File 'lib/spiderfw/model/query_set.rb', line 21

def raw_data
  @raw_data
end

#total_rowsFixnum

Total number of objects that would be returned had the Query no limit.

Returns:

  • (Fixnum)

    The total number of rows corresponding to the Query (without limit).



39
40
41
# File 'lib/spiderfw/model/query_set.rb', line 39

def total_rows
  @total_rows
end

Class Method Details

.autoloading(model, query_or_val = nil) ⇒ QuerySet

Instantiates an autoloading queryset

Parameters:

Returns:



86
87
88
89
90
# File 'lib/spiderfw/model/query_set.rb', line 86

def self.autoloading(model, query_or_val=nil)
    qs = self.new(model, query_or_val)
    qs.autoload = true
    return qs
end

.static(model, query_or_val = nil) ⇒ QuerySet

Instantiates a non-autoloading queryset

Parameters:

Returns:



76
77
78
79
80
# File 'lib/spiderfw/model/query_set.rb', line 76

def self.static(model, query_or_val=nil)
    qs = self.new(model, query_or_val)
    qs.autoload = false
    return qs
end

Instance Method Details

#+(other) ⇒ QuerySet

Returns a new QuerySet containing objects from both this and the other.

Parameters:

Returns:



313
314
315
316
317
318
319
# File 'lib/spiderfw/model/query_set.rb', line 313

def +(other)
    qs = self.clone
    other.each do |obj|
        qs << obj
    end
    return qs
end

#<<(obj, raw = nil) ⇒ void

This method returns an undefined value.

Adds an object to the set. Also stores the raw data if it is passed as the second parameter.

Parameters:

  • obj (BaseModel)

    The object to add

  • raw (Hash) (defaults to: nil)

    Optional raw data associated to the object



214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/spiderfw/model/query_set.rb', line 214

def <<(obj, raw=nil)
    return merge(obj) if (obj.class == QuerySet)
    unless (obj.is_a?(@model))
        obj = instantiate_object(obj)
    end
    @objects << obj
    @fixed.each do |key, val|
        obj.set(key, val)
    end
    index_object(obj)
    @raw_data[@objects.length-1] = raw if raw
    @modified = true
end

#[](index) ⇒ BaseModel

Accesses an object. Data will be loaded according to fetch_window.

Parameters:

  • index (Fixnum)

Returns:



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/spiderfw/model/query_set.rb', line 232

def [](index)
    if (index.is_a?(Range))
        return index.map{ |i| self[i] }
    elsif (index.is_a?(String))
        i, rest = index.split('.', 2)
        i = i.to_i
        val = self[i]
        return '' unless val
        return val[rest]
    end
    start = start_for_index(index)
    array_index = (index - start) + 1
    load_to_index(index) unless (@objects[array_index] && (!@fetch_window || @window_current_start == start)) || loaded?(index) || !autoload?
    val = @objects[array_index]
    val.set_parent(self, nil) if val && !@_no_parent
    return val
end

#[]=(index, val) ⇒ void

This method returns an undefined value.

Sets an object

Parameters:



254
255
256
257
258
259
260
261
262
263
# File 'lib/spiderfw/model/query_set.rb', line 254

def []=(index, val)
    #load_to_index(index) unless loaded?(index) || !autoload?
    val = instantiate_object(val) unless val.is_a?(@model)
    @fixed.each do |fkey, fval|
        val.set(fkey, fval)
    end
    array_index = index
    array_index -= @window_current_start-1 if @window_current_start
    @objects[array_index] = val
end

#all_children(path) ⇒ Array

Given a dotted path, will return an array of all objects reachable by that path Example

objectset.all_children('friends.collegues.addresses.street_name')

Parameters:

  • path (String)

Returns:

  • (Array)

    An array of all found objects



890
891
892
893
894
895
896
# File 'lib/spiderfw/model/query_set.rb', line 890

def all_children(path)
    if (path.length > 0)
        children = @objects.map{ |obj| obj.all_children(path.clone) }.flatten
    else
        return @objects
    end
end

#autoload(value, traverse = true) ⇒ void

This method returns an undefined value.

Enables or disables autoload; if the second argument is true, will traverse contained objects.

Parameters:

  • value (bool)

    Enable or disable autoload

  • traverse (bool) (defaults to: true)

    If true, set autoload to value on contained objects as well



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

def autoload(value, traverse=true)
    @autoload = value
    @objects.each{ |obj| obj.autoload = value } if traverse
end

#autoload=(bool) ⇒ void

This method returns an undefined value.

See ##autoload

Parameters:

  • value (bool)


156
157
158
# File 'lib/spiderfw/model/query_set.rb', line 156

def autoload=(bool)
    autoload(bool)
end

#autoload?bool

Returns True if autoload is enabled, False otherwise.

Returns:

  • (bool)

    True if autoload is enabled, False otherwise



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

def autoload?
    @autoload ? true : false
end

#change_model(model) ⇒ self

Changes the model of the QuerySet; will call BaseModel#become on children.

Parameters:

Returns:

  • (self)


202
203
204
205
206
207
208
# File 'lib/spiderfw/model/query_set.rb', line 202

def change_model(model)
    @model = model
    @objects.each_index do |i|
        @objects[i] = @objects[i].become(model)
    end
    return self
end

#clearvoid

This method returns an undefined value.

Remove all elements from self



430
431
432
433
# File 'lib/spiderfw/model/query_set.rb', line 430

def clear
    @objects = []
    @index_lookup.each_key{ |k| @index_lookup[k] = {} }
end

#cloneQuerySet

Performs a deep copy

Returns:



978
979
980
981
982
983
984
985
986
# File 'lib/spiderfw/model/query_set.rb', line 978

def clone
    c = self.class.new(self.model, self.query.clone)
    c.autoload = self.autoload?
    c_objects = c.instance_variable_get(:@objects)
    @objects.each do |o|
        c_objects << o.clone
    end
    return c
end

#command_exists?(command) ⇒ Boolean

Determines if a shell command exists by searching for it in ENV.

Returns:

  • (Boolean)


747
748
749
# File 'lib/spiderfw/model/query_set.rb', line 747

def command_exists?(command)
  ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) }
end

#current_lengthFixnum

Current number of objects fetched.

Returns:

  • (Fixnum)


358
359
360
# File 'lib/spiderfw/model/query_set.rb', line 358

def current_length
    @objects.length
end

#currently_empty?bool

Returns True if no object has been fetched yet.

Returns:

  • (bool)

    True if no object has been fetched yet.



370
371
372
# File 'lib/spiderfw/model/query_set.rb', line 370

def currently_empty?
    @objects.empty?
end

#cut(*params) ⇒ Array

Returns An array with the results of calling BaseModel#cut on each object.

Returns:

  • (Array)

    An array with the results of calling BaseModel#cut on each object.



718
719
720
721
# File 'lib/spiderfw/model/query_set.rb', line 718

def cut(*params)
    load unless loaded? || !autoload?
    return self.map{ |obj| obj.cut(*params) }
end

#delete(obj) ⇒ BaseModel|nil

Removes the given object from the QuerySet

Parameters:

Returns:



306
307
308
# File 'lib/spiderfw/model/query_set.rb', line 306

def delete(obj)
    @objects.delete(obj)
end

#delete_at(index) ⇒ BaseModel|nil

Removes the object at the given index from the QuerySet

Parameters:

  • index (Fixnum)

Returns:



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

def delete_at(index)
    @objects.delete_at(index)
end

#detect_terminal_sizeObject

Returns [width, height] of terminal when detected, nil if not detected. Think of this as a simpler version of Highline’s Highline::SystemExtensions.terminal_size()



753
754
755
756
757
758
759
760
761
762
763
# File 'lib/spiderfw/model/query_set.rb', line 753

def detect_terminal_size
  if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
    [ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
  elsif (RUBY_PLATFORM =~ /java/ || !STDIN.tty?) && command_exists?('tput')
    [`tput cols`.to_i, `tput lines`.to_i]
  else
    command_exists?('stty') ? `stty size`.scan(/\d+/).map { |s| s.to_i }.reverse : nil
  end
rescue
  nil
end

#each {|BaseModel| ... } ⇒ void

This method returns an undefined value.

Iterates on objects, loading when needed.

Yields:



445
446
447
448
449
450
451
452
453
454
# File 'lib/spiderfw/model/query_set.rb', line 445

def each
    self.each_rolling_index do |i|
        obj = @objects[i]
        prev_parent = obj._parent
        prev_parent_element = obj._parent_element
        obj.set_parent(self, nil)
        yield obj
        obj.set_parent(prev_parent, prev_parent_element)
    end
end

#each_current {|BaseModel| ... } ⇒ void

This method returns an undefined value.

Iterates on currently loaded objects

Yields:



438
439
440
# File 'lib/spiderfw/model/query_set.rb', line 438

def each_current
    @objects.each { |obj| yield obj }
end

#each_current_index {|Fixnum| ... } ⇒ void

This method returns an undefined value.

Iterates on indexes without loading.

Yields:

  • (Fixnum)


484
485
486
487
488
489
# File 'lib/spiderfw/model/query_set.rb', line 484

def each_current_index
    @objects.each_index do |i|
        i += @window_current_start-1 if @window_current_start
        yield i
    end
end

#each_index {|Fixnum| ... } ⇒ void

This method returns an undefined value.

Iterates yielding the queryset index. Will load when needed.

Yields:

  • (Fixnum)


474
475
476
477
478
479
# File 'lib/spiderfw/model/query_set.rb', line 474

def each_index
    self.each_rolling_index do |i|
        i += @window_current_start-1 if @window_current_start
        yield i
    end
end

#each_rolling_index {|BaseModel| ... } ⇒ void

This method returns an undefined value.

Iterates yielding the internal objects index. Will load when needed. If a window is used, the index will roll back to 0 on every window.

Yields:



460
461
462
463
464
465
466
467
468
469
# File 'lib/spiderfw/model/query_set.rb', line 460

def each_rolling_index
    @window_current_start = nil if (@fetch_window)
    while (!@fetch_window || has_more?)
        load_next unless !autoload? || (!@fetch_window && @loaded)
        @objects.each_index do |i|
            yield i
        end
        break unless autoload? && @fetch_window
    end
end

#element_loaded(element) ⇒ void

This method returns an undefined value.

Registers that the element has been loaded.

Parameters:



901
902
903
904
# File 'lib/spiderfw/model/query_set.rb', line 901

def element_loaded(element)
    element = element.name if element.is_a?(Element)
    @loaded_elements[element] = true
end

#element_loaded?(element) ⇒ bool

Returns True if the element has been loaded from the Storage.

Parameters:

Returns:

  • (bool)

    True if the element has been loaded from the Storage.



908
909
910
911
# File 'lib/spiderfw/model/query_set.rb', line 908

def element_loaded?(element)
    element = element.name if element.is_a?(Element)
    @loaded_elements[element]
end

#element_queryset(el) ⇒ QuerySet

Returns The QuerySet corresponding to an element in the current QuerySet.

Parameters:

Returns:

  • (QuerySet)

    The QuerySet corresponding to an element in the current QuerySet



873
874
875
876
877
878
879
880
881
882
883
# File 'lib/spiderfw/model/query_set.rb', line 873

def element_queryset(el)
    el = @model.elements[el] if el.is_a?(Symbol)
    condition = el.condition
    if (el.attributes[:element_query])
        el = @model.elements[el.attributes[:element_query]]
    end
    cond = Spider::Model::Condition.new
    cond[el.reverse] = self.map_current{ |row| row }
    cond = cond.and(condition) if (condition)
    return self.class.new(el.model, Query.new(cond))
end

#empty!void

This method returns an undefined value.

Removes all objects from the QuerySet



852
853
854
# File 'lib/spiderfw/model/query_set.rb', line 852

def empty!
    @objects = []
end

#empty?bool

Returns true if the QuerySet has no elements. Will load if the QuerySet is autoloading.

Returns:

  • (bool)

    True if QuerySet is empty



364
365
366
367
# File 'lib/spiderfw/model/query_set.rb', line 364

def empty?
    load unless @loaded || !autoload?
    @objects.empty?
end

#find(params) ⇒ QuerySet

Searchs the index for objects matching the given params.

Parameters:

  • params (Hash)

    A set of conditions. Keys must match already created indexes.

Returns:

  • (QuerySet)

    A new QuerySet with objects matching params

Raises:

  • (UnimplementedError)


531
532
533
534
535
536
537
538
539
540
541
# File 'lib/spiderfw/model/query_set.rb', line 531

def find(params)
    sorted_keys = params.keys.map{|k| k.to_s}.sort.map{|k| k.to_sym}
    index = sorted_keys.map{ |key| key.to_s }.join(',')
    search_key = sorted_keys.map{ |key| search_key(params, key) }.join(',')
    # TODO: implement find without index
    raise UnimplementedError, "find without an index is not yet implemented" unless @index_lookup[index]
    result = @index_lookup[index][search_key]
    #result = QuerySet.new(result) if (result)
    #@objects = result
    return QuerySet.new(@model, result)
end

#fixed(name, value) ⇒ void

This method returns an undefined value.

Sets a fixed value: it will be applied to every object.

Parameters:



139
140
141
# File 'lib/spiderfw/model/query_set.rb', line 139

def fixed(name, value)
    @fixed[name] = value
end

#has_more?bool

True if the query had a limit, and more results can be fetched.

Returns:

  • (bool)

    True if there are more objects to fetch from the storage.



343
344
345
346
347
348
# File 'lib/spiderfw/model/query_set.rb', line 343

def has_more?
    return true if autoload? && !@loaded
    return false unless query.limit
    pos = query.offset.to_i + length
    return pos < total_rows
end

#identity_mapperIdentityMapper

Returns the current QuerySet IdentityMapper instance, or instantiates a new one

Returns:



915
916
917
918
# File 'lib/spiderfw/model/query_set.rb', line 915

def identity_mapper
    return Spider::Model.identity_mapper if Spider::Model.identity_mapper
    @identity_mapper ||= IdentityMapper.new
end

#identity_mapper=(im) ⇒ void

This method returns an undefined value.

Assigns an IdentityMapper to the QuerySet

Parameters:



923
924
925
# File 'lib/spiderfw/model/query_set.rb', line 923

def identity_mapper=(im)
    @identity_mapper = im
end

#include?(val) ⇒ bool

Returns true if the QuerySet includes the given value.

The value can be a BaseModel, which will be searched as it is;

a Hash, in which case an Object with all the given values will be searched;

or an Object, which will be searched as the (only) primary key of a contained model

Parameters:

Returns:

  • (bool)


508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/spiderfw/model/query_set.rb', line 508

def include?(val)
    self.each do |obj|
        if val.is_a?(BaseModel)
            return true if obj == val
        elsif val.is_a?(Hash)
            has_all = true
            val.each do |k, v|
                unless obj.get(k) == v
                    has_all = false
                    break
                end
                return true if has_all
            end
        elsif @model.primary_keys.length == 1
            return true if obj.primary_keys[0] == val
        end
    end
    return false
end

#index_by(*elements) ⇒ self

Index objects by some elements.

Parameters:

  • elements (*Element)

    Elements to index on

Returns:

  • (self)


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

def index_by(*elements)
    names = elements.map{ |el| (el.is_a?(Spider::Model::Element)) ? el.name.to_s : el.to_s }
    index_name = names.sort.join(',')
    @index_lookup[index_name] = {}
    reindex
    return self
end

#index_object(obj) ⇒ void

This method returns an undefined value.

Adds object to the index

Parameters:



401
402
403
404
405
406
407
408
409
# File 'lib/spiderfw/model/query_set.rb', line 401

def index_object(obj) # :nodoc:
    @index_lookup.keys.each do |index_by|
        names = index_by.split(',')
        search_key = names.map{ |name| 
            search_key(obj, name)
        }.join(',')
        (@index_lookup[index_by][search_key] ||= []) << obj
    end
end

#insertvoid

This method returns an undefined value.

Calls BaseModel#insert on each object in the QuerySet.



664
665
666
# File 'lib/spiderfw/model/query_set.rb', line 664

def insert
    no_autoload(false){ each{ |obj| obj.insert } }
end

#inspectString

Returns A textual description of the QuerySet.

Returns:

  • (String)

    A textual description of the QuerySet



702
703
704
# File 'lib/spiderfw/model/query_set.rb', line 702

def inspect
    return "#{self.class.name}:\n@model=#{@model}, @query=#{query.inspect}, @objects=#{@objects.inspect}"
end

#instantiate_object(val = nil) ⇒ BaseModel

Returns a new instance of @model from val.

Parameters:

  • val (Object) (defaults to: nil)

Returns:



686
687
688
689
690
691
692
693
694
695
696
697
698
699
# File 'lib/spiderfw/model/query_set.rb', line 686

def instantiate_object(val=nil)
    if (@append_element && !val.is_a?(@model) && !(val.is_a?(Hash) && val[@append_element]))
        val = @model.elements[@append_element].type.new(val) unless (val.is_a?(BaseModel))
        val = {@append_element => val}
    end
        
    obj = @model.new(val)
    obj.identity_mapper = @identity_mapper
    obj.autoload = autoload?
    @fixed.each do |key, fval|
        obj.set(key, fval)
    end
    return obj
end

#lastBaseModel

Returns The last object in the QuerySet.

Returns:

  • (BaseModel)

    The last object in the QuerySet



291
292
293
294
# File 'lib/spiderfw/model/query_set.rb', line 291

def last
    load unless (@loaded || !autoload?) && loaded?(total_rows-1)
    @objects.last
end

#lengthFixnum

Number of objects fetched. Will call load if not loaded yet. Note: this is not the total number of objects responding to the Query; it may be equal to the fetch_window, or to the @query.limit.

Returns:

  • (Fixnum)

    length



325
326
327
328
# File 'lib/spiderfw/model/query_set.rb', line 325

def length
    load unless @loaded || !autoload?
    @objects.length
end

#limit(n) ⇒ self

Calls Spider::Model::Query#limit on the query

Returns:

  • (self)


947
948
949
950
# File 'lib/spiderfw/model/query_set.rb', line 947

def limit(n)
    @query.limit = n
    return self
end

#loadself

Executes the query and fetches the objects; (the next batch if a fetch_window is set).

Returns:

  • (self)


577
578
579
580
581
582
583
584
585
586
587
# File 'lib/spiderfw/model/query_set.rb', line 577

def load
    return self unless loadable?
    clear
    @loaded = false
    @loaded_elements = {}
    return load_next if @fetch_window && !@query.offset
    mapper.find(@query.clone, self)
    @loaded = true
    @modified = false
    return self
end

#load_next(page = nil) ⇒ self

Loads the next batch of objects.

Parameters:

  • Page (Fixnum)

    to load (defaults to next page)

Returns:

  • (self)


609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
# File 'lib/spiderfw/model/query_set.rb', line 609

def load_next(page=nil)
    if (@fetch_window)
        @query.limit = @fetch_window
        if (page)
            @window_current_start = (page - 1) * @fetch_window + 1
        else
            if (!@window_current_start)
                @window_current_start = 1
            else
                @window_current_start += @fetch_window
            end
        end
        @query.offset = @window_current_start-1
    end
    return load
end

#load_to_index(i) ⇒ void

This method returns an undefined value.

Loads objects up to index i

Parameters:

  • i (Fixnum)

    Index



600
601
602
603
604
# File 'lib/spiderfw/model/query_set.rb', line 600

def load_to_index(i)
    return load unless @fetch_window
    page = i / @fetch_window + 1
    load_next(page)
end

#loadable?bool

Returns True if the QuerySet can be loaded.

Returns:

  • (bool)

    True if the QuerySet can be loaded



646
647
648
# File 'lib/spiderfw/model/query_set.rb', line 646

def loadable?
    @loadable
end

#loaded?(index = nil) ⇒ bool

If a Fixnum is passed, will tell if the given index is loaded. With no argument, will tell if the QuerySet is fully loaded

Parameters:

  • index (Fixnum) (defaults to: nil)

Returns:

  • (bool)


630
631
632
633
634
635
# File 'lib/spiderfw/model/query_set.rb', line 630

def loaded?(index=nil)
    return @loaded if !@loaded || !index || !@fetch_window
    return false unless @window_current_start
    return true if index >= @window_current_start-1 && index < @window_current_start+@fetch_window-1
    return false
end

#map_currentArray

Returns Calls map on currently loaded objects.

Returns:

  • (Array)

    Calls map on currently loaded objects



825
826
827
828
829
# File 'lib/spiderfw/model/query_set.rb', line 825

def map_current
    a = []
    each_current{ |row| a << yield(row) }
    a
end

#mapperModel::Mapper

Returns The model’s mapper.

Returns:



131
132
133
# File 'lib/spiderfw/model/query_set.rb', line 131

def mapper
    @model.mapper
end

#merge(query_set) ⇒ void

This method returns an undefined value.

Merges the content of another QuerySet.

Parameters:



494
495
496
497
# File 'lib/spiderfw/model/query_set.rb', line 494

def merge(query_set)
    @objects += query_set.instance_variable_get(:"@objects")
    reindex
end

#modified?true

Returns True if the QuerySet, or any of its children, has been modified since loading.

Returns:

  • (true)

    True if the QuerySet, or any of its children, has been modified since loading



282
283
284
285
286
287
288
# File 'lib/spiderfw/model/query_set.rb', line 282

def modified?
    return true if @modified
    @objects.each do |obj|
        return true if obj.modified?
    end
    return false
end

#no_autoload(traverse = true) ⇒ void

This method returns an undefined value.

Disables autoload. If a block is given, the current autoload value will be restored after yielding.

Parameters:

  • traverse (bool) (defaults to: true)

    If true, apply to children as well



177
178
179
180
181
182
# File 'lib/spiderfw/model/query_set.rb', line 177

def no_autoload(traverse=true)
    prev_autoload = autoload?
    self.autoload(false, traverse)
    yield
    self.autoload(prev_autoload, traverse)
end

#offset(n) ⇒ self

Returns:

  • (self)


954
955
956
957
# File 'lib/spiderfw/model/query_set.rb', line 954

def offset(n)
    @query.offset = n
    return self
end

#order_by(*elements) ⇒ self

Calls Spider::Model::Query#order_by on the QuerySet’s query

Parameters:

Returns:

  • (self)


546
547
548
549
# File 'lib/spiderfw/model/query_set.rb', line 546

def order_by(*elements)
    @query.order_by(*elements)
    return self
end

#page(page, rows) ⇒ self

Calls Spider::Model::Query#page on the Query

Returns:

  • (self)


961
962
963
964
# File 'lib/spiderfw/model/query_set.rb', line 961

def page(page, rows)
    @query.page(page, rows)
    self
end

#pagesFixnum|nil

Returns Total number of available pages for current query (or nil if no limit is set).

Returns:

  • (Fixnum|nil)

    Total number of available pages for current query (or nil if no limit is set)



967
968
969
970
# File 'lib/spiderfw/model/query_set.rb', line 967

def pages
    return nil unless @query.limit
    (self.total_rows.to_f / @query.limit).ceil
end

#reindexself

Rebuild object index.

Returns:

  • (self)


388
389
390
391
392
393
394
395
396
# File 'lib/spiderfw/model/query_set.rb', line 388

def reindex
    @index_lookup.each_key do |index|
        @index_lookup[index] = {}
    end
    each_current do |obj|
        index_object(obj)
    end
    return self
end

#reject! {|BaseModel| ... } ⇒ void

This method returns an undefined value.

Removes the objects for which the block returns true from the QuerySet

Yields:



846
847
848
# File 'lib/spiderfw/model/query_set.rb', line 846

def reject!(&proc)
    @objects.reject!(&proc)
end

#reverseArray

Returns A reversed Array.

Returns:

  • (Array)

    A reversed Array



820
821
822
# File 'lib/spiderfw/model/query_set.rb', line 820

def reverse
    self.to_a.reverse
end

#savevoid

This method returns an undefined value.

Saves each object in the QuerySet.



652
653
654
# File 'lib/spiderfw/model/query_set.rb', line 652

def save
    no_autoload(false){ each{ |obj| obj.save } }
end

#save!void

This method returns an undefined value.

Calls BaseModel#save! on each object in the QuerySet.



658
659
660
# File 'lib/spiderfw/model/query_set.rb', line 658

def save!
    no_autoload(false){ each{ |obj| obj.save! } }
end

#save_all(params = {}) ⇒ void

This method returns an undefined value.

Calls BaseModel#save_all on each object in the QuerySet.



676
677
678
679
680
681
# File 'lib/spiderfw/model/query_set.rb', line 676

def save_all(params={})
    @objects.each do |obj| 
#                next if (unit_of_work && !unit_of_work.save?(obj))
        obj.save_all(params)
    end
end

#search_key(obj, name) ⇒ String

Returns The index key for an object’s element.

Parameters:

Returns:

  • (String)

    The index key for an object’s element



414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/spiderfw/model/query_set.rb', line 414

def search_key(obj, name) # :nodoc:
    sub = obj.is_a?(Hash) ? obj[name] : obj.get(name.to_sym)
    if (sub.is_a?(Spider::Model::BaseModel))
        name_parts = name.to_s.split('.')
        model = @model
        name_parts.each do |part|
            model = model.elements[part.to_sym].type
        end
        model.primary_keys.map{ |k| sub.get(k).to_s }.join(',')
    else
        sub.to_s
    end
end

#select(&proc) ⇒ QuerySet

Returns a (static) QuerySet of the objects for which the block evaluates to true.

Parameters:

  • proc (Proc)

    The block to evaluate

Returns:



337
338
339
# File 'lib/spiderfw/model/query_set.rb', line 337

def select(&proc)
    return QuerySet.new(@model, select_array(&proc))
end

#select_arrayArray

 Like #select, but returns an array

Returns:

  • (Array)


332
# File 'lib/spiderfw/model/query_set.rb', line 332

alias :select_array :select

#set(element, value) ⇒ void

This method returns an undefined value.

Sets the value of an element on all currently loaded objects.

Parameters:



564
565
566
567
568
569
570
571
572
573
# File 'lib/spiderfw/model/query_set.rb', line 564

def set(element, value)
    element_name = element.is_a?(Element) ? element.name : element
    fixed(element_name, value)
#            @query.condition.set(element, '=', value)
    no_autoload(false) do
        each do |obj|
            obj.set(element_name, value)
        end
    end
end

#set_data(data) ⇒ void

This method returns an undefined value.

Adds objects to the QuerySet

Parameters:

  • data (Enumerable|Object)

    If the argument is an Enumerable, its contents will be appendend to the QuerySet; otherwise, the object will be appended.



188
189
190
191
192
193
194
195
196
197
# File 'lib/spiderfw/model/query_set.rb', line 188

def set_data(data)
    if (data.is_a?(Enumerable))
        data.each do |val|
            self << val
        end
    else
        self << data
    end
    
end

#set_parent(obj, element) ⇒ void

This method returns an undefined value.

Sets containing model and element.

Parameters:

  • obj (BaseModel)
  • element (Symbol)

    Name of the element inside the parent which points to this QuerySet



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

def set_parent(obj, element)
    @_parent = obj
    @_parent_element = element
end

#start_for_index(i) ⇒ Fixnum

Returns The index to start with to get the page containing the i-th element.

Parameters:

  • i (Fixnum)

Returns:

  • (Fixnum)

    The index to start with to get the page containing the i-th element



591
592
593
594
595
# File 'lib/spiderfw/model/query_set.rb', line 591

def start_for_index(i) # :nodoc:
    return 1 unless @fetch_window
    page = i / @fetch_window + 1
    return (page - 1) * @fetch_window + 1
end

#tablevoid

This method returns an undefined value.

Prints an ASCII table of the QuerySet



740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/spiderfw/model/query_set.rb', line 740

def table
    
    # Functions for determining terminal size:
    # Copyright (c) 2010 Gabriel Horner, MIT LICENSE
    # http://github.com/cldwalker/hirb.git
    
    # Determines if a shell command exists by searching for it in ENV['PATH'].
    def command_exists?(command)
      ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) }
    end

    # Returns [width, height] of terminal when detected, nil if not detected.
    # Think of this as a simpler version of Highline's Highline::SystemExtensions.terminal_size()
    def detect_terminal_size
      if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
        [ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
      elsif (RUBY_PLATFORM =~ /java/ || !STDIN.tty?) && command_exists?('tput')
        [`tput cols`.to_i, `tput lines`.to_i]
      else
        command_exists?('stty') ? `stty size`.scan(/\d+/).map { |s| s.to_i }.reverse : nil
      end
    rescue
      nil
    end
    
    
    return print("Empty\n") if length < 1
    columns = detect_terminal_size[0]
    a = to_flat_array
    m_sizes = Hash.new(0) # one separator column
    a.each do |row|
        row.each do |key, val|
            m_sizes[key] = val.length if val.length > m_sizes[key]
        end
    end
    elements = @model.elements_array.select{ |el| m_sizes[el.name] > 0}
    elements.each do |el|
        m_sizes[el.name] = el.label.length if el.label.length > m_sizes[el.name] + 1
    end
    reduce = columns.to_f/(m_sizes.values.inject{ |sum, s| sum + s })
    sizes = {}
    m_sizes.each_key { |k| sizes[k] = m_sizes[k] * reduce }
    avail = columns - sizes.values.inject{ |sum, s| sum + s }
    while avail > 0 && (truncated = sizes.reject{ |k, v| v < m_sizes[k] }).length > 0
        truncated.each_key do |k|
            break if avail < 1
            sizes[k] += 1; avail -= 1
        end
    end
    sizes.each do |k, v|
        sizes[k] = v.floor
    end
    print "\n"
    1.upto(columns) { print "-" }
    print "\n"
    elements.each do |el|
        print "|"
        print el.label[0..sizes[el.name]-1].ljust(sizes[el.name])
    end
    print "\n"
    1.upto(columns) { print "-" }
    print "\n"
    a.each do |row|
        elements.each do |el|
            print "|"
            print row[el.name][0..sizes[el.name]-1].ljust(sizes[el.name])
        end
        print "\n"
    end
    1.upto(columns) { print "-" }
    print "\n"
    
end

#to_aArray

Returns The Array corresponding to the QuerySet.

Returns:

  • (Array)

    The Array corresponding to the QuerySet



815
816
817
# File 'lib/spiderfw/model/query_set.rb', line 815

def to_a
    self.map{ |row| row }
end

#to_flat_arrayArray

Returns an array of Hashes, with each value of the object is converted to string.

Returns:

  • (Array)


833
834
835
836
837
838
839
840
841
# File 'lib/spiderfw/model/query_set.rb', line 833

def to_flat_array
    map do |obj|
        h = {}
        obj.class.each_element do |el|
            h[el.name] = obj.element_has_value?(el) ? obj.get(el).to_s : ''
        end
        h
    end
end

#to_hash_arrayArray

Returns An array with the results of calling #BaseModel.to_hash_array on each object.

Returns:

  • (Array)

    An array with the results of calling #BaseModel.to_hash_array on each object.



724
725
726
# File 'lib/spiderfw/model/query_set.rb', line 724

def to_hash_array
    return self.map{ |obj| obj.to_hash }
end

#to_indexed_hash(element) ⇒ Hash

Returns A Hash, indexed by the value of element on the object.

Parameters:

  • Element (String|Symbol)

    name (or dotted element path) to index by

Returns:

  • (Hash)

    A Hash, indexed by the value of element on the object



730
731
732
733
734
735
736
# File 'lib/spiderfw/model/query_set.rb', line 730

def to_indexed_hash(element)
    hash = {}
    self.each do |row|
        hash[row.get(element)] = row
    end
    hash
end

#to_json(state = nil, &proc) ⇒ String

Returns The JSON representation of the QuerySet.

Returns:

  • (String)

    The JSON representation of the QuerySet



707
708
709
710
711
712
713
# File 'lib/spiderfw/model/query_set.rb', line 707

def to_json(state=nil, &proc)
    load unless loaded? || !autoload?
    res =  "[" +
        self.map{ |obj| obj.to_json(&proc) }.join(',') +
        "]"
    return res
end

#to_sString

Returns All the objects, to_s, joined by ‘, ’.

Returns:

  • (String)

    All the objects, to_s, joined by ‘, ’



857
858
859
# File 'lib/spiderfw/model/query_set.rb', line 857

def to_s
    self.map{ |o| o.to_s }.join(', ')
end

#updatevoid

This method returns an undefined value.

Calls BaseModel#update on each object in the QuerySet.



670
671
672
# File 'lib/spiderfw/model/query_set.rb', line 670

def update
    no_autoload(false){ each{ |obj| obj.update } }
end

#update_loaded_elementsvoid

This method returns an undefined value.

Ensures children’s loaded_elments match the QuerySet’s ones.



267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/spiderfw/model/query_set.rb', line 267

def update_loaded_elements

    return if currently_empty?
    f_loaded = {}
    @loaded_elements = {}
    @loaded_elements.merge!(@objects[0].loaded_elements)
    self.each_current do |obj|
        @loaded_elements.each do |el, val|
            f_loaded[el] = false unless obj.loaded_elements[el]
        end
    end
    @loaded_elements.merge!(f_loaded)
end

#where(*params, &proc) ⇒ self

Calls Spider::Model::Query#where on the query.

Returns:

  • (self)


940
941
942
943
# File 'lib/spiderfw/model/query_set.rb', line 940

def where(*params, &proc)
    @query.where(*params, &proc)
    return self
end

#with_polymorphsself

Calls Query#with_polymorphs on the QuerySet’s query

Returns:

  • (self)


553
554
555
556
557
558
# File 'lib/spiderfw/model/query_set.rb', line 553

def with_polymorphs
    @model.polymorphic_models.each do |model, attributes|
        @query.with_polymorph(model)
    end
    self
end

#with_superclassself

Returns:

  • (self)


929
930
931
932
# File 'lib/spiderfw/model/query_set.rb', line 929

def with_superclass
    @query.with_superclass
    return self
end