public
Description: Implements ActiveRecord::Base.each instance method
Homepage: http://github.com/guillermo/active_record_each/wikis
Clone URL: git://github.com/guillermo/active_record_each.git
active_record_each / lib / active_record_each.rb
100644 83 lines (72 sloc) 2.42 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# ActiveRecordEach
 
class ActiveRecord::Base
  class << self
    # Each goes througt all entries in a model, without loading all
    # You can pass to it any parameter like find. See find for options you can pass
    #
    # ==== Examples:
    #
    # # Goes throught all users wich name starts by g
    # User.each (:conditions => "users.name LIKE 'g%'") do |u|
    # puts u.name
    # end
    #
    def each(*args,&block)
      options = args.extract_options!
      validate_find_options(options)
      set_readonly_option!(options)
 
      # if we're passed order then fast mode MAY not work, so we'll stick
      # with the slow mode
      if options[:order]
        slow_each(options,&block)
      else
        fast_each(options, &block)
      end
    end
    
    def slow_each(options)
      count(options).times do |i|
        yield(find_initial(options.merge({:offset => i})))
      end
    end
 
    # because :offset can be quite slow for large tables as really the DB
    # still has to execute the query and then seek into the query to return
    # you the row you want.
    # using the primary_key allows us to piggy back on the index
    def fast_each(options)
      i=minimum("#{table_name}.#{primary_key}", options)
      
      # not all the backends always sort primay_key columns so do it manuall
      options.update(:order => "#{table_name}.#{primary_key} ASC")
      
      i=minimum("#{table_name}.#{primary_key}", options) or return
      # first the first object by id
      yield(o=find_one(i, {}))
      # as long as we keep finding objects, keep going
      while o
        with_scope(:find => {:conditions => [ "#{table_name}.#{primary_key} > ?", i]} ) do
          if o=find_initial(options)
            i=o.send primary_key
            yield(o)
          end
        end
      end
    end
 
    # Invokes block once for each element of self. Creates a new array containing the values returned by the block
    #
    # ==== Example:
    #
    # #Get password from md5hash
    # clean_password = User.map { |u| magic_recover_password(u.md5) }
    #
    def map(*args)
      options = args.extract_options!
      validate_find_options(options)
      set_readonly_option!(options)
 
      results = Array.new
      each(options) do |i|
        results << yield(i)
      end
      results
    end
 
    # Collect is an alias for map
    alias_method :collect, :map
 
  end
end