U
    e;                     @   s   d Z ddlZddlZ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 ddlmZ edZed	d
Zdd ZG dd dejZG dd dZG dd dZG dd dZdddZdd Zdd ZG dd dZdS )z
Various data structures used in query construction.

Factored out from django.db.models.query to avoid making the main module very
large and/or so that they can be used by other modules without getting into
circular import difficulties.
    N)
namedtuple)
FieldError)DEFAULT_DB_ALIASDatabaseErrorconnections)
LOOKUP_SEP)treedjango.db.modelsPathInfozGfrom_opts to_opts target_fields join_field m2m direct filtered_relationc                 c   s&   | V  |   D ]}t|E d H  qd S N)__subclasses__
subclassesclssubclass r   @/tmp/pip-unpacked-wheel-lctamlir/django/db/models/query_utils.pyr      s    r   c                       s   e Zd ZdZdZdZdZeZdZddd fd	d

Z	dd Z
dd Zdd Zdd Zdd ZdddZdd ZefddZdd Z  ZS )Qze
    Encapsulate filters as objects that can then be combined logically (using
    `&` and `|`).
    ANDORXORTNF)
_connector_negatedc                   s"   t  j|t| ||d d S )N)children	connectornegated)super__init__sorteditems)selfr   r   argskwargs	__class__r   r   r   0   s
    z
Q.__init__c                 C   sb   t |dddkrt|| s$| S |s:t|tr:|  S | j|d}|| | ||| |S )NconditionalF)r   )getattr	TypeErrorcopy
isinstancer   createadd)r    otherconnobjr   r   r   _combine7   s    z
Q._combinec                 C   s   |  || jS r   )r/   r   r    r,   r   r   r   __or__D   s    zQ.__or__c                 C   s   |  || jS r   )r/   r   r0   r   r   r   __and__G   s    z	Q.__and__c                 C   s   |  || jS r   )r/   r   r0   r   r   r   __xor__J   s    z	Q.__xor__c                 C   s   |   }|  |S r   )r(   negate)r    r.   r   r   r   
__invert__M   s    zQ.__invert__c                 C   s(   |j | ||dd|d\}}|| |S )NF)allow_joinsZ
split_subqZcheck_filterable	summarize)Z_add_qZpromote_joins)r    queryr6   reuser7   Zfor_saveZclauseZjoinsr   r   r   resolve_expressionR   s    

zQ.resolve_expressionc                 c   sH   | V  | j D ]6}t|tr"|d }t|dr<| E dH  q|V  qdS )zg
        Recursively yield this Q object and all subexpressions, in depth-first
        order.
           flattenN)r   r)   tuplehasattrr<   )r    childr   r   r   r<   b   s    


z	Q.flattenc              
   C   s  ddl m}m} ddlm} ddlm} ddlm} |d}|	 D ]*\}	}
t
|
ds^||
}
|j|
|	dd	 qD||d
d t| jjr|t|| d| d n
||  |j|d}z||dk	W S  tk
r } ztd| | W Y dS d}~X Y nX dS )z|
        Do a database query to check if the expressions of the Q instance
        matches against the expressions.
        r   )BooleanFieldValue)Coalesce)Query)SINGLENr:   F)selectr;   _checkT)output_field)usingz.Got a database error calling check() on %r: %s)Zdjango.db.modelsr@   rA   Zdjango.db.models.functionsrB   Zdjango.db.models.sqlrC   Zdjango.db.models.sql.constantsrD   r   r>   Zadd_annotationr   featuresZsupports_comparing_boolean_exprZadd_qr   Zget_compilerZexecute_sqlr   loggerwarning)r    ZagainstrH   r@   rA   rB   rC   rD   r8   namevaluecompilerer   r   r   checkq   s&    

zQ.checkc                 C   sf   d| j j| j jf }|dr*|dd}t| j}i }| j| jkrN| j|d< | j	r\d|d< |||fS )Nz%s.%szdjango.db.models.query_utilsr	   r   Tr   )
r$   
__module____name__
startswithreplacer=   r   r   defaultr   )r    pathr!   r"   r   r   r   deconstruct   s    


zQ.deconstruct)NTNFF)rR   rQ   __qualname____doc__r   r   r   rU   r%   r   r/   r1   r2   r3   r5   r:   r<   r   rP   rW   __classcell__r   r   r#   r   r   #   s*            
r   c                   @   s*   e Zd ZdZdd Zd	ddZdd ZdS )
DeferredAttributez
    A wrapper for a deferred-loading field. When the value is read from this
    object the first time, the query is executed.
    c                 C   s
   || _ d S r   )field)r    r\   r   r   r   r      s    zDeferredAttribute.__init__Nc                 C   sT   |dkr| S |j }| jj}||krL| |}|dkrD|j|gd n|||< || S )zx
        Retrieve and caches the value from the datastore on the first lookup.
        Return the cached value.
        N)fields)__dict__r\   attname_check_parent_chainZrefresh_from_db)r    instancer   data
field_namevalr   r   r   __get__   s    
zDeferredAttribute.__get__c                 C   s6   |j }|| jj}| jjr2| j|kr2t||jS dS )z
        Check if the field value can be fetched from a parent field already
        loaded in the instance. This can be done if the to-be fetched
        field is a primary key field.
        N)_metaZget_ancestor_linkr\   modelprimary_keyr&   r_   )r    ra   optsZ
link_fieldr   r   r   r`      s
    z%DeferredAttribute._check_parent_chain)N)rR   rQ   rX   rY   r   re   r`   r   r   r   r   r[      s   
r[   c                   @   s    e Zd ZdZdd Zdd ZdS )class_or_instance_methodz
    Hook used in RegisterLookupMixin to return partial functions depending on
    the caller type (instance or class of models.Field).
    c                 C   s   || _ || _d S r   )class_methodinstance_method)r    rk   rl   r   r   r   r      s    z!class_or_instance_method.__init__c                 C   s$   |d krt | j|S t | j|S r   )	functoolspartialrk   rl   )r    ra   ownerr   r   r   re      s    z class_or_instance_method.__get__N)rR   rQ   rX   rY   r   re   r   r   r   r   rj      s   rj   c                   @   s   e Zd Zdd Zejdddd Zdd ZeeeZ	e
eZd	d
 Zdd Zedd Ze
dd ZdddZdddZeeeZe
eZdddZdddZeeeZe
eZdS )RegisterLookupMixinc                 C   s   |   |d S r   )get_lookupsget)r    lookup_namer   r   r   _get_lookup   s    zRegisterLookupMixin._get_lookupN)maxsizec                 C   s   dd t | D }| |S )Nc                 S   s   g | ]}|j d i qS )class_lookups)r^   rr   ).0parentr   r   r   
<listcomp>   s    z9RegisterLookupMixin.get_class_lookups.<locals>.<listcomp>)inspectgetmromerge_dicts)r   rv   r   r   r   get_class_lookups   s    z%RegisterLookupMixin.get_class_lookupsc                 C   s$   |   }t| dd  }r ||S |S Ninstance_lookups)r}   r&   )r    rv   r   r   r   r   get_instance_lookups   s    z(RegisterLookupMixin.get_instance_lookupsc                 C   sN   ddl m} | |}|d kr4t| dr4| j|S |d k	rJt||sJd S |S )Nr   )LookuprG   )django.db.models.lookupsr   rt   r>   rG   
get_lookup
issubclass)r    rs   r   foundr   r   r   r      s    
zRegisterLookupMixin.get_lookupc                 C   sN   ddl m} | |}|d kr4t| dr4| j|S |d k	rJt||sJd S |S )Nr   )	TransformrG   )r   r   rt   r>   rG   get_transformr   )r    rs   r   r   r   r   r   r      s    
z!RegisterLookupMixin.get_transformc                 C   s    i }t | D ]}|| q|S )z
        Merge dicts in reverse to preference the order of the original list. e.g.,
        merge_dicts([a, b]) will preference the keys in 'a' over those in 'b'.
        )reversedupdate)Zdictsmergeddr   r   r   r|      s    zRegisterLookupMixin.merge_dictsc                 C   s   t | D ]}|j  qd S r   )r   r}   cache_clearr   r   r   r   _clear_cached_class_lookups  s    z/RegisterLookupMixin._clear_cached_class_lookupsc                 C   s4   |d kr|j }d| jkri | _|| j|< |   |S )Nrv   )rs   r^   rv   r   r   lookuprs   r   r   r   register_class_lookup  s    

z)RegisterLookupMixin.register_class_lookupc                 C   s,   |d kr|j }d| jkri | _|| j|< |S r~   )rs   r^   r   r    r   rs   r   r   r   register_instance_lookup  s    

z,RegisterLookupMixin.register_instance_lookupc                 C   s"   |dkr|j }| j|= |   dS )zn
        Remove given lookup from cls lookups. For use in tests only as it's
        not thread-safe.
        N)rs   rv   r   r   r   r   r   _unregister_class_lookup"  s    z,RegisterLookupMixin._unregister_class_lookupc                 C   s   |dkr|j }| j|= dS )zs
        Remove given lookup from instance lookups. For use in tests only as
        it's not thread-safe.
        N)rs   r   r   r   r   r   _unregister_instance_lookup,  s    z/RegisterLookupMixin._unregister_instance_lookup)N)N)N)N)rR   rQ   rX   rt   rm   	lru_cacher}   r   rj   rq   classmethodr   r   staticmethodr|   r   r   r   Zregister_lookupr   r   Z_unregister_lookupr   r   r   r   rp      s4   








	
 


	 rp   Fc                 C   s   | j s
dS | j jr|sdS |rD|r2|  |kr2dS |sD| j|krDdS |sR| jrRdS |r|r| j|kr| |krtd| jjj d| j ddS )af  
    Return True if this field should be used to descend deeper for
    select_related() purposes. Used by both the query construction code
    (compiler.get_related_selections()) and the model instance creation code
    (compiler.klass_info).

    Arguments:
     * field - the field to be checked
     * restricted - a boolean field, indicating if the field list has been
       manually restricted using a requested clause)
     * requested - The select_related() dictionary.
     * select_mask - the dictionary of selected fields.
     * reverse - boolean, True if we are checking a reverse select related
    FzField .zM cannot be both deferred and traversed using select_related at the same time.T)	Zremote_fieldZparent_linkZrelated_query_namerL   nullr   rg   rf   Zobject_name)r\   Z
restricted	requestedZselect_maskreverser   r   r   select_related_descend;  s.    
r   c                 C   sL   t dt| d D ]4}t| d| }||r|| |d f  S qdS )z
    Check if the lookup_parts contains references to the given annotations set.
    Because the LOOKUP_SEP is contained in the default annotation names, check
    each prefix of the lookup_parts for a match.
    r;   r   N)Nr   )rangelenr   joinrr   )Zlookup_partsannotationsnZlevel_n_lookupr   r   r   refs_expressionb  s
    
r   c                    s,    fdd}||p*t |ddo*||jjS )z
    Check that self.model is compatible with target_opts. Compatibility
    is OK if:
      1) model and opts match (where proxy inheritance is removed)
      2) model is parent of opts' model or the other way around
    c                    s*    j j| jkp(| j j  kp( |  kS r   )rf   Zconcrete_modelZget_parent_list)ri   rg   r   r   rP   w  s
    
z-check_rel_lookup_compatibility.<locals>.checkrh   F)r&   rg   rf   )rg   Ztarget_optsr\   rP   r   r   r   check_rel_lookup_compatibilityo  s    r   c                   @   s@   e Zd ZdZe dddZdd Zdd Zd	d
 Zdd Z	dS )FilteredRelationz7Specify custom filtering in the ON clause of SQL joins.	conditionc                C   s:   |st d|| _d | _t|ts*t d|| _g | _d S )Nzrelation_name cannot be empty.z*condition argument must be a Q() instance.)
ValueErrorrelation_namealiasr)   r   r   rV   )r    r   r   r   r   r   r     s    
zFilteredRelation.__init__c                 C   s4   t || jstS | j|jko2| j|jko2| j|jkS r   )r)   r$   NotImplementedr   r   r   r0   r   r   r   __eq__  s    

zFilteredRelation.__eq__c                 C   s,   t | j| jd}| j|_| jd d  |_|S )Nr   )r   r   r   r   rV   )r    cloner   r   r   r     s    zFilteredRelation.clonec                 O   s   t ddS )zz
        QuerySet.annotate() only accepts expression-like arguments
        (with a resolve_expression() method).
        z0FilteredRelation.resolve_expression() is unused.N)NotImplementedError)r    r!   r"   r   r   r   r:     s    z#FilteredRelation.resolve_expressionc                 C   s&   |j }|j| jt| jd}||S )N)r9   )r8   Zbuild_filtered_relation_qr   setrV   compile)r    rN   
connectionr8   wherer   r   r   as_sql  s    zFilteredRelation.as_sqlN)
rR   rQ   rX   rY   r   r   r   r   r:   r   r   r   r   r   r     s   
	r   )F)rY   rm   rz   loggingcollectionsr   Zdjango.core.exceptionsr   Z	django.dbr   r   r   Zdjango.db.models.constantsr   Zdjango.utilsr   	getLoggerrJ   r
   r   Noder   r[   rj   rp   r   r   r   r   r   r   r   r   <module>   s,   
x)g
'