def _Dynamic_ListDocuments(self, request, response):
    """A local implementation of SearchService.ListDocuments RPC.

    Args:
      request: A search_service_pb.ListDocumentsRequest.
      response: An search_service_pb.ListDocumentsResponse.
    """
    params = request.params()
    index = self._GetIndex(params.index_spec())
    if index is None:
      response.mutable_status().set_code(
          search_service_pb.SearchServiceError.OK)
      return

    num_docs = 0
    start = not params.has_start_doc_id()
    for document in sorted(index.Documents(), key=lambda doc: doc.id()):
      if start:
        if num_docs < params.limit():
          self._AddDocument(response, document, params.keys_only())
          num_docs += 1
      else:
        if document.id() >= params.start_doc_id():
          start = True
          if (document.id() != params.start_doc_id() or
              params.include_start_doc()):
            self._AddDocument(response, document, params.keys_only())
            num_docs += 1

    response.mutable_status().set_code(
        search_service_pb.SearchServiceError.OK)
  def _Dynamic_DeleteSchema(self, request, response):
    """A local implementation of SearchService.DeleteSchema RPC.

    Args:
      request: A search_service_pb.DeleteSchemaRequest.
      response: An search_service_pb.DeleteSchemaResponse.
    """

    params = request.params()
    for index_spec in params.index_spec_list():
      response.add_status().set_code(search_service_pb.SearchServiceError.OK)
  def _Dynamic_IndexDocument(self, request, response):
    """A local implementation of SearchService.IndexDocument RPC.

    Index a new document or update an existing document.

    Args:
      request: A search_service_pb.IndexDocumentRequest.
      response: An search_service_pb.IndexDocumentResponse.
    """
    params = request.params()
    index = self._GetIndex(params.index_spec(), create=True)
    index.IndexDocuments(params.document_list(), response)
  def _Dynamic_DeleteDocument(self, request, response):
    """A local implementation of SearchService.DeleteDocument RPC.

    Args:
      request: A search_service_pb.DeleteDocumentRequest.
      response: An search_service_pb.DeleteDocumentResponse.
    """
    params = request.params()
    index_spec = params.index_spec()
    index = self._GetIndex(index_spec)
    for document_id in params.doc_id_list():
      delete_status = response.add_status()
      if index is None:
        delete_status.set_code(search_service_pb.SearchServiceError.OK)
        delete_status.set_error_detail('Not found')
      else:
        index.DeleteDocument(document_id, delete_status)
  def _Dynamic_Search(self, request, response):
    """A local implementation of SearchService.Search RPC.

    Args:
      request: A search_service_pb.SearchRequest.
      response: An search_service_pb.SearchResponse.
    """
    if request.has_app_id():
      self._RandomSearchResponse(request, response)
      return

    index = self._GetIndex(request.params().index_spec())
    if index is None:
      self._UnknownIndex(response.mutable_status(),
                         request.params().index_spec())
      response.set_matched_count(0)
      return

    params = request.params()
    try:
      results = index.Search(params)
    except query_parser.QueryException as e:
      self._InvalidRequest(response.mutable_status(), e)
      response.set_matched_count(0)
      return
    except expression_evaluator.ExpressionEvaluationError as e:
      self._InvalidRequest(response.mutable_status(), e)
      response.set_matched_count(0)
      return
    except document_matcher.ExpressionTreeException as e:
      self._InvalidRequest(response.mutable_status(), e)
      response.set_matched_count(0)
      return

    facet_analyzer = simple_facet.SimpleFacet(params)
    results = facet_analyzer.RefineResults(results)
    response.set_matched_count(len(results))
    offset = 0
    if params.has_cursor():
      try:
        doc_id = self._DecodeCursor(params.cursor())
      except _InvalidCursorException as e:
        self._InvalidRequest(response.mutable_status(), e)
        response.set_matched_count(0)
        return
      for i, result in enumerate(results):
        if result.document.id() == doc_id:
          offset = i + 1
          break
    elif params.has_offset():
      offset = params.offset()



    if offset < len(results):


      limit = offset + params.limit()
      if limit >= len(results):


        range_end = len(results)
      else:



        range_end = limit
        if params.cursor_type() == search_service_pb.SearchParams.SINGLE:
          document = results[range_end - 1].document
          response.set_cursor(self._EncodeCursor(document))
      result_range = list(range(offset, range_end))
    else:
      result_range = list(range(0))
    field_names = params.field_spec().name_list()
    self._FillSearchResponse(results, result_range, params.cursor_type(),
                             _ScoreRequested(params), response, field_names,
                             params.keys_only())
    facet_analyzer.FillFacetResponse(results, response)

    response.mutable_status().set_code(search_service_pb.SearchServiceError.OK)
  def _RandomSearchResponse(self, request, response):

    random.seed()
    if random.random() < 0.03:
      raise apiproxy_errors.ResponseTooLargeError()
    response.mutable_status().set_code(
        random.choice([search_service_pb.SearchServiceError.OK] * 30 +
                      [search_service_pb.SearchServiceError.TRANSIENT_ERROR] +
                      [search_service_pb.SearchServiceError.INTERNAL_ERROR]))

    params = request.params()
    random.seed(params.query())
    total = random.randint(0, 100)


    if random.random() < 0.3:
      total = 0

    offset = 0
    if params.has_offset():
      offset = params.offset()

    remaining = max(0, total - offset)
    nresults = min(remaining, params.limit())
    matched_count = offset + nresults
    if remaining > nresults:
      matched_count += random.randint(1, 100)

    def RandomText(charset, min_len, max_len):
      return ''.join(random.choice(charset)
                     for _ in range(random.randint(min_len, max_len)))

    for i in range(nresults):
      seed = '%s:%s' % (params.query(), i + offset)
      random.seed(seed)
      result = response.add_result()
      doc = result.mutable_document()
      doc_id = RandomText(string.letters + string.digits, 8, 10)
      doc.set_id(doc_id)
      random.seed(doc_id)
      for _ in params.sort_spec_list():
        result.add_score(random.random())

      for name, probability in [('creator', 0.90), ('last_change', 0.40)]:
        if random.random() < probability:
          field = doc.add_field()
          field.set_name(name)
          value = field.mutable_value()
          value.set_type(document_pb.FieldValue.TEXT)
          value.set_string_value(
              RandomText(string.letters + string.digits, 2, 10)
              + '@google.com')

      field = doc.add_field()
      field.set_name('content')
      value = field.mutable_value()
      value.set_type(document_pb.FieldValue.TEXT)
      value.set_string_value(
          RandomText(string.printable, 0, 15) + params.query() +
          RandomText(string.printable + 10 * string.whitespace, 5, 5000))

      for i in range(random.randint(0, 2)):
        field = doc.add_field()
        field.set_name(RandomText(string.letters, 3, 7))
        value = field.mutable_value()
        value.set_type(document_pb.FieldValue.TEXT)
        value.set_string_value(RandomText(string.printable, 0, 100))

    response.set_matched_count(matched_count)
  def _Dynamic_ListIndexes(self, request, response):
    """A local implementation of SearchService.ListIndexes RPC.

    Args:
      request: A search_service_pb.ListIndexesRequest.
      response: An search_service_pb.ListIndexesResponse.

    Raises:
      ResponseTooLargeError: raised for testing admin console.
    """



    if request.has_app_id():
      if random.choice([True] + [False] * 9):
        raise apiproxy_errors.ResponseTooLargeError()

      for _ in range(random.randint(0, 2) * random.randint(5, 15)):
        new_index_spec = response.add_index_metadata().mutable_index_spec()
        new_index_spec.set_name(
            random.choice(list(_VISIBLE_PRINTABLE_ASCII - set('!'))) +
            ''.join(random.choice(list(_VISIBLE_PRINTABLE_ASCII))
                    for _ in range(random.randint(
                        0, search.MAXIMUM_INDEX_NAME_LENGTH))))
      response.mutable_status().set_code(
          random.choice([search_service_pb.SearchServiceError.OK] * 10 +
                        [search_service_pb.SearchServiceError.TRANSIENT_ERROR] +
                        [search_service_pb.SearchServiceError.INTERNAL_ERROR]))
      return

    response.mutable_status().set_code(
        search_service_pb.SearchServiceError.OK)

    namespace = self._GetNamespace(request.params().namespace())
    if namespace not in self.__indexes or not self.__indexes[namespace]:
      return

    keys, indexes = list(zip(*sorted(
        iter(self.__indexes[namespace].items()), key=lambda v: v[0])))
    position = 0
    params = request.params()
    if params.has_start_index_name():
      position = bisect.bisect_left(keys, params.start_index_name())
      if (not params.include_start_index() and position < len(keys)
          and keys[position] == params.start_index_name()):
        position += 1
    elif params.has_index_name_prefix():
      position = bisect.bisect_left(keys, params.index_name_prefix())
    if params.has_offset():
      position += params.offset()
    end_position = position + params.limit()
    prefix = params.index_name_prefix()
    for index in indexes[min(position, len(keys)):min(end_position, len(keys))]:
      index_spec = index.index_spec
      if prefix and not index_spec.name().startswith(prefix):
        break
      metadata = response.add_index_metadata()
      new_index_spec = metadata.mutable_index_spec()
      new_index_spec.set_name(index_spec.name())
      new_index_spec.set_namespace(index_spec.namespace())
      if params.fetch_schema():
        self._AddSchemaInformation(index, metadata)
      self._AddStorageInformation(index, metadata)