module RailsConnector
# Provides an enumerator, to iterate over obj search results and return "real" objs.
# This is done using the {http://ruby-doc.org/core-1.8.7/Enumerable.html Enumerable
mixin}, which provided methods like map
, select
or take
.
#
# This enumerator is lazy. Let's say, that when looking for Objs with the ObjClass Publication there are 123 objs in total. Now enum.take(10)
will only fetch the first 10 objs, leaving the other 113 objs untouched.
# This also means, that iterating multiple times over this enumerator, each time the search results and objs are fetched again. If you want to get all objs at once, use enum.to_a
.
#
# For all possible query
's and options
have a look at the cms api documentation about objs/search.
# There is one exception: To adjust how many search results should be fetch with one chunk, use the option :batch_size
. The default is 10
. The :size
option will be silently ignored.
#
# @example All objs, which are Publications
# enum = ObjSearchEnumerator([{:field => '_obj_class', :operator => 'equal', :value => 'Publication'}])
# enum.each { |obj| puts obj.path }
class ObjSearchEnumerator
include Enumerable
attr_reader :query
attr_reader :options
# @param [Array] query
# @param [Hash] options
def initialize(query, options = {})
@query = query
@query.freeze
options.delete(:size)
options.delete('size')
if batch_size = options.delete(:batch_size)
options[:size] = batch_size
end
@options = options
@options.freeze
end
def each
offset = 0
current_batch, total = fetch_next_batch(offset)
loop do
if current_batch.size == 0
if offset < total
current_batch, total = fetch_next_batch(offset)
else
raise StopIteration
end
end
offset += 1
hit = current_batch.shift
yield Obj.find(hit['id'])
end
end
# The total size of all results.
# @return [Integer]
def size
if @size.blank?
@size = CmsRestApi.get(resource_path, {:query => query, :size => 1})['total'].to_i
end
@size
end
alias_method :length, :size
private
def fetch_next_batch(offset)
request_result = CmsRestApi.get(resource_path, search_dsl(offset))
[request_result['results'], request_result['total'].to_i]
end
def resource_path
"revisions/#{Workspace.current.revision_id}/objs/search"
end
def search_dsl(offset)
options.merge({
:offset => offset,
:query => query,
})
end
end
end