a
    Dg                     @   s  d dl 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mZ ddlmZmZmZ e Zefd	d
Zeee jZeee jZeee jZeee jZdZedZdd Zdd Z defddZ!dd Z"dd Z#dd Z$dd Z%dd Z&dd Z'dS )    N)partial)apps)connections)	QueryDict)RelatedFieldsSearchField   )
MATCH_NONEPhrase	PlainTextc                 C   s   t |tst|}|tur:t|dkr*|S | |t| |S t|dkrPtdnNt|dkrd|d S t|d }t| |d| }t| ||d }| ||S dS )aD  
    Has the same result as Python's reduce function, but performs the calculations in a different order.

    This is important when the operator is constructing data structures such as search query classes.
    This method will make the resulting data structures flatter, so operations that need to traverse
    them don't end up crashing with recursion errors.

    For example:

    Python's builtin reduce() function will do the following calculation:

    reduce(add, [1, 2, 3, 4, 5, 6, 7, 8])
    (1 + (2 + (3 + (4 + (5 + (6 + (7 + 8)))))))

    When using this with query classes, it would create a large data structure with a depth of 7
    Whereas balanced_reduce will execute this like so:

    balanced_reduce(add, [1, 2, 3, 4, 5, 6, 7, 8])
    ((1 + 2) + (3 + 4)) + ((5 + 6) + (7 + 8))

    Which only has a depth of 2
    r   z0reduce() of empty sequence with no initial valuer      N)
isinstancelistNOT_SETlenbalanced_reduce	TypeError)operatorseqZinitializerZbreak_pointZ	first_setZ
second_set r   S/var/www/lab.imftr.de/x/nb_venv/lib/python3.9/site-packages/wagtail/search/utils.pyr      s    

r      z \b(\w+):(\w+|"[^"]+"|\'[^\']+\')c                 C   s*   | d t  } |  } tdd|  } | S )Nz + )MAX_QUERY_STRING_LENGTHlowerresubstrip)query_stringr   r   r   normalise_query_stringK   s    r   c                 C   sR   t dd}t| D ]$}| \}}|||di qtd|  } || fS )NT)Zmutablez"' )r   filters_regexpfinditergroupsupdater   r   )r   filtersZmatch_objectkeyvaluer   r   r   separate_filters_from_queryW   s    
r(   c           	      C   s   t | \}} d}g }d| v r(| d}n
| d}|D ]B}| }|rr|rZ|t| n|t||pjtjd | }q6|r|dkrt|}qt|}n|}||fS )aT  
    This takes a query string typed in by a user and extracts the following:

     - Quoted terms (for phrase search)
     - Filters

    For example, the following query:

      `hello "this is a phrase" live:true` would be parsed into:

    filters: {'live': 'true'}
    tokens: And([PlainText('hello'), Phrase('this is a phrase')])
    F"')r   or)	r(   splitr   appendr
   r   ZDEFAULT_OPERATORORAND)	r   r   Z
zero_termsr%   Z	is_phrasetokenspartspartZsearch_queryr   r   r   parse_query_stringb   s*    


r3   c                    s$    fddt  D }|  |S )zI
    Returns all descendants of a model, including the model itself.
    c                    s   h | ]}t | r|qS r   )
issubclass).0Zother_modelmodelr   r   	<setcomp>   s   
z(get_descendant_models.<locals>.<setcomp>)r   Z
get_modelsadd)r7   Zdescendant_modelsr   r6   r   get_descendant_models   s
    

r:   c                 C   s   ddl m} |j| jS )Nr   ContentType)"django.contrib.contenttypes.modelsr<   objectsZget_for_modelpkr7   r<   r   r   r   get_content_type_pk   s    rA   c                 C   s,   ddl m} dd |jj| j   D S )zR
    Returns content types ids for the ancestors of this model, excluding it.
    r   r;   c                 S   s   g | ]
}|j qS r   r?   r5   ctr   r   r   
<listcomp>   s   z3get_ancestors_content_types_pks.<locals>.<listcomp>)r=   r<   r>   get_for_modelsZ_metaZget_parent_listvaluesr@   r   r   r   get_ancestors_content_types_pks   s    rH   c                 C   s*   ddl m} dd |jjt|   D S )zT
    Returns content types ids for the descendants of this model, including it.
    r   r;   c                 S   s   g | ]
}|j qS r   rB   rC   r   r   r   rE      s   z5get_descendants_content_types_pks.<locals>.<listcomp>)r=   r<   r>   rF   r:   rG   r@   r   r   r   !get_descendants_content_types_pks   s    rI   c                 c   s:   | D ]0}t |tr|V  qt |trt|jE d H  qd S )N)r   r   r   get_search_fieldsfields)Zsearch_fieldsZsearch_fieldr   r   r   rJ      s
    

rJ   c                   C   s   dd t  D S )Nc                 S   s   g | ]}|j d kr|qS )Z
postgresql)vendor)r5   
connectionr   r   r   rE      s   
z.get_postgresql_connections.<locals>.<listcomp>)r   allr   r   r   r   get_postgresql_connections   s    rO   )(r   r   	functoolsr   Zdjango.appsr   Z	django.dbr   Zdjango.httpr   Zwagtail.search.indexr   r   queryr	   r
   r   objectr   r   or_r.   and_r/   r9   ZADDmulZMULr   compiler!   r   r(   r3   r:   rA   rH   rI   rJ   rO   r   r   r   r   <module>   s0   .
/