o
    ˷e;                  	   @   sX  d 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
mZmZmZmZmZmZ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mZm Z m!Z! ddl"m#Z# G dd dej$e	Z%G dd deZ&de e%gef de&fddZ'de#de(de)dej*fddZ+eefde,de,de,de,fdd Z-dS )!zEHelpers for applying Google Cloud Firestore changes in a transaction.    N)gapic_v1)retry)_BaseTransactionalBaseTransactionMAX_ATTEMPTS_CANT_BEGIN_CANT_ROLLBACK_CANT_COMMIT_WRITE_READ_ONLY_INITIAL_SLEEP
_MAX_SLEEP_MULTIPLIER_EXCEED_ATTEMPTS_TEMPLATE)
exceptions)async_batch)_helpers)types)AsyncDocumentReference)DocumentSnapshot)
AsyncQuery)AnyAsyncGeneratorCallable	Coroutine)Clientc                       s   e Zd ZdZedfd fddZdeddf fdd	Zdd
eddfddZ	dddZ
defddZejjdfdedejdedeeef fddZejjdfdejdedeeef fddZ  ZS )AsyncTransactionaD  Accumulate read-and-write operations to be sent in a transaction.

    Args:
        client (:class:`~google.cloud.firestore_v1.client.Client`):
            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returnNc                    s"   t t| | t| || d S N)superr   __init__r   )selfclientmax_attempts	read_only	__class__ b/var/www/ideatree/venv/lib/python3.10/site-packages/google/cloud/firestore_v1/async_transaction.pyr   B   s   zAsyncTransaction.__init__	write_pbsc                    s"   | j rtttt| | dS )a  Add `Write`` protobufs to this transaction.

        Args:
            write_pbs (List[google.cloud.proto.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+   F   s   
zAsyncTransaction._add_write_pbsretry_idc                    sT   | 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_apibegin_transaction_database_string_options_protobuf_rpc_metadatatransaction)r    r,   msgtransaction_responser&   r&   r'   _beginU   s   
zAsyncTransaction._beginc                    sR   | j sttz| jjj| jj| jd| jjdI dH  W | 	  dS | 	  w )znRoll back the transaction.

        Raises:
            ValueError: If no transaction is in progress.
        )r-   r;   r/   N)
r2   r*   r   r5   r6   rollbackr8   r4   r:   	_clean_up)r    r&   r&   r'   	_rollbackl   s   zAsyncTransaction._rollbackc                    s:   | j sttt| j| j| jI dH }|   t|j	S )a  Transactionally commit the changes accumulated.

        Returns:
            List[:class:`google.cloud.proto.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.
        N)
r2   r*   r	   _commit_with_retryr5   
_write_pbsr4   r@   listwrite_results)r    commit_responser&   r&   r'   _commit   s   

zAsyncTransaction._commit
referencesr   timeoutc                    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_kwargsr5   get_all)r    rH   r   rI   kwargsr&   r&   r'   rK      s   zAsyncTransaction.get_allc                    sd   t ||}t|tr| jj|gfd| i|I dH S t|tr.|jdd| i|I dH S td)aW  
        Retrieve a document or a query result from the database.

        Args:
            ref_or_query 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.

        Yields:
            .DocumentSnapshot: The next document snapshot that fulfills the
            query, or :data:`None` if the document does not exist.
        r;   NzSValue for argument "ref_or_query" must be a AsyncDocumentReference or a AsyncQuery.r&   )	r   rJ   
isinstancer   r5   rK   r   streamr*   )r    ref_or_queryr   rI   rL   r&   r&   r'   get   s   

zAsyncTransaction.getr   Nr   )__name__
__module____qualname____doc__r   r   rD   r+   bytesr>   rA   rG   r   methodDEFAULTretriesRetryfloatr   r   r   rK   rP   __classcell__r&   r&   r$   r'   r   4   s6    



r   c                       sN   e Zd ZdZd fddZdedefddZdedef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   Nc                    s   t t| | d S r   )r   r]   r   )r    to_wrapr$   r&   r'   r      s   z_AsyncTransactional.__init__r;   c                    sp   |   |j| jdI dH  |j| _| jdu r| j| _z| j|g|R i |I dH W S    | I dH   )a;  Begin transaction and call the wrapped coroutine.

        If the coroutine raises an exception, the transaction will be rolled
        back. If not, the transaction will be "ready" for ``Commit`` (i.e.
        it will have staged writes).

        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,   r4   
current_idr^   rA   )r    r;   argsrL   r&   r&   r'   _pre_commit   s   
 z_AsyncTransactional._pre_commitc              
      sV   z
|  I dH  W dS  tjy* } z|jr t|tjr%W Y d}~dS  d}~ww )a  Try to commit the transaction.

        If the transaction is read-write and the ``Commit`` fails with the
        ``ABORTED`` status code, it will be retried. Any other failure will
        not be caught.

        Args:
            transaction
                (:class:`~google.cloud.firestore_v1.transaction.Transaction`):
                The transaction to be ``Commit``-ed.

        Returns:
            bool: Indicating if the commit succeeded.
        NTF)rG   r   GoogleAPICallErrorr)   rM   Aborted)r    r;   excr&   r&   r'   _maybe_commit  s   z!_AsyncTransactional._maybe_commitc                    sv   |    t|jD ]}| j|g|R i |I dH }| |I dH }|r)|  S q
| I dH  t|j}t|)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``.
        N)	_resetrange_max_attemptsra   re   rA   r   r3   r*   )r    r;   r`   rL   attemptresult	succeededr<   r&   r&   r'   __call__!  s   	z_AsyncTransactional.__call__rQ   )rR   rS   rT   rU   r   r   r   ra   boolre   rl   r\   r&   r&   r$   r'   r]      s    

(r]   r^   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.
    )r]   )r^   r&   r&   r'   async_transactionalG  s   rn   r!   r(   transaction_idc                    sR   t }	 z| jj| j||d| jdI dH W S  tjy    Y nw t|I dH }q)a.  Call ``Commit`` on the GAPIC client with retry / sleep.

    Retries the ``Commit`` RPC on Unavailable. Usually this RPC-level
    retry is handled by the underlying GAPICd client, but in this case it
    doesn't because ``Commit`` is not always idempotent. But here we know it
    is "idempotent"-like because it has a transaction ID. We also need to do
    our own retry to special-case the ``INVALID_ARGUMENT`` error.

    Args:
        client (:class:`~google.cloud.firestore_v1.client.Client`):
            A client with GAPIC client and configuration details.
        write_pbs (List[:class:`google.cloud.proto.firestore.v1.write.Write`, ...]):
            A ``Write`` protobuf instance to be committed.
        transaction_id (bytes):
            ID of an existing transaction that this commit will run in.

    Returns:
        :class:`google.cloud.firestore_v1.types.CommitResponse`:
        The protobuf response from ``Commit``.

    Raises:
        ~google.api_core.exceptions.GoogleAPICallError: If a non-retryable
            exception is encountered.
    T)r-   writesr;   r/   N)r   r6   commitr8   r:   r   ServiceUnavailable_sleep)r!   r(   ro   current_sleepr&   r&   r'   rB   Y  s    rB   rt   	max_sleep
multiplierc                    s,   t d| }t|I dH  t||  |S )a  Sleep and produce a new sleep time.

    .. _Exponential Backoff And Jitter: https://www.awsarchitectureblog.com/                                        2015/03/backoff.html

    Select a duration between zero and ``current_sleep``. It might seem
    counterintuitive to have so much jitter, but
    `Exponential Backoff And Jitter`_ argues that "full jitter" is
    the best strategy.

    Args:
        current_sleep (float): The current "max" for sleep interval.
        max_sleep (Optional[float]): Eventual "max" sleep time
        multiplier (Optional[float]): Multiplier for exponential backoff.

    Returns:
        float: Newly doubled ``current_sleep`` or ``max_sleep`` (whichever
        is smaller)
    g        N)randomuniformasynciosleepmin)rt   ru   rv   actual_sleepr&   r&   r'   rs     s   rs   ).rU   ry   rw   google.api_corer   r   rY   *google.cloud.firestore_v1.base_transactionr   r   r   r   r   r	   r
   r   r   r   r   r   google.cloud.firestore_v1r   r   r   (google.cloud.firestore_v1.async_documentr   r   %google.cloud.firestore_v1.async_queryr   typingr   r   r   r    google.cloud.firestore_v1.clientr   AsyncWriteBatchr   r]   rn   rD   rV   CommitResponserB   r[   rs   r&   r&   r&   r'   <module>   sT   4 x

.