Class: DataMapper::Collection

Inherits:
LazyArray show all
Defined in:
lib/dm-core/collection.rb

Overview

The Collection class represents a list of resources persisted in a repository and identified by a query.

A Collection should act like an Array in every way, except that it will attempt to defer loading until the results from the repository are needed.

A Collection is typically returned by the Model#all method.

Direct Known Subclasses

Associations::OneToMany::Collection

Instance Attribute Summary collapse

Attributes inherited from LazyArray

#head, #tail

Instance Method Summary collapse

Methods inherited from LazyArray

#==, #any?, #empty?, #eql?, #fetch, #freeze, #frozen?, #include?, #index, #kind_of?, #lazy_possible?, #load_with, #loaded?, #to_a, #values_at

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object (private)

Delegates to Model, Relationships or the superclass (LazyArray)

When this receives a method that belongs to the Model the Collection is scoped to, it will execute the method within the same scope as the Collection and return the results.

When this receives a method that is a relationship the Model has defined, it will execute the association method within the same scope as the Collection and return the results.

Otherwise this method will delegate to a method in the superclass (LazyArray) and return the results.

Returns:

  • (Object)

    the return values of the delegated methods



1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
# File 'lib/dm-core/collection.rb', line 1414

private def method_missing(method, *args, &block)
  relationships = self.relationships

  if model.respond_to?(method)
    delegate_to_model(method, *args, &block)
  elsif (relationship = relationships[method]) || relationships[DataMapper::Inflector.singularize(method.to_s).to_sym]
    delegate_to_relationship(relationship, *args)
  else
    super
  end
end

Instance Attribute Details

#queryQuery (readonly)

Returns the Query the Collection is scoped with

Returns:

  • (Query)

    the Query the Collection is scoped with



26
27
28
# File 'lib/dm-core/collection.rb', line 26

def query
  @query
end

Instance Method Details

#<<(resource) ⇒ self

Append one Resource to the Collection and relate it

Parameters:

  • resource (Resource)

    the resource to add to this collection

Returns:

  • (self)


532
533
534
# File 'lib/dm-core/collection.rb', line 532

def <<(resource)
  super(resource_added(resource))
end

#[](*args) ⇒ Resource, ... Also known as: slice

Simulates Array#slice and returns a new Collection whose query has a new offset or limit according to the arguments provided.

If you provide a range, the min is used as the offset and the max minus the offset is used as the limit.

Parameters:

  • *args (Integer, Array(Integer), Range)

    the offset, offset and limit, or range indicating first and last position

Returns:

  • (Resource, Collection, nil)

    The entry which resides at that offset and limit, or a new Collection object with the set limits and offset

  • (nil)

    The offset (or starting offset) is out of range

Raises:

  • (ArgumentError)

    “arguments may be 1 or 2 Integers, or 1 Range object, was: #DataMapper::Collection.argsargs.inspect”



388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/dm-core/collection.rb', line 388

def [](*args)
  offset, limit = extract_slice_arguments(*args)

  return at(offset) if args.size == 1 && args.first.is_a?(Integer)

  query = sliced_query(offset, limit)

  if loaded? || partially_loaded?(offset, limit)
    new_collection(query, super)
  else
    new_collection(query)
  end
end

#[]=(*args) ⇒ Resource, ... Also known as: splice

Splice a list of Resources at a given offset or range

When nil is provided instead of a Resource or a list of Resources this will remove all of the Resources at the specified position.

Parameters:

  • *args (Integer, Array(Integer), Range)

    The offset, offset and limit, or range indicating first and last position. The last argument may be a Resource, a list of Resources or nil.

Returns:

  • (Resource, Enumerable)

    the Resource or list of Resources that was spliced into the Collection

  • (nil)

    If nil was used to delete the entries



448
449
450
451
452
453
454
455
456
457
458
# File 'lib/dm-core/collection.rb', line 448

def []=(*args)
  orphans = Array(superclass_slice(*args[0..-2]))

  # relate new resources
  resources = resources_added(super)

  # mark resources as removed
  resources_removed(orphans - loaded_entries)

  resources
end

#all(query = Undefined) ⇒ Collection

Returns a new Collection optionally scoped by query

This returns a new Collection scoped relative to the current Collection.

cars_from_91 = Cars.all(:year_manufactured => 1991)
toyotas_91 = cars_from_91.all(:manufacturer => 'Toyota')
toyotas_91.all? { |car| car.year_manufactured == 1991 }       #=> true
toyotas_91.all? { |car| car.manufacturer == 'Toyota' }        #=> true

If query is a Hash, results will be found by merging query with this Collection’s query. If query is a Query, results will be found using query as an absolute query.

Parameters:

  • query (Hash, Query) (defaults to: Undefined)

    optional parameters to scope results with

Returns:



212
213
214
215
216
217
218
219
220
# File 'lib/dm-core/collection.rb', line 212

def all(query = Undefined)
  if query.equal?(Undefined) || (query.is_a?(Hash) && query.empty?)
    dup
  else
    # TODO: if there is no order parameter, and the Collection is not loaded
    # check to see if the query can be satisfied by the head/tail
    new_collection(scoped_query(query))
  end
end

#at(offset) ⇒ Resource?

Lookup a Resource from the Collection by offset

Parameters:

  • offset (Integer)

    offset of the Resource in the Collection

Returns:

  • (Resource)

    Resource which matches the supplied offset

  • (nil)

    No Resource matches the supplied offset



345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/dm-core/collection.rb', line 345

def at(offset)
  if loaded? || partially_loaded?(offset)
    super
  elsif offset == 0
    first
  elsif offset > 0
    first(offset: offset)
  elsif offset == -1
    last
  else
    last(offset: offset.abs - 1)
  end
end

#clean?Boolean

Checks if all the resources have no changes to save

Returns:

  • (Boolean)

    true if the resource may not be persisted



943
944
945
# File 'lib/dm-core/collection.rb', line 943

def clean?
  !dirty?
end

#clearself

Removes all Resources from the Collection

This should remove and orphan each Resource from the Collection

Returns:

  • (self)


723
724
725
726
# File 'lib/dm-core/collection.rb', line 723

def clear
  resources_removed(self) if loaded?
  super
end

#collect! {|Resource| ... } ⇒ self Also known as: map!

Invoke the block for each resource and replace it the return value

Yields:

  • (Resource)

    Each resource in the collection

Returns:

  • (self)


518
519
520
# File 'lib/dm-core/collection.rb', line 518

def collect!
  super { |resource| resource_added(yield(resource_removed(resource))) }
end

#concat(resources) ⇒ self

Appends the resources to self

Parameters:

  • resources (Enumerable)

    List of Resources to append to the collection

Returns:

  • (self)


544
545
546
# File 'lib/dm-core/collection.rb', line 544

def concat(resources)
  super(resources_added(resources))
end

#create(attributes = {}) ⇒ Resource

Create a Resource in the Collection

Parameters:

  • attributes (Hash(Symbol => Object)) (defaults to: {})

    attributes to set

Returns:

  • (Resource)

    the newly created Resource instance



787
788
789
# File 'lib/dm-core/collection.rb', line 787

def create(attributes = {})
  _create(attributes)
end

#create!(attributes = {}) ⇒ Resource

Create a Resource in the Collection, bypassing hooks

Parameters:

  • attributes (Hash(Symbol => Object)) (defaults to: {})

    attributes to set

Returns:

  • (Resource)

    the newly created Resource instance



800
801
802
# File 'lib/dm-core/collection.rb', line 800

def create!(attributes = {})
  _create(attributes, false)
end

#delete(resource) ⇒ Resource?

Remove Resource from the Collection

This should remove an included Resource from the Collection and orphan it from the Collection. If the Resource is not within the Collection, it should return nil.

Parameters:

  • resource (Resource)

    the Resource to remove from the Collection

Returns:

  • (Resource)

    If resource is within the Collection

  • (nil)

    If resource is not within the Collection



631
632
633
634
635
# File 'lib/dm-core/collection.rb', line 631

def delete(resource)
  return unless (resource = super)

  resource_removed(resource)
end

#delete_at(offset) ⇒ Resource?

Remove Resource from the Collection by offset

This should remove the Resource from the Collection at a given offset and orphan it from the Collection. If the offset is out of range return nil.

Parameters:

  • offset (Integer)

    the offset of the Resource to remove from the Collection

Returns:

  • (Resource)

    If offset is within the Collection

  • (nil)

    If offset is not within the Collection



652
653
654
655
656
# File 'lib/dm-core/collection.rb', line 652

def delete_at(offset)
  return unless (resource = super)

  resource_removed(resource)
end

#delete_if {|Resource| ... } ⇒ self

Deletes every Resource for which block evaluates to true.

Yields:

  • (Resource)

    Each resource in the Collection

Returns:

  • (self)


665
666
667
# File 'lib/dm-core/collection.rb', line 665

def delete_if
  super { |resource| yield(resource) && resource_removed(resource) }
end

#destroyBoolean

Remove every Resource in the Collection from the repository

This performs a deletion of each Resource in the Collection from the repository and clears the Collection.

Returns:

  • (Boolean)

    true if the resources were successfully destroyed



885
886
887
888
889
890
891
# File 'lib/dm-core/collection.rb', line 885

def destroy
  if (destroyed = all?(&:destroy))
    clear
  end

  destroyed
end

#destroy!Boolean

Remove all Resources from the repository, bypassing validation

This performs a deletion of each Resource in the Collection from the repository and clears the Collection while skipping validation.

Returns:

  • (Boolean)

    true if the resources were successfully destroyed



903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
# File 'lib/dm-core/collection.rb', line 903

def destroy!
  repository = self.repository
  deleted    = repository.delete(self)

  if loaded?
    return false unless deleted == size

    each do |resource|
      resource.persistence_state = Resource::PersistenceState::Immutable.new(resource)
    end

    clear
  else
    mark_loaded
  end

  true
end

#difference(other) ⇒ Collection Also known as: -

Return the difference with another collection

Parameters:

Returns:

  • (Collection)

    the difference of the collection and other



122
123
124
# File 'lib/dm-core/collection.rb', line 122

def difference(other)
  set_operation(:-, other)
end

#dirty?Boolean

Checks if any resources have unsaved changes

Returns:

  • (Boolean)

    true if the resources have unsaved changed



953
954
955
# File 'lib/dm-core/collection.rb', line 953

def dirty?
  loaded_entries.any?(&:dirty?) || @removed.any?
end

#each {|Resource| ... } ⇒ self

Iterate over each Resource

Yields:

  • (Resource)

    Each resource in the collection

Returns:

  • (self)


499
500
501
502
503
504
505
506
507
508
509
# File 'lib/dm-core/collection.rb', line 499

def each
  return to_enum unless block_given?

  super do |resource|
    original = resource.collection
    resource.collection = self
    yield resource
  ensure
    resource.collection = original
  end
end

#first(*args) ⇒ Resource, Collection

Return the first Resource or the first N Resources in the Collection with an optional query

When there are no arguments, return the first Resource in the Collection. When the first argument is an Integer, return a Collection containing the first N Resources. When the last (optional) argument is a Hash scope the results to the query.

Parameters:

  • limit (Integer)

    (optional) limit the returned Collection to a specific number of entries

  • query (Hash)

    (optional) scope the returned Resource or Collection to the supplied query

Returns:

  • (Resource, Collection)

    The first resource in the entries of this collection, or a new collection whose query has been merged



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/dm-core/collection.rb', line 239

def first(*args)
  first_arg = args.first
  last_arg  = args.last

  limit_specified = first_arg.is_a?(Integer)
  with_query      = (last_arg.is_a?(Hash) && !last_arg.empty?) || last_arg.is_a?(Query)

  limit = limit_specified ? first_arg : 1
  query = with_query      ? last_arg  : {}

  query = self.query.slice(0, limit).update(query)

  # TODO: when a query provided, and there are enough elements in head to
  # satisfy the query.limit, filter the head with the query, and make
  # sure it matches the limit exactly.  if so, use that result instead
  # of calling all()
  #   - this can probably only be done if there is no :order parameter

  loaded = loaded?
  head   = self.head

  collection = if !with_query && (loaded || lazy_possible?(head, limit))
                 new_collection(query, super(limit))
               else
                 all(query)
               end

  return collection if limit_specified

  resource = collection.to_a.first

  if with_query || loaded
    resource
  elsif resource
    head[0] = resource
  end
end

#first_or_create(conditions = {}, attributes = {}) ⇒ Resource

Finds the first Resource by conditions, or creates a new Resource with the attributes if none found

Parameters:

  • conditions (Hash) (defaults to: {})

    The conditions to be used to search

  • attributes (Hash) (defaults to: {})

    The attributes to be used to create the resource with if none found

Returns:

  • (Resource)

    The instance found by query, or created with attributes if none found



759
760
761
# File 'lib/dm-core/collection.rb', line 759

def first_or_create(conditions = {}, attributes = {})
  first(conditions) || create(conditions.merge(attributes))
end

#first_or_new(conditions = {}, attributes = {}) ⇒ Resource

Finds the first Resource by conditions, or initializes a new Resource with the attributes if none found

Parameters:

  • conditions (Hash) (defaults to: {})

    The conditions to be used to search

  • attributes (Hash) (defaults to: {})

    The attributes to be used to initialize the resource with if none found

Returns:

  • (Resource)

    The instance found by query, or created with attributes if none found



744
745
746
# File 'lib/dm-core/collection.rb', line 744

def first_or_new(conditions = {}, attributes = {})
  first(conditions) || new(conditions.merge(attributes))
end

#get(*key) ⇒ Resource?

Lookup a Resource in the Collection by key

This looks up a Resource by key, typecasting the key to the proper object if necessary.

toyotas = Cars.all(:manufacturer => 'Toyota')
toyo = Cars.first(:manufacturer => 'Toyota')
toyotas.get(toyo.id) == toyo                  #=> true

Parameters:

  • *key (Enumerable)

    keys which uniquely identify a resource in the Collection

Returns:

  • (Resource)

    Resource which matches the supplied key

  • (nil)

    No Resource matches the supplied key



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/dm-core/collection.rb', line 146

def get(*key)
  assert_valid_key_size(key)

  key   = model_key.typecast(key)
  query = self.query

  @identity_map[key] || if !loaded? && (query.limit || query.offset > 0)
                          # current query is exclusive, find resource within the set

                          # TODO: use a subquery to retrieve the Collection and then match
                          #   it up against the key.  This will require some changes to
                          #   how subqueries are generated, since the key may be a
                          #   composite key.  In the case of DO adapters, it means subselects
                          #   like the form "(a, b) IN(SELECT a, b FROM ...)", which will
                          #   require making it so the Query condition key can be a
                          #   Property or an Array of Property objects

                          # use the brute force approach until subquery lookups work
                          lazy_load
                          @identity_map[key]
                        else
                          # current query is all inclusive, lookup using normal approach
                          first(model.key_conditions(repository, key).update(order: nil))
                        end
end

#get!(*key) ⇒ Resource?

Lookup a Resource in the Collection by key, raising an exception if not found

This looks up a Resource by key, typecasting the key to the proper object if necessary.

Parameters:

  • *key (Enumerable)

    keys which uniquely identify a resource in the Collection

Returns:

  • (Resource)

    Resource which matches the supplied key

  • (nil)

    No Resource matches the supplied key

Raises:



188
189
190
# File 'lib/dm-core/collection.rb', line 188

def get!(*key)
  get(*key) || raise(ObjectNotFoundError, "Could not find #{model.name} with key #{key.inspect}")
end

#hashObject



969
970
971
# File 'lib/dm-core/collection.rb', line 969

def hash
  [self.class, query].hash
end

#insert(offset, *resources) ⇒ self

Inserts the Resources before the Resource at the offset (which may be negative).

Parameters:

  • offset (Integer)

    The offset to insert the Resources before

  • *resources (Enumerable)

    List of Resources to insert

Returns:

  • (self)


588
589
590
# File 'lib/dm-core/collection.rb', line 588

def insert(offset, *resources)
  super(offset, *resources_added(resources))
end

#inspectString

Gets a Human-readable representation of this collection, showing all elements contained in it

Returns:

  • (String)

    Human-readable representation of this collection, showing all elements



964
965
966
# File 'lib/dm-core/collection.rb', line 964

def inspect
  "[#{map(&:inspect).join(', ')}]"
end

#intersection(other) ⇒ Collection Also known as: &

Return the intersection with another collection

Parameters:

Returns:

  • (Collection)

    the intersection of the collection and other



107
108
109
# File 'lib/dm-core/collection.rb', line 107

def intersection(other)
  set_operation(:&, other)
end

#last(*args) ⇒ Resource, Collection

Return the last Resource or the last N Resources in the Collection with an optional query

When there are no arguments, return the last Resource in the Collection. When the first argument is an Integer, return a Collection containing the last N Resources. When the last (optional) argument is a Hash scope the results to the query.

Parameters:

  • limit (Integer)

    (optional) limit the returned Collection to a specific number of entries

  • query (Hash)

    (optional) scope the returned Resource or Collection to the supplied query

Returns:

  • (Resource, Collection)

    The last resource in the entries of this collection, or a new collection whose query has been merged



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/dm-core/collection.rb', line 294

def last(*args)
  first_arg = args.first
  last_arg  = args.last

  limit_specified = first_arg.is_a?(Integer)
  with_query      = (last_arg.is_a?(Hash) && !last_arg.empty?) || last_arg.is_a?(Query)

  limit = limit_specified ? first_arg : 1
  query = with_query      ? last_arg  : {}

  query = self.query.slice(0, limit).update(query).reverse!

  # tell the Query to prepend each result from the adapter
  query.update(add_reversed: !query.add_reversed?)

  # TODO: when a query provided, and there are enough elements in tail to
  # satisfy the query.limit, filter the tail with the query, and make
  # sure it matches the limit exactly.  if so, use that result instead
  # of calling all()

  loaded = loaded?
  tail   = self.tail

  collection = if !with_query && (loaded || lazy_possible?(tail, limit))
                 new_collection(query, super(limit))
               else
                 all(query)
               end

  return collection if limit_specified

  resource = collection.to_a.last

  if with_query || loaded
    resource
  elsif resource
    tail[tail.empty? ? 0 : -1] = resource
  end
end

#loaded_entriesArray<Resource> (protected)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Loaded Resources in the collection

Returns:

  • (Array<Resource>)

    Resources in the collection



989
990
991
# File 'lib/dm-core/collection.rb', line 989

protected def loaded_entries
  (loaded? ? self : head + tail).reject(&:destroyed?)
end

#modelModel

Returns the Model

Returns:

  • (Model)

    the Model the Collection is associated with



44
45
46
# File 'lib/dm-core/collection.rb', line 44

def model
  query.model
end

#model_keyPropertySet (protected)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the model key

Returns:



979
980
981
# File 'lib/dm-core/collection.rb', line 979

protected def model_key
  model.key(repository_name)
end

#new(attributes = {}) ⇒ Resource

Initializes a Resource and appends it to the Collection

Parameters:

  • attributes (Hash) (defaults to: {})

    Attributes with which to initialize the new resource

Returns:

  • (Resource)

    a new Resource initialized with attributes



772
773
774
775
776
# File 'lib/dm-core/collection.rb', line 772

def new(attributes = {})
  resource = repository.scope { model.new(attributes) }
  self << resource
  resource
end

#popResource

Removes and returns the last Resource in the Collection

Returns:

  • (Resource)

    the last Resource in the Collection



598
599
600
601
602
# File 'lib/dm-core/collection.rb', line 598

def pop(*)
  return unless (removed = super)

  resources_removed(removed)
end

#propertiesPropertySet (protected)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the PropertySet representing the fields in the Collection scope

Returns:

  • (PropertySet)

    The set of properties this Collection’s query will retrieve



999
1000
1001
# File 'lib/dm-core/collection.rb', line 999

protected def properties
  model.properties(repository_name)
end

#push(*resources) ⇒ self

Append one or more Resources to the Collection

This should append one or more Resources to the Collection and relate each to the Collection.

Parameters:

  • *resources (Enumerable)

    List of Resources to append

Returns:

  • (self)


559
560
561
# File 'lib/dm-core/collection.rb', line 559

def push(*resources)
  super(*resources_added(resources))
end

#reject! {|Resource| ... } ⇒ Collection?

Deletes every Resource for which block evaluates to true

Yields:

  • (Resource)

    Each resource in the Collection

Returns:

  • (Collection)

    If resources were removed

  • (nil)

    If no resources were removed



679
680
681
# File 'lib/dm-core/collection.rb', line 679

def reject!
  super { |resource| yield(resource) && resource_removed(resource) }
end

#relationshipsHash (protected)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the Relationships for the Collection’s Model

Returns:

  • (Hash)

    The model’s relationships, mapping the name to the Associations::Relationship object



1010
1011
1012
# File 'lib/dm-core/collection.rb', line 1010

protected def relationships
  model.relationships(repository_name)
end

#reload(other_query = Undefined) ⇒ self

Reloads the Collection from the repository

If query is provided, updates this Collection’s query with its conditions

cars_from_91 = Cars.all(:year_manufactured => 1991)
cars_from_91.first.year_manufactured = 2001   # note: not saved
cars_from_91.reload
cars_from_91.first.year                       #=> 1991

Parameters:

  • other_query (Query, Hash) (defaults to: Undefined)

    (optional) further restrict results with query

Returns:

  • (self)


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/dm-core/collection.rb', line 63

def reload(other_query = Undefined)
  query = self.query
  query = other_query.equal?(Undefined) ? query.dup : query.merge(other_query)

  # make sure the Identity Map contains all the existing resources
  identity_map = repository.identity_map(model)

  loaded_entries.each do |resource|
    identity_map[resource.key] = resource
  end

  # sort fields based on declared order, for more consistent reload queries
  properties = self.properties
  fields     = properties & (query.fields | model_key | [properties.discriminator].compact)

  # replace the list of resources
  replace(all(query.update(fields: fields, reload: true)))
end

#replace(other) ⇒ self

Replace the Resources within the Collection

Parameters:

  • other (Enumerable)

    List of other Resources to replace with

Returns:

  • (self)


697
698
699
700
701
# File 'lib/dm-core/collection.rb', line 697

def replace(other)
  other = resources_added(other)
  resources_removed(entries - other)
  super(other)
end

#repositoryRepository

Returns the Repository

Returns:

  • (Repository)

    the Repository this Collection is associated with



34
35
36
# File 'lib/dm-core/collection.rb', line 34

def repository
  query.repository
end

#respond_to?(method, include_private = false) ⇒ Boolean

Check to see if collection can respond to the method

Parameters:

  • method (Symbol)

    method to check in the object

  • include_private (Boolean) (defaults to: false)

    if set to true, collection will check private methods

Returns:

  • (Boolean)

    true if method can be responded to



933
934
935
# File 'lib/dm-core/collection.rb', line 933

def respond_to?(method, include_private = false)
  super || model.respond_to?(method) || relationships.named?(method)
end

#reverseCollection

Return a copy of the Collection sorted in reverse

Returns:

  • (Collection)

    Collection equal to self but ordered in reverse



468
469
470
# File 'lib/dm-core/collection.rb', line 468

def reverse
  dup.reverse!
end

#reverse!self

Return the Collection sorted in reverse

Returns:

  • (self)


477
478
479
480
481
482
483
484
485
486
487
488
489
490
# File 'lib/dm-core/collection.rb', line 477

def reverse!
  query.reverse!

  # reverse without kicking if possible
  if loaded?
    @array.reverse!
  else
    # reverse and swap the head and tail
    @head = tail.reverse!
    @tail = head.reverse!
  end

  self
end

#saveBoolean

Save every Resource in the Collection

Returns:

  • (Boolean)

    true if the resources were successfully saved



862
863
864
# File 'lib/dm-core/collection.rb', line 862

def save
  _save
end

#save!Boolean

Save every Resource in the Collection bypassing validation

Returns:

  • (Boolean)

    true if the resources were successfully saved



872
873
874
# File 'lib/dm-core/collection.rb', line 872

def save!
  _save(false)
end

#set(resources) ⇒ self

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

(Private) Set the Collection

Parameters:

  • resources (Array)

    resources to add to the collection

Returns:

  • (self)


711
712
713
714
# File 'lib/dm-core/collection.rb', line 711

def set(resources)
  superclass_replace(resources_added(resources))
  self
end

#shiftResource

Removes and returns the first Resource in the Collection

Returns:

  • (Resource)

    the first Resource in the Collection



610
611
612
613
614
# File 'lib/dm-core/collection.rb', line 610

def shift(*)
  return unless (removed = super)

  resources_removed(removed)
end

#slice!(*args) ⇒ Resource, ...

Deletes and Returns the Resources given by an offset or a Range

Parameters:

  • *args (Integer, Array(Integer), Range)

    the offset, offset and limit, or range indicating first and last position

Returns:

  • (Resource, Collection)

    The entry which resides at that offset and limit, or a new Collection object with the set limits and offset

  • (Resource, Collection, nil)

    The offset is out of range



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/dm-core/collection.rb', line 416

def slice!(*args)
  removed = super

  resources_removed(removed) unless removed.nil?

  # Workaround for Ruby <= 1.8.6
  compact! if RUBY_VERSION <= '1.8.6'

  return removed unless removed.is_a?(Enumerable)

  offset, limit = extract_slice_arguments(*args)

  query = sliced_query(offset, limit)

  new_collection(query, removed)
end

#union(other) ⇒ Collection Also known as: |, +

Return the union with another collection

Parameters:

Returns:

  • (Collection)

    the union of the collection and other



91
92
93
# File 'lib/dm-core/collection.rb', line 91

def union(other)
  set_operation(:|, other)
end

#unshift(*resources) ⇒ self

Prepend one or more Resources to the Collection

This should prepend one or more Resources to the Collection and relate each to the Collection.

Parameters:

  • *resources (Enumerable)

    The Resources to prepend

Returns:

  • (self)


574
575
576
# File 'lib/dm-core/collection.rb', line 574

def unshift(*resources)
  super(*resources_added(resources))
end

#update(attributes) ⇒ Boolean

Update every Resource in the Collection

Person.all(:age.gte => 21).update(:allow_beer => true)

Parameters:

  • attributes (Hash)

    attributes to update with

Returns:

  • (Boolean)

    true if the resources were successfully updated



815
816
817
818
819
820
# File 'lib/dm-core/collection.rb', line 815

def update(attributes)
  assert_update_clean_only(:update)

  dirty_attributes = model.new(attributes).dirty_attributes
  dirty_attributes.empty? || all? { |resource| resource.update(attributes) }
end

#update!(attributes) ⇒ Boolean

Update every Resource in the Collection bypassing validation

Person.all(:age.gte => 21).update!(:allow_beer => true)

Parameters:

  • attributes (Hash)

    attributes to update

Returns:

  • (Boolean)

    true if the resources were successfully updated



833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
# File 'lib/dm-core/collection.rb', line 833

def update!(attributes)
  assert_update_clean_only(:update!)

  model = self.model

  dirty_attributes = model.new(attributes).dirty_attributes

  unless dirty_attributes.empty?
    dirty_attributes.each do |property, value|
      property.assert_valid_value(value)
    end
    return false unless _update(dirty_attributes)

    if loaded?
      each do |resource|
        dirty_attributes.each { |property, value| property.set!(resource, value) }
        repository.identity_map(model)[resource.key] = resource
      end
    end
  end
  true
end