The core function of the package. These are the arguments we consider.


    Args:
        search_string (str): This is what you are looking for in your pony database.
    Optional Args:
        opt: The following opts are available for the search function:
        * add_wildcars(bool): This opt allows you to search no literal queries.
        * fields: This opt let you filter your search result on some model by the fields you want to search.
        * include_entity: This opt let you see not only the result and the register fields but all the instance from the entity of the database.
        * except_fields: Tell the searcher to not look on these fields.
        * use_dict: This option let you activate the dict for the items in the search result, or just view them as a list.
        We implement this because we wanted that the  first field registered of the model would be the most important one.
        As was explained in the IndexView section.
    Returns:
        (dict): A python dictionary with the results for the model.

def search(self, search_string, **opt):
    """The core function of the package. These are the arguments we consider.


    Args:
        search_string (str): This is what you are looking for in your pony database.
    Optional Args:
        opt: The following opts are available for the search function:
        * add_wildcars(bool): This opt allows you to search no literal queries.
        * fields: This opt let you filter your search result on some model by the fields you want to search.
        * include_entity: This opt let you see not only the result and the register fields but all the instance from the entity of the database.
        * except_fields: Tell the searcher to not look on these fields.
        * use_dict: This option let you activate the dict for the items in the search result, or just view them as a list.
        We implement this because we wanted that the  first field registered of the model would be the most important one.
        As was explained in the IndexView section.
    Returns:
        (dict): A python dictionary with the results for the model.
    """

    prepped_string = self.prep_search_string(
        search_string
      , self.to_bool(opt.get('add_wildcards', False))
      )

    with self._whoosh.searcher() as searcher:
      fields = opt.get('fields', self._schema.names())
      fields = [x for x in fields if len(x) > 0]

      field = opt.get('field', '')
      if len(field) > 0:
        if isinstance(field, str) or isinstance(field, str):
          fields = [field]
        elif isinstance(field, list):
          fields = fields + field

      fields = [x for x in fields if len(x) > 0]

      if len(fields) == 0:
        fields = self._schema.names()

      if len(fields) > 0:
        fields = set(fields) & set(self._schema.names())
        fields = list(fields)

      except_fields = opt.get('except_fields', [])
      except_fields = [x for x in except_fields if len(x) > 0]

      if len(except_fields) > 0:
        fields = list(set(fields) - set(except_fields))

      parser = qparser.MultifieldParser(
          fields, self._whoosh.schema
        , group=opt.get('group', qparser.OrGroup)
        )

      query       = parser.parse(prepped_string)
      search_opts = self.parse_opts_searcher(opt, self._parameters)
      results     = searcher.search(query, terms=True, **search_opts)

      ma = defaultdict(set)
      for f, term in results.matched_terms():
        ma[f].add(term)

      dic = {
          'runtime'       : results.runtime
        , 'cant_results'  : results.estimated_length()
        , 'matched_terms' : {k: list(v) for k, v in list(ma.items())}
        , 'facet_names'   : results.facet_names()
        }

      if dic['cant_results'] == 0 and self.to_bool(opt.get('something', False)):
        opt['add_wildcards'] = True
        opt['something']     = False
        return self.search(search_string, **opt)

      value_results = {}

      for r in results:
        params = {k:r[k] for k in self._primary_key}
        ans = {
            'docnum' : r.docnum
          , 'pk'     : tuple(params.values())
          , 'score'  : r.score
        }

        if self.to_bool(opt.get('include_entity', False)):
          entity     = self._model.get(**params)
          dic_entity = entity.to_dict()

          if opt.get('use_dict', True):
            ans['entity'] = dic_entity
          else:
            fields_missing      = set(dic_entity.keys()) - set(self._fields)
            ans['other_fields'] = [(k, dic_entity[k]) for k in fields_missing]
            ans['entity']       = [(k, dic_entity[k]) for k in self._fields]
          ans['model'] = self._name
        value_results[ans['pk']] = ans

      dic["results"] = list(value_results.values())
      return dic