module Scrivito module Backend module ObjQuery def self.query(revision, index, keys) cache = Backend::ObjDataCache.view_for_revision(revision) missing_keys = [] ids_from_cache = keys.map do |key| result = if key == nil # querys for `nil` are not supported since they kill performance. # return empty list without asking the backend. [] else cache.read_index(index.id, key, &index.method(:update)) end missing_keys << key unless result result end if missing_keys.blank? return load_nested_ids(revision, ids_from_cache) end backend_ids, tentative = revision.obj_search_request(index.query(missing_keys)) all_obj_datas = load_nested_ids(revision, ids_from_cache + [backend_ids]) cache_obj_datas = all_obj_datas[0..-2] backend_obj_datas = all_obj_datas.last grouped_backend_results = index.group_by(missing_keys, backend_obj_datas) grouped_backend_results.each_with_index do |result, i| ids = result.map { |obj_data| obj_data.value_of("_id") } cache.write_index(index.id, missing_keys[i], ids, persistent: !tentative) end cache_obj_datas.map do |obj_datas| obj_datas || grouped_backend_results.shift end end # nested_ids is a list containing elements that are either lists of ids or nil # returns a corresponding list # containing elements that are either lists of obj_datas or nil private_class_method def self.load_nested_ids(revision, nested_ids) all_ids = nested_ids.inject([]) do |list, ids| ids ? list + ids : list end all_obj_datas = Backend::ObjLoad.load(revision, all_ids) nested_ids.map do |ids| # use 'compact' to filter out any objs that are still referenced by id # in the cache, but have been deleted in the backend concurrently. all_obj_datas.shift(ids.length).compact if ids end end end end end