193 lines
6 KiB
Ruby
193 lines
6 KiB
Ruby
|
module Elasticsearch
|
||
|
module Model
|
||
|
module Response
|
||
|
|
||
|
# Pagination for search results/records
|
||
|
#
|
||
|
module Pagination
|
||
|
# Allow models to be paginated with the "kaminari" gem [https://github.com/amatsuda/kaminari]
|
||
|
#
|
||
|
module Kaminari
|
||
|
def self.included(base)
|
||
|
# Include the Kaminari configuration and paging method in response
|
||
|
#
|
||
|
base.__send__ :include, ::Kaminari::ConfigurationMethods::ClassMethods
|
||
|
base.__send__ :include, ::Kaminari::PageScopeMethods
|
||
|
|
||
|
# Include the Kaminari paging methods in results and records
|
||
|
#
|
||
|
Elasticsearch::Model::Response::Results.__send__ :include, ::Kaminari::ConfigurationMethods::ClassMethods
|
||
|
Elasticsearch::Model::Response::Results.__send__ :include, ::Kaminari::PageScopeMethods
|
||
|
Elasticsearch::Model::Response::Records.__send__ :include, ::Kaminari::PageScopeMethods
|
||
|
|
||
|
Elasticsearch::Model::Response::Results.__send__ :delegate, :limit_value, :offset_value, :total_count, :max_pages, to: :response
|
||
|
Elasticsearch::Model::Response::Records.__send__ :delegate, :limit_value, :offset_value, :total_count, :max_pages, to: :response
|
||
|
|
||
|
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||
|
# Define the `page` Kaminari method
|
||
|
#
|
||
|
def #{::Kaminari.config.page_method_name}(num=nil)
|
||
|
@results = nil
|
||
|
@records = nil
|
||
|
@response = nil
|
||
|
@page = [num.to_i, 1].max
|
||
|
@per_page ||= __default_per_page
|
||
|
|
||
|
self.search.definition.update size: @per_page,
|
||
|
from: @per_page * (@page - 1)
|
||
|
|
||
|
self
|
||
|
end
|
||
|
RUBY
|
||
|
end
|
||
|
|
||
|
# Returns the current "limit" (`size`) value
|
||
|
#
|
||
|
def limit_value
|
||
|
case
|
||
|
when search.definition[:size]
|
||
|
search.definition[:size]
|
||
|
else
|
||
|
__default_per_page
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Returns the current "offset" (`from`) value
|
||
|
#
|
||
|
def offset_value
|
||
|
case
|
||
|
when search.definition[:from]
|
||
|
search.definition[:from]
|
||
|
else
|
||
|
0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Set the "limit" (`size`) value
|
||
|
#
|
||
|
def limit(value)
|
||
|
return self if value.to_i <= 0
|
||
|
@results = nil
|
||
|
@records = nil
|
||
|
@response = nil
|
||
|
@per_page = value.to_i
|
||
|
|
||
|
search.definition.update :size => @per_page
|
||
|
search.definition.update :from => @per_page * (@page - 1) if @page
|
||
|
self
|
||
|
end
|
||
|
|
||
|
# Set the "offset" (`from`) value
|
||
|
#
|
||
|
def offset(value)
|
||
|
return self if value.to_i < 0
|
||
|
@results = nil
|
||
|
@records = nil
|
||
|
@response = nil
|
||
|
@page = nil
|
||
|
search.definition.update :from => value.to_i
|
||
|
self
|
||
|
end
|
||
|
|
||
|
# Returns the total number of results
|
||
|
#
|
||
|
def total_count
|
||
|
results.total
|
||
|
end
|
||
|
|
||
|
# Returns the models's `per_page` value or the default
|
||
|
#
|
||
|
# @api private
|
||
|
#
|
||
|
def __default_per_page
|
||
|
klass.respond_to?(:default_per_page) && klass.default_per_page || ::Kaminari.config.default_per_page
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Allow models to be paginated with the "will_paginate" gem [https://github.com/mislav/will_paginate]
|
||
|
#
|
||
|
module WillPaginate
|
||
|
def self.included(base)
|
||
|
base.__send__ :include, ::WillPaginate::CollectionMethods
|
||
|
|
||
|
# Include the paging methods in results and records
|
||
|
#
|
||
|
methods = [:current_page, :offset, :length, :per_page, :total_entries, :total_pages, :previous_page, :next_page, :out_of_bounds?]
|
||
|
Elasticsearch::Model::Response::Results.__send__ :delegate, *methods, to: :response
|
||
|
Elasticsearch::Model::Response::Records.__send__ :delegate, *methods, to: :response
|
||
|
end
|
||
|
|
||
|
def offset
|
||
|
(current_page - 1) * per_page
|
||
|
end
|
||
|
|
||
|
def length
|
||
|
search.definition[:size]
|
||
|
end
|
||
|
|
||
|
# Main pagination method
|
||
|
#
|
||
|
# @example
|
||
|
#
|
||
|
# Article.search('foo').paginate(page: 1, per_page: 30)
|
||
|
#
|
||
|
def paginate(options)
|
||
|
param_name = options[:param_name] || :page
|
||
|
page = [options[param_name].to_i, 1].max
|
||
|
per_page = (options[:per_page] || __default_per_page).to_i
|
||
|
|
||
|
search.definition.update size: per_page,
|
||
|
from: (page - 1) * per_page
|
||
|
self
|
||
|
end
|
||
|
|
||
|
# Return the current page
|
||
|
#
|
||
|
def current_page
|
||
|
search.definition[:from] / per_page + 1 if search.definition[:from] && per_page
|
||
|
end
|
||
|
|
||
|
# Pagination method
|
||
|
#
|
||
|
# @example
|
||
|
#
|
||
|
# Article.search('foo').page(2)
|
||
|
#
|
||
|
def page(num)
|
||
|
paginate(page: num, per_page: per_page) # shorthand
|
||
|
end
|
||
|
|
||
|
# Return or set the "size" value
|
||
|
#
|
||
|
# @example
|
||
|
#
|
||
|
# Article.search('foo').per_page(15).page(2)
|
||
|
#
|
||
|
def per_page(num = nil)
|
||
|
if num.nil?
|
||
|
search.definition[:size]
|
||
|
else
|
||
|
paginate(page: current_page, per_page: num) # shorthand
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Returns the total number of results
|
||
|
#
|
||
|
def total_entries
|
||
|
results.total
|
||
|
end
|
||
|
|
||
|
# Returns the models's `per_page` value or the default
|
||
|
#
|
||
|
# @api private
|
||
|
#
|
||
|
def __default_per_page
|
||
|
klass.respond_to?(:per_page) && klass.per_page || ::WillPaginate.per_page
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
end
|