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



868
869
870
871
872
873
874
875
# File 'lib/spiderfw/model/query_set.rb', line 868

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:



319
320
321
322
323
324
325
# File 'lib/spiderfw/model/query_set.rb', line 319

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:

Returns:

  • (Array)

    An array of all found objects



896
897
898
899
900
901
902
# File 'lib/spiderfw/model/query_set.rb', line 896

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



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

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

#cloneQuerySet

Performs a deep copy

Returns:



984
985
986
987
988
989
990
991
992
# File 'lib/spiderfw/model/query_set.rb', line 984

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)


753
754
755
# File 'lib/spiderfw/model/query_set.rb', line 753

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)


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

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.



376
377
378
# File 'lib/spiderfw/model/query_set.rb', line 376

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.



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

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:



312
313
314
# File 'lib/spiderfw/model/query_set.rb', line 312

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

#delete_if(&proc) ⇒ nil

Deletes every element for which block evaluates to true

Returns:

  • (nil)


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

def delete_if(&proc)
    @objects.delete_if(&proc)
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()



759
760
761
762
763
764
765
766
767
768
769
# File 'lib/spiderfw/model/query_set.rb', line 759

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:



451
452
453
454
455
456
457
458
459
460
# File 'lib/spiderfw/model/query_set.rb', line 451

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:



444
445
446
# File 'lib/spiderfw/model/query_set.rb', line 444

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)


490
491
492
493
494
495
# File 'lib/spiderfw/model/query_set.rb', line 490

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)


480
481
482
483
484
485
# File 'lib/spiderfw/model/query_set.rb', line 480

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:



466
467
468
469
470
471
472
473
474
475
# File 'lib/spiderfw/model/query_set.rb', line 466

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:



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

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.



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

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



879
880
881
882
883
884
885
886
887
888
889
# File 'lib/spiderfw/model/query_set.rb', line 879

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



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

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



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

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)


537
538
539
540
541
542
543
544
545
546
547
# File 'lib/spiderfw/model/query_set.rb', line 537

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.



349
350
351
352
353
354
# File 'lib/spiderfw/model/query_set.rb', line 349

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:



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

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:



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

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)


514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
# File 'lib/spiderfw/model/query_set.rb', line 514

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)


383
384
385
386
387
388
389
# File 'lib/spiderfw/model/query_set.rb', line 383

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:



407
408
409
410
411
412
413
414
415
# File 'lib/spiderfw/model/query_set.rb', line 407

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.



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

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



708
709
710
# File 'lib/spiderfw/model/query_set.rb', line 708

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:



692
693
694
695
696
697
698
699
700
701
702
703
704
705
# File 'lib/spiderfw/model/query_set.rb', line 692

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



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

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

#limit(n) ⇒ self

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

Returns:

  • (self)


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

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)


583
584
585
586
587
588
589
590
591
592
593
# File 'lib/spiderfw/model/query_set.rb', line 583

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)


615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
# File 'lib/spiderfw/model/query_set.rb', line 615

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



606
607
608
609
610
# File 'lib/spiderfw/model/query_set.rb', line 606

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



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

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)


636
637
638
639
640
641
# File 'lib/spiderfw/model/query_set.rb', line 636

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



831
832
833
834
835
# File 'lib/spiderfw/model/query_set.rb', line 831

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:



500
501
502
503
# File 'lib/spiderfw/model/query_set.rb', line 500

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)


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

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)


552
553
554
555
# File 'lib/spiderfw/model/query_set.rb', line 552

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)


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

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)



973
974
975
976
# File 'lib/spiderfw/model/query_set.rb', line 973

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

#reindexself

Rebuild object index.

Returns:

  • (self)


394
395
396
397
398
399
400
401
402
# File 'lib/spiderfw/model/query_set.rb', line 394

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:



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

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

#reverseArray

Returns A reversed Array.

Returns:

  • (Array)

    A reversed Array



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

def reverse
    self.to_a.reverse
end

#savevoid

This method returns an undefined value.

Saves 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!void

This method returns an undefined value.

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



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

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.



682
683
684
685
686
687
# File 'lib/spiderfw/model/query_set.rb', line 682

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



420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/spiderfw/model/query_set.rb', line 420

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:



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

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

#select_arrayArray

 Like #select, but returns an array

Returns:

  • (Array)


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

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:



570
571
572
573
574
575
576
577
578
579
# File 'lib/spiderfw/model/query_set.rb', line 570

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



597
598
599
600
601
# File 'lib/spiderfw/model/query_set.rb', line 597

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



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
813
814
815
816
817
818
# File 'lib/spiderfw/model/query_set.rb', line 746

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



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

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)


839
840
841
842
843
844
845
846
847
# File 'lib/spiderfw/model/query_set.rb', line 839

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.



730
731
732
# File 'lib/spiderfw/model/query_set.rb', line 730

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



736
737
738
739
740
741
742
# File 'lib/spiderfw/model/query_set.rb', line 736

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



713
714
715
716
717
718
719
# File 'lib/spiderfw/model/query_set.rb', line 713

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 ‘, ’



863
864
865
# File 'lib/spiderfw/model/query_set.rb', line 863

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.



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

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)


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

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

#with_polymorphsself

Calls Query#with_polymorphs on the QuerySet’s query

Returns:

  • (self)


559
560
561
562
563
564
# File 'lib/spiderfw/model/query_set.rb', line 559

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

#with_superclassself

Returns:

  • (self)


935
936
937
938
# File 'lib/spiderfw/model/query_set.rb', line 935

def with_superclass
    @query.with_superclass
    return self
end