
    Nwg                     Z   d dl Z d dl mZ d dlmZ d dlmZ d dlmZ d dlmZ d dl	m
Z
 d dlmZ d d	lmZmZmZ d d
lmZmZ d dlmZ d dlmZ d dlmZ g dZ e       Zd Z G d d      Z G d d      ZeZ  G d de
jB                        Z" G d dee"      Z# G d d      Z$ G d d      Z%y)    N)deepcopy)time)settings)Q)	ModelBase)tree	force_str)DEFAULT_ALIASFILTER_SEPARATORVALID_FILTERS)FacetingErrorMoreLikeThisError)SearchResult)get_model_ct)UnifiedIndex)yearmonthdayhourminutesecondc                       fd}|S )zy
    A decorator for pseudo-logging search queries. Used in the ``SearchBackend``
    to wrap the ``search`` method.
    c                    t               }	  | |g|i |t               }t        j                  r<ddlm} || j
                     j                  j                  |||d||z
  z  ||d       S S # t               }t        j                  r<ddlm} || j
                     j                  j                  |||d||z
  z  ||d       w w xY w)Nr   connectionsz%.3f)query_stringadditional_argsadditional_kwargsr   startstop)r   r   DEBUGhaystackr   connection_aliasqueriesappend)objr   argskwargsr    r!   r   funcs          Q/var/www/horilla/myenv/lib/python3.12/site-packages/haystack/backends/__init__.pywrapperzlog_query.<locals>.wrapper   s    	\;D;F;6D~~0C00199@@(4+/-3 &$, 7!& $	  6D~~0C00199@@(4+/-3 &$, 7!& $	 s   A0 0AC )r*   r,   s   ` r+   	log_queryr.      s    , N    c                        e Zd ZdZg Zd Zd Zy)EmptyResultsr   c                      y)Nr   r-   selfs    r+   __len__zEmptyResults.__len__9   s    r/   c                 <    t        |t              rg S t        d      )NzIt's not here.)
isinstanceslice
IndexError)r4   ks     r+   __getitem__zEmptyResults.__getitem__<   s    aI-..r/   N)__name__
__module____qualname__hitsdocsr5   r;   r-   r/   r+   r1   r1   5   s    DD/r/   r1   c                       e Zd ZdZg Zg Zd ZddZd ZddZ	e
d        Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZd	 Z	 dd
Zd Zd Zd Zy)BaseSearchBackendz,
    Abstract search engine base class.
    c                     || _         |j                  dd      | _        |j                  dd      | _        |j                  dd      | _        |j                  dd      | _        |j                  d	d      | _        y )
NTIMEOUT
   INCLUDE_SPELLINGF
BATCH_SIZEi  SILENTLY_FAILTDISTANCE_AVAILABLE)r$   gettimeoutinclude_spelling
batch_sizesilently_faildistance_available)r4   r$   connection_optionss      r+   __init__zBaseSearchBackend.__init__L   ss     0)--i< 2 6 67I5 Q,00tD/33OTJ"4"8"89Mu"Ur/   c                     t         )z
        Updates the backend when given a SearchIndex and a collection of
        documents.

        This method MUST be implemented by each backend, as it will be highly
        specific to each one.
        NotImplementedError)r4   indexiterablecommits       r+   updatezBaseSearchBackend.updateT   s
     "!r/   c                     t         )a7  
        Removes a document/object from the backend. Can be either a model
        instance or the identifier (i.e. ``app_name.model_name.id``) in the
        event the object no longer exists.

        This method MUST be implemented by each backend, as it will be highly
        specific to each one.
        rS   )r4   obj_or_strings     r+   removezBaseSearchBackend.remove^   s
     "!r/   Nc                     t         )z
        Clears the backend of all documents/objects for a collection of models.

        This method MUST be implemented by each backend, as it will be highly
        specific to each one.
        rS   )r4   modelsrW   s      r+   clearzBaseSearchBackend.cleari   s
     "!r/   c                     t         )a  
        Takes a query to search on and returns dictionary.

        The query should be a string that is appropriate syntax for the backend.

        The returned dictionary should contain the keys 'results' and 'hits'.
        The 'results' value should be an iterable of populated SearchResult
        objects. The 'hits' should be an integer count of the number of matched
        results the search backend found.

        This method MUST be implemented by each backend, as it will be highly
        specific to each one.
        rS   r4   r   r)   s      r+   searchzBaseSearchBackend.searchr   s
     "!r/   c                     t         NrS   )r4   r   sort_bystart_offset
end_offsetfields	highlightfacetsdate_facetsquery_facetsnarrow_queriesspelling_querywithindwithindistance_pointr]   limit_to_registered_modelsresult_classextra_kwargss                      r+   build_search_kwargsz%BaseSearchBackend.build_search_kwargs   s
    . "!r/   c                     t        |      S )z
        Hook to give the backend a chance to prep an attribute value before
        sending it to the search engine. By default, just force it to unicode.
        r	   )r4   values     r+   
prep_valuezBaseSearchBackend.prep_value   s    
 r/   c                     t        d      )z
        Takes a model object and returns results the backend thinks are similar.

        This method MUST be implemented by each backend, as it will be highly
        specific to each one.
        zrSubclasses must provide a way to fetch similar record via the 'more_like_this' method if supported by the backend.rS   )r4   model_instanceadditional_query_stringrr   s       r+   more_like_thisz BaseSearchBackend.more_like_this   s     " A
 	
r/   c                     t        d      )a  
        Hook to allow backends which support rich-content types such as PDF,
        Word, etc. extraction to process the provided file object and return
        the contents for indexing

        Returns None if metadata cannot be extracted; otherwise returns a
        dictionary containing at least two keys:

            :contents:
                        Extracted full-text content, if applicable
            :metadata:
                        key:value pairs of text strings
        zgSubclasses must provide a way to extract metadata via the 'extract' method if supported by the backend.rS   )r4   file_objs     r+   extract_file_contentsz'BaseSearchBackend.extract_file_contents   s     "u
 	
r/   c                     t        d      )z
        Takes a dictionary of fields and returns schema information.

        This method MUST be implemented by each backend, as it will be highly
        specific to each one.
        z4Subclasses must provide a way to build their schema.rS   )r4   rg   s     r+   build_schemazBaseSearchBackend.build_schema   s     "B
 	
r/   c                     ddl m} g }|| j                     j                         j	                         D ]  }|j                  t        |              |S )a9  
        Builds a list of models for searching.

        The ``search`` method should use this and the ``django_ct`` field to
        narrow the results (unless the user indicates not to). This helps ignore
        any results that are not currently handled models and ensures
        consistent caching.
        r   r   )r#   r   r$   get_unified_indexget_indexed_modelsr&   r   )r4   r   r]   models       r+   build_models_listz#BaseSearchBackend.build_models_list   sT     	) --.@@BUUW	/E MM,u-.	/
 r/   )T)NT)Nr   N FNNNNNNNNNNNNN)r<   r=   r>   __doc__RESERVED_WORDSRESERVED_CHARACTERSrQ   rX   r[   r^   r.   ra   rt   rw   r{   r~   r   r   r-   r/   r+   rB   rB   C   s    
 NV"	"" " "& #'%"2  JN

&	
r/   rB   c                       e Zd ZdZdZdZeZddZddZ e	e      Zd Z
d Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zy)
SearchNodea  
    Manages an individual condition within a query.

    Most often, this will be a lookup to ensure that a certain word or phrase
    appears in the documents being indexed. However, it also supports filtering
    types (such as 'lt', 'gt', 'in' and others) for more complex lookups.

    This object creates a tree, with children being a list of either more
    ``SQ`` objects or the expressions/values themselves.
    ANDORNc                 n    |xr |dd xs g | _         |xs | j                  | _        g | _        || _        y)a  
        Constructs a new Node. If no connector is given, the default will be
        used.

        Warning: You probably don't want to pass in the 'negated' parameter. It
        is NOT the same as constructing a node and calling negate() on the
        result.
        N)childrendefault	connectorsubtree_parentsnegated)r4   r   r   r   s       r+   rQ   zSearchNode.__init__   s8     !0Xa[6B"2dll!r/   c                 .    t        |||      }| |_        |S )a  
        This is called to create a new instance of this class when we need new
        Nodes (or subclasses) in the internal code in this class. Normally, it
        just shadows __init__(). However, subclasses with an __init__ signature
        that is not an extension of Node.__init__ might need to implement this
        method to allow a Node to create a new instance of them (if they have
        any extra setting up to do).
        )r   	__class__)clsr   r   r   r'   s        r+   _new_instancezSearchNode._new_instance  s     9g6
r/   c                 :   | j                   rCd| j                  ddj                  | j                  D cg c]  }t	        |       c}      dS d| j                  ddj                  | j                  D cg c]  }t	        |       c}      dS c c}w c c}w )Nz(NOT (z: , z))())r   r   joinr   str)r4   cs     r+   __str__zSearchNode.__str__  ss    <<		4==9a3q69:  
 "^^TYY7V1A7V-WXX :7Vs   B7Bc                     t        | j                  | j                        }| j                  |_        t	        j
                  | j                  |      |_        t	        j
                  | j                  |      |_        |S )z9
        Utility method used by copy.deepcopy().
        )r   r   )r   r   r   r   copyr   r   r   )r4   memodictr'   s      r+   __deepcopy__zSearchNode.__deepcopy__#  sW     4>>4<<H}}T]]H="mmD,@,@(K
r/   c                 ,    t        | j                        S )zF
        The size of a node if the number of children it has.
        )lenr   r3   s    r+   r5   zSearchNode.__len__-  s     4==!!r/   c                 ,    t        | j                        S )z*
        For truth value testing.
        )boolr   r3   s    r+   __bool__zSearchNode.__bool__3  s     DMM""r/   c                     || j                   v S )zM
        Returns True is 'other' is a direct child of this instance.
        )r   )r4   others     r+   __contains__zSearchNode.__contains__9  s     %%r/   c                    || j                   v r|| j                  k(  ryt        | j                         dk  r|| _        | j                  |k(  rot        |t              rC|j                  |k(  st        |      dk(  r&| j                   j                  |j                          y| j                   j                  |       y| j                  | j                   | j                  | j                        }|| _        ||g| _         y)a6  
        Adds a new node to the tree. If the conn_type is the same as the root's
        current connector type, the node is added to the first level.
        Otherwise, the whole tree is pushed down one level and a new root
        connector is created, connecting the existing tree and the new node.
        N      )	r   r   r   r7   r   extendr&   r   r   )r4   node	conn_typer'   s       r+   addzSearchNode.add?  s     4== Y$..%@t}}!&DN>>Y&$
+)+s4yA~$$T]]3$$T*$$T]]DNNDLLQC&DN $KDMr/   c                     | j                  | j                  | j                  | j                         g| _        | j                  | _        y)a  
        Negate the sense of the root connector. This reorganises the children
        so that the current node has a single child: a negated node containing
        all the previous children. This slightly odd construction makes adding
        new children behave more intuitively.

        Interpreting the meaning of this negate is up to client code. This
        method is useful for implementing "not" arrangements.
        N)r   r   r   r   r   r3   s    r+   negatezSearchNode.negateV  s;     t}}dnn$,,>NO
 r/   c                    t        | j                        dk(  r|| _        nT| j                  |k7  rE| j                  | j                  | j                  | j                        g| _        || _        d| _        | j
                  j                  | j                  | j                  | j                  | j                               | j                  | _        d| _        g | _        y)z
        Sets up internal state so that new nodes are added to a subtree of the
        current node. The conn_type specifies how the sub-tree is joined to the
        existing children.
        r   FN)	r   r   r   r   r   r   r&   r   r   )r4   r   s     r+   start_subtreezSearchNode.start_subtreee  s     t}}"&DN^^y(""4==$..$,,ODM 'DN DL##NN4==$..$,,G	
 r/   c                     | j                   j                         }| j                  | j                  | j                        }|j                  | _        |j
                  | _        |j                  | _        | j                  j                  |       y)z
        Closes off the most recently unmatched start_subtree() call.

        This puts the current state into a node of the parent tree and returns
        the current instances state to be the parent.
        N)r   popr   r   r   r   r&   )r4   r'   r   s      r+   end_subtreezSearchNode.end_subtree{  sc     ""&&(~~dmmT^^<{{T"r/   c                 Z    d| j                   d| j                  | j                        dS )Nz<SQ:  >)r   as_query_string_repr_query_fragment_callbackr3   s    r+   __repr__zSearchNode.__repr__  s'    NN  !C!CD
 	
r/   c                 2    |t         |dt        |      S )N=)r   r
   r4   fieldfilter_typerv   s       r+   r   z(SearchNode._repr_query_fragment_callback  s    #%5{IeDTUUr/   c                    g }| j                   D ]a  }t        |d      r!|j                  |j                  |             0|\  }}| j	                  |      \  }}|j                   ||||             c d| j
                  z  }|j                  |      }	|	r0| j                  rd|	z  }	|	S t        | j                         dk7  rd|	z  }	|	S )zf
        Produces a portion of the search query from the current SQ and its
        children.
        r   z %s zNOT (%s)r   (%s))	r   hasattrr&   r   split_expressionr   r   r   r   )
r4   query_fragment_callbackresultchild
expressionrv   r   r   connr   s
             r+   r   zSearchNode.as_query_string  s    
 ]] 	REu/0e334KLM$)!
E%)%:%::%F"{5e[%PQ	R &yy(||)L8  T]]#q(%4r/   c                     |j                  t              }|d   }t        |      dk(  s|d   t        vrd}||fS |j	                         }||fS )z>Parses an expression and determines the field and filter type.r   r   content)splitr   r   r   r   )r4   r   partsr   r   s        r+   r   zSearchNode.split_expression  s\      !12au:?eBi}<#K {##  ))+K{##r/   )NNF)r<   r=   r>   r   r   r   r   rQ   r   classmethodr   r   r5   r   r   r   r   r   r   r   r   r   r   r-   r/   r+   r   r      sq    	 C	BG   .MY"#&(.&,# 
V4	$r/   r   c                       e Zd ZdZy)SQa"  
    Manages an individual condition within a query.

    Most often, this will be a lookup to ensure that a certain word or phrase
    appears in the documents being indexed. However, it also supports filtering
    types (such as 'lt', 'gt', 'in' and others) for more complex lookups.
    N)r<   r=   r>   r   r-   r/   r+   r   r     s     	r/   r   c                   P   e Zd ZdZefdZd Zd Zd Zd Z	d1dZ
d1d	Zd
 Zd Zd Zd Zd Zd Zd Zd1dZd Zd Zd Zej0                  fdZd Zd Zd Zd Zd2dZd Zd Z d Z!d3dZ"d Z#d  Z$d! Z%d" Z&d# Z'd$ Z(d% Z)d& Z*d' Z+d( Z,d4d)Z-d* Z.d+ Z/d, Z0d- Z1d1d.Z2d/ Z3d3d0Z4y)5BaseSearchQuerya   
    A base class for handling the query itself.

    This class acts as an intermediary between the ``SearchQuerySet`` and the
    ``SearchBackend`` itself.

    The ``SearchQuery`` object maintains a tree of ``SQ`` objects. Each ``SQ``
    object supports what field it looks up against, what kind of lookup (i.e.
    the __'s), what value it's looking for, if it's a AND/OR/NOT and tracks
    any children it may have. The ``SearchQuery.build_query`` method starts with
    the root of the tree, building part of the final query at each node until
    the full final query is ready for the ``SearchBackend``.

    Backends should extend this class and provide implementations for
    ``build_query_fragment``, ``clean`` and ``run``. See the ``solr`` backend for an example
    implementation.
    c                    t               | _        g | _        t               | _        i | _        d| _        d | _        d| _        i | _	        i | _
        g | _        t               | _        g | _        i | _        i | _        i | _        d | _        i | _        d| _        d | _        d | _        d | _        d | _        d | _        t2        | _        d | _        t8        | _        i | _        ddlm } || _!        || jB                     jE                         | _#        y )Nr   Fr   )$r   query_filterorder_bysetr]   boostre   rf   rh   ri   rj   rk   rl   rg   rn   ro   rp   
_raw_query_raw_query_params_more_like_this_mlt_instance_results
_hit_count_facet_counts_statsSPELLING_SUGGESTION_HAS_NOT_RUN_spelling_suggestionrm   r   rr   statsr#   r   _usingget_backendbackend)r4   usingr   s      r+   rQ   zBaseSearchQuery.__init__  s    &Le
!e
  !#$!!$C!"(
("4;;/;;=r/   c                 "    | j                         S rc   )build_queryr3   s    r+   r   zBaseSearchQuery.__str__   s    !!r/   c                 @    | j                   j                         }|d= |S )zFor pickling.r   )__dict__r   )r4   obj_dicts     r+   __getstate__zBaseSearchQuery.__getstate__  s!    ==%%'Yr/   c                     ddl m} | j                  j                  |       || j                     j                         | _        y)zFor unpickling.r   r   N)r#   r   r   rX   r   r   r   )r4   r   r   s      r+   __setstate__zBaseSearchQuery.__setstate__	  s0    (X&"4;;/;;=r/   c                 6    d| j                   | j                  fvS )z)Indicates if any query has been been run.N)r   r   r3   s    r+   has_runzBaseSearchQuery.has_run  s    DMM4??;;;r/   Nc                 \   d| j                   i}| j                  r| j                  |d<   | j                  | j                  |d<   | j                  r| j                  |d<   | j                  r| j                  |d<   | j
                  r| j
                  |d<   | j                  r| j                  |d<   | j                  r| j                  |d<   |r||d	<   n| j                  r| j                  |d	<   | j                  r| j                  |d
<   | j                  r| j                  |d<   | j                  r| j                  |d<   | j                  r| j                  |d<   | j                  r| j                  |d<   | j                  r| j                  |d<   | j                  r| j                  |d<   |S )z1Generates a list of params to use when searching.re   rd   rf   rh   ri   rj   rk   rl   rm   r   rn   ro   rp   rr   rg   r]   )re   r   rf   rh   ri   rj   rk   rl   rm   r   rn   ro   rp   rr   rg   r]   )r4   rm   r)   s      r+   build_paramszBaseSearchQuery.build_params  s}    $"3"34== $F9??&#'??F< >>"&..F;;;#{{F8$($4$4F=!%)%6%6F>"'+':':F#$'5F#$  '+':':F#$::"jjF7O;;#{{F8<< $F9'+':':F#$%)%6%6F>";;#{{F8;;#{{F8r/   c                 ^   | j                         }| j                  |      }|r|j                  |        | j                  j                  |fi |}|j                  dg       | _        |j                  dd      | _        | j                  |      | _	        |j                  dd      | _
        y)z@Builds and executes the query. Returns a list of search results.rm   resultsr?   r   spelling_suggestionN)r   r   rX   r   ra   rJ   r   r   post_process_facetsr   r   )r4   rm   r)   final_querysearch_kwargsr   s         r+   runzBaseSearchQuery.runI  s    &&()))H  (%$,,%%kC]CIr2!++fa0!55g>$+KK0Et$L!r/   c                    | j                   du s| j                  t        d      d| j                  i}| j                  r| j                  |d<   |r|j                  |       | j                         } | j                  j                  | j                  |fi |}|j                  dg       | _
        |j                  dd      | _        y)	z
        Executes the More Like This. Returns a list of search results similar
        to the provided document (and optionally query).
        FNz?No instance was provided to determine 'More Like This' results.rr   r]   r   r?   r   )r   r   r   rr   r]   rX   r   r   r{   rJ   r   r   )r4   r)   r   rz   r   s        r+   run_mltzBaseSearchQuery.run_mltW  s    
 5(D,>,>,F#Q  ():):;;;&*kkM(#  ("&"2"2"4-$,,-- 7
;H
  Ir2!++fa0r/   c                    | j                         }|j                  | j                         |r|j                  |        | j                  j                  | j
                  fi |}|j                  dg       | _        |j                  dd      | _        |j                  di       | _	        |j                  dd      | _
        y)z7Executes a raw query. Returns a list of search results.r   r?   r   ri   r   N)r   rX   r   r   ra   r   rJ   r   r   r   r   )r4   r)   r   r   s       r+   run_rawzBaseSearchQuery.run_rawp  s    ))+T334  (%$,,%%dooGGIr2!++fa0$[[26$+KK0Et$L!r/   c                    | j                   s| j                  sd| _        | j                  r| j                          | j                   S | j                  r| j                          | j                   S | j                          | j                   S )z
        Returns the number of results the backend found for the query.

        If the query has not been run, this will execute the query and store
        the results.
        r   )r   rf   r   r  r   r  r   r3   s    r+   	get_countzBaseSearchQuery.get_count~  so     ??" ??"###    
r/   c                     | j                   f| j                  r | j                  di | | j                   S | j                  r | j                  di | | j                   S  | j
                  di | | j                   S )z
        Returns the results received from the backend.

        If the query has not been run, this will execute the query and store
        the results.
        r-   )r   r   r  r   r  r   r4   r)   s     r+   get_resultszBaseSearchQuery.get_results  sw     == ##&v& }} &v& }} "6"}}r/   c                 R    | j                   | j                          | j                   S )z
        Returns the facet counts received from the backend.

        If the query has not been run, this will execute the query and store
        the results.
        )r   r   r3   s    r+   get_facet_countsz BaseSearchQuery.get_facet_counts  s%     %HHJ!!!r/   c                 R    | j                   | j                          | j                   S )z
        Returns the stats received from the backend.

        If the query has not been run, this will execute the query and store
        the results
        )r   r   r3   s    r+   	get_statszBaseSearchQuery.get_stats  s!     ;;HHJ{{r/   c                     || _         y rc   r   )r4   rm   s     r+   set_spelling_queryz"BaseSearchQuery.set_spelling_query  s
    ,r/   c                 b    | j                   t        u r| j                  |       | j                   S )z
        Returns the spelling suggestion received from the backend.

        If the query has not been run, this will execute the query and store
        the results.
        r   )r   r   r   )r4   preferred_querys     r+   get_spelling_suggestionz'BaseSearchQuery.get_spelling_suggestion  s-     $$(GGHHOH4(((r/   c                     |d|S )z?Generates query fragment for boosting a single word/value pair.^r-   )r4   
boost_wordboost_values      r+   boost_fragmentzBaseSearchQuery.boost_fragment  s    $k22r/   c                      y)z/Generates the query that matches all documents.*r-   r3   s    r+   matching_all_fragmentz%BaseSearchQuery.matching_all_fragment  s    r/   c                 B   | j                   j                  | j                        }|s| j                         }| j                  r[g }| j                  j                         D ]&  \  }}|j                  | j                  ||             ( |ddj                  |      }|S )zw
        Interprets the collected query metadata and builds the final query to
        be sent to the backend.
        r   )	r   r   build_query_fragmentr  r   itemsr&   r  r   )r4   r   
boost_listr  r  s        r+   r   zBaseSearchQuery.build_query  s    
 ''778Q8QR446K::J+/::+;+;+= P'
K!!$"5"5j+"NOP &1#((:2FGKr/   c                     |t         j                  k(  r| j                  |j                         y |t         j                  k(  r| j                  |j                  d       y y )NT)use_or)r   r   
add_filterr   r   )r4   rhsr   s      r+   combinezBaseSearchQuery.combine  sG    OOC,,-"%%OOC,,TO:  r/   c                     t        d      )z
        Generates a query fragment from a field, filter type and a value.

        Must be implemented in backends as this will be highly backend specific.
        z`Subclasses must provide a way to generate query fragments via the 'build_query_fragment' method.rS   r   s       r+   r  z$BaseSearchQuery.build_query_fragment  s     "n
 	
r/   c                 l   t        |t              s|S |j                         }g }|D ]{  }|| j                  j                  v r |j                  ||j                               }| j                  j                  D ]  }|j                  |d|z        } |j                  |       } dj                  |      S )z
        Provides a mechanism for sanitizing user input before presenting the
        value to the backend.

        A basic (override-able) implementation is provided.
        z\%sr   )
r7   r   r   r   r   replacelowerr   r&   r   )r4   query_fragmentwordscleaned_wordswordchars         r+   cleanzBaseSearchQuery.clean   s     .#.!!$$& 	'Dt||222||D$**,788 9||D&4-89   &	' xx&&r/   c                     d|v rd|z  }d|z  S )Nr   r   zNOT %sr-   r4   r   s     r+   build_not_queryzBaseSearchQuery.build_not_query  s    ,!L0L,&&r/   c                     d|z  S )Nz"%s"r-   r/  s     r+   build_exact_queryz!BaseSearchQuery.build_exact_query  s    $$r/   c                    |rt         j                  }nt         j                  }| j                  r;|j                  |k7  r,t        |      dkD  r| j                  j                  |       d}nd}|j                  D ]  }t        |t        j                        rG| j                  j                  |       | j                  |       | j                  j                          n#|\  }}| j                  j                  ||f|       |j                  } |j                  r| j                  j                          |r| j                  j                          yy)z1
        Adds a SQ to the current query.
        r   TFN)r   r   r   r   r   r   r   r   r7   r   Noder!  r   r   r   r   )r4   r   r   r   subtreer   r   rv   s           r+   r!  zBaseSearchQuery.add_filter!  s    II &&)3L!A%++I6GG!** 		/E%+!!//	:&!!--/$)!
E!!%%z5&99E$..I		/ $$&))+ r/   c                 :    | j                   j                  |       y)z$Orders the search result by a field.N)r   r&   )r4   r   s     r+   add_order_byzBaseSearchQuery.add_order_byE  s    U#r/   c                     g | _         y)zp
        Clears out all ordering that has been already added, reverting the
        query to relevancy.
        N)r   r3   s    r+   clear_order_byzBaseSearchQuery.clear_order_byI  s    
 r/   c                 p    t        |t              st        d      | j                  j	                  |       y)z
        Restricts the query requiring matches in the given model.

        This builds upon previous additions, so you can limit to multiple models
        by chaining this method several times.
        z:The model being added to the query must derive from Model.N)r7   r   AttributeErrorr]   r   )r4   r   s     r+   	add_modelzBaseSearchQuery.add_modelP  s0     %+ L  	r/   c                 N    |t        |      | _        |t        |      | _        yy)zFRestricts the query by altering either the start, end or both offsets.N)intre   rf   )r4   lowhighs      r+   
set_limitszBaseSearchQuery.set_limits^  s)    ? #CD!$iDO r/   c                 "    d\  | _         | _        y)zClears any existing limits.)r   NN)re   rf   r3   s    r+   clear_limitszBaseSearchQuery.clear_limitsf  s    -4*4?r/   c                 "    || j                   |<   y)z<Adds a boosted term and the amount to boost it to the query.N)r   )r4   termr  s      r+   	add_boostzBaseSearchQuery.add_boostj  s    &

4r/   c                      || _         || _        y)aN  
        Runs a raw query (no parsing) against the backend.

        This method causes the SearchQuery to ignore the standard query
        generating facilities, running only what was provided instead.

        Note that any kwargs passed along will override anything provided
        to the rest of the ``SearchQuerySet``.
        N)r   r   r`   s      r+   
raw_searchzBaseSearchQuery.raw_searchn  s     '!'r/   c                      d| _         || _        y)z
        Allows backends with support for "More Like This" to return results
        similar to the provided instance.
        TN)r   r   )r4   ry   s     r+   r{   zBaseSearchQuery.more_like_this{  s    
  $+r/   c                 "    || j                   |<   y)z9Adds stats and stats_facets queries for the Solr backend.N)r   )r4   stats_fieldstats_facetss      r+   add_stats_queryzBaseSearchQuery.add_stats_query  s    ".

;r/   c                     |xs d| _         y)z(Adds highlighting to the search results.TN)rh   r  s     r+   add_highlightzBaseSearchQuery.add_highlight  s    4r/   c                 >    ddl m} | ||       ||      d| _        y)z-Adds bounding box parameters to search query.r   ensure_point)r   point_1point_2N)haystack.utils.georR  rn   )r4   r   rS  rT  rR  s        r+   
add_withinzBaseSearchQuery.add_within  s#    3 #G,#G,
r/   c                 B    ddl m}m} | ||       ||      d| _        y)z-Adds radius-based parameters to search query.r   )ensure_distancerR  )r   pointdistanceN)rU  rX  rR  ro   )r4   r   rY  rZ  rX  rR  s         r+   add_dwithinzBaseSearchQuery.add_dwithin  s#    D !%('1
r/   c                 0    ddl m} | ||      d| _        y)zm
        Denotes that results should include distance measurements from the
        point passed in.
        r   rQ  )r   rY  N)rU  rR  rp   )r4   r   rY  rR  s       r+   add_distancezBaseSearchQuery.add_distance  s    
 	4(-U8KLr/   c                     ddl m} || j                     j                         j	                  |      }|j                         | j                  |<   y)z Adds a regular facet on a field.r   r   N)r#   r   r   r   get_facet_fieldnamer   ri   )r4   r   optionsr   
field_names        r+   add_field_facetzBaseSearchQuery.add_field_facet  sB    ( $668LLUS 	 #*,,.Jr/   c                     ddl m} |t        vr%t        d|ddj	                  t              d      ||||d}|| j
                  || j                     j                         j                  |      <   y)	z#Adds a date-based facet on a field.r   r   zThe gap_by ('z!') must be one of the following: r   .)
start_dateend_dategap_by
gap_amountN)	r#   r   
VALID_GAPSr   r   rj   r   r   r_  )r4   r   re  rf  rg  rh  r   detailss           r+   add_date_facetzBaseSearchQuery.add_date_facet  sw    (#499Z02  % $	
  	$668LLUS	
r/   c                     ddl m} | j                  j                  || j                     j                         j                  |      |f       y)zAdds a query facet on a field.r   r   N)r#   r   rk   r&   r   r   r_  )r4   r   queryr   s       r+   add_query_facetzBaseSearchQuery.add_query_facet  sB    (  DKK(::<PPQVW	
r/   c                 :    | j                   j                  |       y)z
        Narrows a search to a subset of all documents per the query.

        Generally used in conjunction with faceting.
        N)rl   r   )r4   rm  s     r+   add_narrow_queryz BaseSearchQuery.add_narrow_query  s     	&r/   c                 "    |t         }|| _        y)z
        Sets the result class to use for results.

        Overrides any previous usages. If ``None`` is provided, Haystack will
        revert back to the default ``SearchResult`` object.
        N)r   rr   )r4   klasss     r+   set_result_classz BaseSearchQuery.set_result_class  s     = E!r/   c                 T   ddl m} i }|| j                     j                         j	                         }|j                  di       j                         D ]Q  \  }}i }|j                         D ]2  \  }}	|}
||v r"t        ||   d      r||   j                         }
|	||
<   4 |||<   S |S )Nr   r   ri   get_facet_for_name)	r#   r   r   r   all_searchfieldsrJ   r  r   ru  )r4   r   r   revised_facets
field_data
facet_typefield_detailstemp_facetsr   field_facets	fieldnames              r+   r   z#BaseSearchQuery.post_process_facets  s    ( -??ARRT
)0Xr)B)H)H)J 	5%JK'4':':'< 6#|!	J&7u%';, !+5 1 D D FI)5I&6 *5N:&	5 r/   c                 &    | j                  |      S )z
        Allows for overriding which connection should be used. This
        disables the use of routers when performing the query.

        If ``None`` is provided, it has no effect on what backend is used.
        r   )_cloner4   r   s     r+   r   zBaseSearchQuery.using  s     {{{''r/   c                 D    d| _         d| _        d| _        t        | _        y)z
        Resets the instance's internal state to appear as though no query has
        been run before. Only need to tweak a few variables we check.
        N)r   r   r   r   r   r3   s    r+   _resetzBaseSearchQuery._reset  s"    
 !$C!r/   c                 `   || j                   }nddlm} ||   j                  }|| j                  } ||      }t        | j                        |_        | j                  d d  |_        | j                  j                         |_        | j                  j                         |_
        | j                  |_        | j                  j                         |_        | j                  j                         |_        | j                  j                         |_        | j                  d d  |_        | j                   j                         |_        | j"                  |_        | j$                  |_        | j&                  |_        | j(                  j                         |_        | j*                  j                         |_        | j,                  j                         |_        | j.                  |_        | j0                  |_        | j2                  |_        | j4                  |_        | j6                  |_        |S )Nr   r   r  )r   r#   r   rm  r   r   r   r   r]   r   r   rh   r   ri   rj   rk   rl   re   rf   rr   rn   ro   rp   r   r   rm   r   r   )r4   rr  r   r   clones        r+   r  zBaseSearchQuery._clone  s   =KKE,&,,E=NNEE"%d&7&78q){{'')jjoo'..jjoo'{{'') ,,113!..q1#22779!..??!..{{'')))+#22779??"&"8"8#22 $ 4 4"00r/   rc   )Fr   )r   )5r<   r=   r>   r   r   rQ   r   r   r   r   r   r   r  r  r  r	  r  r  r  r  r  r  r   r   r   r#  r  r-  r0  r2  r!  r7  r9  r<  rA  rC  rF  rH  r{   rM  rO  rV  r[  r]  rb  rk  rn  rp  rs  r   r   r  r  r-   r/   r+   r   r     s   $ + %>N"><3jM12M0&
"	-
)3* &(VV ;
'0'%",H$(5'(,/(

M1(	
'
".(D"r/   r   c                   >    e Zd ZeZeZeZddZ	d Z
d Zd Zd Zd Zy)	
BaseEngineNc                     |t         }|| _        t        j                  j	                  | j                  i       | _        g | _        d | _        d | _        y rc   )	r   r   r   HAYSTACK_CONNECTIONSrJ   r`  r%   _index_backendr  s     r+   rQ   zBaseEngine.__init__8  sF    =!E
4488RHr/   c                     | j                   , | j                  | j                  fi | j                  | _         | j                   S rc   )r  r   r   r`  r3   s    r+   r   zBaseEngine.get_backendB  s5    == (DLLDt||DDM}}r/   c                     d| _         y)z3Reset any transient connections, file handles, etc.N)r  r3   s    r+   reset_sessionszBaseEngine.reset_sessionsG  s	    r/   c                 :    | j                  | j                        S )Nr  )rm  r   r3   s    r+   	get_queryzBaseEngine.get_queryK  s    zz

z++r/   c                 "    | j                   d d = y rc   )r%   r3   s    r+   reset_querieszBaseEngine.reset_queriesN  s    LLOr/   c                     | j                   0| j                  | j                  j                  dg             | _         | j                   S )NEXCLUDED_INDEXES)r  unified_indexr`  rJ   r3   s    r+   r   zBaseEngine.get_unified_indexQ  s;    ;;,,T\\-=-=>PRT-UVDK{{r/   rc   )r<   r=   r>   rB   r   r   rm  r   r  rQ   r   r  r  r  r   r-   r/   r+   r  r  3  s/    GE M
,r/   r  )&r   r   r   django.confr   django.db.modelsr   django.db.models.baser   django.utilsr   django.utils.encodingr
   haystack.constantsr   r   r   haystack.exceptionsr   r   haystack.modelsr   haystack.utilsr   haystack.utils.loadingr   ri  objectr   r.   r1   rB   SearchBackendr4  r   r   r   r  r-   r/   r+   <module>r     s          +  + M M @ ( ' /A
"(( >/ /] ]B "P$ P$f		J 		j	 j	Z" "r/   