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



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

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)


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

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



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

def clean?
  !dirty?
end

#clearself

Removes all Resources from the Collection

This should remove and orphan each Resource from the Collection

Returns:

  • (self)


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

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)


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

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)


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

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



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

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



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

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



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

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



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

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)


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

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



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

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



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

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

  if loaded?
    unless deleted == size
      return false
    end

    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



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



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

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

def each
  return to_enum unless block_given?
  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



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

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



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

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



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

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)


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

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



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

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



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

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:



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

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



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

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



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

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



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

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)


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

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



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

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



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

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)


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

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



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

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



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

def save
  _save
end

#save!Boolean

Save every Resource in the Collection bypassing validation

Returns:

  • (Boolean)

    true if the resources were successfully saved



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

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)


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

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



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

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)


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

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



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

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



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

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