module CouchRest::WillPaginate::ClassMethods

Public Instance Methods

paginate_all(options = {}) click to toggle source

Generate a Will Paginate collection from all the available documents stored with a matching couchrest-type.

Requires no declaration as the ‘all’ view is built into couchrest Extended Documents.

# File lib/will_paginate_couchrest/class_methods.rb, line 108
def paginate_all(options = {})
  paginated_view(:all, options)
end
paginated_view(view_name, options = {}) click to toggle source

Return a WillPaginate collection suitable for usage

# File lib/will_paginate_couchrest/class_methods.rb, line 115
def paginated_view(view_name, options = {})
  raise "Missing per_page parameter" if options[:per_page].nil?

  options[:page] ||= 1

  ::WillPaginate::Collection.create( options[:page], options[:per_page] ) do |pager|
    # perform view count first (should create designs if missing)
    if view_name.to_sym == :all
      pager.total_entries = count({:database => options[:database]})
    else
      total = view( view_name, options.update(:reduce => true).dup )['rows'].pop
      pager.total_entries = total ? total['value'] : 0
    end
    p_options = options.merge(
      :design_doc => self.to_s,
      :view_name => view_name,
      :include_docs => true
    )
    # Only provide the reduce parameter when necessary. This is when the view has
    # been set with a reduce method and requires the reduce boolean parameter
    # to be either true or false on all requests.
    p_options[:reduce] = false unless view_name.to_sym == :all
    results = paginate(p_options)
    pager.replace( results )
  end
end
paginated_view_by(*keys) click to toggle source

Define a CouchDB will paginate view. The name of the view will be the concatenation of paginate_by and the keys joined by and

Example paginated views:

class Post
  # view with default options
  # query with Post.paginate_by_date
  paginated_view_by :date, :descending => true

  # view with compound sort-keys
  # query with Post.by_user_id_and_date
  paginated_view_by :user_id, :date

  # view with custom map/reduce functions
  # query with Post.by_tags :reduce => true
  paginated_view_by :tags,                                                
    :map =>                                                     
      "function(doc) {                                          
        if (doc['couchrest-type'] == 'Post' && doc.tags) {                   
          doc.tags.forEach(function(tag){                       
            emit(doc.tag, 1);                                   
          });                                                   
        }                                                       
      }",                                                       
    :reduce =>                                                  
      "function(keys, values, rereduce) {                       
        return sum(values);                                     
      }"                                                        
end

paginated_view_by :date will create a view defined by this Javascript function:

function(doc) {
  if (doc['couchrest-type'] == 'Post' && doc.date) {
    emit(doc.date, 1);
  }
}

And a standard summing reduce function like the following:

function(keys, values, rereduce) {                       
  return sum(values);
}

It can be queried by calling Post.paginate_by_date which accepts all valid options for CouchRest::Database#view. In addition, calling with the :raw => true option will return the view rows themselves. By default Post.by_date will return the documents included in the generated view.

For further details on view_by‘s other options, please see the standard documentation.

# File lib/will_paginate_couchrest/class_methods.rb, line 63
      def paginated_view_by(*keys)

        # Prepare the Traditional view
        opts = keys.last.is_a?(Hash) ? keys.pop : {}
        view_name = "by_#{keys.join('_and_')}"
        method_name = "paginate_#{view_name}"

        doc_keys = keys.collect{|k| "doc['#{k}']"}
        key_emit = doc_keys.length == 1 ? "#{doc_keys.first}" : "[#{doc_keys.join(', ')}]"
        guards = opts.delete(:guards) || []
        guards.push("(doc['couchrest-type'] == '#{self.to_s}')")
        guards.concat doc_keys

        opts = {
          :map => "
            function( doc ) {
              if (#{guards.join(' && ')}) {
                emit(#{key_emit}, 1 );
              }
            }
          ",
          :reduce => "
            function(keys, values, rereduce) {                       
              return sum(values);
            }
          "
        }.merge(opts)

        # View prepared, send to traditional view_by
        view_by keys, opts

        instance_eval "          def #{method_name}(options = {})
            paginated_view('#{view_name}', options)
          end
", __FILE__, __LINE__ + 1
      end