Class: Spider::Model::QuerySet
- 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
-
#_no_identity_mapper ⇒ Object
Don’t put this queryset’s objects into the IdentityMapper.
-
#_no_parent ⇒ Object
Disables parent setting for this QuerySet.
-
#_parent ⇒ Object
BaseModel instance pointing to this QuerySet.
-
#_parent_element ⇒ Object
Element inside the _parent pointing to this QuerySet.
-
#append_element ⇒ Object
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.
-
#fetch_window ⇒ Object
(Fixnum) How many objects to load at a time.
-
#keep_window ⇒ Object
(Fixnum) How many objects to keep in memory when advancing the window.
-
#last_query ⇒ Object
Set by mapper.
-
#loadable ⇒ Object
(bool) If false, prevents the QuerySet from loading.
-
#loaded ⇒ Object
(bool) Wether the QuerySet has been loaded.
-
#loaded_elements ⇒ Object
readonly
An Hash of autoloaded elements.
-
#model ⇒ Object
The BaseModel.
-
#modified ⇒ Object
Returns the value of attribute modified.
-
#objects ⇒ Object
readonly
The actual fetched objects.
-
#query ⇒ Object
The Query.
-
#raw_data ⇒ Object
readonly
Raw data returned by the mapper, if requested.
-
#total_rows ⇒ Object
Total number of objects that would be returned had the Query no limit.
Class Method Summary collapse
- .autoloading(model, query_or_val = nil) ⇒ Object
-
.static(model, query_or_val = nil) ⇒ Object
Instantiates a non-autoloading queryset.
Instance Method Summary collapse
-
#+(other) ⇒ Object
Returns a new QuerySet containing objects from both this and the other.
-
#<<(obj, raw = nil) ⇒ Object
Adds an object to the set.
-
#[](index) ⇒ Object
Accesses an object.
-
#[]=(index, val) ⇒ Object
Sets an object.
-
#all_children(path) ⇒ Object
Given a dotted path, will return an array of all objects reachable by that path Example objectset.all_children(‘friends.collegues.addresses.street_name’).
-
#autoload(bool, traverse = true) ⇒ Object
Enables or disables autoload; if the second argument is true, will traverse contained objects.
-
#autoload=(bool) ⇒ Object
Enables or disables autoload.
- #autoload? ⇒ Boolean
- #change_model(model) ⇒ Object
-
#clear ⇒ Object
Remove all elements from self.
-
#clone ⇒ Object
Performs a deep copy.
-
#command_exists?(command) ⇒ Boolean
Determines if a shell command exists by searching for it in ENV.
-
#current_length ⇒ Object
Current number of objects fetched.
- #currently_empty? ⇒ Boolean
-
#cut(*params) ⇒ Object
Returns an array with the results of calling #BaseModel.cut on each object.
- #delete(obj) ⇒ Object
-
#delete_at(index) ⇒ Object
Deletes object at the given index.
-
#detect_terminal_size ⇒ Object
Returns [width, height] of terminal when detected, nil if not detected.
-
#each ⇒ Object
Iterates on objects, loading when needed.
-
#each_current ⇒ Object
Iterates on currently loaded objects.
-
#each_current_index ⇒ Object
Iterates on indexes without loading.
-
#each_index ⇒ Object
Iterates yielding the queryset index.
-
#each_rolling_index ⇒ Object
Iterates yielding the internal objects index.
-
#element_loaded(element) ⇒ Object
Registers that the element has been loaded.
-
#element_loaded?(element) ⇒ Boolean
Returns whether the element has been loaded from the Storage.
- #element_queryset(el) ⇒ Object
- #empty! ⇒ Object
-
#empty? ⇒ Boolean
True if no objects were fetched (yet).
-
#find(params) ⇒ Object
Searchs the index for objects matching the given params.
-
#fixed(name, value) ⇒ Object
Sets a fixed value: it will be applied to every object.
-
#has_more? ⇒ Boolean
True if the query had a limit, and more results can be fetched.
-
#identity_mapper ⇒ Object
Returns the QuerySet IdentityMapper instance.
-
#identity_mapper=(im) ⇒ Object
Assigns an IdentityMapper.
- #include?(val) ⇒ Boolean
-
#index_by(*elements) ⇒ Object
Index objects by some elements.
-
#index_object(obj) ⇒ Object
Adds object to the index.
-
#initialize(model, query_or_val = nil) ⇒ QuerySet
constructor
The first argument must be a BaseModel subclass.
-
#insert ⇒ Object
Calls #BaseModel.insert on each object in the QuerySet.
- #inspect ⇒ Object
-
#instantiate_object(val = nil) ⇒ Object
Returns a new instance of @model from val.
-
#last ⇒ Object
Returns the last object.
-
#length ⇒ Object
Number of objects fetched.
-
#limit(n) ⇒ Object
Calls #Query.limit.
-
#load ⇒ Object
Executes the query and fetches the objects; (the next batch if a fetch_window is set).
-
#load_next(page = nil) ⇒ Object
Loads the next batch of objects.
-
#load_to_index(i) ⇒ Object
Loads objects up to index i.
- #loadable? ⇒ Boolean
-
#loaded?(index = nil) ⇒ Boolean
If a Fixnum is passed, will tell if the given index is loaded.
- #map_current ⇒ Object
-
#mapper ⇒ Object
Model mapper.
-
#merge(query_set) ⇒ Object
Merges the content of another QuerySet.
- #method_missing(method, *args, &proc) ⇒ Object
- #modified? ⇒ Boolean
-
#no_autoload(traverse = true) ⇒ Object
Disables autoload.
-
#offset(n) ⇒ Object
Calls #Query.offset.
-
#order_by(*elements) ⇒ Object
Calls Query.order_by.
- #page(page, rows) ⇒ Object
- #pages ⇒ Object
-
#reindex ⇒ Object
Rebuild object index.
- #reject!(&proc) ⇒ Object
- #reverse ⇒ Object
-
#save ⇒ Object
Saves each object in the QuerySet.
- #save! ⇒ Object
-
#save_all(params = {}) ⇒ Object
Calls #BaseModel.save_all on each object in the QuerySet.
-
#search_key(obj, name) ⇒ Object
FIXME: ???.
-
#select(&proc) ⇒ Object
Returns a (static) QuerySet of the objects for which the block evaluates to true.
-
#select_array ⇒ Object
Like #select, but returns an array.
-
#set(element, value) ⇒ Object
Sets the value of an element on all currently loaded objects.
-
#set_data(data) ⇒ Object
Adds objects to the QuerySet.
-
#set_parent(obj, element) ⇒ Object
Sets containing model and element.
-
#start_for_index(i) ⇒ Object
Start for the query to get index i.
-
#table ⇒ Object
Prints an ASCII table.
- #to_a ⇒ Object
-
#to_flat_array ⇒ Object
Returns an array of Hashes, with each value of the object is converted to string.
-
#to_hash_array ⇒ Object
Returns an array with the results of calling #BaseModel.to_hash_array on each object.
- #to_indexed_hash(element) ⇒ Object
- #to_json(state = nil, &proc) ⇒ Object
- #to_s ⇒ Object
-
#update ⇒ Object
Calls #BaseModel.update on each object in the QuerySet.
-
#update_loaded_elements ⇒ Object
Checks contained objects’ loaded elements.
-
#where(*params, &proc) ⇒ Object
Calls #Query.where.
- #with_polymorphs ⇒ Object
- #with_superclass ⇒ Object
Constructor Details
#initialize(model, query_or_val = nil) ⇒ QuerySet
The first argument must be a BaseModel subclass. The second argument may be a Query, or data that will be passed to #set_data. If data is passed, the QuerySet will be instantiated with autoload set to false.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/spiderfw/model/query_set.rb', line 71 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
714 715 716 717 718 719 720 721 |
# File 'lib/spiderfw/model/query_set.rb', line 714 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_mapper ⇒ Object
Don’t put this queryset’s objects into the IdentityMapper
52 53 54 |
# File 'lib/spiderfw/model/query_set.rb', line 52 def _no_identity_mapper @_no_identity_mapper end |
#_no_parent ⇒ Object
Disables parent setting for this QuerySet
15 16 17 |
# File 'lib/spiderfw/model/query_set.rb', line 15 def _no_parent @_no_parent end |
#_parent ⇒ Object
BaseModel instance pointing to this QuerySet
11 12 13 |
# File 'lib/spiderfw/model/query_set.rb', line 11 def _parent @_parent end |
#_parent_element ⇒ Object
Element inside the _parent pointing to this QuerySet.
13 14 15 |
# File 'lib/spiderfw/model/query_set.rb', line 13 def _parent_element @_parent_element end |
#append_element ⇒ Object
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
48 49 50 |
# File 'lib/spiderfw/model/query_set.rb', line 48 def append_element @append_element end |
#fetch_window ⇒ Object
(Fixnum) How many objects to load at a time. If nil, all the objects returned by the Query will be loaded.
34 35 36 |
# File 'lib/spiderfw/model/query_set.rb', line 34 def fetch_window @fetch_window end |
#keep_window ⇒ Object
(Fixnum) How many objects to keep in memory when advancing the window. If nil, all objects will be kept.
36 37 38 |
# File 'lib/spiderfw/model/query_set.rb', line 36 def keep_window @keep_window end |
#last_query ⇒ Object
Set by mapper
25 26 27 |
# File 'lib/spiderfw/model/query_set.rb', line 25 def last_query @last_query end |
#loadable ⇒ Object
(bool) If false, prevents the QuerySet from loading.
50 51 52 |
# File 'lib/spiderfw/model/query_set.rb', line 50 def loadable @loadable end |
#loaded ⇒ Object
(bool) Wether the QuerySet has been loaded
31 32 33 |
# File 'lib/spiderfw/model/query_set.rb', line 31 def loaded @loaded end |
#loaded_elements ⇒ Object (readonly)
An Hash of autoloaded elements.
19 20 21 |
# File 'lib/spiderfw/model/query_set.rb', line 19 def loaded_elements @loaded_elements end |
#model ⇒ Object
The BaseModel
27 28 29 |
# File 'lib/spiderfw/model/query_set.rb', line 27 def model @model end |
#modified ⇒ Object
Returns the value of attribute modified.
53 54 55 |
# File 'lib/spiderfw/model/query_set.rb', line 53 def modified @modified end |
#objects ⇒ Object (readonly)
The actual fetched objects.
21 22 23 |
# File 'lib/spiderfw/model/query_set.rb', line 21 def objects @objects end |
#query ⇒ Object
The Query
23 24 25 |
# File 'lib/spiderfw/model/query_set.rb', line 23 def query @query end |
#raw_data ⇒ Object (readonly)
Raw data returned by the mapper, if requested.
17 18 19 |
# File 'lib/spiderfw/model/query_set.rb', line 17 def raw_data @raw_data end |
#total_rows ⇒ Object
Total number of objects that would be returned had the Query no limit.
29 30 31 |
# File 'lib/spiderfw/model/query_set.rb', line 29 def total_rows @total_rows end |
Class Method Details
.autoloading(model, query_or_val = nil) ⇒ Object
62 63 64 65 66 |
# File 'lib/spiderfw/model/query_set.rb', line 62 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) ⇒ Object
Instantiates a non-autoloading queryset
56 57 58 59 60 |
# File 'lib/spiderfw/model/query_set.rb', line 56 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) ⇒ Object
Returns a new QuerySet containing objects from both this and the other.
250 251 252 253 254 255 256 |
# File 'lib/spiderfw/model/query_set.rb', line 250 def +(other) qs = self.clone other.each do |obj| qs << obj end return qs end |
#<<(obj, raw = nil) ⇒ Object
Adds an object to the set. Also stores the raw data if it is passed as the second parameter.
165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/spiderfw/model/query_set.rb', line 165 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) ⇒ Object
Accesses an object. Data will be loaded according to fetch_window.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/spiderfw/model/query_set.rb', line 181 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) ⇒ Object
Sets an object.
200 201 202 203 204 205 206 207 208 209 |
# File 'lib/spiderfw/model/query_set.rb', line 200 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) ⇒ Object
Given a dotted path, will return an array of all objects reachable by that path Example
objectset.all_children('friends.collegues.addresses.street_name')
738 739 740 741 742 743 744 |
# File 'lib/spiderfw/model/query_set.rb', line 738 def all_children(path) if (path.length > 0) children = @objects.map{ |obj| obj.all_children(path.clone) }.flatten else return @objects end end |
#autoload(bool, traverse = true) ⇒ Object
Enables or disables autoload; if the second argument is true, will traverse contained objects.
116 117 118 119 |
# File 'lib/spiderfw/model/query_set.rb', line 116 def autoload(bool, traverse=true) @autoload = bool @objects.each{ |obj| obj.autoload = bool } if traverse end |
#autoload=(bool) ⇒ Object
Enables or disables autoload.
122 123 124 |
# File 'lib/spiderfw/model/query_set.rb', line 122 def autoload=(bool) autoload(bool) end |
#autoload? ⇒ Boolean
126 127 128 |
# File 'lib/spiderfw/model/query_set.rb', line 126 def autoload? @autoload ? true : false end |
#change_model(model) ⇒ Object
156 157 158 159 160 161 162 |
# File 'lib/spiderfw/model/query_set.rb', line 156 def change_model(model) @model = model @objects.each_index do |i| @objects[i] = @objects[i].become(model) end return self end |
#clear ⇒ Object
Remove all elements from self
349 350 351 352 |
# File 'lib/spiderfw/model/query_set.rb', line 349 def clear @objects = [] @index_lookup.each_key{ |k| @index_lookup[k] = {} } end |
#clone ⇒ Object
Performs a deep copy
811 812 813 814 815 816 817 818 819 |
# File 'lib/spiderfw/model/query_set.rb', line 811 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.
610 611 612 |
# File 'lib/spiderfw/model/query_set.rb', line 610 def command_exists?(command) ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) } end |
#current_length ⇒ Object
Current number of objects fetched.
288 289 290 |
# File 'lib/spiderfw/model/query_set.rb', line 288 def current_length @objects.length end |
#currently_empty? ⇒ Boolean
298 299 300 |
# File 'lib/spiderfw/model/query_set.rb', line 298 def currently_empty? @objects.empty? end |
#cut(*params) ⇒ Object
Returns an array with the results of calling #BaseModel.cut on each object.
584 585 586 587 |
# File 'lib/spiderfw/model/query_set.rb', line 584 def cut(*params) load unless loaded? || !autoload? return self.map{ |obj| obj.cut(*params) } end |
#delete(obj) ⇒ Object
245 246 247 |
# File 'lib/spiderfw/model/query_set.rb', line 245 def delete(obj) @objects.delete(obj) end |
#delete_at(index) ⇒ Object
Deletes object at the given index.
241 242 243 |
# File 'lib/spiderfw/model/query_set.rb', line 241 def delete_at(index) @objects.delete_at(index) end |
#detect_terminal_size ⇒ Object
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()
616 617 618 619 620 621 622 623 624 625 626 |
# File 'lib/spiderfw/model/query_set.rb', line 616 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 ⇒ Object
Iterates on objects, loading when needed.
360 361 362 363 364 365 366 367 368 369 |
# File 'lib/spiderfw/model/query_set.rb', line 360 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 ⇒ Object
Iterates on currently loaded objects
355 356 357 |
# File 'lib/spiderfw/model/query_set.rb', line 355 def each_current @objects.each { |obj| yield obj } end |
#each_current_index ⇒ Object
Iterates on indexes without loading.
393 394 395 396 397 398 |
# File 'lib/spiderfw/model/query_set.rb', line 393 def each_current_index @objects.each_index do |i| i += @window_current_start-1 if @window_current_start yield i end end |
#each_index ⇒ Object
Iterates yielding the queryset index. Will load when needed.
385 386 387 388 389 390 |
# File 'lib/spiderfw/model/query_set.rb', line 385 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 ⇒ Object
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.
373 374 375 376 377 378 379 380 381 382 |
# File 'lib/spiderfw/model/query_set.rb', line 373 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) ⇒ Object
Registers that the element has been loaded.
747 748 749 750 |
# File 'lib/spiderfw/model/query_set.rb', line 747 def element_loaded(element) element = element.name if element.is_a?(Element) @loaded_elements[element] = true end |
#element_loaded?(element) ⇒ Boolean
Returns whether the element has been loaded from the Storage.
753 754 755 756 |
# File 'lib/spiderfw/model/query_set.rb', line 753 def element_loaded?(element) element = element.name if element.is_a?(Element) @loaded_elements[element] end |
#element_queryset(el) ⇒ Object
723 724 725 726 727 728 729 730 731 732 733 |
# File 'lib/spiderfw/model/query_set.rb', line 723 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! ⇒ Object
706 707 708 |
# File 'lib/spiderfw/model/query_set.rb', line 706 def empty! @objects = [] end |
#empty? ⇒ Boolean
True if no objects were fetched (yet).
293 294 295 296 |
# File 'lib/spiderfw/model/query_set.rb', line 293 def empty? load unless @loaded || !autoload? @objects.empty? end |
#find(params) ⇒ Object
Searchs the index for objects matching the given params.
427 428 429 430 431 432 433 434 435 436 437 |
# File 'lib/spiderfw/model/query_set.rb', line 427 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) ⇒ Object
Sets a fixed value: it will be applied to every object.
110 111 112 |
# File 'lib/spiderfw/model/query_set.rb', line 110 def fixed(name, value) @fixed[name] = value end |
#has_more? ⇒ Boolean
True if the query had a limit, and more results can be fetched.
275 276 277 278 279 280 |
# File 'lib/spiderfw/model/query_set.rb', line 275 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_mapper ⇒ Object
Returns the QuerySet IdentityMapper instance
759 760 761 762 |
# File 'lib/spiderfw/model/query_set.rb', line 759 def identity_mapper return Spider::Model.identity_mapper if Spider::Model.identity_mapper @identity_mapper ||= IdentityMapper.new end |
#identity_mapper=(im) ⇒ Object
Assigns an IdentityMapper
765 766 767 |
# File 'lib/spiderfw/model/query_set.rb', line 765 def identity_mapper=(im) @identity_mapper = im end |
#include?(val) ⇒ Boolean
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/spiderfw/model/query_set.rb', line 406 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) ⇒ Object
Index objects by some elements.
303 304 305 306 307 308 309 |
# File 'lib/spiderfw/model/query_set.rb', line 303 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) ⇒ Object
Adds object to the index
323 324 325 326 327 328 329 330 331 |
# File 'lib/spiderfw/model/query_set.rb', line 323 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 |
#insert ⇒ Object
Calls #BaseModel.insert on each object in the QuerySet.
537 538 539 |
# File 'lib/spiderfw/model/query_set.rb', line 537 def insert no_autoload(false){ each{ |obj| obj.insert } } end |
#inspect ⇒ Object
570 571 572 |
# File 'lib/spiderfw/model/query_set.rb', line 570 def inspect return "#{self.class.name}:\n@model=#{@model}, @query=#{query.inspect}, @objects=#{@objects.inspect}" end |
#instantiate_object(val = nil) ⇒ Object
Returns a new instance of @model from val.
555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/spiderfw/model/query_set.rb', line 555 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 |
#last ⇒ Object
Returns the last object.
235 236 237 238 |
# File 'lib/spiderfw/model/query_set.rb', line 235 def last load unless (@loaded || !autoload?) && loaded?(total_rows-1) @objects.last end |
#length ⇒ Object
Number of objects fetched. Will call load if not loaded yet. Note: this is not the total number of objects corresponding to the Query; it may be equal to the fetch_window, or to the @query.limit.
261 262 263 264 |
# File 'lib/spiderfw/model/query_set.rb', line 261 def length load unless @loaded || !autoload? @objects.length end |
#limit(n) ⇒ Object
Calls #Query.limit
785 786 787 788 |
# File 'lib/spiderfw/model/query_set.rb', line 785 def limit(n) @query.limit = n return self end |
#load ⇒ Object
Executes the query and fetches the objects; (the next batch if a fetch_window is set).
465 466 467 468 469 470 471 472 473 474 475 |
# File 'lib/spiderfw/model/query_set.rb', line 465 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) ⇒ Object
Loads the next batch of objects.
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/spiderfw/model/query_set.rb', line 492 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) ⇒ Object
Loads objects up to index i
485 486 487 488 489 |
# File 'lib/spiderfw/model/query_set.rb', line 485 def load_to_index(i) return load unless @fetch_window page = i / @fetch_window + 1 load_next(page) end |
#loadable? ⇒ Boolean
523 524 525 |
# File 'lib/spiderfw/model/query_set.rb', line 523 def loadable? @loadable end |
#loaded?(index = nil) ⇒ Boolean
If a Fixnum is passed, will tell if the given index is loaded. With no argument, will tell if the QuerySet is loaded
511 512 513 514 515 516 |
# File 'lib/spiderfw/model/query_set.rb', line 511 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_current ⇒ Object
685 686 687 688 689 |
# File 'lib/spiderfw/model/query_set.rb', line 685 def map_current a = [] each_current{ |row| a << yield(row) } a end |
#mapper ⇒ Object
Model mapper.
105 106 107 |
# File 'lib/spiderfw/model/query_set.rb', line 105 def mapper @model.mapper end |
#merge(query_set) ⇒ Object
Merges the content of another QuerySet.
401 402 403 404 |
# File 'lib/spiderfw/model/query_set.rb', line 401 def merge(query_set) @objects += query_set.instance_variable_get(:"@objects") reindex end |
#modified? ⇒ Boolean
226 227 228 229 230 231 232 |
# File 'lib/spiderfw/model/query_set.rb', line 226 def modified? return true if @modified @objects.each do |obj| return true if obj.modified? end return false end |
#no_autoload(traverse = true) ⇒ Object
Disables autoload. If a block is given, the current autoload value will be restored after yielding.
137 138 139 140 141 142 |
# File 'lib/spiderfw/model/query_set.rb', line 137 def no_autoload(traverse=true) prev_autoload = autoload? self.autoload(false, traverse) yield self.autoload(prev_autoload, traverse) end |
#offset(n) ⇒ Object
Calls #Query.offset
791 792 793 794 |
# File 'lib/spiderfw/model/query_set.rb', line 791 def offset(n) @query.offset = n return self end |
#order_by(*elements) ⇒ Object
Calls Query.order_by
440 441 442 443 |
# File 'lib/spiderfw/model/query_set.rb', line 440 def order_by(*elements) @query.order_by *elements return self end |
#page(page, rows) ⇒ Object
796 797 798 799 |
# File 'lib/spiderfw/model/query_set.rb', line 796 def page(page, rows) @query.page(page, rows) self end |
#pages ⇒ Object
801 802 803 804 |
# File 'lib/spiderfw/model/query_set.rb', line 801 def pages return nil unless @query.limit (self.total_rows.to_f / @query.limit).ceil end |
#reindex ⇒ Object
Rebuild object index.
312 313 314 315 316 317 318 319 320 |
# File 'lib/spiderfw/model/query_set.rb', line 312 def reindex # :nodoc: @index_lookup.each_key do |index| @index_lookup[index] = {} end each_current do |obj| index_object(obj) end return self end |
#reject!(&proc) ⇒ Object
702 703 704 |
# File 'lib/spiderfw/model/query_set.rb', line 702 def reject!(&proc) @objects.reject!(&proc) end |
#reverse ⇒ Object
681 682 683 |
# File 'lib/spiderfw/model/query_set.rb', line 681 def reverse self.to_a.reverse end |
#save ⇒ Object
Saves each object in the QuerySet.
528 529 530 |
# File 'lib/spiderfw/model/query_set.rb', line 528 def save no_autoload(false){ each{ |obj| obj.save } } end |
#save! ⇒ Object
532 533 534 |
# File 'lib/spiderfw/model/query_set.rb', line 532 def save! no_autoload(false){ each{ |obj| obj.save! } } end |
#save_all(params = {}) ⇒ Object
Calls #BaseModel.save_all on each object in the QuerySet.
547 548 549 550 551 552 |
# File 'lib/spiderfw/model/query_set.rb', line 547 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) ⇒ Object
FIXME: ???
334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/spiderfw/model/query_set.rb', line 334 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) ⇒ Object
Returns a (static) QuerySet of the objects for which the block evaluates to true.
270 271 272 |
# File 'lib/spiderfw/model/query_set.rb', line 270 def select(&proc) return QuerySet.new(@model, select_array(&proc)) end |
#select_array ⇒ Object
Like #select, but returns an array
267 |
# File 'lib/spiderfw/model/query_set.rb', line 267 alias :select_array :select |
#set(element, value) ⇒ Object
Sets the value of an element on all currently loaded objects.
453 454 455 456 457 458 459 460 461 462 |
# File 'lib/spiderfw/model/query_set.rb', line 453 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) ⇒ Object
Adds objects to the QuerySet. The argument must be an Enumerable (and should contain BaseModel instances).
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/spiderfw/model/query_set.rb', line 145 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) ⇒ Object
Sets containing model and element.
131 132 133 134 |
# File 'lib/spiderfw/model/query_set.rb', line 131 def set_parent(obj, element) @_parent = obj @_parent_element = element end |
#start_for_index(i) ⇒ Object
Start for the query to get index i
478 479 480 481 482 |
# File 'lib/spiderfw/model/query_set.rb', line 478 def start_for_index(i) # :nodoc: return 1 unless @fetch_window page = i / @fetch_window + 1 return (page - 1) * @fetch_window + 1 end |
#table ⇒ Object
Prints an ASCII table
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
# File 'lib/spiderfw/model/query_set.rb', line 603 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_a ⇒ Object
677 678 679 |
# File 'lib/spiderfw/model/query_set.rb', line 677 def to_a self.map{ |row| row } end |
#to_flat_array ⇒ Object
Returns an array of Hashes, with each value of the object is converted to string.
692 693 694 695 696 697 698 699 700 |
# File 'lib/spiderfw/model/query_set.rb', line 692 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_array ⇒ Object
Returns an array with the results of calling #BaseModel.to_hash_array on each object.
590 591 592 |
# File 'lib/spiderfw/model/query_set.rb', line 590 def to_hash_array return self.map{ |obj| obj.to_hash } end |
#to_indexed_hash(element) ⇒ Object
594 595 596 597 598 599 600 |
# File 'lib/spiderfw/model/query_set.rb', line 594 def to_indexed_hash(element) hash = {} self.each do |row| hash[row.get(element)] = row end hash end |
#to_json(state = nil, &proc) ⇒ Object
574 575 576 577 578 579 580 |
# File 'lib/spiderfw/model/query_set.rb', line 574 def to_json(state=nil, &proc) load unless loaded? || !autoload? res = "[" + self.map{ |obj| obj.to_json(&proc) }.join(',') + "]" return res end |
#to_s ⇒ Object
710 711 712 |
# File 'lib/spiderfw/model/query_set.rb', line 710 def to_s self.map{ |o| o.to_s }.join(', ') end |
#update ⇒ Object
Calls #BaseModel.update on each object in the QuerySet.
542 543 544 |
# File 'lib/spiderfw/model/query_set.rb', line 542 def update no_autoload(false){ each{ |obj| obj.update } } end |
#update_loaded_elements ⇒ Object
Checks contained objects’ loaded elements.
212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/spiderfw/model/query_set.rb', line 212 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) ⇒ Object
Calls #Query.where
779 780 781 782 |
# File 'lib/spiderfw/model/query_set.rb', line 779 def where(*params, &proc) @query.where(*params, &proc) return self end |
#with_polymorphs ⇒ Object
445 446 447 448 449 450 |
# File 'lib/spiderfw/model/query_set.rb', line 445 def with_polymorphs @model.polymorphic_models.each do |model, attributes| @query.with_polymorph(model) end self end |
#with_superclass ⇒ Object
769 770 771 772 |
# File 'lib/spiderfw/model/query_set.rb', line 769 def with_superclass @query.with_superclass return self end |