Class: Mongoid::Association::Referenced::HasMany::Enumerable
- Inherits:
-
Object
- Object
- Mongoid::Association::Referenced::HasMany::Enumerable
- Extended by:
- Forwardable
- Includes:
- Enumerable, FieldReadable, Pluckable
- Defined in:
- lib/mongoid/association/referenced/has_many/enumerable.rb
Overview
This class is the wrapper for all referenced associations that have a target that can be a criteria or array of _loaded documents. This handles both cases or a combination of the two.
Instance Attribute Summary collapse
-
#_added ⇒ Object
The three main instance variables are collections of documents.
-
#_added Documents that have been appended.(Documentsthathavebeenappended.) ⇒ Object
The three main instance variables are collections of documents.
-
#_loaded ⇒ Object
The three main instance variables are collections of documents.
-
#_loaded Persisted documents that have been _loaded.(Persisteddocumentsthathavebeen_loaded.) ⇒ Object
The three main instance variables are collections of documents.
-
#_unloaded ⇒ Object
The three main instance variables are collections of documents.
-
#_unloaded A criteria representing persisted docs.(Acriteriarepresentingpersisteddocs.) ⇒ Object
The three main instance variables are collections of documents.
Instance Method Summary collapse
-
#<<(document) ⇒ Document
(also: #push)
Append a document to the enumerable.
-
#==(other) ⇒ true | false
Check if the enumerable is equal to the other object.
-
#===(other) ⇒ true | false
Check equality of the enumerable against the provided object for case statements.
-
#_loaded? ⇒ true | false
Has the enumerable been _loaded? This will be true if the criteria has been executed or we manually load the entire thing.
-
#any?(*args) ⇒ true | false
Returns whether the association has any documents, optionally subject to the provided filters.
-
#as_json(options = {}) ⇒ Hash
Send #as_json to the entries, without encoding.
-
#avg(field) ⇒ Float | nil
Get the average of the provided field for all documents in the enumerable.
-
#clear(&block) ⇒ Array<Document>
Clears out all the documents in this enumerable.
-
#clone ⇒ Array<Document>
Clones each document in the enumerable.
-
#delete(document) {|doc| ... } ⇒ Document
Delete the supplied document from the enumerable.
-
#delete_if(&block) ⇒ Array<Document>
Deletes every document in the enumerable for where the block returns true.
-
#each ⇒ true
Iterating over this enumerable has to handle a few different scenarios.
-
#empty? ⇒ true | false
Is the enumerable empty? Will determine if the count is zero based on whether or not it is _loaded.
-
#first(limit = nil) ⇒ Document
Get the first document in the enumerable.
-
#in_memory ⇒ Array<Document>
Return all the documents in the enumerable that have been _loaded or _added.
-
#include?(doc) ⇒ true | false
Does the target include the provided document?.
-
#initialize(target, base = nil, association = nil) ⇒ Enumerable
constructor
Initialize the new enumerable either with a criteria or an array.
-
#inspect ⇒ String
Inspection will just inspect the entries for nice array-style printing.
-
#last(limit = nil) ⇒ Document
Get the last document in the enumerable.
-
#marshal_dump ⇒ Array<Object>
Provides the data needed to Marshal.dump an enumerable proxy.
-
#marshal_load(data) ⇒ Array<Object>
Loads the data needed to Marshal.load an enumerable proxy.
-
#max(field = nil) ⇒ Numeric | nil
Get the maximum value of the provided field for all documents in the enumerable.
-
#min(field = nil) ⇒ Numeric | nil
Get the minimum value of the provided field for all documents in the enumerable.
-
#pluck(*keys) ⇒ Array | Array<Array>
Plucks the given field names from the documents in the target.
-
#reset ⇒ false
Reset the enumerable back to its persisted state.
-
#reset_unloaded(criteria) ⇒ Object
Resets the underlying unloaded criteria object with a new one.
-
#respond_to?(name, include_private = false) ⇒ true | false
Does this enumerable respond to the provided method?.
-
#size ⇒ Integer
(also: #length)
Gets the total size of this enumerable.
-
#sum(field = nil) ⇒ Numeric
Get the sum of the provided field for all documents in the enumerable.
-
#to_json(options = {}) ⇒ String
Send #to_json to the entries.
-
#uniq ⇒ Array<Document>
Return all the unique documents in the enumerable.
Constructor Details
#initialize(target, base = nil, association = nil) ⇒ Enumerable
Initialize the new enumerable either with a criteria or an array.
262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 262 def initialize(target, base = nil, association = nil) @_base = base @_association = association if target.is_a?(Criteria) @_added, @executed, @_loaded, @_unloaded = {}, false, {}, target else @_added, @executed = {}, true @_loaded = target.each_with_object({}) do |doc, _target| _target[doc._id] = doc if doc end end end |
Instance Attribute Details
#_added ⇒ Object
The three main instance variables are collections of documents.
24 25 26 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 24 def _added @_added end |
#_added Documents that have been appended.(Documentsthathavebeenappended.) ⇒ Object
The three main instance variables are collections of documents.
24 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 24 attr_accessor :_added, :_loaded, :_unloaded |
#_loaded ⇒ Object
The three main instance variables are collections of documents.
24 25 26 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 24 def _loaded @_loaded end |
#_loaded Persisted documents that have been _loaded.(Persisteddocumentsthathavebeen_loaded.) ⇒ Object
The three main instance variables are collections of documents.
24 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 24 attr_accessor :_added, :_loaded, :_unloaded |
#_unloaded ⇒ Object
The three main instance variables are collections of documents.
24 25 26 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 24 def _unloaded @_unloaded end |
#_unloaded A criteria representing persisted docs.(Acriteriarepresentingpersisteddocs.) ⇒ Object
The three main instance variables are collections of documents.
24 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 24 attr_accessor :_added, :_loaded, :_unloaded |
Instance Method Details
#<<(document) ⇒ Document Also known as: push
Append a document to the enumerable.
65 66 67 68 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 65 def <<(document) _added[document._id] = document self end |
#==(other) ⇒ true | false
Check if the enumerable is equal to the other object.
36 37 38 39 40 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 36 def ==(other) return false unless other.respond_to?(:entries) entries == other.entries end |
#===(other) ⇒ true | false
Check equality of the enumerable against the provided object for case statements.
51 52 53 54 55 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 51 def ===(other) return false unless other.respond_to?(:entries) entries === other.entries end |
#_loaded? ⇒ true | false
Has the enumerable been _loaded? This will be true if the criteria has been executed or we manually load the entire thing.
353 354 355 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 353 def _loaded? !!@executed end |
#any?(*args) ⇒ true | false
Returns whether the association has any documents, optionally subject to the provided filters.
This method returns true if the association has any persisted documents and if it has any not yet persisted documents.
If the association is already loaded, this method inspects the loaded documents and does not query the database. If the association is not loaded, the argument-less and block-less version does not load the association; the other versions (that delegate to Enumerable) may or may not load the association completely depending on whether it is iterated to completion.
This method can take a parameter and a block. The behavior with either the parameter or the block is delegated to the standard library Enumerable module.
Note that when Enumerable's any? method is invoked with both a block and a pattern, it only uses the pattern.
225 226 227 228 229 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 225 def any?(*args) return super if args.any? || block_given? !empty? end |
#as_json(options = {}) ⇒ Hash
Send #as_json to the entries, without encoding.
506 507 508 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 506 def as_json( = {}) entries.as_json() end |
#avg(field) ⇒ Float | nil
Get the average of the provided field for all documents in the enumerable. When the association is loaded, computes in memory without querying the database.
536 537 538 539 540 541 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 536 def avg(field) values = field_values_for(field) return nil if values.empty? values.sum / values.size.to_f end |
#clear(&block) ⇒ Array<Document>
Clears out all the documents in this enumerable. If passed a block it will yield to each document that is in memory.
84 85 86 87 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 84 def clear(&block) in_memory(&block) if block_given? _loaded.clear and _added.clear end |
#clone ⇒ Array<Document>
This loads all documents into memory.
Clones each document in the enumerable.
97 98 99 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 97 def clone collect { |doc| doc.clone } end |
#delete(document) {|doc| ... } ⇒ Document
Delete the supplied document from the enumerable.
109 110 111 112 113 114 115 116 117 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 109 def delete(document) doc = _loaded.delete(document._id) || _added.delete(document._id) if !doc && _unloaded && _unloaded.where(_id: document._id).exists? yield(document) if block_given? return document end yield(doc) if block_given? doc end |
#delete_if(&block) ⇒ Array<Document>
This operation loads all documents from the database.
Deletes every document in the enumerable for where the block returns true.
130 131 132 133 134 135 136 137 138 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 130 def delete_if(&block) load_all! deleted = in_memory.select(&block) deleted.each do |doc| _loaded.delete(doc._id) _added.delete(doc._id) end self end |
#each ⇒ true
Iterating over this enumerable has to handle a few different scenarios.
If the enumerable has its criteria _loaded into memory then it yields to all the _loaded docs and all the _added docs.
If the enumerable has not _loaded the criteria then it iterates over the cursor while loading the documents and then iterates over the _added docs.
If no block is passed then it returns an enumerator containing all docs.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 163 def each return to_enum unless block_given? if _loaded? _loaded.each_pair do |_id, doc| document = _added.delete(doc._id) || doc set_base(document) yield(document) end else unloaded_documents.each do |doc| document = _added.delete(doc._id) || _loaded.delete(doc._id) || doc _loaded[document._id] = document set_base(document) yield(document) end end _added.each_pair do |_id, doc| yield(doc) end @executed = true end |
#empty? ⇒ true | false
Is the enumerable empty? Will determine if the count is zero based on whether or not it is _loaded.
193 194 195 196 197 198 199 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 193 def empty? if _loaded? in_memory.empty? else _added.empty? && !_unloaded.exists? end end |
#first(limit = nil) ⇒ Document
Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first or #last, use #take instead. Be aware that #take won't guarantee order.
Get the first document in the enumerable. Will check the persisted documents first. Does not load the entire enumerable.
246 247 248 249 250 251 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 246 def first(limit = nil) _loaded.try(:values).try(:first) || _added[(ul = _unloaded.try(:first, limit)).try(:_id)] || ul || _added.values.try(:first) end |
#in_memory ⇒ Array<Document>
When passed a block it yields to each document.
Return all the documents in the enumerable that have been _loaded or _added.
309 310 311 312 313 314 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 309 def in_memory docs = (_loaded.values + _added.values) docs.each do |doc| yield(doc) if block_given? end end |
#include?(doc) ⇒ true | false
Does the target include the provided document?
283 284 285 286 287 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 283 def include?(doc) return super unless _unloaded _unloaded.where(_id: doc._id).exists? || _added.has_key?(doc._id) end |
#inspect ⇒ String
Inspection will just inspect the entries for nice array-style printing.
296 297 298 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 296 def inspect entries.inspect end |
#last(limit = nil) ⇒ Document
Automatically adding a sort on _id when no other sort is defined on the criteria has the potential to cause bad performance issues. If you experience unexpected poor performance when using #first or #last, use #take instead. Be aware that #take won't guarantee order.
Get the last document in the enumerable. Will check the new documents first. Does not load the entire enumerable.
331 332 333 334 335 336 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 331 def last(limit = nil) _added.values.try(:last) || _loaded.try(:values).try(:last) || _added[(ul = _unloaded.try(:last, limit)).try(:_id)] || ul end |
#marshal_dump ⇒ Array<Object>
Provides the data needed to Marshal.dump an enumerable proxy.
363 364 365 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 363 def marshal_dump [ _added, _loaded, _unloaded, @executed ] end |
#marshal_load(data) ⇒ Array<Object>
Loads the data needed to Marshal.load an enumerable proxy.
373 374 375 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 373 def marshal_load(data) @_added, @_loaded, @_unloaded, @executed = data end |
#max(field = nil) ⇒ Numeric | nil
Get the maximum value of the provided field for all documents in the enumerable. When the association is loaded, computes in memory without querying the database.
569 570 571 572 573 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 569 def max(field = nil) return super() if block_given? field_values_for(field).max end |
#min(field = nil) ⇒ Numeric | nil
Get the minimum value of the provided field for all documents in the enumerable. When the association is loaded, computes in memory without querying the database.
553 554 555 556 557 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 553 def min(field = nil) return super() if block_given? field_values_for(field).min end |
#pluck(*keys) ⇒ Array | Array<Array>
Plucks the given field names from the documents in the target. If the collection has been loaded, it plucks from the loaded documents; otherwise, it plucks from the unloaded criteria. Regardless, it also plucks from any added documents.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 386 def pluck(*keys) [].tap do |results| if _loaded? || _added.any? klass = @_association.klass prepared = prepare_pluck(keys, document_class: klass) end if _loaded? docs = _loaded.values.map { |v| BSON::Document.new(v.attributes) } results.concat pluck_from_documents(docs, prepared[:field_names], document_class: klass) elsif _unloaded criteria = if _added.any? ids_to_exclude = _added.keys _unloaded.not(:_id.in => ids_to_exclude) else _unloaded end results.concat criteria.pluck(*keys) end if _added.any? docs = _added.values.map { |v| BSON::Document.new(v.attributes) } results.concat pluck_from_documents(docs, prepared[:field_names], document_class: klass) end end end |
#reset ⇒ false
Reset the enumerable back to its persisted state.
420 421 422 423 424 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 420 def reset _loaded.clear _added.clear @executed = false end |
#reset_unloaded(criteria) ⇒ Object
Resets the underlying unloaded criteria object with a new one. Used my HABTM associations to keep the underlying array in sync.
433 434 435 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 433 def reset_unloaded(criteria) @_unloaded = criteria if _unloaded.is_a?(Criteria) end |
#respond_to?(name, include_private = false) ⇒ true | false
Does this enumerable respond to the provided method?
447 448 449 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 447 def respond_to?(name, include_private = false) [].respond_to?(name, include_private) || super end |
#size ⇒ Integer Also known as: length
Gets the total size of this enumerable. This is a combination of all the persisted and unpersisted documents.
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 458 def size # If _unloaded is present, then it will match the set of documents # that belong to this association, which have already been persisted # to the database. This set of documents must be considered when # computing the size of the association, along with anything that has # since been added. if _unloaded if _added.any? # Note that _added may include records that _unloaded already # matches. This is the case if the association is assigned an array # of items and some of them were already elements of the association. # # we need to thus make sure _unloaded.count excludes any elements # that already exist in _added. count = _unloaded.not(:_id.in => _added.values.map(&:id)).count count + _added.values.count else _unloaded.count end else _loaded.count + _added.count end end |
#sum(field = nil) ⇒ Numeric
Get the sum of the provided field for all documents in the enumerable. When the association is loaded, computes in memory without querying the database.
520 521 522 523 524 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 520 def sum(field = nil) return super(field || 0) if block_given? field_values_for(field).sum || 0 end |
#to_json(options = {}) ⇒ String
Send #to_json to the entries.
494 495 496 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 494 def to_json( = {}) entries.to_json() end |
#uniq ⇒ Array<Document>
This operation loads all documents from the database.
Return all the unique documents in the enumerable.
583 584 585 |
# File 'lib/mongoid/association/referenced/has_many/enumerable.rb', line 583 def uniq entries.uniq end |