U
    >i~4                     @  s   d Z ddlmZ ddlmZ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mZ ddlmZ ddlmZ dd	lmZmZmZmZmZmZmZmZ erdd
lm Z  ddl!m"Z" ddl#m$Z$ G dd dej%eZ&G dd deZ'dddddZ(dS )zEHelpers for applying Google Cloud Firestore changes in a transaction.    )annotations)TYPE_CHECKINGAnyAsyncGeneratorCallable	CoroutineOptional)
exceptionsgapic_v1)retry_async)_helpersasync_batch)AsyncDocumentReference)
AsyncQuery)_CANT_BEGIN_CANT_COMMIT_CANT_ROLLBACK_EXCEED_ATTEMPTS_TEMPLATE_WRITE_READ_ONLYMAX_ATTEMPTSBaseTransaction_BaseTransactional)AsyncStreamGenerator)DocumentSnapshot)ExplainOptionsc                      s   e Zd ZdZedfdd fddZddd fd	d
Zd"dddddZddddZddddZ	e
jjdfdddddddZe
jjdfddddddddd d!Z  ZS )#AsyncTransactionaO  Accumulate read-and-write operations to be sent in a transaction.

    Args:
        client (:class:`~google.cloud.firestore_v1.async_client.AsyncClient`):
            The client that created this transaction.
        max_attempts (Optional[int]): The maximum number of attempts for
            the transaction (i.e. allowing retries). Defaults to
            :attr:`~google.cloud.firestore_v1.transaction.MAX_ATTEMPTS`.
        read_only (Optional[bool]): Flag indicating if the transaction
            should be read-only or should allow writes. Defaults to
            :data:`False`.
    FNonereturnc                   s"   t t| | t| || d S N)superr   __init__r   )selfclientZmax_attemptsZ	read_only	__class__ O/tmp/pip-unpacked-wheel-599y42ri/google/cloud/firestore_v1/async_transaction.pyr!   :   s    zAsyncTransaction.__init__list)	write_pbsr   c                   s"   | j rtttt| | dS )a
  Add `Write`` protobufs to this transaction.

        Args:
            write_pbs (List[google.cloud.firestore_v1.                write.Write]): A list of write protobufs to be added.

        Raises:
            ValueError: If this transaction is read-only.
        N)
_read_only
ValueErrorr   r    r   _add_write_pbs)r"   r)   r$   r&   r'   r,   >   s    
zAsyncTransaction._add_write_pbsNzbytes | None)retry_idr   c                   sR   | j rt| j}t|| jjj| jj| 	|d| jj
dI dH }|j| _dS )zBegin the transaction.

        Args:
            retry_id (Optional[bytes]): Transaction ID of a transaction to be
                retried.

        Raises:
            ValueError: If the current transaction has already begun.
        )databaseoptionsrequestmetadataN)in_progressr   format_idr+   _client_firestore_apiZbegin_transaction_database_stringZ_options_protobuf_rpc_metadatatransaction)r"   r-   msgZtransaction_responser&   r&   r'   _beginM   s    
zAsyncTransaction._beginc                   sJ   | j sttz,| jjj| jj| jd| jj	dI dH  W 5 |   X dS )zRoll back the transaction.

        Raises:
            ValueError: If no transaction is in progress.
            google.api_core.exceptions.GoogleAPICallError: If the rollback fails.
        )r.   r:   r0   N)
r3   r+   r   	_clean_upr6   r7   rollbackr8   r5   r9   )r"   r&   r&   r'   	_rollbackd   s    	zAsyncTransaction._rollbackc                   s\   | j stt| jjj| jj| j| jd| jj	dI dH }| 
  t|j| _|j| _| jS )a  Transactionally commit the changes accumulated.

        Returns:
            List[:class:`google.cloud.firestore_v1.write.WriteResult`, ...]:
            The write results corresponding to the changes committed, returned
            in the same order as the changes were applied to this transaction.
            A write result contains an ``update_time`` field.

        Raises:
            ValueError: If no transaction is in progress.
        )r.   Zwritesr:   r0   N)r3   r+   r   r6   r7   commitr8   Z
_write_pbsr5   r9   r=   r(   Zwrite_resultsZcommit_time)r"   Zcommit_responser&   r&   r'   _commit{   s    	zAsyncTransaction._commitz"retries.AsyncRetry | object | Nonezfloat | Nonez%AsyncGenerator[DocumentSnapshot, Any])
referencesretrytimeoutr   c                   s*   t ||}| jj|fd| i|I dH S )at  Retrieves multiple documents from Firestore.

        Args:
            references (List[.AsyncDocumentReference, ...]): Iterable of document
                references to be retrieved.
            retry (google.api_core.retry.Retry): Designation of what errors, if any,
                should be retried.  Defaults to a system-specified policy.
            timeout (float): The timeout for this request.  Defaults to a
                system-specified value.

        Yields:
            .DocumentSnapshot: The next document snapshot that fulfills the
            query, or :data:`None` if the document does not exist.
        r:   N)r   make_retry_timeout_kwargsr6   get_all)r"   rB   rC   rD   kwargsr&   r&   r'   rF      s    zAsyncTransaction.get_all)explain_optionsz#AsyncDocumentReference | AsyncQueryzOptional[float]zOptional[ExplainOptions]zNAsyncGenerator[DocumentSnapshot, Any] | AsyncStreamGenerator[DocumentSnapshot])ref_or_queryrC   rD   rH   r   c                  s   t ||}t|trF|dk	r&td| jj|gfd| i|I dH S t|trt|dk	r`||d< |jf d| i|S tddS )a  
        Retrieve a document or a query result from the database.

        Args:
            ref_or_query (AsyncDocumentReference | AsyncQuery):
                The document references or query object to return.
            retry (google.api_core.retry.Retry): Designation of what errors, if any,
                should be retried.  Defaults to a system-specified policy.
            timeout (float): The timeout for this request.  Defaults to a
                system-specified value.
            explain_options
                (Optional[:class:`~google.cloud.firestore_v1.query_profile.ExplainOptions`]):
                Options to enable query profiling for this query. When set,
                explain_metrics will be available on the returned generator.
                Can only be used when running a query, not a document reference.

        Yields:
            DocumentSnapshot: The next document snapshot that fulfills the query,
            or :data:`None` if the document does not exist.

        Raises:
            ValueError: if `ref_or_query` is not one of the supported types, or
            explain_options is provided when `ref_or_query` is a document
            reference.
        Nz^When type of `ref_or_query` is `AsyncDocumentReference`, `explain_options` cannot be provided.r:   rH   zSValue for argument "ref_or_query" must be a AsyncDocumentReference or a AsyncQuery.)	r   rE   
isinstancer   r+   r6   rF   r   stream)r"   rI   rC   rD   rH   rG   r&   r&   r'   get   s(    !

zAsyncTransaction.get)N)__name__
__module____qualname____doc__r   r!   r,   r<   r?   rA   r
   methodDEFAULTrF   rL   __classcell__r&   r&   r$   r'   r   ,   s    r   c                      s>   e Zd ZdZdd fddZdddd	d
Zdd Z  ZS )_AsyncTransactionalal  Provide a callable object to use as a transactional decorater.

    This is surfaced via
    :func:`~google.cloud.firestore_v1.async_transaction.transactional`.

    Args:
        to_wrap (Coroutine[[:class:`~google.cloud.firestore_v1.async_transaction.AsyncTransaction`, ...], Any]):
            A coroutine that should be run (and retried) in a transaction.
    r   r   c                   s   t t| | d S r   )r    rT   r!   )r"   to_wrapr$   r&   r'   r!      s    z_AsyncTransactional.__init__r   r   )r:   r   c                   sN   |   |j| jdI dH  |j| _| jdkr6| j| _| j|f||I dH S )a}  Begin transaction and call the wrapped coroutine.

        Args:
            transaction
                (:class:`~google.cloud.firestore_v1.async_transaction.AsyncTransaction`):
                A transaction to execute the coroutine within.
            args (Tuple[Any, ...]): The extra positional arguments to pass
                along to the wrapped coroutine.
            kwargs (Dict[str, Any]): The extra keyword arguments to pass
                along to the wrapped coroutine.

        Returns:
            Any: result of the wrapped coroutine.

        Raises:
            Exception: Any failure caused by ``to_wrap``.
        )r-   N)r=   r<   r-   r5   Z
current_idrU   )r"   r:   argsrG   r&   r&   r'   _pre_commit   s    
z_AsyncTransactional._pre_commitc           
        s   |    |jstjnd}d}zt|jD ]^}| j|f||I dH }z| I dH  |W   W S  |k
r } z|}W 5 d}~X Y q(X q(t	|j}	t
|	|W n$ tk
r   | I dH   Y nX dS )a  Execute the wrapped callable within a transaction.

        Args:
            transaction
                (:class:`~google.cloud.firestore_v1.transaction.Transaction`):
                A transaction to execute the callable within.
            args (Tuple[Any, ...]): The extra positional arguments to pass
                along to the wrapped callable.
            kwargs (Dict[str, Any]): The extra keyword arguments to pass
                along to the wrapped callable.

        Returns:
            Any: The result of the wrapped callable.

        Raises:
            ValueError: If the transaction does not succeed in
                ``max_attempts``.
        r&   N)Z_resetr*   r	   ZAbortedrangeZ_max_attemptsrW   rA   r   r4   r+   BaseExceptionr?   )
r"   r:   rV   rG   Zretryable_exceptionslast_excattemptresultexcr;   r&   r&   r'   __call__  s"    	z_AsyncTransactional.__call__)rM   rN   rO   rP   r!   rW   r^   rS   r&   r&   r$   r'   rT      s   
rT   z!Callable[[AsyncTransaction], Any])rU   r   c                 C  s   t | S )a  Decorate a callable so that it runs in a transaction.

    Args:
        to_wrap
            (Callable[[:class:`~google.cloud.firestore_v1.transaction.Transaction`, ...], Any]):
            A callable that should be run (and retried) in a transaction.

    Returns:
        Callable[[:class:`~google.cloud.firestore_v1.transaction.Transaction`, ...], Any]:
        the wrapped callable.
    )rT   )rU   r&   r&   r'   async_transactionalC  s    r_   N))rP   
__future__r   typingr   r   r   r   r   r   Zgoogle.api_corer	   r
   r   retriesZgoogle.cloud.firestore_v1r   r   Z(google.cloud.firestore_v1.async_documentr   Z%google.cloud.firestore_v1.async_queryr   Z*google.cloud.firestore_v1.base_transactionr   r   r   r   r   r   r   r   Z0google.cloud.firestore_v1.async_stream_generatorr   Z'google.cloud.firestore_v1.base_documentr   Z'google.cloud.firestore_v1.query_profiler   ZAsyncWriteBatchr   rT   r_   r&   r&   r&   r'   <module>   s     ( 9_