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



1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
# File 'lib/dm-core/collection.rb', line 1440

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



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

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)


535
536
537
# File 'lib/dm-core/collection.rb', line 535

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 minues 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”



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

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

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

  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



453
454
455
456
457
458
459
460
461
462
463
# File 'lib/dm-core/collection.rb', line 453

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:



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

def all(query = Undefined)
  if query.equal?(Undefined) || (query.kind_of?(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



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

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



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

def clean?
  !dirty?
end

#clearself

Removes all Resources from the Collection

This should remove and orphan each Resource from the Collection

Returns:

  • (self)


726
727
728
729
730
731
# File 'lib/dm-core/collection.rb', line 726

def clear
  if loaded?
    resources_removed(self)
  end
  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)


521
522
523
# File 'lib/dm-core/collection.rb', line 521

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)


547
548
549
# File 'lib/dm-core/collection.rb', line 547

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



792
793
794
# File 'lib/dm-core/collection.rb', line 792

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



805
806
807
# File 'lib/dm-core/collection.rb', line 805

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



634
635
636
637
638
# File 'lib/dm-core/collection.rb', line 634

def delete(resource)
  if resource = super
    resource_removed(resource)
  end
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



655
656
657
658
659
# File 'lib/dm-core/collection.rb', line 655

def delete_at(offset)
  if resource = super
    resource_removed(resource)
  end
end

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

Deletes every Resource for which block evaluates to true.

Yields:

  • (Resource)

    Each resource in the Collection

Returns:

  • (self)


668
669
670
# File 'lib/dm-core/collection.rb', line 668

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



894
895
896
897
898
899
900
# File 'lib/dm-core/collection.rb', line 894

def destroy
  if destroyed = all? { |resource| resource.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



912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
# File 'lib/dm-core/collection.rb', line 912

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

  if loaded?
    unless deleted == size
      return false
    end

    each do |resource|
      resource.persisted_state = Resource::State::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



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

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



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

def dirty?
  loaded_entries.any? { |resource| resource.dirty? } || @removed.any?
end

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

Iterate over each Resource

Yields:

  • (Resource)

    Each resource in the collection

Returns:

  • (self)


503
504
505
506
507
508
509
510
511
512
# File 'lib/dm-core/collection.rb', line 503

def each
  super do |resource|
    begin
      original, resource.collection = resource.collection, self
      yield resource
    ensure
      resource.collection = original
    end
  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



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
276
# File 'lib/dm-core/collection.rb', line 240

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

  limit_specified = first_arg.kind_of?(Integer)
  with_query      = (last_arg.kind_of?(Hash) && !last_arg.empty?) || last_arg.kind_of?(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



764
765
766
# File 'lib/dm-core/collection.rb', line 764

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



749
750
751
# File 'lib/dm-core/collection.rb', line 749

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 looksup 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



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

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 looksup 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:



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

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

#hashObject



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

def hash
  self.class.hash ^ 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)


591
592
593
# File 'lib/dm-core/collection.rb', line 591

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



975
976
977
# File 'lib/dm-core/collection.rb', line 975

def inspect
  "[#{map { |resource| resource.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



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

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



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
333
# File 'lib/dm-core/collection.rb', line 295

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

  limit_specified = first_arg.kind_of?(Integer)
  with_query      = (last_arg.kind_of?(Hash) && !last_arg.empty?) || last_arg.kind_of?(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



1002
1003
1004
# File 'lib/dm-core/collection.rb', line 1002

def loaded_entries
  (loaded? ? self : head + tail).reject { |resource| resource.destroyed? }
end

#modelModel

Returns the Model

Returns:

  • (Model)

    the Model the Collection is associated with



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

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:



992
993
994
# File 'lib/dm-core/collection.rb', line 992

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



777
778
779
780
781
# File 'lib/dm-core/collection.rb', line 777

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



601
602
603
604
605
# File 'lib/dm-core/collection.rb', line 601

def pop(*)
  if removed = super
    resources_removed(removed)
  end
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



1012
1013
1014
# File 'lib/dm-core/collection.rb', line 1012

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)


562
563
564
# File 'lib/dm-core/collection.rb', line 562

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



682
683
684
# File 'lib/dm-core/collection.rb', line 682

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



1023
1024
1025
# File 'lib/dm-core/collection.rb', line 1023

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:

  • query (Query, Hash)

    (optional) further restrict results with query

Returns:

  • (self)


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

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)


700
701
702
703
704
# File 'lib/dm-core/collection.rb', line 700

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



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

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



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

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



473
474
475
# File 'lib/dm-core/collection.rb', line 473

def reverse
  dup.reverse!
end

#reverse!self

Return the Collection sorted in reverse

Returns:

  • (self)


482
483
484
485
486
487
488
489
490
491
492
493
494
# File 'lib/dm-core/collection.rb', line 482

def reverse!
  query.reverse!

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

  self
end

#saveBoolean

Save every Resource in the Collection

Returns:

  • (Boolean)

    true if the resources were successfully saved



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

def save
  _save
end

#save!Boolean

Save every Resource in the Collection bypassing validation

Returns:

  • (Boolean)

    true if the resources were successfully saved



881
882
883
# File 'lib/dm-core/collection.rb', line 881

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)


714
715
716
717
# File 'lib/dm-core/collection.rb', line 714

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



613
614
615
616
617
# File 'lib/dm-core/collection.rb', line 613

def shift(*)
  if removed = super
    resources_removed(removed)
  end
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



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/dm-core/collection.rb', line 419

def slice!(*args)
  removed = super

  resources_removed(removed) unless removed.nil?

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

  unless removed.kind_of?(Enumerable)
    return removed
  end

  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



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

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)


577
578
579
# File 'lib/dm-core/collection.rb', line 577

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



820
821
822
823
824
825
# File 'lib/dm-core/collection.rb', line 820

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



838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
# File 'lib/dm-core/collection.rb', line 838

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

  model = self.model

  dirty_attributes = model.new(attributes).dirty_attributes

  if dirty_attributes.empty?
    true
  elsif dirty_attributes.any? { |property, value| !property.valid?(value) }
    false
  else
    unless _update(dirty_attributes)
      return false
    end

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

    true
  end
end