U
    @f;/                     @   s   d 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 ddlmZmZmZ ddlmZ G d	d
 d
eZG dd deZdS )z4CommandCursor class to iterate over command results.    )deque)&_convert_raw_document_lists_to_streams)integer_types)_SocketManager_CURSOR_CLOSED_ERRORS)ConnectionFailureInvalidOperationOperationFailure)_CursorAddress_GetMore_RawBatchGetMore)PinnedResponsec                   @   s   e Zd ZdZeZd/ddZdd Zd0d	d
Zdd Z	dd Z
dd Zdd Zedd Zdd Zdd Zd1ddZdd Zedd Zedd  Zed!d" Zed#d$ Zd%d& Zd'd( ZeZd)d* Zd+d, Zd-d. ZdS )2CommandCursorz)A cursor / iterator over command cursors.r   NFc	           	      C   s   d| _ || _|d | _t|d | _|d| _|| _|| _|| _	|| _
|| _| jdk| _| jrj| d d|kr~|d | _n|j| _| | t|ts|dk	rtddS )	zSCreate a new command cursor.

        The parameter 'retrieved' is unused.
        Nid
firstBatchpostBatchResumeTokenr   Tnsz,max_await_time_ms must be an integer or None)_CommandCursor__sock_mgr_CommandCursor__collection_CommandCursor__idr   _CommandCursor__dataget$_CommandCursor__postbatchresumetoken_CommandCursor__address_CommandCursor__batch_size!_CommandCursor__max_await_time_ms_CommandCursor__session _CommandCursor__explicit_session_CommandCursor__killed_CommandCursor__end_session_CommandCursor__nsZ	full_name
batch_size
isinstancer   	TypeError	selfZ
collectionZcursor_infoaddressZ	retrievedr!   Zmax_await_time_mssessionZexplicit_session r(   :/tmp/pip-unpacked-wheel-gs_301nf/pymongo/command_cursor.py__init__#   s*    



zCommandCursor.__init__c                 C   s   |    d S N_CommandCursor__dier%   r(   r(   r)   __del__C   s    zCommandCursor.__del__c                 C   sj   | j }d| _ | jr,|s,| j}t| j| j}nd}d}| jjj|||| j	| j
| j | js`d| _
d| _	dS )zCloses this cursor.
        Tr   N)r   r   r
   r   r    r   databaseclientZ_cleanup_cursorr   r   r   )r%   synchronousZalready_killed	cursor_idr&   r(   r(   r)   Z__dieF   s*    
 
zCommandCursor.__diec                 C   s$   | j r | js | j j|d d | _ d S )N)lock)r   r   Z_end_session)r%   r2   r(   r(   r)   Z__end_session^   s    zCommandCursor.__end_sessionc                 C   s   |  d dS )z-Explicitly close / kill this cursor.
        TNr,   r.   r(   r(   r)   closec   s    zCommandCursor.closec                 C   s8   t |tstd|dk r"td|dkr.dp0|| _| S )a  Limits the number of documents returned in one batch. Each batch
        requires a round trip to the server. It can be adjusted to optimize
        performance and limit data transfer.

        .. note:: batch_size can not override MongoDB's internal limits on the
           amount of data it will return to the client in a single batch (i.e
           if you set batch size to 1,000,000,000, MongoDB will currently only
           return 4-16MB of results per batch).

        Raises :exc:`TypeError` if `batch_size` is not an integer.
        Raises :exc:`ValueError` if `batch_size` is less than ``0``.

        :Parameters:
          - `batch_size`: The size of each batch of results requested.
        zbatch_size must be an integerr   zbatch_size must be >= 0      )r"   r   r#   
ValueErrorr   )r%   r!   r(   r(   r)   r!   h   s    
zCommandCursor.batch_sizec                 C   s   t | jdkS )zUReturns `True` if the cursor has documents remaining from the
        previous batch.r   )lenr   r.   r(   r(   r)   	_has_next   s    zCommandCursor._has_nextc                 C   s   | j S )zcRetrieve the postBatchResumeToken from the response to a
        changeStream aggregate or getMore.)r   r.   r(   r(   r)   _post_batch_resume_token   s    z&CommandCursor._post_batch_resume_tokenc                 C   sP   | j jj}|| jsd S | jsL|  t|d}| jdkrF|	  n|| _d S )NFr   )
r   r0   r1   Z_should_pin_cursorr   r   Z
pin_cursorr   r   r5   )r%   Z	sock_infor1   Zsock_mgrr(   r(   r)   _maybe_pin_connection   s    



z#CommandCursor._maybe_pin_connectionc              
   C   s$  | j jj}z|j|| j| jd}W nz tk
r^ } z|jtkrDd| _	| 
   W 5 d}~X Y n@ tk
r   d| _	| 
   Y n tk
r   | 
   Y nX t|tr| jst|j|j| _|jr|jd d }|d }|d| _|d | _n|j}|jj| _| jdkr| 
  t|| _dS )	z8Send a getmore message and handle the response.
        )r&   TNr   cursorZ	nextBatchr   r   )r   r0   r1   Z_run_operation_unpack_responser   r	   coder   r   r5   r   	Exceptionr"   r   r   r   Zsocket_infoZmore_to_comeZfrom_commandZdocsr   r   r   datar3   r   r   )r%   Z	operationr1   responseexcr=   Z	documentsr(   r(   r)   Z__send_message   sD    
  



zCommandCursor.__send_messagec                 C   s   | ||||S r+   )Zunpack_response)r%   rB   r3   codec_optionsuser_fieldslegacy_responser(   r(   r)   r>      s    
zCommandCursor._unpack_responsec                 C   s   t | js| jrt | jS | jrz| jdd\}}| j| j}| 	| 
||| j| j| jj|| j| jjj| j| jd n
| d t | jS )a  Refreshes the cursor with more data from the server.

        Returns the length of self.__data after refresh. Will exit early if
        self.__data is already non-empty. Raises OperationFailure when the
        cursor cannot be refreshed due to an error on the query.
        .r6   FT)r9   r   r   r   r    splitr   Z_read_preference_forr'   _CommandCursor__send_message_getmore_classr   rD   r   r0   r1   r   r   r-   )r%   ZdbnameZcollnameZ	read_prefr(   r(   r)   _refresh   s*    
 
zCommandCursor._refreshc                 C   s   t t| jp| j S )a  Does this cursor have the potential to return more data?

        Even if :attr:`alive` is ``True``, :meth:`next` can raise
        :exc:`StopIteration`. Best to use a for loop::

            for doc in collection.aggregate(pipeline):
                print(doc)

        .. note:: :attr:`alive` can be True while iterating a cursor from
          a failed server. In this case :attr:`alive` will return False after
          :meth:`next` fails to retrieve the next batch of results from the
          server.
        )boolr9   r   r   r.   r(   r(   r)   alive   s    zCommandCursor.alivec                 C   s   | j S )zReturns the id of the cursor.)r   r.   r(   r(   r)   r3      s    zCommandCursor.cursor_idc                 C   s   | j S )zUThe (host, port) of the server used, or None.

        .. versionadded:: 3.0
        )r   r.   r(   r(   r)   r&      s    zCommandCursor.addressc                 C   s   | j r| jS dS )zmThe cursor's :class:`~pymongo.client_session.ClientSession`, or None.

        .. versionadded:: 3.6
        N)r   r   r.   r(   r(   r)   r'     s    zCommandCursor.sessionc                 C   s   | S r+   r(   r.   r(   r(   r)   __iter__  s    zCommandCursor.__iter__c                 C   s&   | j r| d}|dk	r |S q tdS )zAdvance the cursor.TN)rM   	_try_nextStopIteration)r%   docr(   r(   r)   next  s
    
zCommandCursor.nextc                 C   sH   t | js| js|r|   t | jr@| j}|j| j |S dS dS )z<Advance the cursor blocking for at most one getMore command.N)r9   r   r   rK   r   r0   Z_fix_outgoingpopleft)r%   Zget_more_allowedZcollr(   r(   r)   rO     s    
zCommandCursor._try_nextc                 C   s   | S r+   r(   r.   r(   r(   r)   	__enter__$  s    zCommandCursor.__enter__c                 C   s   |    d S r+   )r5   )r%   exc_typeexc_valexc_tbr(   r(   r)   __exit__'  s    zCommandCursor.__exit__)r   r   NNF)F)NF)__name__
__module____qualname____doc__r   rJ   r*   r/   r-   r   r5   r!   r:   propertyr;   r<   rI   r>   rK   rM   r3   r&   r'   rN   rR   __next__rO   rT   rX   r(   r(   r(   r)   r      sH          
 

*   






r   c                       s4   e Zd ZeZd
 fdd	ZdddZdd	 Z  ZS )RawBatchCommandCursorr   NFc	           	   
      s0   | drttt| |||||||| dS )aL  Create a new cursor / iterator over raw batches of BSON data.

        Should not be called directly by application developers -
        see :meth:`~pymongo.collection.Collection.aggregate_raw_batches`
        instead.

        .. seealso:: The MongoDB documentation on `cursors <https://dochub.mongodb.org/core/cursors>`_.
        r   N)r   AssertionErrorsuperr_   r*   r$   	__class__r(   r)   r*   .  s    
      zRawBatchCommandCursor.__init__c                 C   s"   |j ||d}|st|d  |S )N)rE   r   )raw_responser   )r%   rB   r3   rD   rE   rF   rd   r(   r(   r)   r>   >  s     z&RawBatchCommandCursor._unpack_responsec                 C   s   t dd S )Nz)Cannot call __getitem__ on RawBatchCursor)r   )r%   indexr(   r(   r)   __getitem__H  s    z!RawBatchCommandCursor.__getitem__)r   r   NNF)NF)	rY   rZ   r[   r   rJ   r*   r>   rf   __classcell__r(   r(   rb   r)   r_   +  s             

r_   N)r\   collectionsr   Zbsonr   Zbson.py3compatr   Zpymongo.cursorr   r   Zpymongo.errorsr   r   r	   Zpymongo.messager
   r   r   Zpymongo.responser   objectr   r_   r(   r(   r(   r)   <module>   s     