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
|
||||
class AccessControl::Anonymous < AccessControl::Generic
|
||||
def self.new
|
||||
@instace ||= super
|
||||
end
|
||||
|
||||
# use when Authorization header is not set
|
||||
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
|
||||
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
|
||||
@options = options
|
||||
@list = list
|
||||
@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
|
||||
|
||||
def render
|
||||
result = { :"@type" => type }
|
||||
result[:@href] = @href if @href
|
||||
included = @included.dup
|
||||
result[collection_key] = @list.map do |entry|
|
||||
rendered = render_entry(entry, included: included, mode: :standard, **@options)
|
||||
result = fields
|
||||
included = self.included.dup
|
||||
result[collection_key] = list.map do |entry|
|
||||
rendered = render_entry(entry, included: included, mode: :standard, **options)
|
||||
included << entry
|
||||
rendered
|
||||
end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
module Travis::API::V3
|
||||
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)
|
||||
@access_control, @type, @resource, @status = access_control, type, resource, status
|
||||
def initialize(access_control, type, resource = [], status: 200, **meta_data)
|
||||
@access_control, @type, @resource, @status, @meta_data = access_control, type, resource, status, meta_data
|
||||
end
|
||||
|
||||
def respond_to_missing?(method, *)
|
||||
|
@ -19,7 +19,12 @@ module Travis::API::V3
|
|||
href = self.href
|
||||
href = V3.location(env) if href.nil? and env['REQUEST_METHOD'.freeze] == 'GET'.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
|
||||
|
||||
def method_missing(method, *args)
|
||||
|
|
|
@ -24,6 +24,19 @@ module Travis::API::V3
|
|||
@params
|
||||
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
|
||||
|
||||
def initialize(access_control, params)
|
||||
|
@ -68,7 +81,15 @@ module Travis::API::V3
|
|||
def run
|
||||
not_found unless result = run!
|
||||
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
|
||||
|
||||
def params_for?(prefix)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
module Travis::API::V3
|
||||
class Services::Builds::Find < Service
|
||||
paginate
|
||||
|
||||
def run!
|
||||
query.find(find(:repository))
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user