v3: add pagination
This commit is contained in:
parent
ac522d6fdd
commit
b3f47d3856
|
@ -2,6 +2,10 @@ require 'travis/api/v3/access_control/generic'
|
||||||
|
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class AccessControl::Anonymous < AccessControl::Generic
|
class AccessControl::Anonymous < AccessControl::Generic
|
||||||
|
def self.new
|
||||||
|
@instace ||= super
|
||||||
|
end
|
||||||
|
|
||||||
# use when Authorization header is not set
|
# use when Authorization header is not set
|
||||||
auth_type(nil)
|
auth_type(nil)
|
||||||
|
|
||||||
|
|
42
lib/travis/api/v3/paginator.rb
Normal file
42
lib/travis/api/v3/paginator.rb
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Paginator
|
||||||
|
attr_accessor :default_limit, :max_limit
|
||||||
|
|
||||||
|
def initialize(default_limit: 25, max_limit: 100)
|
||||||
|
@default_limit = default_limit
|
||||||
|
@max_limit = max_limit
|
||||||
|
end
|
||||||
|
|
||||||
|
def paginate(result, limit: nil, offset: nil, access_control: AccessControl::Anonymous.new)
|
||||||
|
limit &&= Integer(limit, :limit)
|
||||||
|
limit ||= default_limit
|
||||||
|
limit = default_limit if limit < 0
|
||||||
|
|
||||||
|
unless access_control.full_access?
|
||||||
|
limit = max_limit if limit > max_limit or limit < 1
|
||||||
|
end
|
||||||
|
|
||||||
|
offset &&= Integer(offset, :offset)
|
||||||
|
offset = 0 if offset.nil? or offset < 0
|
||||||
|
|
||||||
|
count = result.resource ? result.resource.count : 0
|
||||||
|
result.resource &&= result.resource.limit(limit) unless limit == 0
|
||||||
|
result.resource &&= result.resource.offset(offset) unless offset == 0
|
||||||
|
|
||||||
|
pagination_info = {
|
||||||
|
limit: limit,
|
||||||
|
offset: offset,
|
||||||
|
count: count,
|
||||||
|
}
|
||||||
|
|
||||||
|
result.meta_data[:pagination] = pagination_info
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def Integer(value, key)
|
||||||
|
super(value)
|
||||||
|
rescue ArgumentError
|
||||||
|
raise WrongParams, "#{key} must be an integer"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
95
lib/travis/api/v3/paginator/url_generator.rb
Normal file
95
lib/travis/api/v3/paginator/url_generator.rb
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
require "addressable/uri"
|
||||||
|
|
||||||
|
module Travis::API::V3
|
||||||
|
class Paginator
|
||||||
|
class URLGenerator
|
||||||
|
class FancyParser
|
||||||
|
def initialize(href)
|
||||||
|
@uri = Addressable::URI.parse(href)
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate(offset, limit)
|
||||||
|
uri = @uri.dup
|
||||||
|
uri.query_values = uri.query_values.merge("offset".freeze => offset, "limit".freeze => limit)
|
||||||
|
uri.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FastParser
|
||||||
|
PATTERN = /\?(?:&?(?:limit|offset)=[^=]*)*\Z/
|
||||||
|
|
||||||
|
def self.can_handle?(href)
|
||||||
|
return true unless href.include? ??.freeze
|
||||||
|
href =~ PATTERN
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(href)
|
||||||
|
@path_info = href.split(??.freeze, 2).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate(offset, limit)
|
||||||
|
"#{@path_info}?limit=#{limit}&offset=#{offset}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(href, limit: 0, offset: 0, count: 0, **)
|
||||||
|
@parser = FastParser.can_handle?(href) ? FastParser.new(href) : FancyParser.new(href)
|
||||||
|
@href = href
|
||||||
|
@limit = limit
|
||||||
|
@offset = offset
|
||||||
|
@count = count
|
||||||
|
end
|
||||||
|
|
||||||
|
def last?
|
||||||
|
@count <= @offset + @limit
|
||||||
|
end
|
||||||
|
|
||||||
|
def first?
|
||||||
|
@offset == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_info
|
||||||
|
info(offset: @offset + @limit) unless last?
|
||||||
|
end
|
||||||
|
|
||||||
|
def previous_info
|
||||||
|
return if @offset == 0
|
||||||
|
@offset <= @limit ? info(offset: 0, limit: @offset) : info(offset: @offset - @limit, limit: @limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
def first_info
|
||||||
|
info(offset: 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def last_info
|
||||||
|
offset = @count / @limit * @limit
|
||||||
|
offset -= @limit if offset == @count
|
||||||
|
info(offset: offset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def info(offset: @offset, limit: @limit)
|
||||||
|
{
|
||||||
|
:@href => uri_with(offset, limit),
|
||||||
|
:offset => offset,
|
||||||
|
:limit => limit
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_h
|
||||||
|
{
|
||||||
|
is_first: first?,
|
||||||
|
is_last: last?,
|
||||||
|
next: next_info,
|
||||||
|
prev: previous_info,
|
||||||
|
first: first_info,
|
||||||
|
last: last_info
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def uri_with(offset, limit)
|
||||||
|
return @href if offset == @offset and limit == @limit
|
||||||
|
@parser.generate(offset, limit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,19 +17,34 @@ module Travis::API::V3
|
||||||
available_attributes << value
|
available_attributes << value
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(list, href: nil, included: [], **options)
|
attr_reader :href, :options, :list, :included, :meta_data
|
||||||
|
|
||||||
|
def initialize(list, href: nil, included: [], meta_data: {}, **options)
|
||||||
@href = href
|
@href = href
|
||||||
@options = options
|
@options = options
|
||||||
@list = list
|
@list = list
|
||||||
@included = included
|
@included = included
|
||||||
|
@meta_data = meta_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def fields
|
||||||
|
fields = { :"@type" => type }
|
||||||
|
fields[:@href] = href if href
|
||||||
|
fields[:pagination] = pagination_info if meta_data.include? :pagination
|
||||||
|
fields
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_info
|
||||||
|
return meta_data[:@pagination] unless href
|
||||||
|
generator = V3::Paginator::URLGenerator.new(href, **meta_data[:pagination])
|
||||||
|
meta_data[:pagination].merge generator.to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
def render
|
def render
|
||||||
result = { :"@type" => type }
|
result = fields
|
||||||
result[:@href] = @href if @href
|
included = self.included.dup
|
||||||
included = @included.dup
|
result[collection_key] = list.map do |entry|
|
||||||
result[collection_key] = @list.map do |entry|
|
rendered = render_entry(entry, included: included, mode: :standard, **options)
|
||||||
rendered = render_entry(entry, included: included, mode: :standard, **@options)
|
|
||||||
included << entry
|
included << entry
|
||||||
rendered
|
rendered
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Result
|
class Result
|
||||||
attr_accessor :access_control, :type, :resource, :status, :href
|
attr_accessor :access_control, :type, :resource, :status, :href, :meta_data
|
||||||
|
|
||||||
def initialize(access_control, type, resource = [], status: 200)
|
def initialize(access_control, type, resource = [], status: 200, **meta_data)
|
||||||
@access_control, @type, @resource, @status = access_control, type, resource, status
|
@access_control, @type, @resource, @status, @meta_data = access_control, type, resource, status, meta_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def respond_to_missing?(method, *)
|
def respond_to_missing?(method, *)
|
||||||
|
@ -19,7 +19,12 @@ module Travis::API::V3
|
||||||
href = self.href
|
href = self.href
|
||||||
href = V3.location(env) if href.nil? and env['REQUEST_METHOD'.freeze] == 'GET'.freeze
|
href = V3.location(env) if href.nil? and env['REQUEST_METHOD'.freeze] == 'GET'.freeze
|
||||||
include = params['include'.freeze].to_s.split(?,.freeze)
|
include = params['include'.freeze].to_s.split(?,.freeze)
|
||||||
Renderer[type].render(resource, href: href, script_name: env['SCRIPT_NAME'.freeze], include: include, access_control: access_control)
|
Renderer[type].render(resource,
|
||||||
|
href: href,
|
||||||
|
script_name: env['SCRIPT_NAME'.freeze],
|
||||||
|
include: include,
|
||||||
|
access_control: access_control,
|
||||||
|
meta_data: meta_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def method_missing(method, *args)
|
def method_missing(method, *args)
|
||||||
|
|
|
@ -24,6 +24,19 @@ module Travis::API::V3
|
||||||
@params
|
@params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.paginate(**options)
|
||||||
|
params("limit".freeze, "offset".freeze)
|
||||||
|
@paginator = Paginator.new(**options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.paginator
|
||||||
|
@paginator ||= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.paginate?
|
||||||
|
!!@paginator if defined? @paginator
|
||||||
|
end
|
||||||
|
|
||||||
attr_accessor :access_control, :params
|
attr_accessor :access_control, :params
|
||||||
|
|
||||||
def initialize(access_control, params)
|
def initialize(access_control, params)
|
||||||
|
@ -68,7 +81,15 @@ module Travis::API::V3
|
||||||
def run
|
def run
|
||||||
not_found unless result = run!
|
not_found unless result = run!
|
||||||
result = result(result_type, result) unless result.is_a? Result
|
result = result(result_type, result) unless result.is_a? Result
|
||||||
result
|
self.class.paginate? ? paginate(result) : result
|
||||||
|
end
|
||||||
|
|
||||||
|
def paginate(result)
|
||||||
|
p params
|
||||||
|
self.class.paginator.paginate(result,
|
||||||
|
limit: params['limit'.freeze],
|
||||||
|
offset: params['offset'.freeze],
|
||||||
|
access_control: access_control)
|
||||||
end
|
end
|
||||||
|
|
||||||
def params_for?(prefix)
|
def params_for?(prefix)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Services::Builds::Find < Service
|
class Services::Builds::Find < Service
|
||||||
|
paginate
|
||||||
|
|
||||||
def run!
|
def run!
|
||||||
query.find(find(:repository))
|
query.find(find(:repository))
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user