U
    Lk7g(                    @   sB  d dl Z d dlZd dlZd dlZd dlmZ d dlZd dl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 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mZ d dl m!Z!m"Z"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.m/Z/ dZ0d Z1dZ2dZ3dZ4dZ5G dd dZ6dS )    N)Mapping)SON	json_util)Code)ReturnDocument)validate_read_preference)ReadConcern)signalsget_document)_import_class)get_db)!no_dereferencing_active_for_classset_read_write_concernset_write_concern	switch_db)BulkWriteErrorInvalidQueryErrorLookUpErrorNotUniqueErrorOperationError)LEGACY_JSON_OPTIONScount_documents)	transform)QueryFieldList)QQNode)BaseQuerySet
DO_NOTHINGNULLIFYCASCADEDENYPULL            c                   @   s  e Zd ZdZdd Zdd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dddZdd Zdd Zdd Zdd d!Zdd#d$Zdd%d&Zdd'd(Zdd)d*Zdd+d,Zdd-d.Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Zdd>d?Z d@dA Z!dBdC Z"ddDdEZ#ddFdGZ$dHdI Z%dJdK Z&dLdM Z'dNdO Z(ddPdQZ)dRdS Z*ddTdUdVZ+dWdX Z,dYdZ Z-d[d\ Z.d]d^ Z/d_d` Z0dadb Z1dcdd Z2dedf Z3dgdh Z4didj Z5dkdl Z6dmdn Z7dodp Z8dqdr Z9dsdt Z:ddudvZ;dwdx Z<dydz Z=d{d| Z>d}d~ Z?dddZ@dd ZAdd ZBeCdd ZDeCdd ZEeCdd ZFdd ZGeCdd ZHeCdd ZIeCdd ZJdd ZKdddZLdddZMdd ZNdd ZOdd ZPdd ZQdd ZRdS )r   zA set of results returned from a query. Wraps a MongoDB cursor,
    providing :class:`~mongoengine.Document` objects as the results.
    c                 C   s  || _ || _d | _t | _i | _d | _t | _d | _	d| _
d| _d| _d | _d | _d| _g | _d| _d| _d | _d | _d| _d| _|jddkrt| j jdkrd| j jd i| _ndd| j jii| _tdgd| _d | _d | _d | _d	| _d | _d | _ d | _!d | _"d| _#d S )
NFTallow_inheritancer#   _clsr   $inalways_include)$	_document_collection_obj_mongo_queryr   
_query_obj
_cls_query_where_clauser   _loaded_fields	_ordering	_snapshot_timeout_allow_disk_use_read_preference_read_concern_iter_scalar_none_as_pymongo_search_text_search_text_score_BaseQuerySet__dereference_BaseQuerySet__auto_dereference_metagetlen_subclasses_cursor_obj_limit_skip_hint
_collation_batch_size_max_time_ms_comment_empty)selfdocument
collection rR   =/tmp/pip-unpacked-wheel-n1etwkgt/mongoengine/queryset/base.py__init__7   sF    zBaseQuerySet.__init__Nc                 K   sV   t f |}|r0t|ts(d| }t|||M }|  }| j|M  _d|_d|_|S )a  Filter the selected documents by calling the
        :class:`~mongoengine.queryset.QuerySet` with a query.

        :param q_obj: a :class:`~mongoengine.queryset.Q` object to be used in
            the query; the :class:`~mongoengine.queryset.QuerySet` is filtered
            multiple times with different :class:`~mongoengine.queryset.Q`
            objects, only the last one will be used.
        :param query: Django-style query keyword arguments.
        z8Not a query object: %s. Did you intend to use key=value?N)r   
isinstancer   r   cloner0   r/   rF   )rO   Zq_objquerymsgquerysetrR   rR   rS   __call__i   s    


zBaseQuerySet.__call__c                 C   s    | j  }|d d|d< |S )o
        Need for pickling queryset

        See https://github.com/MongoEngine/mongoengine/issues/442
        r.   NrF   )__dict__copypoprO   Zobj_dictrR   rR   rS   __getstate__   s    

zBaseQuerySet.__getstate__c                 C   s    |d   |d< | j| dS )r[   r-   r.   N)_get_collectionr\   updater_   rR   rR   rS   __setstate__   s    zBaseQuerySet.__setstate__c                 C   s   |   }d|_t|trd|j| |_|j|j |_|_	|jrP|jrP|j|j |_	|j	dkr`d|_|S t|t
r|jr||jj|j| | jdS |jr|j| S |jj|j| | jdS tddS )a  Return a document instance corresponding to a given index if
        the key is an integer. If the key is a slice, translate its
        bounds into a skip and a limit, and return a cloned queryset
        with that skip/limit applied. For example:

        >>> User.objects[0]
        <User: User object>
        >>> User.objects[1:3]
        [<User: User object>, <User: User object>]
        Fr   T_auto_dereferencez#Provide a slice or an integer indexN)rV   rN   rU   slice_cursorrF   startstoprH   rG   intr;   _get_scalarr-   	_from_sonre   r=   	TypeError)rO   keyrY   rR   rR   rS   __getitem__   s2    



zBaseQuerySet.__getitem__c                 C   s   t d S N)NotImplementedErrorrO   rR   rR   rS   __iter__   s    zBaseQuerySet.__iter__c                 C   s   |   }| dkrdS dS )z#Return True if cursor has any data.NFT)order_byfirstrO   rY   rR   rR   rS   	_has_data   s    zBaseQuerySet._has_datac                 C   s   |   S )z/Avoid to open all records in an if stmt in Py3.)rw   rr   rR   rR   rS   __bool__   s    zBaseQuerySet.__bool__c                 C   s   |   S )z'Returns a copy of the current QuerySet.rZ   rr   rR   rR   rS   all   s    zBaseQuerySet.allc                 O   s   | j ||S )z;An alias of :meth:`~mongoengine.queryset.QuerySet.__call__`ry   )rO   q_objsrW   rR   rR   rS   filter   s    zBaseQuerySet.filterTc                 C   sb   |   }|jrtdtd|i}|r.||d< | jtd|idM  _d|_d|_||_||_|S )a  
        Start a text search, using text indexes.
        Require: MongoDB server version 2.6+.

        :param language:  The language that determines the list of stop words
            for the search and the rules for the stemmer and tokenizer.
            If not specified, the search uses the default language of the index.
            For supported languages, see
            `Text Search Languages <https://docs.mongodb.org/manual/reference/text-search-languages/#text-search-languages>`.
        :param text_score:  True to have it return the text_score (available through get_text_score()), False to disable that
            Note that unless you order the results, leaving text_score=True may provide randomness in the returned documents
        z0It is not possible to use search_text two times.z$searchz	$languagez$text__raw__N)	rV   r>   r   r   r0   r   r/   rF   r?   )rO   textlanguageZ
text_scorerY   Zquery_kwargsrR   rR   rS   search_text   s    zBaseQuerySet.search_textc                 O   s   |   }| d}|j||}zt|}W n, tk
rZ   d|jj }|j|Y nX zt| W n tk
r   | Y S X |j	ddS )a4  Retrieve the matching object raising
        :class:`~mongoengine.queryset.MultipleObjectsReturned` or
        `DocumentName.MultipleObjectsReturned` exception if multiple results
        and :class:`~mongoengine.queryset.DoesNotExist` or
        `DocumentName.DoesNotExist` if no results are found.
        r$   z!%s matching query does not exist.z&2 or more items returned, instead of 1N)
rV   rt   limitr|   nextStopIterationr-   _class_nameZDoesNotExistZMultipleObjectsReturned)rO   r{   rW   rY   resultrX   rR   rR   rS   rC     s    
zBaseQuerySet.getc                 K   s   | j f |jddS )z5Create new object. Returns the saved object instance.T)Zforce_insert)r-   save)rO   kwargsrR   rR   rS   create"  s    zBaseQuerySet.createc                 C   sB   |   }| js| jrdS z|d }W n tk
r<   d}Y nX |S )z-Retrieve the first object matching the query.Nr   )rV   r<   rN   
IndexError)rO   rY   r   rR   rR   rS   ru   &  s    
zBaseQuerySet.firstc              
      sb  t d}|dkri }|}d}t||s2t|j|r<d}|g}|D ]>}t|| jsfdt| j }	t|	|jr@|js@d}	t|	q@|pi }t	j
j| jfd|i| dd	 |D }
t| j|}|j}|r|
d
 }
|j}W 5 Q R X z||
}|r|jgn|j}W n tjjk
r6 } zd}t|| W 5 d}~X Y n tjjk
rn } zd}t||j W 5 d}~X Y nZ tjjk
r } z6d}tdt|rd}t|| t|| W 5 d}~X Y nX t||D ]\}}||_q|st	jj| jf|dd| |r|d
 S |S | |  fdd	|D }t	jj| jf|dd| |r^|d
 S |S )am  bulk insert documents

        :param doc_or_docs: a document or list of documents to be inserted
        :param load_bulk (optional): If True returns the list of document
            instances
        :param write_concern: Extra keyword arguments are passed down to
                :meth:`~pymongo.collection.Collection.insert`
                which will be used as options for the resultant
                ``getLastError`` command.  For example,
                ``insert(..., {w: 2, fsync: True})`` will wait until at least
                two servers have recorded the write and will force an fsync on
                each server being written to.
        :param signal_kwargs: (optional) kwargs dictionary to be passed to
            the signal calls.

        By default returns document instances, set ``load_bulk`` to False to
        return just ``ObjectIds``
        DocumentNFTz.Some documents inserted aren't instances of %sz7Some documents have ObjectIds, use doc.update() instead	documentsc                 S   s   g | ]}|  qS rR   )Zto_mongo.0docrR   rR   rS   
<listcomp>_  s     z'BaseQuerySet.insert.<locals>.<listcomp>r   zCould not save document (%s)zBulk write error: (%s)z^E1100[01] duplicate keyz(Tried to save duplicate unique keys (%s))r   Zloadedc                    s   g | ]}  |qS rR   )rC   )r   Zobj_idr   rR   rS   r     s     )r   rU   
issubclass	__class__r-   strr   pkZ_createdr	   Zpre_bulk_insertsendr   _collectionZinsert_manyZ
insert_oneZinserted_idZinserted_idspymongoerrorsDuplicateKeyErrorr   r   detailsOperationFailurerematchzipZpost_bulk_insertin_bulk)rO   Zdoc_or_docsZ	load_bulkwrite_concernZsignal_kwargsr   docsZ
return_oner   rX   rawrQ   Zinsert_funcZinserted_resultidserrmessageZdoc_idresultsrR   r   rS   insert2  s    


 
 zBaseQuerySet.insertFc                 C   s   | j dkr|dks| js| jr"dS |r4| j | jdni }| j dkrN|dd | jdkrb| j|d< | jrr| j|d< tf | jj	| j
d	|}d| _|S )
zCount the selected elements in the query.

        :param with_limit_and_skip (optional): take any :meth:`limit` or
            :meth:`skip` that has been applied to this cursor into account when
            getting the count
        r   F)r   skipr   N)r,   Nhint	collation)rQ   r|   )rG   r<   rN   rH   r^   rI   rJ   r   rg   rQ   _queryrF   )rO   Zwith_limit_and_skipr   countrR   rR   rS   r     s2    




zBaseQuerySet.countc              
   C   sH  |   }|j}|dkri }tjo6tj|p6tj|}|jsH|jsH|oL| }|rxd}|D ]}|j	f | |d7 }qZ|S |j
dpi }	t|	 }	|	D ]^\}
}|
\}}|j
drq|tkr|jf |d | i}|d dkrtd|j|f q|	D ]\}
}|
\}}|j
drq|tkr|dkr8t n|}|j|jkrb|D ]}||j qN|jf |d | d|i}| dkr|j	||d	 q|tkr|jf |d | ijf d
|id| di q|tkr|jf |d | ijf d
|id| | i qt|j|,}||j}|jr:|j W  5 Q R  S W 5 Q R X dS )ak  Delete the documents matched by the query.

        :param write_concern: Extra keyword arguments are passed down which
            will be used as options for the resultant
            ``getLastError`` command.  For example,
            ``save(..., write_concern={w: 2, fsync: True}, ...)`` will
            wait until at least two servers have recorded the write and
            will force an fsync on the primary server.
        :param _from_doc_delete: True when called from document delete therefore
            signals will have been triggered so don't loop.

        :returns number of deleted documents
        Nr   r#   delete_rulesZabstractZ__inz.Could not delete document (%s.%s refers to it)Zpk__nin)r   cascade_refsr   z	unset__%szpull_all__%s)!rV   r-   r	   Zsignals_availableZ
pre_deleteZhas_receivers_forZpost_deleterH   rG   deleterB   rC   listitemsr!   objectsr   r   r   __name__r    setr   addidr   rb   r"   r   Zdelete_manyr   ZacknowledgedZdeleted_count)rO   r   Z_from_doc_deleter   rY   r   Zhas_delete_signalZcall_document_deleteZcntr   Z
rule_entryZruleZdocument_cls
field_namerefsrefrQ   r   rR   rR   rS   r     s|    





zBaseQuerySet.deletec              
      s  |s|st d|dkri }| js(| jr,dS |    j}d|krht|d trh fdd|d D }ntj j	f|}|rd|krd|kr j	j
|d d< nd j	j
i|d< z\t j||&}	|	j}
|r|	j}
|
||||d	}W 5 Q R X |r|W S |jr|jd
 W S W n tjjk
r> } ztd| W 5 d}~X Y nN tjjk
r } z*t|dkrnd}t |t d| W 5 d}~X Y nX dS )a  Perform an atomic update on the fields matched by the query.

        :param upsert: insert if document doesn't exist (default ``False``)
        :param multi: Update multiple documents.
        :param write_concern: Extra keyword arguments are passed down which
            will be used as options for the resultant
            ``getLastError`` command.  For example,
            ``save(..., write_concern={w: 2, fsync: True}, ...)`` will
            wait until at least two servers have recorded the write and
            will force an fsync on the primary server.
        :param read_concern: Override the read concern for the operation
        :param full_result: Return the associated ``pymongo.UpdateResult`` rather than just the number
            updated items
        :param array_filters: A list of filters specifying which array elements an update should apply.
        :param update: Django-style update keyword arguments

        :returns the number of updated documents (unless ``full_result`` is True)
        z'No update parameters, would remove dataNr   r~   c                    s    g | ]}t j jfd |iqS r}   )r   rb   r-   )r   urY   rR   rS   r   <  s   z'BaseQuerySet.update.<locals>.<listcomp>r(   z$set)upsertarray_filtersnUpdate failed (%s)zmulti not coded yetz'update() method requires MongoDB 1.1.3+)r   r<   rN   rV   r   rU   r   r   rb   r-   r   r   r   
update_oneZupdate_many
raw_resultr   r   r   r   r   r   )rO   r   multir   read_concernfull_resultr   rb   rW   rQ   Zupdate_funcr   r   r   rR   r   rS   rb     s^    
 
     zBaseQuerySet.updatec                 K   sD   | j f dd||dd|}|jd r0|  }n| jj|j}|S )aw  Overwrite or add the first document matched by the query.

        :param write_concern: Extra keyword arguments are passed down which
            will be used as options for the resultant
            ``getLastError`` command.  For example,
            ``save(..., write_concern={w: 2, fsync: True}, ...)`` will
            wait until at least two servers have recorded the write and
            will force an fsync on the primary server.
        :param read_concern: Override the read concern for the operation
        :param update: Django-style update keyword arguments

        :returns the new or overwritten document
        FT)r   r   r   r   r   ZupdatedExisting)rb   r   rC   r-   r   with_idZupserted_id)rO   r   r   rb   Zatomic_updaterP   rR   rR   rS   
upsert_one_  s    	

zBaseQuerySet.upsert_onec                 K   s   | j f |d|||d|S )a  Perform an atomic update on the fields of the first document
        matched by the query.

        :param upsert: insert if document doesn't exist (default ``False``)
        :param write_concern: Extra keyword arguments are passed down which
            will be used as options for the resultant
            ``getLastError`` command.  For example,
            ``save(..., write_concern={w: 2, fsync: True}, ...)`` will
            wait until at least two servers have recorded the write and
            will force an fsync on the primary server.
        :param full_result: Return the associated ``pymongo.UpdateResult`` rather than just the number
            updated items
        :param array_filters: A list of filters specifying which array elements an update should apply.
        :param update: Django-style update keyword arguments
            full_result
        :returns the number of updated documents (unless ``full_result`` is True)
        F)r   r   r   r   r   )rb   )rO   r   r   r   r   rb   rR   rR   rS   r   }  s    zBaseQuerySet.update_onec              
   K   sr  |r|rt d|s$|s$|s$t d| js0| jr4dS |  }|j}|sVtj|jf|}|j}	zl|rrd}
t	
|
t |r|jj|fd|	i| j}n4|rtj}ntj}|jj||f||	||d| j}W nd tjjk
r } ztd| W 5 d}~X Y n4 tjjk
r, } zt d| W 5 d}~X Y nX |rX|d dk	rn| j|d |d< n|dk	rn| j|}|S )	a  Update and return the updated document.

        Returns either the document before or after modification based on `new`
        parameter. If no documents match the query and `upsert` is false,
        returns ``None``. If upserting and `new` is false, returns ``None``.

        If the full_response parameter is ``True``, the return value will be
        the entire response object from the server, including the 'ok' and
        'lastErrorObject' fields, rather than just the modified document.
        This is useful mainly because the 'lastErrorObject' document holds
        information about the command's execution.

        :param upsert: insert if document doesn't exist (default ``False``)
        :param full_response: return the entire response object from the
            server (default ``False``, not available for PyMongo 3+)
        :param remove: remove rather than updating (default ``False``)
        :param new: return updated rather than original document
            (default ``False``)
        :param array_filters: A list of filters specifying which array elements an update should apply.
        :param update: Django-style update keyword arguments
        z&Conflicting parameters: remove and newz2No update parameters, must either update or removeNzEWith PyMongo 3+, it is not possible anymore to get the full response.sort)r   r   Zreturn_documentr   r   value)r   r<   rN   rV   r   r   rb   r-   r4   warningswarnDeprecationWarningr   Zfind_one_and_delete_cursor_argsr   ZAFTERZBEFOREZfind_one_and_updater   r   r   r   r   rl   )rO   r   Zfull_responseremovenewr   rb   rY   rW   r   rX   r   Z
return_docr   rR   rR   rS   modify  s^    
	
zBaseQuerySet.modifyc                 C   s*   |   }|jrd}t||j|d S )a  Retrieve the object matching the id provided.  Uses `object_id` only
        and raises InvalidQueryError if a filter has been applied. Returns
        `None` if no document exists with that id.

        :param object_id: the value for the id of the document to look up
        z*Cannot use a filter whilst using `with_id`)r   )rV   r0   r   r|   ru   )rO   Z	object_idrY   rX   rR   rR   rS   r     s
    zBaseQuerySet.with_idc                 C   s   i }| j jdd|iif| j}| jrJ|D ]}| | j|||d < q(nB| jrh|D ]}|||d < qTn$|D ]}| jj|| jd||d < ql|S )zRetrieve a set of documents by their ids.

        :param object_ids: a list or tuple of ObjectId's
        :rtype: dict of ObjectId's as keys and collection-specific
                Document subclasses as values.
        _idr)   rd   )	r   findr   r;   rk   r-   rl   r=   re   )rO   Z
object_idsZdoc_mapr   r   rR   rR   rS   r     s    zBaseQuerySet.in_bulkc                 C   s   |   }d|_|S )zReturns a queryset that never returns any objects and no query will be executed when accessing the results
        inspired by django none() https://docs.djangoproject.com/en/dev/ref/models/querysets/#none
        T)rV   r<   rv   rR   rR   rS   none  s    zBaseQuerySet.nonec                 C   s$   | j jddkr d| j ji| _| S )zqFilter for only the instances of this specific document.

        Do NOT return any inherited documents.
        r'   Tr(   )r-   rB   rC   r   r1   rr   rR   rR   rS   no_sub_classes  s    zBaseQuerySet.no_sub_classesc              	   C   s4   t | j|}| }W 5 Q R X | | | j|S )zThis method is for controlling which database the QuerySet will be
        evaluated against if you are using more than one database.

        :param alias: The database alias
        )r   r-   ra   _clone_intor   )rO   aliasclsrQ   rR   rR   rS   using)  s    zBaseQuerySet.usingc                 C   s   |  | | j| jS )z&Create a copy of the current queryset.)r   r   r-   r.   rr   rR   rR   rS   rV   5  s    zBaseQuerySet.clonec                 C   s`   t |tstd|j d}|D ] }t| |}t||t| q | j|_| jr\| j	 |_|S )zCopy all the relevant properties of this queryset to
        a new queryset (which has to be an instance of
        :class:`~mongoengine.queryset.base.BaseQuerySet`).
        z$%s is not a subclass of BaseQuerySet)r/   r1   r<   r0   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r=   rG   rH   rN   rI   rJ   r>   r?   rL   rM   rK   )
rU   r   r   r   getattrsetattrr]   rA   rF   rV   )rO   Znew_qsZ
copy_propspropvalrR   rR   rS   r   9  s    

zBaseQuerySet._clone_intor#   c                 C   s   |d7 }|   }|j||dS )zHandles dereferencing of :class:`~bson.dbref.DBRef` objects or
        :class:`~bson.object_id.ObjectId` a maximum depth in order to cut down
        the number queries to mongodb.
        r#   )	max_depth)rV   _dereference)rO   r   rY   rR   rR   rS   select_relatedj  s    zBaseQuerySet.select_relatedc                 C   s,   |   }||_d|_|jr(|j|j |S )a&  Limit the number of returned documents to `n`. This may also be
        achieved using array-slicing syntax (e.g. ``User.objects[:5]``).

        :param n: the maximum number of objects to return if n is greater than 0.
        When 0 is passed, returns all the documents in the cursor
        F)rV   rG   rN   rF   r   rO   r   rY   rR   rR   rS   r   t  s    zBaseQuerySet.limitc                 C   s&   |   }||_|jr"|j|j |S )zSkip `n` documents before returning the results. This may also be
        achieved using array-slicing syntax (e.g. ``User.objects[5:]``).

        :param n: the number of objects to skip before returning results
        )rV   rH   rF   r   r   rR   rR   rS   r     s
    zBaseQuerySet.skipc                 C   s&   |   }||_|jr"|j|j |S )a  Added 'hint' support, telling Mongo the proper index to use for the
        query.

        Judicious use of hints can greatly improve query performance. When
        doing a query on multiple fields (at least one of which is indexed)
        pass the indexed field as a hint to the query.

        Hinting will not do anything if the corresponding index does not exist.
        The last hint applied to this cursor takes precedence over all others.
        )rV   rI   rF   r   )rO   indexrY   rR   rR   rS   r     s
    zBaseQuerySet.hintc                 C   s$   |   }||_|jr |j| |S )a\  
        Collation allows users to specify language-specific rules for string
        comparison, such as rules for lettercase and accent marks.
        :param collation: `~pymongo.collation.Collation` or dict with
        following fields:
            {
                locale: str,
                caseLevel: bool,
                caseFirst: str,
                strength: int,
                numericOrdering: bool,
                alternate: str,
                maxVariable: str,
                backwards: str
            }
        Collation should be added to indexes like in test example
        )rV   rJ   rF   r   )rO   r   rY   rR   rR   rS   r     s
    zBaseQuerySet.collationc                 C   s&   |   }||_|jr"|j|j |S )a&  Limit the number of documents returned in a single batch (each
        batch requires a round trip to the server).

        See https://pymongo.readthedocs.io/en/stable/api/pymongo/cursor.html#pymongo.cursor.Cursor
        for details.

        :param size: desired size of each batch.
        )rV   rK   rF   
batch_size)rO   sizerY   rR   rR   rS   r     s
    	zBaseQuerySet.batch_sizec           
         sd  |   }z| |g }W n tk
r0   Y nX |j|}| jsH|S | j|d|| jd}| jj	
|ddd }d td}td}td}t||rt|d	|}t|||frt|d
d d|kr8|ddd D ]X}	 rt|||fr }t||	|}t||rt|d	|}t|||frt|d
d qވ r`t|||fr` fdd|D }|S )zReturn a list of distinct values for a given field.

        :param field: the field to select distinct values from

        .. note:: This is a command and won't take ordering or limit into
           account.
        r#   )nameinstance.r   NEmbeddedDocumentField	ListFieldGenericEmbeddedDocumentFieldfieldZdocument_typec                    s   g | ]} f |qS rR   rR   r   r   rR   rS   r   
  s     z)BaseQuerySet.distinct.<locals>.<listcomp>)rV   _fields_to_dbfieldsr^   r   rg   distinctre   r   r-   _fieldsrC   splitr   rU   r   )
rO   r   rY   Z
raw_valuesr   Z	doc_fieldr   r   r   Z
field_partrR   r   rS   r     sN    

   zBaseQuerySet.distinctc                 G   s   dd |D }| j d|S )a  Load only a subset of this document's fields. ::

            post = BlogPost.objects(...).only('title', 'author.name')

        .. note :: `only()` is chainable and will perform a union ::
            So with the following it will fetch both: `title` and `author.name`::

                post = BlogPost.objects.only('title').only('author.name')

        :func:`~mongoengine.queryset.QuerySet.all_fields` will reset any
        field filters.

        :param fields: fields to include
        c                 S   s   i | ]}|t jqS rR   )r   ZONLYr   frR   rR   rS   
<dictcomp>  s      z%BaseQuerySet.only.<locals>.<dictcomp>T)TfieldsrO   r   rR   rR   rS   only  s    zBaseQuerySet.onlyc                 G   s   dd |D }| j f |S )a  Opposite to .only(), exclude some document's fields. ::

            post = BlogPost.objects(...).exclude('comments')

        .. note :: `exclude()` is chainable and will perform a union ::
            So with the following it will exclude both: `title` and `author.name`::

                post = BlogPost.objects.exclude('title').exclude('author.name')

        :func:`~mongoengine.queryset.QuerySet.all_fields` will reset any
        field filters.

        :param fields: fields to exclude
        c                 S   s   i | ]}|t jqS rR   )r   ZEXCLUDEr   rR   rR   rS   r   /  s      z(BaseQuerySet.exclude.<locals>.<dictcomp>r   r   rR   rR   rS   exclude   s    zBaseQuerySet.excludec                 K   s   ddg}g }|  D ]L\}}|d}|d |krH|d}d| |i}d|}|||f qdd }	t||	d	}
|  }t|
d
d D ]8\}}dd |D }
|	|
}
| j
t|
||d7  _
q|S )a[  Manipulate how you load this document's fields. Used by `.only()`
        and `.exclude()` to manipulate which fields to retrieve. If called
        directly, use a set of kwargs similar to the MongoDB projection
        document. For example:

        Include only a subset of fields:

            posts = BlogPost.objects(...).fields(author=1, title=1)

        Exclude a specific field:

            posts = BlogPost.objects(...).fields(comments=0)

        To retrieve a subrange or sublist of array elements,
        support exist for both the `slice` and `elemMatch` projection operator:

            posts = BlogPost.objects(...).fields(slice__comments=5)
            posts = BlogPost.objects(...).fields(elemMatch__comments="test")

        :param kwargs: A set of keyword arguments identifying what to
            include, exclude, or slice.
        rf   Z	elemMatch__r   $r   c                 S   s   | \}}t |tr|S dS )Nr$   )rU   rj   )Zfield_tuple_r   rR   rR   rS   	_sort_keyX  s    
z&BaseQuerySet.fields.<locals>._sort_key)rn   c                 S   s   | d S )Nr#   rR   )xrR   rR   rS   <lambda>c      z%BaseQuerySet.fields.<locals>.<lambda>c                 S   s   g | ]\}}|qS rR   rR   )r   r   r   rR   rR   rS   r   d  s     z'BaseQuerySet.fields.<locals>.<listcomp>)r   _only_called)r   r   r^   joinappendsortedrV   	itertoolsgroupbyr   r3   r   )rO   r   r   	operatorsZcleaned_fieldsrn   r   partsopr   r   rY   grouprR   rR   rS   r   2  s*    



  zBaseQuerySet.fieldsc                 C   s   |   }t|jjd|_|S )zInclude all fields. Reset all previously calls of .only() or
        .exclude(). ::

            post = BlogPost.objects.exclude('comments').all_fields()
        r*   )rV   r   r3   r+   rv   rR   rR   rS   
all_fieldsl  s
    zBaseQuerySet.all_fieldsr}   c                G   s^   |r|rt d|  }|j}|r(|}n
||}|jrT|rJ|j| n
|rTd|_||_|S )a   Order the :class:`~mongoengine.queryset.QuerySet` by the given keys.

        The order may be specified by prepending each of the keys by a "+" or
        a "-". Ascending order is assumed if there's no prefix.

        If no keys are passed, existing ordering is cleared instead.

        :param keys: fields to order the query results by; keys may be
            prefixed with "+" or a "-" to determine the ordering direction.
        :param __raw__: a raw pymongo "sort" argument (provided as a list of (key, direction))
            see 'key_or_list' in `pymongo.cursor.Cursor.sort doc <https://pymongo.readthedocs.io/en/stable/api/pymongo/cursor.html#pymongo.cursor.Cursor.sort>`.
            If both keys and __raw__ are provided, an exception is raised
        z2Can not use both keys and __raw__ with order_by() N)r   rV   r4   _get_order_byrF   r   )rO   r~   keysrY   Zold_orderingZnew_orderingrR   rR   rS   rt   x  s    
zBaseQuerySet.order_byc                 C   s   |   }i |_|S )ab  Clear the default "_cls" query.

        By default, all queries generated for documents that allow inheritance
        include an extra "_cls" clause. In most cases this is desirable, but
        sometimes you might achieve better performance if you clear that
        default query.

        Scan the code for `_cls_query` to get more details.
        )rV   r1   rv   rR   rR   rS   clear_cls_query  s    
zBaseQuerySet.clear_cls_queryc                 C   s   |  d|S )zAdd a comment to the query.

        See https://www.mongodb.com/docs/manual/reference/method/cursor.comment/
        for details.
        comment_chainable_method)rO   r   rR   rR   rS   r    s    zBaseQuerySet.commentc                 C   s
   | j  S )zfReturn an explain plan record for the
        :class:`~mongoengine.queryset.QuerySet` cursor.
        )rg   explainrr   rR   rR   rS   r    s    zBaseQuerySet.explainc                 C   s"   d}t |t |  }||_|S )zxEnable or disable snapshot mode when querying.

        :param enabled: whether or not snapshot mode is enabled
        zAsnapshot is deprecated as it has no impact when using PyMongo 3+.)r   r   r   rV   r5   )rO   enabledrX   rY   rR   rR   rS   snapshot  s
    zBaseQuerySet.snapshotc                 C   s   |   }||_|S )zEnable or disable the use of temporary files on disk while processing a blocking sort operation.
         (To store data exceeding the 100 megabyte system memory limit)

        :param enabled: whether or not temporary files on disk are used
        )rV   r7   rO   r  rY   rR   rR   rS   allow_disk_use  s    zBaseQuerySet.allow_disk_usec                 C   s   |   }||_|S )zEnable or disable the default mongod timeout when querying. (no_cursor_timeout option)

        :param enabled: whether or not the timeout is used
        )rV   r6   r  rR   rR   rS   timeout  s    zBaseQuerySet.timeoutc                 C   s"   t d| |  }||_d|_|S )zChange the read_preference when querying.

        :param read_preference: override ReplicaSetConnection-level
            preference.
        read_preferenceN)r   rV   r8   rF   )rO   r  rY   rR   rR   rS   r    s
    
zBaseQuerySet.read_preferencec                 C   sJ   |dk	r t |ts t|d|  }|dk	r:tf |nd|_d|_|S )zChange the read_concern when querying.

        :param read_concern: override ReplicaSetConnection-level
            preference.
        Nz is not a valid read concern.)rU   r   rm   rV   r   r9   rF   )rO   r   rY   rR   rR   rS   r     s    zBaseQuerySet.read_concernc                 G   s.   |   }t||_|r"|j| }n| }|S )a  Instead of returning Document instances, return either a specific
        value or a tuple of values in order.

        Can be used along with
        :func:`~mongoengine.queryset.QuerySet.no_dereference` to turn off
        dereferencing.

        .. note:: This effects all results and can be unset by calling
                  ``scalar`` without arguments. Calls ``only`` automatically.

        :param fields: One or more fields to return instead of a Document.
        )rV   r   r;   r   r	  )rO   r   rY   rR   rR   rS   scalar  s    
zBaseQuerySet.scalarc                 G   s
   | j | S )zAn alias for scalar)r  r   rR   rR   rS   values_list  s    zBaseQuerySet.values_listc                 C   s   |   }d|_|S )zInstead of returning Document instances, return raw values from
        pymongo.

        This method is particularly useful if you don't need dereferencing
        and care primarily about the speed of data retrieval.
        T)rV   r=   rv   rR   rR   rS   
as_pymongo  s    zBaseQuerySet.as_pymongoc                 C   s   |  d|S )zWait `ms` milliseconds before killing the query on the server

        :param ms: the number of milliseconds before killing the query on the server
        max_time_msr  )rO   msrR   rR   rS   r    s    zBaseQuerySet.max_time_msc                 O   s2   d|krt dt t|d< tj|  f||S )zConverts a queryset to JSONZjson_optionsa  No 'json_options' are specified! Falling back to LEGACY_JSON_OPTIONS with uuid_representation=PYTHON_LEGACY. For use with other MongoDB drivers specify the UUID representation to use. This will be changed to uuid_representation=UNSPECIFIED in a future release.)r   r   r   r   r   dumpsr  )rO   argsr   rR   rR   rS   to_json%  s    zBaseQuerySet.to_jsonc                    s   t |} fdd|D S )z%Converts json data to unsaved objectsc                    s   g | ]} j |qS rR   )r-   rl   )r   datarr   rR   rS   r   6  s     z*BaseQuerySet.from_json.<locals>.<listcomp>)r   loads)rO   Z	json_dataZson_datarR   rr   rS   	from_json3  s    
zBaseQuerySet.from_jsonc           
      O   s4  t |tpt|}t |tr"|gnt|}|r>d}t|t ||7 }g }| jsV| jrv|	ddi |	dddii | j
r|	d| j
i | jr|	dt| ji | jdk	r|	d| j| jpd	 i | jdk	r|	d
| ji || }| j}	| jdk	s
| jdk	r| jj| j| jd}	|	j|fdi i|S )aA  Perform an aggregate function based on your queryset params

        :param pipeline: list of aggregation commands,
            see: https://www.mongodb.com/docs/manual/core/aggregation-pipeline/
        :param suppl_pipeline: unpacked list of pipeline (added to support deprecation of the old interface)
            parameter will be removed shortly
        :param kwargs: (optional) kwargs dictionary to be passed to pymongo's aggregate call
            See https://pymongo.readthedocs.io/en/stable/api/pymongo/collection.html#pymongo.collection.Collection.aggregate
        zCalling .aggregate() with un unpacked list (*pipeline) is deprecated, it will soon change and will expect a list (similar to pymongo.Collection.aggregate interface), see documentationz$limitr#   $matchz$exprFz$sortNr   z$skipr  r   cursor)rU   dictboolr   r   r   r   r<   rN   r  r   r4   rG   rH   r   r8   r9   with_options	aggregate)
rO   pipelineZsuppl_pipeliner   Zusing_deprecated_interfaceZuser_pipelinerX   Zinitial_pipelineZfinal_pipelinerQ   rR   rR   rS   r(  8  s4    


 zBaseQuerySet.aggregatec                 c   s|  |   }td}i }	t|tr,|j}	t|}t|||	p<d}i }
t|tr\|j}
t|}||}t||
ppd}d|ji}|ri }t|tr|j}t|}||}t||pd}||d< |r||d< |r||d< |dkr|jsd}dd	i|d
< nd}t|tr||d
< nt|t	rg }dD ]*}|
|}|r$|||f  qXq$td|
d}dddg}|r|dt|jf |d= |D ]$}|
|}|r|||f qt||d
< |j }||j ||d|}|r|d }nDt|d tr||d   }n"|d }|j|d  |d   }|jrP||j}|D ]"}||j|j|d |d V  qTdS )a4  Perform a map/reduce query using the current query spec
        and ordering. While ``map_reduce`` respects ``QuerySet`` chaining,
        it must be the last call made, as it does not return a maleable
        ``QuerySet``.

        See the :meth:`~mongoengine.tests.QuerySetTest.test_map_reduce`
        and :meth:`~mongoengine.tests.QuerySetTest.test_map_advanced`
        tests in ``tests.queryset.QuerySetTest`` for usage examples.

        :param map_f: map function, as :class:`~bson.code.Code` or string
        :param reduce_f: reduce function, as
                         :class:`~bson.code.Code` or string
        :param output: output collection name, if set to 'inline' will return
           the results inline. This can also be a dictionary containing output options
           see: https://www.mongodb.com/docs/manual/reference/command/mapReduce/#mongodb-dbcommand-dbcmd.mapReduce
        :param finalize_f: finalize function, an optional function that
                           performs any post-reduction processing.
        :param scope: values to insert into map/reduce global scope. Optional.
        :param limit: number of objects from current query to provide
                      to map/reduce method

        Returns an iterator yielding
        :class:`~mongoengine.document.MapReduceDocument`.
        MapReduceDocumentNrW   finalizescoper   inlineTr#   outF)replacemergereducez#actionData not specified for outputdb_aliasdbZshardedZ	nonAtomicr   )Z	mapReducemapr1  r   r   rQ   r   r   )rV   r   rU   r   r,  r   _sub_js_fieldsr   r4   r%  rC   r  r   r   r   r   r-   _get_dbcommand_get_collection_namer   clientr   r   )rO   Zmap_fZreduce_foutputZ
finalize_fr   r,  rY   r*  Zmap_f_scopeZreduce_f_scopeZreduce_f_codeZmr_argsZfinalize_f_scopeZfinalize_f_coder-  Zordered_outputpartr   r2  Zremaing_argsr3  r   r   infor   rR   rR   rS   
map_reducek  s    












	
   zBaseQuerySet.map_reducec                    s   |     |} fdd|D } j }||p6i d} j} jrR j|d< ||d< t||d} j }|jd||d	d	S )
a  Execute a Javascript function on the server. A list of fields may be
        provided, which will be translated to their correct names and supplied
        as the arguments to the function. A few extra variables are added to
        the function's scope: ``collection``, which is the name of the
        collection in use; ``query``, which is an object representing the
        current query; and ``options``, which is an object containing any
        options specified as keyword arguments.

        As fields in MongoEngine may use different names in the database (set
        using the :attr:`db_field` keyword argument to a :class:`Field`
        constructor), a mechanism exists for replacing MongoEngine field names
        with the database field names in Javascript code. When accessing a
        field, use square-bracket notation, and prefix the MongoEngine field
        name with a tilde (~).

        :param code: a string of Javascript code to execute
        :param fields: fields that you will be using in your function, which
            will be passed in to your function as arguments
        :param options: options that you want available to the function
            (accessed in Javascript through the ``options`` object)
        c                    s   g | ]} j |qS rR   )r-   _translate_field_namer   r   rR   rS   r     s     z(BaseQuerySet.exec_js.<locals>.<listcomp>)rQ   optionsz$whererW   )r,  eval)r  retval)
rV   r5  r-   r8  r   r2   r   r6  r7  rC   )rO   coder   r?  rQ   r,  rW   r3  rR   r   rS   exec_js  s    



zBaseQuerySet.exec_jsc                 C   s   |   }||}||_|S )a  Filter ``QuerySet`` results with a ``$where`` clause (a Javascript
        expression). Performs automatic field name substitution like
        :meth:`mongoengine.queryset.Queryset.exec_js`.

        .. note:: When using this mode of query, the database will call your
                  function, or evaluate your predicate clause, for each object
                  in the collection.
        )rV   r5  r2   )rO   where_clauserY   rR   rR   rS   where  s    	
zBaseQuerySet.wherec                 C   s   |  |g }d| jidddd| idig}td}|d}| j|}t|d	 |rp|d
dd| i t	| j
 |}|r|d d S dS )zSum over the values of the specified field.

        :param field: the field to sum over; use dot notation to refer to
            embedded document fields
        r"  $groupsumz$sumr   r   totalr   r   r,   r#   $unwindr   rI  r   r^   r   r   r   r-   _lookup_fieldrU   r   tuplera   r(  rO   r   db_fieldr)  r   field_partsZfield_instancesr   rR   rR   rS   rG    s    
zBaseQuerySet.sumc                 C   s   |  |g }d| jidddd| idig}td}|d}| j|}t|d	 |rp|d
dd| i t	| j
 |}|r|d d S dS )zAverage over the values of the specified field.

        :param field: the field to average over; use dot notation to refer to
            embedded document fields
        r"  rF  avgz$avgr   rH  r   r   r,   r#   rJ  r   rI  rK  rN  rR   rR   rS   average6  s    
zBaseQuerySet.averagec                 C   s    |r| j ||dS | j||dS )a"  Returns a dictionary of all items present in a field across
        the whole queried set of documents, and their corresponding frequency.
        This is useful for generating tag clouds, or searching documents.

        .. note::

            Can only do direct simple mappings and cannot map across
            :class:`~mongoengine.fields.ReferenceField` or
            :class:`~mongoengine.fields.GenericReferenceField` for more complex
            counting a manual map reduce call is required.

        If the field is a :class:`~mongoengine.fields.ListField`, the items within
        each list will be counted individually.

        :param field: the field to use
        :param normalize: normalize the results so they add to 1.0
        :param map_reduce: Use map_reduce over exec_js
        )	normalize)_item_frequencies_map_reduce_item_frequencies_exec_js)rO   r   rS  r=  rR   rR   rS   item_frequenciesP  s    zBaseQuerySet.item_frequenciesc                 C   sJ   | j s| jrtt| j}| jr$|S | jj|| jd}| j	rF| 
|S |S )z;Wrap the result in a :class:`~mongoengine.Document` object.rd   )r<   rN   r   r   rg   r=   r-   rl   re   r;   rk   )rO   Zraw_docr   rR   rR   rS   __next__i  s    

zBaseQuerySet.__next__c                 C   s   d| _ | j  dS )z+Rewind the cursor to its unevaluated state.FN)r:   rg   rewindrr   rR   rR   rS   rX  }  s    zBaseQuerySet.rewindc                 C   s   | j S )zProperty that returns the collection object. This allows us to
        perform operations only if the collection is accessed.
        )r.   rr   rR   rR   rS   r     s    zBaseQuerySet._collectionc                 C   s~   d}| j rd}t|t i }| js,d|d< | jr:d|d< | jrN| j ||< | jrz||krdi ||< | j	rzddi|| d< |S )	NZ
projectionz<The snapshot option is not anymore available with PyMongo 3+TZno_cursor_timeoutr  $meta	textScore_text_score)
r5   r   r   r   r6   r7   r3   Zas_dictr>   r?   )rO   Zfields_namerX   Zcursor_argsrR   rR   rS   r     s"    zBaseQuerySet._cursor_argsc                 C   sf  | j dk	r| j S | jdk	s$| jdk	rJ| jj| j| jdj| jf| j| _ n| jj| jf| j| _ | jr~| 	| j}| j 
| | jr| j | j n4| jdkr| jjd r| | jjd }| j | | jdk	r| j | j | jdk	r| j | j | jdkr| j | j | jdk	r,| j | j | jdk	rF| j | j | jdk	r`| j | j | j S )z>Return a PyMongo cursor object corresponding to this queryset.Nr#  Zorderingr,   )rF   r8   r9   r   r'  r   r   r   r2   r5  rE  r4   r   r-   rB   r
  rG   r   rH   r   rI   r   rJ   r   rK   r   rM   r  )rO   rD  orderrR   rR   rS   rg     sB    
 	

zBaseQuerySet._cursorc                 C   s   |   S )z;Essential for chained queries with ReferenceFields involved)rV   )rO   memorR   rR   rS   __deepcopy__  s    zBaseQuerySet.__deepcopy__c                 C   sR   | j d krL| j| j| _ | jrLd| j kr>d| j| j gi| _ n| j | j | j S )Nr(   z$and)r/   r0   Zto_queryr-   r1   rb   rr   rR   rR   rS   r     s    

zBaseQuerySet._queryc                 C   s   | j std | _ | j S )NZDeReference)r@   r   rr   rR   rR   rS   r     s    zBaseQuerySet._dereferencec                 C   s   t | j }|o| jS rp   )r   r-   rA   )rO   Zshould_derefrR   rR   rS   re     s    zBaseQuerySet._auto_dereferencec                 C   s   |   }d|_|S )z<Turn off any dereferencing for the results of this queryset.F)rV   rA   rv   rR   rR   rS   no_dereference  s    zBaseQuerySet.no_dereferencec           	         s   dj |d}d}| ||d}i }|D ]6}|j}t|trNt||krNt|}t|j||< q&|rt|   fdd|	 D }|S )Na  
            function() {{
                var path = '{{{{~{field}}}}}'.split('.');
                var field = this;

                for (p in path) {{
                    if (typeof field != 'undefined')
                       field = field[path[p]];
                    else
                       break;
                }}
                if (field && field.constructor == Array) {{
                    field.forEach(function(item) {{
                        emit(item, 1);
                    }});
                }} else if (typeof field != 'undefined') {{
                    emit(field, 1);
                }} else {{
                    emit(null, 1);
                }}
            }}
        )r   a%  
            function(key, values) {
                var total = 0;
                var valuesSize = values.length;
                for (var i=0; i < valuesSize; i++) {
                    total += parseInt(values[i], 10);
                }
                return total;
            }
        r-  c                    s   i | ]\}}|t |  qS rR   floatr   kvr   rR   rS   r   2  s      z=BaseQuerySet._item_frequencies_map_reduce.<locals>.<dictcomp>)
formatr=  rn   rU   ra  rj   r   rG  valuesr   )	rO   r   rS  Zmap_funcZreduce_funcrg  frequenciesr   rn   rR   re  rS   rT    s     

z)BaseQuerySet._item_frequencies_map_reducec           	         s   d}|  ||\ }fdd| D }|rF fdd| D }i }| D ].\}}t|trxt||krxt|}|||< qR|S )zUses exec_js to executeaa  
            function(path) {
                var path = path.split('.');

                var total = 0.0;
                db[collection].find(query).forEach(function(doc) {
                    var field = doc;
                    for (p in path) {
                        if (field)
                            field = field[path[p]];
                         else
                            break;
                    }
                    if (field && field.constructor == Array) {
                       total += field.length;
                    } else {
                       total++;
                    }
                });

                var frequencies = {};
                var types = {};
                var inc = 1.0;

                db[collection].find(query).forEach(function(doc) {
                    field = doc;
                    for (p in path) {
                        if (field)
                            field = field[path[p]];
                        else
                            break;
                    }
                    if (field && field.constructor == Array) {
                        field.forEach(function(item) {
                            frequencies[item] = inc + (isNaN(frequencies[item]) ? 0: frequencies[item]);
                        });
                    } else {
                        var item = field;
                        types[item] = item;
                        frequencies[item] = inc + (isNaN(frequencies[item]) ? 0: frequencies[item]);
                    }
                });
                return [total, frequencies, types];
            }
        c                    s    i | ]\}}  |t|qS rR   )rC   rj   rb  )typesrR   rS   r   f  s      z:BaseQuerySet._item_frequencies_exec_js.<locals>.<dictcomp>c                    s   i | ]\}}|t |  qS rR   r`  rb  )rI  rR   rS   r   i  s      )rC  r   rU   ra  rj   )	rO   r   rS  Z	freq_funcr  rg  rh  rc  rd  rR   )rI  ri  rS   rU  6  s    -

z&BaseQuerySet._item_frequencies_exec_jsc           
      C   s   g }| j jd r*dd | j jD dd }g }|D ]}|d}z*ddd | j |D }|| W q2 tk
r } zbd	}|D ]L}z2dd
d ||D }	||	 d}W  qW q tk
r   Y qX q|s|W 5 d}~X Y q2X q2|S )z0Translate fields' paths to their db equivalents.r'   c                 S   s   g | ]}t |qS rR   r
   )r   r   rR   rR   rS   r   y  s     z4BaseQuerySet._fields_to_dbfields.<locals>.<listcomp>r#   Nr   c                 s   s"   | ]}t |tr|n|jV  qd S rp   rU   r   rO  r   rR   rR   rS   	<genexpr>  s   z3BaseQuerySet._fields_to_dbfields.<locals>.<genexpr>Fc                 s   s"   | ]}t |tr|n|jV  qd S rp   rj  r   rR   rR   rS   rk    s   T)r-   rB   rE   r   r   rL  r  r   )
rO   r   Z
subclassesZdb_field_pathsr   rP  r   foundZsubdocZsubfieldrR   rR   rS   r   u  s4    





z BaseQuerySet._fields_to_dbfieldsc              	   C   s   g }|D ]}|sq|dkr.| dddif qtj}|d dkrFtj}|d dkr^|dd	 }|d
d}z| j|}W n tk
r   Y nX | ||f q|S )a  Given a list of MongoEngine-style sort keys, return a list
        of sorting tuples that can be applied to a PyMongo cursor. For
        example:

        >>> qs._get_order_by(['-last_name', 'first_name'])
        [('last_name', -1), ('first_name', 1)]
        z$text_scorer[  rY  rZ  r   -)rm  +r#   Nr   r   )r  r   Z	ASCENDINGZ
DESCENDINGr/  r-   r>  	Exception)rO   r  Zkey_listrn   	directionrR   rR   rS   r
    s&    zBaseQuerySet._get_order_byc                    s:   dd  fdd| j D }t|dkr2|d S t|S )Nc                 S   s"   | d}|D ]}t| |} q| S )Nr   )r   r   )objr   chunkschunkrR   rR   rS   lookup  s    
z(BaseQuerySet._get_scalar.<locals>.lookupc                    s   g | ]} |qS rR   rR   )r   r   r   rt  rR   rS   r     s     z,BaseQuerySet._get_scalar.<locals>.<listcomp>r#   r   )r;   rD   rM  )rO   r   r  rR   ru  rS   rk     s
    zBaseQuerySet._get_scalarc                    s8    fdd} fdd}t d||}t d||}|S )a  When fields are specified with [~fieldname] syntax, where
        *fieldname* is the Python name of a field, *fieldname* will be
        substituted for the MongoDB name of the field (specified using the
        :attr:`name` keyword argument in a field's constructor).
        c                    s*   |  dd} j|}d|d j S )Nr#   r   z["%s"]r,   )r  r   r-   rL  rO  r   r   r   rr   rR   rS   	field_sub  s    z.BaseQuerySet._sub_js_fields.<locals>.field_subc                    s0   |  dd} j|}ddd |D S )Nr#   r   c                 S   s   g | ]
}|j qS rR   )rO  r   rR   rR   rS   r     s     zGBaseQuerySet._sub_js_fields.<locals>.field_path_sub.<locals>.<listcomp>)r  r   r-   rL  r   rv  rr   rR   rS   field_path_sub  s    z3BaseQuerySet._sub_js_fields.<locals>.field_path_subz\[\s*~([A-z_][A-z_0-9.]+?)\s*\]z#\{\{\s*~([A-z_][A-z_0-9.]+?)\s*\}\})r   sub)rO   rB  rw  rx  rR   rr   rS   r5    s
    zBaseQuerySet._sub_js_fieldsc                 C   s0   |   }|j}t||| t|d| | |S )z{Call a particular method on the PyMongo cursor call a particular chainable method
        with the provided value.
        r   )rV   rg   r   r   )rO   method_namer   rY   r$  rR   rR   rS   r    s
    zBaseQuerySet._chainable_method)N)NT)TNN)F)NFN)FTNNFN)NN)FNFN)FFFFN)r#   )N)N)F)NNN)FT)F)F)Sr   
__module____qualname____doc__rT   rZ   r`   rc   ro   rs   rw   rx   rz   r|   r   rC   r   ru   r   r   r   rb   r   r   r   r   r   r   r   r   rV   r   r   r   r   r   r   r   r   r   r   r   r	  rt   r  r  r  r  r  r  r  r   r  r  r  r  r  r!  r(  r=  rC  rE  rG  rR  rV  rW  rX  propertyr   r   rg   r^  r   r   re   r_  rT  rU  r   r
  rk   r5  r  rR   rR   rR   rS   r   2   s   2
.
     
^
(
]      
L
     
$     
R
1



:
:'
		4     
z)



:




2
?%#r   )7r]   r  r   r   collections.abcr   r   Zpymongo.errorsZbsonr   r   Z	bson.coder   Zpymongo.collectionr   Zpymongo.commonr   Zpymongo.read_concernr   Zmongoenginer	   Zmongoengine.baser   Zmongoengine.commonr   Zmongoengine.connectionr   Zmongoengine.context_managersr   r   r   r   Zmongoengine.errorsr   r   r   r   r   Zmongoengine.pymongo_supportr   r   Zmongoengine.querysetr   Zmongoengine.queryset.field_listr   Zmongoengine.queryset.visitorr   r   __all__r   r   r    r!   r"   r   rR   rR   rR   rS   <module>   s8   