o
    h`                     @   s  d dl 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mZmZ d dlmZmZmZmZmZmZmZ d dlmZ d dlmZ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$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z: ddl(m;Z; ddl<m=Z=m>Z> eede dZ?G dd dZ@G dd dZAG dd de8ZBG dd deBZCG d d! d!e9ZDG d"d# d#ZEG d$d% d%eEZFG d&d' d'e7ZGeGZHdS )(    N)OrderedDict)reduce)SearchQuery
SearchRankSearchVector)NotSupportedErrorconnectionsroutertransaction)AvgCountFManagerQ	TextFieldValue)
LOOKUP_SEP)CastLength)InsertQuery)	force_str)cached_property   )AutocompleteFieldRelatedFieldsSearchFieldget_indexed_models)
IndexEntry)AndBoostMatchAllNotOrPhrase	PlainText)ADDMULORget_content_type_pk!get_descendants_content_types_pks   )BaseSearchBackendBaseSearchQueryCompilerBaseSearchResultsFilterFieldError   )Lexeme)get_sql_weights
get_weight output_fieldc                   @   sb   e Zd ZdZdd Zdd Zdd Zdd	d
Zedd Z	edd Z
edd Zedd ZdS )ObjectIndexerzW
    Responsible for extracting data from an object to be inserted into the index.
    c                 C   s$   || _ | | _|j| _|j| _d S N)objget_search_fieldssearch_fieldsconfigautocomplete_config)selfr8   backend r?   r/var/www/html/ndineBlogger/venv/lib/python3.10/site-packages/wagtail/search/backends/database/postgres/postgres.py__init__.   s   
zObjectIndexer.__init__c                    s^   t |tr|S t |trd fdd|D S t |tr+d fdd| D S t|S )N, c                 3       | ]}  |V  qd S r7   prepare_value.0itemr=   r?   r@   	<genexpr>9       z.ObjectIndexer.prepare_value.<locals>.<genexpr>c                 3   rC   r7   rD   rF   rI   r?   r@   rJ   <   rK   )
isinstancestrlistjoindictvaluesr   )r=   valuer?   rI   r@   rE   4   s   


zObjectIndexer.prepare_valuec                 c   s    t |tr|t|j| ||fV  d S t |tr*|d| ||fV  d S t |trb||}|d u r:d S t |trD|	 }n
t
|rK| }|g}|D ]}|jD ]}| ||E d H  qUqPd S d S )ND)rL   r   r2   boostrE   	get_valuer   r   r   allcallablefieldsprepare_field)r=   r8   fieldsub_objsub_objs	sub_fieldr?   r?   r@   rY   @   s.   







zObjectIndexer.prepare_fieldFc                    sJ   dd |D }dd |D }|st S |r| jn| j t fdd|D S )zW
        Converts an array of strings into a SearchVector that can be indexed.
        c                 S   s   g | ]
\}}|  |fqS r?   )striprG   textweightr?   r?   r@   
<listcomp>b       z+ObjectIndexer.as_vector.<locals>.<listcomp>c                 S   s   g | ]
\}}|r||fqS r?   r?   r_   r?   r?   r@   rb   c   rc   c                    s(   g | ]\}}t t|t d | dqS )r4   )ra   r;   )r   r   r   r_   search_configr?   r@   rb   k   s    )EMPTY_VECTORr<   r;   r%   )r=   textsfor_autocompleter?   rd   r@   	as_vector^   s   
zObjectIndexer.as_vectorc                 C   s   t | jjS )zO
        Returns the value to use as the ID of the record in the index
        )r   r8   pkrI   r?   r?   r@   idu   s   zObjectIndexer.idc                 C   sV   g }| j D ] }| | j|D ]\}}}t|tr$|jdkr$|||f qq| |S )z
        Returns all values to index as "title". This is the value of all SearchFields that have the field_name 'title'
        titler:   rY   r8   rL   r   
field_nameappendri   r=   rg   rZ   current_fieldrT   rR   r?   r?   r@   rl   |      


zObjectIndexer.titlec                 C   sV   g }| j D ] }| | j|D ]\}}}t|tr$|jdks$|||f qq| |S )zr
        Returns all values to index as "body". This is the value of all SearchFields excluding the title
        rl   rm   rp   r?   r?   r@   body   rr   zObjectIndexer.bodyc                 C   sP   g }| j D ]}| | j|D ]\}}}t|tr|||f qq| j|ddS )zl
        Returns all values to index as "autocomplete". This is the value of all AutocompleteFields
        T)rh   )r:   rY   r8   rL   r   ro   ri   rp   r?   r?   r@   autocomplete   s   

zObjectIndexer.autocompleteNF)__name__
__module____qualname____doc__rA   rE   rY   ri   r   rk   rl   rs   rt   r?   r?   r?   r@   r6   )   s    



r6   c                   @   s^   e Zd Zdd Zdd Zdd Zddd	Zd
d Zdd Zdd Z	dd Z
dd Zdd ZdS )Indexc                 C   s`   || _ | j j| _ttt | _ttt | _	| jj
dks$| j	j
dkr(tdtj | _d S )N
postgresqlz?You must select a PostgreSQL database to use PostgreSQL search.)r>   
index_namenamer   r	   db_for_readr   read_connectiondb_for_writewrite_connectionvendorr   _default_managerrV   entriesr=   r>   r?   r?   r@   rA      s   
zIndex.__init__c                 C      d S r7   r?   r=   modelr?   r?   r@   	add_model      zIndex.add_modelc                 C   r   r7   r?   rI   r?   r?   r@   refresh   r   zIndex.refreshFc                 C   sn   | j jtddjddtdd }|r| j }n| j jdd}|jtddjddj|td d d	S )
a  
        Refreshes the value of the title_norm field.

        This needs to be set to 'lavg/ld' where:
         - lavg is the average length of titles in all documents (also in terms)
         - ld is the length of the title field in this document (in terms)
        rl   )title_lengthr   )title_length__gtr   title_length__avg      ?)
title_normN)r   annotater   filter	aggregater   updater   )r=   fulllavgr   r?   r?   r@   _refresh_title_norms   s   

zIndex._refresh_title_normsc                 C   sF   |j jtdt dd}t|}| jj|dj|d}|	  d S )Nrj   )	object_idr   )content_type_id__in)object_id__in)
r   r   r   r   rQ   r)   r   r   excludedelete)r=   r   existing_pkscontent_types_pksstale_entriesr?   r?   r@   delete_stale_model_entries   s   
z Index.delete_stale_model_entriesc                 C   s"   t  D ]}|jjs| | qd S r7   )r   _metaparentsr   r   r?   r?   r@   delete_stale_entries   s
   

zIndex.delete_stale_entriesc                 C   s   |  |jj|g d S r7   )	add_itemsr   r   r=   r8   r?   r?   r@   add_item   s   zIndex.add_itemc                    s  |  }|sd S  fdd|D }|sd S t|}ttj jd}g }g }g }	g }
|D ]d}|
||jf |tj	
d|j}|| j\}}|| |
| |tj	
d|j}|| j\}}|| |
| |tj	
d|j}|| j\}}|	| |
| q,ddd t|||	D } j }|d	tj	j|f |
 W d    n1 sw   Y     d S )
Nc                    s   g | ]}t | jqS r?   )r6   r>   )rG   r8   rI   r?   r@   rb      s    z#Index.add_items.<locals>.<listcomp>)
connectionrl   rt   rs   rB   c              	   S   s*   g | ]\}}}d | d| d| dqS )z	(%s, %s, rB   z, 1.0)r?   )rG   abcr?   r?   r@   rb   %  s    a  
                INSERT INTO %s (content_type_id, object_id, title, autocomplete, body, title_norm)
                (VALUES %s)
                ON CONFLICT (content_type_id, object_id)
                DO UPDATE SET title = EXCLUDED.title,
                              title_norm = 1.0,
                              autocomplete = EXCLUDED.autocomplete,
                              body = EXCLUDED.body
                )r9   r(   r   r   get_compilerr   extendrk   rE   r   	get_fieldrl   as_sqlro   rt   rs   rO   zipcursorexecutedb_tabler   )r=   r   objsr:   indexerscontent_type_pkcompiler	title_sqlautocomplete_sqlbody_sqldata_paramsindexerrR   sqlparamsdata_sqlr   r?   rI   r@   r      s`   






	
zIndex.add_itemsc                 C   s   |j  j| jjd d S )Nusing)index_entriesrV   _raw_deleter   alias)r=   rH   r?   r?   r@   delete_item<  s   zIndex.delete_itemc                 C   s   | j S r7   )r}   rI   r?   r?   r@   __str__?     zIndex.__str__Nru   )rv   rw   rx   rA   r   r   r   r   r   r   r   r   r   r?   r?   r?   r@   rz      s    

Grz   c                       s   e Zd ZdZdZeZ fddZdd Zdd Z	d#d
dZ
d$ddZd#ddZd%ddZdd Zdd Zdd Zdd Zd#ddZdd Zdd  Zd!d" Z  ZS )&PostgresSearchQueryCompilerandFc                    sR   t  j|i |   t _jd u r _d S  fddjD _d S )Nc                    s   i | ]
}|j | d qS ))rX   )get_search_field)rG   field_lookuplocal_search_fieldsr=   r?   r@   
<dictcomp>W  s    z8PostgresSearchQueryCompiler.__init__.<locals>.<dictcomp>)superrA   get_search_fields_for_modelr1   sql_weightsrX   r:   )r=   argskwargs	__class__r   r@   rA   H  s   

z$PostgresSearchQueryCompiler.__init__c                 C      |j S r7   r;   r   r?   r?   r@   
get_config^  r   z&PostgresSearchQueryCompiler.get_configc                 C      | j j S r7   )querysetr   get_searchable_search_fieldsrI   r?   r?   r@   r   a     z7PostgresSearchQueryCompiler.get_search_fields_for_modelNc                 C   s~   |d u r| j }t|v r|td\}}nd }|D ]$}t|| jr)|j|kr)|  S t|tr<|j|kr<| ||j  S qd S )Nr/   )	r:   r   splitrL   TARGET_SEARCH_FIELD_TYPErn   r   r   rX   )r=   r   rX   sub_field_namerZ   r?   r?   r@   r   d  s   

z,PostgresSearchQueryCompiler.get_search_fieldc                    sB  t |tr:|j }|sd S | }t|jd}|D ]}t|d}|jdkr.||M }q||O }qt|d dS t |t	rGt|jd dS t |t
r]d}	t|	t j|j dS t |trlj|j  dS t |ttfr fd	d
|jD }
t |t}r| }|rtdd |
S tdd |
S td|jj )N)invertprefix)r   r   raw)search_typer;   phrasezBThe Boost query is not supported by the PostgreSQL search backend.r;   r   c                    s   g | ]
}j | d qS )r   build_tsquery_contentrG   subqueryr;   r   r=   r?   r@   rb     s    zEPostgresSearchQueryCompiler.build_tsquery_content.<locals>.<listcomp>c                 S   s   | |@ S r7   r?   r   r   r?   r?   r@   <lambda>      zCPostgresSearchQueryCompiler.build_tsquery_content.<locals>.<lambda>c                 S   s   | |B S r7   r?   r   r?   r?   r@   r     r   7`%s` is not supported by the PostgreSQL search backend.)rL   r$   query_stringr   popr0   LAST_TERM_IS_PREFIXoperatorr   r#   r   warningswarnRuntimeWarningr   r   r!   r   r"   
subqueriesr   NotImplementedErrorr   rv   )r=   queryr;   r   terms	last_termlexemesterm
new_lexememsgsubquery_lexemesis_andr?   r   r@   r   z  sN   









z1PostgresSearchQueryCompiler.build_tsquery_contentc                 C   s   | j ||dS )Nr   r   )r=   r   r;   r?   r?   r@   build_tsquery     z)PostgresSearchQueryCompiler.build_tsqueryr   c                    s   t |tttfrtj|djd} dkr| 9 }|S t |tr3 |j9  j	|j
 dS t |trIt fdd|jD d S t |trdt fdd|jD t|jpbd S td	|jj )
Nr   )weightsr   r;   rT   c                 3   s&    | ]}d j | d V  qdS )r/   r  Nbuild_tsrankr   rT   r;   r=   vectorr?   r@   rJ     s
    
z;PostgresSearchQueryCompiler.build_tsrank.<locals>.<genexpr>r/   c                 3   s"    | ]}j | d V  qdS )r  Nr  r   r  r?   r@   rJ     s
    
r   )rL   r#   r$   r!   r   r   r   r   rT   r  r   r   r&   r   r"   r%   lenr   r   rv   )r=   r  r   r;   rT   rank_expressionr?   r  r@   r    s<   



z(PostgresSearchQueryCompiler.build_tsrankc                 C   s   t dt dft ddfgS )Nindex_entries__titleindex_entries__title_normindex_entries__bodyr   r   r=   search_queryr?   r?   r@   get_index_vectors  s   
z-PostgresSearchQueryCompiler.get_index_vectorsc                        fdd| j  D S )Nc                    s$   g | ]\}}t | jd |jfqS r   )r   r;   rT   rG   r   search_fieldr  r?   r@   rb     s    zBPostgresSearchQueryCompiler.get_fields_vectors.<locals>.<listcomp>r:   itemsr  r?   r  r@   get_fields_vectors  s   
z.PostgresSearchQueryCompiler.get_fields_vectorsc                 C   s   | j d u r
| |S | |S r7   )rX   r  r  r  r?   r?   r@   get_search_vectors  s   


z.PostgresSearchQueryCompiler.get_search_vectorsc                    s:    fdd|D }|d }|dd  D ]}||7 }q|S )Nc                    s&   g | ]\}}j |j d | qS r  )r  r   )rG   r  rT   r;   r=   r?   r@   rb     s    zFPostgresSearchQueryCompiler._build_rank_expression.<locals>.<listcomp>r   r/   r?   )r=   vectorsr;   rank_expressionsr	  other_rank_expressionr?   r  r@   _build_rank_expression  s   
z2PostgresSearchQueryCompiler._build_rank_expressionc                 C   s  t | jtr| j|| S t | jtrt | jjtr| j S | j| j|d}| |}| 	||}|d d }|dd  D ]\}	}
|
|	dd}q>| jj|dj|d}| jra|| d}n|jjsn|d}td}|d ur||jd	i ||i}||| S )
Nr   r   r/   z||F)_vector_z-pkrj   r?   )rL   r   r    r   r!   r   noner   r  r  _combiner   r   order_by_relevanceorder_bydescr   )r=   r;   startstopscore_fieldr  r  r	  combined_vectorr  rT   r   r?   r?   r@   search  s*   


z"PostgresSearchQueryCompiler.searchc                 C   s(   | | jjd | }tdi ||iS )N__r?   )get_attnamer   r   r   )r=   rZ   lookuprR   lhsr?   r?   r@   _process_lookup0  s   z+PostgresSearchQueryCompiler._process_lookupc                 C   s
   t g dS )N)pk__inr   rI   r?   r?   r@   _process_match_none4     
z/PostgresSearchQueryCompiler._process_match_nonec                 C   s@   |dkr	t | }n|dkrtdd |D }nd S |r| }|S )NANDr'   c                 S   s   g | ]}t |qS r?   r0  )rG   filr?   r?   r@   rb   <  s    z@PostgresSearchQueryCompiler._connect_filters.<locals>.<listcomp>)r   r'   )r=   filters	connectornegatedqr?   r?   r@   _connect_filters7  s   
z,PostgresSearchQueryCompiler._connect_filtersr7   )NF)Nr   )rv   rw   rx   DEFAULT_OPERATORr   r   r   rA   r   r   r   r   r   r  r  r  r  r  r)  r.  r1  r9  __classcell__r?   r?   r   r@   r   C  s&    


H
%
!r   c                   @   s4   e Zd ZdZeZdd Zdd Zdd Zdd	 Z	d
S )!PostgresAutocompleteQueryCompilerTc                 C   r   r7   )r<   r   r?   r?   r@   r   K  r   z,PostgresAutocompleteQueryCompiler.get_configc                 C   r   r7   )r   r   get_autocomplete_search_fieldsrI   r?   r?   r@   r   N  r   z=PostgresAutocompleteQueryCompiler.get_search_fields_for_modelc                 C   s   t ddfgS )Nindex_entries__autocompleter   r  r  r?   r?   r@   r  Q  r  z3PostgresAutocompleteQueryCompiler.get_index_vectorsc                    r  )Nc                    s$   g | ]\}}t | jd ddfqS )rS   )r;   ra   r   )r   r;   r  r  r?   r@   rb   U  s    	zHPostgresAutocompleteQueryCompiler.get_fields_vectors.<locals>.<listcomp>r  r  r?   r  r@   r  T  s   
	z4PostgresAutocompleteQueryCompiler.get_fields_vectorsN)
rv   rw   rx   r   r   r   r   r   r  r  r?   r?   r?   r@   r<  G  s    r<  c                   @   s2   e Zd ZdddZdd Zdd ZdZd	d
 ZdS )PostgresSearchResultsFc                 C   s:   |rd }d }n| j }| j}| jj| j| j||| jdS )N)r'  )r%  r&  query_compilerr)  r   r>   _score_field)r=   	for_countr%  r&  r?   r?   r@   get_querysetc  s   z"PostgresSearchResults.get_querysetc                 C   s   t |  S r7   )rN   rC  rI   r?   r?   r@   
_do_searchr  r   z PostgresSearchResults._do_searchc                 C   s   | j dd S )NT)rB  )rC  countrI   r?   r?   r@   	_do_countu  s   zPostgresSearchResults._do_countTc                    s   | j  }|d u r td  d   d | j jjj d  d| j | j | jd d }|	 j
tddd}t fd	d
|D S )Nz(Cannot facet search results with field "z!". Please add index.FilterField('z') to z.search_fields.rn   rj   rE  z-countc                    s   g | ]
}|  |d  fqS rH  r?   )rG   resultrG  r?   r@   rb     rc   z/PostgresSearchResults.facet.<locals>.<listcomp>)r@  _get_filterable_fieldr.   r   r   rv   r)  r   r>   rQ   r   r   r#  r   )r=   rn   rZ   r   resultsr?   rG  r@   facetz  s4   
zPostgresSearchResults.facetNru   )rv   rw   rx   rC  rD  rF  supports_facetrL  r?   r?   r?   r@   r?  b  s    
r?  c                   @   s$   e Zd Zdd Zdd Zdd ZdS )PostgresSearchRebuilderc                 C   s
   || _ d S r7   )indexr=   rO  r?   r?   r@   rA     r2  z PostgresSearchRebuilder.__init__c                 C   s   | j   | j S r7   )rO  r   rI   r?   r?   r@   r%    s   
zPostgresSearchRebuilder.startc                 C   s   | j jdd d S )NTr   )rO  r   rI   r?   r?   r@   finish  s   zPostgresSearchRebuilder.finishN)rv   rw   rx   rA   r%  rR  r?   r?   r?   r@   rN    s    rN  c                       s8   e Zd Z fddZ fddZdd Zdd Z  ZS )	PostgresSearchAtomicRebuilderc                    s(   t  | tj|jjd| _d| _d S )Nr   F)r   rA   r
   atomicr   r   transaction_openedrP  r   r?   r@   rA     s   
z&PostgresSearchAtomicRebuilder.__init__c                    s   | j   d| _t  S NT)r
   	__enter__rU  r   r%  rI   r   r?   r@   r%    s   

z#PostgresSearchAtomicRebuilder.startc                 C   s(   | j jdd | jd d d  d| _d S )NTrQ  F)rO  r   r
   __exit__rU  rI   r?   r?   r@   rR    s   
z$PostgresSearchAtomicRebuilder.finishc                 C   s   | j rd| j_|   d S d S rV  )rU  r
   needs_rollbackrR  rI   r?   r?   r@   __del__  s   z%PostgresSearchAtomicRebuilder.__del__)rv   rw   rx   rA   r%  rR  rZ  r;  r?   r?   r   r@   rS    s
    rS  c                       sp   e Zd ZeZeZeZe	Z
eZ fddZdd Zdd Zdd Zd	d
 Zdd Zdd Zdd Zdd Z  ZS )PostgresSearchBackendc                    sP   t  | |dd| _|d| _|dd| _|ddr&| j| _d S d S )NINDEXdefaultSEARCH_CONFIGAUTOCOMPLETE_SEARCH_CONFIGsimpleATOMIC_REBUILDF)r   rA   getr|   r;   r<   atomic_rebuilder_classrebuilder_class)r=   r   r   r?   r@   rA     s   zPostgresSearchBackend.__init__c                 C   s   t | S r7   )rz   r   r?   r?   r@   get_index_for_model  s   z)PostgresSearchBackend.get_index_for_modelc                 C   s   |  |jjS r7   )re  r   r   r   r?   r?   r@   get_index_for_object  r  z*PostgresSearchBackend.get_index_for_objectc                 C   s0   dd t  D D ]}tj j|jd q	d S )Nc                 S   s   g | ]	}|j d kr|qS )r{   )r   )rG   r   r?   r?   r@   rb     s
    
z5PostgresSearchBackend.reset_index.<locals>.<listcomp>r   )r   rV   r   r   r   r   )r=   r   r?   r?   r@   reset_index  s
   
z!PostgresSearchBackend.reset_indexc                 C   r   r7   r?   r   r?   r?   r@   add_type  r   zPostgresSearchBackend.add_typec                 C   r   r7   r?   rI   r?   r?   r@   refresh_index  r   z#PostgresSearchBackend.refresh_indexc                 C      |  || d S r7   )rf  r   r   r?   r?   r@   add     zPostgresSearchBackend.addc                 C   s"   |r|  |d || d S d S )Nr   )rf  r   )r=   r   obj_listr?   r?   r@   add_bulk  s   zPostgresSearchBackend.add_bulkc                 C   rj  r7   )rf  r   r   r?   r?   r@   r     rl  zPostgresSearchBackend.delete)rv   rw   rx   r   query_compiler_classr<  !autocomplete_query_compiler_classr?  results_classrN  rd  rS  rc  rA   re  rf  rg  rh  ri  rk  rn  r   r;  r?   r?   r   r@   r[    s    r[  )Ir   collectionsr   	functoolsr   django.contrib.postgres.searchr   r   r   	django.dbr   r   r	   r
   django.db.modelsr   r   r   r   r   r   r   django.db.models.constantsr   django.db.models.functionsr   r   django.db.models.sql.subqueriesr   django.utils.encodingr   django.utils.functionalr   rO  r   r   r   r   modelsr   r   r   r   r    r!   r"   r#   r$   utilsr%   r&   r'   r(   r)   baser+   r,   r-   r.   r0   r  r1   r2   rf   r6   rz   r   r<  r?  rN  rS  r[  SearchBackendr?   r?   r?   r@   <module>   s@    $$    33