
    =wgq                        d Z ddlmZmZmZ ddlmZmZmZm	Z	m
Z
 ddlmZ  G d de      Zd Z G d d	ej                         Z G d
 de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d  d!e      Zy")#as  
This module contains Query objects that deal with "spans".

Span queries allow for positional constraints on matching documents. For
example, the :class:`whoosh.spans.SpanNear` query matches documents where one
term occurs near another. Because you can nest span queries, and wrap them
around almost any non-span query, you can create very complex constraints.

For example, to find documents containing "whoosh" at most 5 positions before
"library" in the "text" field::

    from whoosh import query, spans
    t1 = query.Term("text", "whoosh")
    t2 = query.Term("text", "library")
    q = spans.SpanNear(t1, t2, slop=5)

    )mcorewrappersbinary)QueryAndAndMaybeOrTerm)make_binary_treec                       e Zd ZdZ	 	 ddZd Zd Zd Zd Zd Z	d	 Z
ed
        Zd Zd Zd Zd Zd Zd Zd Zd Zy)Spanstartend	startcharendcharboostNc                 `    ||}||k  sJ || _         || _        || _        || _        || _        y Nr   )selfr   r   r   r   r   s         I/var/www/horilla/myenv/lib/python3.12/site-packages/whoosh/query/spans.py__init__zSpan.__init__8   s;    ;C||
"
    c                     | j                   | j                  1d| j                  | j                  | j                   | j                  fz  S d| j                  | j                  fz  S )Nz<%d-%d %d:%d>z<%d-%d>)r   r   r   r   r   s    r   __repr__zSpan.__repr__C   sZ    >>%)A"djj$((DNN&*ll&4 4 4 

DHH555r   c                     | j                   |j                   k(  xrO | j                  |j                  k(  xr4 | j                  |j                  k(  xr | j                  |j                  k(  S r   )r   r   r   r   r   spans     r   __eq__zSpan.__eq__J   sX    

djj( 1HH(1NNdnn41 LLDLL0	2r   c                 j    | j                   |j                   k7  xs | j                  |j                  k7  S r   r   r   r   s     r   __ne__zSpan.__ne__P   s'    zzTZZ'?488txx+??r   c                 4    | j                   |j                   k  S r   r   r   s     r   __lt__zSpan.__lt__S       zzDJJ&&r   c                 4    | j                   |j                   kD  S r   r%   r   s     r   __gt__zSpan.__gt__V   r'   r   c                 D    t        | j                  | j                  f      S r   )hashr   r   r   s    r   __hash__zSpan.__hash__Y   s    TZZ*++r   c                 n   d}|t        |      dz
  k  r||   }|dz   }|t        |      k  rr||   }|j                  |j                  dz   kD  rnP|j                  |      s|j	                  |      r|j                  |      }|||<   ||= n|dz  }|t        |      k  rr|dz  }|t        |      dz
  k  r|S )zMerges overlapping and touches spans in the given list of spans.

        Note that this modifies the original list.

        >>> spans = [Span(1,2), Span(3)]
        >>> Span.merge(spans)
        >>> spans
        [<1-3>]
        r      )lenr   r   touchesoverlapsto)clsspansiherejtheres         r   mergez
Span.merge\   s     #e*q. 8DAAc%j.a;;A-<<&$--*>775>D#E!HaFA c%j. FA #e*q.  r   c                    | j                   |j                   }n9|j                   | j                   }n t        | j                   |j                         }| j                  |j                  }n9|j                  | j                  }n t        | j                  |j                        }t        | j                  |j                        }t        | j
                  |j
                        }| j                  ||||      S r   )r   minr   maxr   r   	__class__)r   r   mincharmaxcharminposmaxposs         r   r2   zSpan.toy   s    >>!nnG^^#nnG$..$..9G<<llG\\!llG$,,5GTZZ,TXXtxx(~~ffgw??r   c                    | j                   |j                   k\  xr | j                   |j                  k  xs | j                  |j                   k\  xr | j                  |j                  k  xsj |j                   | j                   k\  xr |j                   | j                  k  xs4 |j                  | j                   k\  xr |j                  | j                  k  S r   r"   r   s     r   r1   zSpan.overlaps   s    tzz)DdjjDHH.D EHH

*Ctxx488/CEJJ$**,Gtxx1GE HH

*Ctxx488/C	Fr   c                 j    | j                   |j                   k  xr | j                  |j                  kD  S r   r"   r   s     r   	surroundszSpan.surrounds   s'    zzDJJ&>488dhh+>>r   c                 j    | j                   |j                   k\  xr | j                  |j                  k  S r   r"   r   s     r   	is_withinzSpan.is_within   s'    zzTZZ'@DHH,@@r   c                 4    | j                   |j                  k  S r   )r   r   r   s     r   	is_beforezSpan.is_before   s    xx$**$$r   c                 4    | j                   |j                  kD  S r   r"   r   s     r   is_afterzSpan.is_after   s    zzDHH$$r   c                 v    | j                   |j                  dz   k(  xs | j                  |j                   dz
  k(  S Nr.   r"   r   s     r   r0   zSpan.touches   s/    zzTXX\)GTXXa-GGr   c                     | j                  |      ry| j                  |      r|j                  | j                  z
  S | j                  |j                  z
  S )Nr   )r1   rH   r   r   r   s     r   distance_tozSpan.distance_to   sC    ==^^D!::((::((r   )NNNg      ?)__name__
__module____qualname__	__slots__r   r   r    r#   r&   r)   r,   classmethodr9   r2   r1   rD   rF   rH   rJ   r0   rN    r   r   r   r   5   sq    AI@D	62@'',  8@$F?A%%H)r   r   c                 z    d}t        |       }||k  r(||z   dz  }| |   j                  |k  r|dz   }n|}||k  r(|S )Nr      r.   )r/   r   )r4   r   lohimids        r   bisect_spansrZ      sT    	
B	UB
r'Bw1n:e#qBB r' Ir   c                   L     e Zd ZdZ fdZd Zd Zd Zd Zd Z	d Z
d	 Z xZS )
SpanWrappingMatcherac  An abstract matcher class that wraps a "regular" matcher. This matcher
    uses the sub-matcher's matching logic, but only matches documents that have
    matching spans, i.e. where ``_get_spans()`` returns a non-empty list.

    Subclasses must implement the ``_get_spans()`` method, which returns a list
    of valid spans for the current document.
    c                 |    t         t        |   |       d | _        | j	                         r| j                          y y r   )superr\   r   _spans	is_active
_find_next)r   childr=   s     r   r   zSpanWrappingMatcher.__init__   s3    !41%8>>OO r   c                 z    | j                  | j                  j                               }| j                  |_        |S r   )r=   rb   copyr_   r   ms     r   rd   zSpanWrappingMatcher.copy   s+    NN4::??,-;;r   c                 $    | j                  |      S r   r=   r   newchilds     r   _replacementz SpanWrappingMatcher._replacement   s    ~~h''r   c                 &   | j                         sy | j                  }d}| j                         }|j                         rJ|sH|j                         xs |}|j                         sy| j                         }|j                         r|sH|| _        |S NFT)r`   rb   
_get_spansnextr_   )r   rb   rr4   s       r   ra   zSpanWrappingMatcher._find_next   sz    ~~

!oo

!A??$OO%E	 oo
 r   c                     | j                   S r   )r_   r   s    r   r4   zSpanWrappingMatcher.spans   s    {{r   c                 X    | j                   j                          | j                          y r   )rb   ro   ra   r   s    r   ro   zSpanWrappingMatcher.next   s    

r   c                 Z    | j                   j                  |       | j                          y r   )rb   skip_tora   )r   ids     r   rt   zSpanWrappingMatcher.skip_to   s    

2r   c              #      K   | j                         rD| j                         r| j                          | j                          | j                         rCy y wr   )r`   r4   ru   ro   r   s    r   all_idszSpanWrappingMatcher.all_ids   s9     nnzz|ggiIIK nns   AAA)rO   rP   rQ   __doc__r   rd   rk   ra   r4   ro   rt   rw   __classcell__rh   s   @r   r\   r\      s0    
("r   r\   c                        e Zd Zd Zd ZddZy)SpanBiMatcherc                     | j                  | j                  j                         | j                  j                               S r   )r=   ard   br   s    r   rd   zSpanBiMatcher.copy   s'    ~~dffkkmTVV[[];;r   c                     dt        | j                  j                         | j                  j                               z   S rL   )r<   r}   depthr~   r   s    r   r   zSpanBiMatcher.depth   s(    3tvv||~tvv||~666r   c                 N    | j                         st        j                         S | S r   r`   r   NullMatcherr   
minqualitys     r   replacezSpanBiMatcher.replace   s     ~~$$&&r   Nr   )rO   rP   rQ   rd   r   r   rT   r   r   r{   r{      s    <7r   r{   c                   6    e Zd ZdZd	dZd Zd Zd Zd Zd Z	y)
	SpanQuerya  Abstract base class for span-based queries. Each span query type wraps
    a "regular" query that implements the basic document-matching functionality
    (for example, SpanNear wraps an And query, because SpanNear requires that
    the two sub-queries occur in the same documents. The wrapped query is
    stored in the ``q`` attribute.

    Subclasses usually only need to implement the initializer to set the
    wrapped query, and ``matcher()`` to return a span-aware matcher object.
    Nc                 :    | j                   j                  ||      S r   )qmatcher)r   scontexts      r   _submzSpanQuery._subm  s    vv~~a))r   c                 N    | j                   j                  d| j                  dS )N())r=   rO   r   r   s    r   r   zSpanQuery.__repr__  s    >>22DFF;;r   c                 p    |xr3 | j                   |j                   u xr | j                  |j                  k(  S r   )r=   r   r   others     r   r    zSpanQuery.__eq__  s3     &$..EOO; &FFegg%	'r   c                 l    t        | j                  j                        t        | j                        z  S r   )r+   r=   rO   r   r   s    r   r,   zSpanQuery.__hash__  s$    DNN++,tDFF|;;r   c                      y r   rT   r   s    r   fieldzSpanQuery.field      r   c                      y)NTrT   r   s    r   needs_spanszSpanQuery.needs_spans  r   r   r   )
rO   rP   rQ   rx   r   r   r    r,   r   r   rT   r   r   r   r     s%    *<'<r   r   c                       e Zd Zd Zd Zd Zy)WrappingSpanc                      yNFrT   r   s    r   is_leafzWrappingSpan.is_leaf!      r   c                 \    | j                   || j                        | j                        S N)limitr=   r   r   r   fns     r   applyzWrappingSpan.apply$  s!    ~~bj

~;;r   c                 6    | j                   j                         S r   )r   r   r   s    r   r   zWrappingSpan.field'  s    vv||~r   N)rO   rP   rQ   r   r   r   rT   r   r   r   r      s    <r   r   c                   B    e Zd ZdZd	dZd Zd Zd
dZ G d de      Z	y)	SpanFirstzMatches spans that end within the first N positions. This lets you
    for example only match terms near the beginning of the document.
    c                      || _         || _        y)z
        :param q: the query to match.
        :param limit: the query must match within this position at the start
            of a document. The default is ``0``, which means the query must
            match at the first position.
        N)r   r   )r   r   r   s      r   r   zSpanFirst.__init__0  s     
r   c                     |xrN | j                   |j                   u xr4 | j                  |j                  k(  xr | j                  |j                  k(  S r   r   r   s     r   r    zSpanFirst.__eq__;  sL     D$..EOO; DFFegg%D*.***C	Er   c                 X    t        | j                        t        | j                        z  S r   )r+   r   r   r   s    r   r,   zSpanFirst.__hash__?  s    DFF|d4::...r   Nc                 h    | j                  ||      }t        j                  || j                        S r   )r   r   SpanFirstMatcherr   )r   searcherr   rf   s       r   r   zSpanFirst.matcherB  s,    JJx)))!4::)>>r   c                   2     e Zd Zd fd	Zd Zd Zd Z xZS )SpanFirst.SpanFirstMatcherc                 N    || _         t        t        j                  |   |       y r   )r   r^   r   r   r   )r   rb   r   r=   s      r   r   z#SpanFirst.SpanFirstMatcher.__init__G  s    DJ),,d<UCr   c                 l    | j                  | j                  j                         | j                        S r   )r=   rb   rd   r   r   s    r   rd   zSpanFirst.SpanFirstMatcher.copyK  s$    >>$**//"34::>FFr   c                 <    | j                  || j                        S r   )r=   r   ri   s     r   rk   z'SpanFirst.SpanFirstMatcher._replacementN  s    >>($**>==r   c                     | j                   j                         D cg c]  }|j                  | j                  k  r| c}S c c}w r   )rb   r4   r   r   r   s     r   rn   z%SpanFirst.SpanFirstMatcher._get_spansQ  s>    %)ZZ%5%5%7 /Txx4::-  / / /s   "Ar   )rO   rP   rQ   r   rd   rk   rn   ry   rh   s   @r   r   r   F  s    	D	G	>	/r   r   r   r   )
rO   rP   rQ   rx   r   r    r,   r   r\   r   rT   r   r   r   r   +  s)    	E/?/. /r   r   c                   f    e Zd ZdZddZd Zd Zd Zd Zd Z	dd	Z
edd
       Z G d de      Zy)SpanNearap  
    Note: for new code, use :class:`SpanNear2` instead of this class. SpanNear2
    takes a list of sub-queries instead of requiring you to create a binary
    tree of query objects.

    Matches queries that occur near each other. By default, only matches
    queries that occur right next to each other (slop=1) and in order
    (ordered=True).

    For example, to find documents where "whoosh" occurs next to "library"
    in the "text" field::

        from whoosh import query, spans
        t1 = query.Term("text", "whoosh")
        t2 = query.Term("text", "library")
        q = spans.SpanNear(t1, t2)

    To find documents where "whoosh" occurs at most 5 positions before
    "library"::

        q = spans.SpanNear(t1, t2, slop=5)

    To find documents where "whoosh" occurs at most 5 positions before or after
    "library"::

        q = spans.SpanNear(t1, t2, slop=5, ordered=False)

    You can use the ``phrase()`` class method to create a tree of SpanNear
    queries to match a list of terms::

        q = spans.SpanNear.phrase("text", ["whoosh", "search", "library"],
                                  slop=2)
    c                 n    t        ||g      | _        || _        || _        || _        || _        || _        y)a  
        :param a: the first query to match.
        :param b: the second query that must occur within "slop" positions of
            the first query.
        :param slop: the number of positions within which the queries must
            occur. Default is 1, meaning the queries must occur right next
            to each other.
        :param ordered: whether a must occur before b. Default is True.
        :pram mindist: the minimum distance allowed between the queries.
        N)r   r   r}   r~   sloporderedmindist)r   r}   r~   r   r   r   s         r   r   zSpanNear.__init__y  s6     aV	r   c                     d| j                   j                  | j                  | j                  | j                  | j
                  fz  S Nz'%s(%r, slop=%d, ordered=%s, mindist=%d))r=   rO   r   r   r   r   r   s    r   r   zSpanNear.__repr__  s:    9>>**DFFDIIt||<<!! 	"r   c                    |xr | j                   |j                   k(  xrj | j                  |j                  k(  xrO | j                  |j                  k(  xr4 | j                  |j                  k(  xr | j                  |j                  k(  S r   )r=   r   r   r   r   r   s     r   r    zSpanNear.__eq__  st     2$..EOO; 2FFegg%2*.))uzz*A2LLEMM12 LLEMM1	3r   c                     t        | j                        t        | j                        z  t        | j                        z  t        | j                        z  t        | j
                        z  S r   )r+   r}   r~   r   r   r   r   s    r   r,   zSpanNear.__hash__  sN    TVVtDFF|+d499o=t||$%'+DLL'9: 	;r   c                      yr   rT   r   s    r   r   zSpanNear.is_leaf  r   r   c                     | j                   || j                         || j                        | j                  | j                  | j
                        S N)r   r   r   )r=   r}   r~   r   r   r   r   s     r   r   zSpanNear.apply  sA    ~~bj"TVV*499&*llDLL  J 	Jr   Nc                     | j                   j                  ||      }| j                  j                  ||      }t        j	                  ||| j
                  | j                  | j                        S r   )r}   r   r~   r   SpanNearMatcherr   r   r   r   r   r   mambs        r   r   zSpanNear.matcher  sZ    VV^^Hg.VV^^Hg.''BTYY0404 ( > 	>r   c                 \    |D cg c]  }t        ||       }}t        | |||      S c c}w )a  Returns a tree of SpanNear queries to match a list of terms.

        This class method is a convenience for constructing a phrase query
        using a binary tree of SpanNear queries::

            SpanNear.phrase("content", ["alfa", "bravo", "charlie", "delta"])

        :param fieldname: the name of the field to search in.
        :param words: a sequence of texts to search for.
        :param slop: the number of positions within which the terms must
            occur. Default is 1, meaning the terms must occur right next
            to each other.
        :param ordered: whether the terms must occur in order. Default is True.
        )r   r   )r
   r   )r3   	fieldnamewordsr   r   wordtermss          r   phrasezSpanNear.phrase  s4    " 4994i&99UwGG :s   )c                   4     e Zd Zd fd	Zd ZddZd Z xZS )SpanNear.SpanNearMatcherc                     || _         || _        || _        || _        || _        t        j                  ||      }t        t        j                  | +  |       y r   )r}   r~   r   r   r   r   IntersectionMatcherr^   r   r   r   )r   r}   r~   r   r   r   isectr=   s          r   r   z!SpanNear.SpanNearMatcher.__init__  sM    DFDFDI"DL"DL..q!4E(**D:5Ar   c                     | j                  | j                  j                         | j                  j                         | j                  | j
                  | j                        S r   )r=   r}   rd   r~   r   r   r   r   s    r   rd   zSpanNear.SpanNearMatcher.copy  sE    >>$&&++-TYY*.,, " N Nr   c                 N    | j                         st        j                         S | S r   r   r   s     r   r   z SpanNear.SpanNearMatcher.replace       >>#((**Kr   c                     | j                   }| j                  }| j                  }t               }| j                  j                         }| j                  j                         D ]  }|D ]  }|j                  |j                  |z
  k  s|r|j                  |j                  kD  r;|j                  |j                  |z   kD  r ^|j                  |      }||cxk  r|k  svn y|j                  |j                  |               t        |      S r   )r   r   r   setr~   r4   r}   r   r   rN   addr2   sorted)	r   r   r   r   r4   bspansaspanbspandists	            r   rn   z#SpanNear.SpanNearMatcher._get_spans  s    99DllGllGEEVV\\^F 3# 3E		EKK$$66#ekk(A !{{UYY%55  !,,U3D$.$.		%((5/233$ %= r   r.   Tr.   r   rO   rP   rQ   r   rd   r   rn   ry   rh   s   @r   r   r     s    	B	N		!r   r   r   r   )r.   T)rO   rP   rQ   rx   r   r   r    r,   r   r   r   rS   r   r\   r   rT   r   r   r   r   V  sO     D&"
3;J> H H&-!- -!r   r   c                   l    e Zd ZdZddZd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd ZddZ G d de      Zy)	SpanNear2a  
    Matches queries that occur near each other. By default, only matches
    queries that occur right next to each other (slop=1) and in order
    (ordered=True).

    New code should use this query type instead of :class:`SpanNear`.

    (Unlike :class:`SpanNear`, this query takes a list of subqueries instead of
    requiring you to build a binary tree of query objects. This query should
    also be slightly faster due to less overhead.)

    For example, to find documents where "whoosh" occurs next to "library"
    in the "text" field::

        from whoosh import query, spans
        t1 = query.Term("text", "whoosh")
        t2 = query.Term("text", "library")
        q = spans.SpanNear2([t1, t2])

    To find documents where "whoosh" occurs at most 5 positions before
    "library"::

        q = spans.SpanNear2([t1, t2], slop=5)

    To find documents where "whoosh" occurs at most 5 positions before or after
    "library"::

        q = spans.SpanNear2(t1, t2, slop=5, ordered=False)
    c                 <    || _         || _        || _        || _        y)a  
        :param qs: a sequence of sub-queries to match.
        :param slop: the number of positions within which the queries must
            occur. Default is 1, meaning the queries must occur right next
            to each other.
        :param ordered: whether a must occur before b. Default is True.
        :pram mindist: the minimum distance allowed between the queries.
        N)qsr   r   r   )r   r   r   r   r   s        r   r   zSpanNear2.__init__  s      	r   c                     d| j                   j                  | j                  | j                  | j                  | j
                  fz  S r   )r=   rO   r   r   r   r   r   s    r   r   zSpanNear2.__repr__  s:    9>>**DGGTYY<<!! 	"r   c                    |xr | j                   |j                   k(  xrj | j                  |j                  k(  xrO | j                  |j                  k(  xr4 | j                  |j                  k(  xr | j                  |j                  k(  S r   r=   r   r   r   r   r   s     r   r    zSpanNear2.__eq__   st     2$..EOO; 2GGuxx'2,0II,C2LLEMM12 LLEMM1	3r   c                     t        | j                        t        | j                        z  t        | j                        z  }| j                  D ]  }|t        |      z  } |S r   )r+   r   r   r   r   )r   hr   s      r   r,   zSpanNear2.__hash__&  sP    Od4<<0043EE 	AaLA	r   c                 @    t         j                  | j                        S r   )r   r   r   r   s    r   
_and_queryzSpanNear2._and_query,  s    uuTWW~r   c                 @    | j                         j                  |      S r   )r   estimate_sizer   ixreaders     r   r   zSpanNear2.estimate_size/  s     ..x88r   c                 @    | j                         j                  |      S r   )r   estimate_min_sizer   s     r   r   zSpanNear2.estimate_min_size2  s     228<<r   c                      yr   rT   r   s    r   r   zSpanNear2.is_leaf5  r   r   c                     | j                   S r   )r   r   s    r   childrenzSpanNear2.children8  s    wwr   c                     | j                  | j                  D cg c]
  } ||       c}| j                  | j                  | j                        S c c}w r   r   )r   r   r   s      r   r   zSpanNear2.apply;  sE    ~~dgg6r!u6TYY&*llDLL  J 	J6s   ANc                     | j                   D cg c]  }|j                  ||       }}| j                  || j                  | j                  | j
                        S c c}w r   )r   r   SpanNear2Matcherr   r   r   )r   r   r   r   mss        r   r   zSpanNear2.matcher?  sV    48GG<qaii'*<<$$Rdii-1\\ % ; 	; =s   Ac                   4     e Zd Zd fd	Zd ZddZd Z xZS )SpanNear2.SpanNear2Matcherc                     || _         || _        || _        || _        t	        t
        j                  |      }t        t        j                  | +  |       y r   )r   r   r   r   r   r   r   r^   r   r   r   )r   r   r   r   r   r   r=   s         r   r   z#SpanNear2.SpanNear2Matcher.__init__E  sF    DGDI"DL"DL$V%?%?DE),,d<UCr   c                     | j                  | j                  D cg c]  }|j                          c}| j                  | j                  | j
                        S c c}w r   )r=   r   rd   r   r   r   re   s     r   rd   zSpanNear2.SpanNear2Matcher.copyM  sG    >>TWW"=1668"=DII*.,, " N N"=s   Ac                 N    | j                         st        j                         S | S r   r   r   s     r   r   z"SpanNear2.SpanNear2Matcher.replaceQ  r   r   c                 @   | j                   }| j                  }| j                  }| j                  }|d   j	                         }d}|t        |      k  r9|r6||   j	                         }t               }|D ]  }	|r|	j                  }
nt        d|	j                  |z
        }
t        ||
      }|t        |      k  sF||   }|dz  }|j                  |	j                  |z
  k  s|r|	j                  |j                  kD  rQ|j                  |	j                  |z   kD  r|	j                  |      }||cxk  r|k  r#n n |j                  |	j                  |             |t        |      k  r t        |      }|dz  }|t        |      k  r|r6|t        |      k(  r|S g S )Nr   r.   )r   r   r   r   r4   r/   r   r   r<   rZ   r   rN   r   r2   r   )r   r   r   r   r   aspansr5   r   r4   r   r   r7   r   r   s                 r   rn   z%SpanNear2.SpanNear2Matcher._get_spansW  sz   99DllGllGBU[[]FAc"g+&A# 7E  % #Au{{T'9 :$VU3Ac&k/ &q	Q!IId(:: 'EKK%++,E % ;;T)99 "  %007"d2d2!IIehhuo6% c&k/78  QA c"g+&D CG|	r   r   r   r   rh   s   @r   r   r   D  s    	D	N	-	r   r   r   r   )rO   rP   rQ   rx   r   r   r    r,   r   r   r   r   r   r   r   r\   r   rT   r   r   r   r     sN    <"
39=J;
@. @r   r   c                   @    e Zd ZdZd Zd Zd Zd	dZ G d de      Z	y)
SpanOrzMatches documents that match any of a list of sub-queries. Unlike
    query.Or, this class merges together matching spans from the different
    sub-queries when they overlap.
    c                 2    t        |      | _        || _        y)z;
        :param subqs: a list of queries to match.
        N)r	   r   subqs)r   r  s     r   r   zSpanOr.__init__  s    
 E
r   c                      yr   rT   r   s    r   r   zSpanOr.is_leaf  r   r   c                 j    | j                  | j                  D cg c]
  } ||       c}      S c c}w r   )r=   r  )r   r   sqs      r   r   zSpanOr.apply  s'    ~~

;"r"v;<<;s   0Nc                     | j                   D cg c]  }|j                  ||       }}t        t        j                  |      S c c}w r   )r  r   r   r  SpanOrMatcher)r   r   r   r   matcherss        r   r   zSpanOr.matcher  s=    :>**EQAIIh0EE 4 4h?? Fs   Ac                   $     e Zd Z fdZd Z xZS )SpanOr.SpanOrMatcherc                     || _         || _        t        j                  ||      }t        t
        j                  |   |       y r   )r}   r~   r   UnionMatcherr^   r  r	  r   )r   r}   r~   umr=   s       r   r   zSpanOr.SpanOrMatcher.__init__  s8    DFDF$$Q*B&&&6r:r   c                    | j                   j                         }| j                  j                         }|r| j                   j                         }|r| j                  j                         }||k(  rQt	        t        | j                   j                               t        | j                  j                               z        }np||k  r| j                   j                         }nP| j                  j                         }n5| j                   j                         }n| j                  j                         }t        j                  |       |S r   )	r}   r`   r~   ru   r   r   r4   r   r9   )r   a_activeb_activea_idb_idr4   s         r   rn   zSpanOr.SpanOrMatcher._get_spans  s    vv'')Hvv'')Hvvyy{6699;Dt| &s466<<>':),TVV\\^)<(= !> $ $ FFLLNEJJuLr   rO   rP   rQ   r   rn   ry   rh   s   @r   r	  r    s    	;	r   r	  r   )
rO   rP   rQ   rx   r   r   r   r   r{   r	  rT   r   r   r  r    s(    
=@ r   r  c                        e Zd Zd Zd ZddZy)SpanBiQueryc                      yr   rT   r   s    r   r   zSpanBiQuery.is_leaf  r   r   c                 f    | j                   || j                         || j                              S r   )r=   r}   r~   r   s     r   r   zSpanBiQuery.apply  s#    ~~bj"TVV*55r   Nc                     | j                   j                  ||      }| j                  j                  ||      }| j                  ||      S r   )r}   r   r~   _Matcherr   s        r   r   zSpanBiQuery.matcher  s;    VV^^Hg.VV^^Hg.}}R$$r   r   )rO   rP   rQ   r   r   r   rT   r   r   r  r    s    6%r   r  c                   ,    e Zd ZdZd Z G d de      Zy)SpanNota)  Matches spans from the first query only if they don't overlap with
    spans from the second query. If there are no non-overlapping spans, the
    document does not match.

    For example, to match documents that contain "bear" at most 2 places after
    "apple" in the "text" field but don't have "cute" between them::

        from whoosh import query, spans
        t1 = query.Term("text", "apple")
        t2 = query.Term("text", "bear")
        near = spans.SpanNear(t1, t2, slop=2)
        q = spans.SpanNot(near, query.Term("text", "cute"))
    c                 B    t        ||      | _        || _        || _        y)z
        :param a: the query to match.
        :param b: do not match any spans that overlap with spans from this
            query.
        N)r   r   r}   r~   r   r}   r~   s      r   r   zSpanNot.__init__  s     !Qr   c                   $     e Zd Z fdZd Z xZS )SpanNot._Matcherc                     || _         || _        t        j                  ||      }t        t
        j                  |   |       y r   )r}   r~   r   AndMaybeMatcherr^   r  r  r   )r   r}   r~   ammr=   s       r   r   zSpanNot._Matcher.__init__  s8    DFDF((A.C'""D237r   c                 ~   | j                   j                         | j                  j                         k(  rog }| j                  j                         }| j                   j                         D ]4  }d}|D ]  }|j	                  |      sd} n |r$|j                  |       6 |S | j                   j                         S rm   )r}   ru   r~   r4   r1   append)r   r4   r   r   
overlappedr   s         r   rn   zSpanNot._Matcher._get_spans  s    vvyy{dffiik)!VV\\^ ,E!&J!' " >>%0)-J!" &U+, vv||~%r   r  rh   s   @r   r  r!    s    	8	&r   r  NrO   rP   rQ   rx   r   r{   r  rT   r   r   r  r    s    	&= &r   r  c                   ,    e Zd ZdZd Z G d de      Zy)SpanContainsa  Matches documents where the spans of the first query contain any spans
    of the second query.

    For example, to match documents where "apple" occurs at most 10 places
    before "bear" in the "text" field and "cute" is between them::

        from whoosh import query, spans
        t1 = query.Term("text", "apple")
        t2 = query.Term("text", "bear")
        near = spans.SpanNear(t1, t2, slop=10)
        q = spans.SpanContains(near, query.Term("text", "cute"))
    c                 D    t        ||g      | _        || _        || _        y)z
        :param a: the query to match.
        :param b: the query whose spans must occur within the matching spans
            of the first query.
        N)r   r   r}   r~   r  s      r   r   zSpanContains.__init__  s!     aVr   c                   $     e Zd Z fdZd Z xZS )SpanContains._Matcherc                     || _         || _        t        j                  ||      }t        t
        j                  |   |       y r   )r}   r~   r   r   r^   r*  r  r   r   r}   r~   imr=   s       r   r   zSpanContains._Matcher.__init__  s8    DFDF++Aq1B,''7;r   c                 <   g }| j                   j                         }| j                  j                         D ]b  }|D ][  }|j                  |j                  kD  r|j                  |j                  k  r =|j                  |      sJ|j                  |        b d |S r   )r~   r4   r}   r   r   rF   r&  )r   r4   r   r   r   s        r   rn   z SpanContains._Matcher._get_spans  s    EVV\\^F 	# E{{UYY. yy5;;.u-U+	 Lr   r  rh   s   @r   r  r-    s    	<	r   r  Nr(  rT   r   r   r*  r*    s    	= r   r*  c                   ,    e Zd ZdZd Z G d de      Zy)
SpanBeforea_  Matches documents where the spans of the first query occur before any
    spans of the second query.

    For example, to match documents where "apple" occurs anywhere before
    "bear"::

        from whoosh import query, spans
        t1 = query.Term("text", "apple")
        t2 = query.Term("text", "bear")
        q = spans.SpanBefore(t1, t2)
    c                 D    || _         || _        t        ||g      | _        y)z
        :param a: the query that must occur before the second.
        :param b: the query that must occur after the first.
        Nr}   r~   r   r   r  s      r   r   zSpanBefore.__init__<  s!     aVr   c                   $     e Zd Z fdZd Z xZS )SpanBefore._Matcherc                     || _         || _        t        j                  ||      }t        t
        j                  |   |       y r   )r}   r~   r   r   r^   r3  r  r   r/  s       r   r   zSpanBefore._Matcher.__init__G  s8    DFDF++Aq1B*%%t5b9r   c                     t        d | j                  j                         D              }| j                  j                         D cg c]  }|j                  |k  s| c}S c c}w )Nc              3   4   K   | ]  }|j                     y wr   r%   ).0r   s     r   	<genexpr>z1SpanBefore._Matcher._get_spans.<locals>.<genexpr>N  s     DEEKKDs   )r;   r~   r4   r}   r   )r   	bminstartr   s      r   rn   zSpanBefore._Matcher._get_spansM  sE    DTVV\\^DDI'+vv||~OeY9NEOOOs   A#A#r  rh   s   @r   r  r7  F  s    	:	Pr   r  Nr(  rT   r   r   r3  r3  /  s    
	P= 	Pr   r3  c                   ,    e Zd ZdZd Z G d de      Zy)SpanConditiona  Matches documents that satisfy both subqueries, but only uses the spans
    from the first subquery.

    This is useful when you want to place conditions on matches but not have
    those conditions affect the spans returned.

    For example, to get spans for the term ``alfa`` in documents that also
    must contain the term ``bravo``::

        SpanCondition(Term("text", u"alfa"), Term("text", u"bravo"))

    c                 D    || _         || _        t        ||g      | _        y r   r5  r  s      r   r   zSpanCondition.__init__`  s    aVr   c                   $     e Zd Z fdZd Z xZS )SpanCondition._Matcherc                 z    || _         t        j                  ||      }t        t        j
                  |   |       y r   )r}   r   r   r^   r?  r  r   r/  s       r   r   zSpanCondition._Matcher.__init__f  s1    DF++Aq1B-(($8<r   c                 6    | j                   j                         S r   )r}   r4   r   s    r   rn   z!SpanCondition._Matcher._get_spansk  s    66<<>!r   r  rh   s   @r   r  rB  e  s    	=
	"r   r  Nr(  rT   r   r   r?  r?  R  s    
"= "r   r?  N)rx   whoosh.matchingr   r   r   whoosh.queryr   r   r   r	   r
   whoosh.utilr   objectr   rZ   WrappingMatcherr\   r{   r   r   r   r   r   r  r  r  r*  r3  r?  rT   r   r   <module>rJ     s   8$ 4 3 7 7 (
q)6 q)h	7(22 7t'   >9 (/ (/VT!y T!nW	 Wt4Y 4n%) %/&k /&d-; -` P  PF"K "r   