o
    tBhd5                     @   s   d Z ddlZddl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 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" G dd dZ#G dd dZ$dS )zDClasses for representing bundles for the Google Cloud Firestore API.    N)BundledDocumentMetadataBundledQueryBundleElementBundleMetadata
NamedQuery)_datetime_to_pb_timestampUTC)limit_type_of_query)
AsyncQuery)
BaseClient)DocumentSnapshot)	BaseQuery)DocumentReference)_helpers)	Timestamp)json_format)DictListOptionalUnionc                   @   s  e Zd ZU dZdZeed< deddfddZd	e	dd fd
dZ
dededd fddZdededejfddZdededejddfddZd	ededejfddZded	edejdefddZdeejef ddfddZdededefddZdefd d!Zdedefd"d#Zd$d% ZdS )&FirestoreBundleae  A group of serialized documents and queries, suitable for
    longterm storage or query resumption.

    If any queries are added to this bundle, all associated documents will be
    loaded and stored in memory for serialization.

    Usage:

        from google.cloud.firestore import Client
        from google.cloud.firestore_bundle import FirestoreBundle
        from google.cloud.firestore import _helpers

        db = Client()
        bundle = FirestoreBundle('my-bundle')
        bundle.add_named_query('all-users', db.collection('users')._query())
        bundle.add_named_query(
            'top-ten-hamburgers',
            db.collection('hamburgers').limit(limit=10)._query(),
        )
        serialized: str = bundle.build()

        # Store somewhere like your GCS for retrieval by a client SDK.

    Args:
        name (str): The Id of the bundle.
       BUNDLE_SCHEMA_VERSIONnamereturnNc                 C   s*   || _ i | _i | _tddd| _d | _d S )Nr   )secondsnanos)r   	documentsnamed_queriesr   latest_read_time_deserialized_metadata)selfr    r"   {/var/www/html/riverr-enterprise-integrations-main/venv/lib/python3.10/site-packages/google/cloud/firestore_bundle/bundle.py__init__K   s
   
zFirestoreBundle.__init__snapshotc                 C   s   g }|j j}| j|}|r|jj}|du p t|j|j	jdk}|r4t
|t||j|j|dd| j|< | |j |   | S )a  Adds a document to the bundle.

        Args:
            snapshot (DocumentSnapshot): The fully-loaded Firestore document to
                be preserved.

        Example:

            from google.cloud import firestore

            db = firestore.Client()
            collection_ref = db.collection(u'users')

            bundle = firestore.FirestoreBundle('my bundle')
            bundle.add_document(collection_ref.documents('some_id').get())

        Returns:
            FirestoreBundle: self
        Nr   )r   	read_timeexistsqueriesr%   metadata)	reference_document_pathr   getr*   r(   r   compare_timestampsr&   r%   _BundledDocumentr   r'   _update_last_read_time_reset_metadata)r!   r%   original_queriesfull_document_pathoriginal_documentshould_use_snaphotr"   r"   r#   add_documentR   s2   


zFirestoreBundle.add_documentqueryc                 C   sb   t |tstdt|j d|| jv rtd| d| j||d}| ||| |   | S )a  Adds a query to the bundle, referenced by the provided name.

        Args:
            name (str): The name by which the provided query should be referenced.
            query (Query): Query of documents to be fully loaded and stored in
                the bundle for future access.

        Example:

            from google.cloud import firestore

            db = firestore.Client()
            collection_ref = db.collection(u'users')

            bundle = firestore.FirestoreBundle('my bundle')
            bundle.add_named_query('all the users', collection_ref._query())

        Returns:
            FirestoreBundle: self

        Raises:
            ValueError: If anything other than a BaseQuery (e.g., a Collection)
                is supplied. If you have a Collection, call its `_query()`
                method to get what this method expects.
            ValueError: If the supplied name has already been added.
        z&Attempted to add named query of type: z. Expected BaseQuery.zQuery name conflict: z has already been added.)
query_name)	
isinstancer   
ValueErrortype__name__r   _save_documents_from_query_save_named_queryr1   )r!   r   r7   
_read_timer"   r"   r#   add_named_query   s   

zFirestoreBundle.add_named_queryr8   c                 C   s|   t j jjtd}t|trdd l}| }|| 	||S |
 D ]}| | | j|jj}|jj| |j}q"|S )Ntzinfor   )datetimeminreplacer   r9   r
   asyncioget_event_looprun_until_complete_process_async_querystreamr6   r   r-   r+   r,   r*   r(   appendr&   )r!   r7   r8   r?   rF   loopdocbundled_documentr"   r"   r#   r=      s   

z*FirestoreBundle._save_documents_from_queryr&   c                 C   s$   | j |||d| j|< | | d S )N)r   r%   r&   )_build_named_queryr   r0   )r!   r   r7   r&   r"   r"   r#   r>      s   z!FirestoreBundle._save_named_queryc                    s\   t j jjtd}| 2 z3 d H W }| | | j|jj	}|j
j| |j}q6 |S )NrA   )rC   rD   rE   r   rJ   r6   r   r-   r+   r,   r*   r(   rK   r&   )r!   r%   r8   r?   rM   rN   r"   r"   r#   rI      s   
z$FirestoreBundle._process_async_queryc                 C   s(   t |t|| jt|dt|dS )N)parentstructured_query
limit_type)r   bundled_queryr&   )r   r   _to_protobuf_pbr	   r   build_timestamp)r!   r   r%   r&   r"   r"   r#   rO      s   z"FirestoreBundle._build_named_queryc                 C   s6   t |tr|nt|}t|| jdkr|| _d S d S )Nr   )r9   r   r   r   r.   r   )r!   r&   _tsr"   r"   r#   r0      s   
z&FirestoreBundle._update_last_read_timebundle_elementclientr;   c          	      C   s  ddl m} t| dddu ri | _|dkr|j| _dS |dkr)|j| j|jj< dS |dkr7|j	| j|j	j< dS |dkrt
|jj}tt
||jd	j|d
t|j|j|d| j|jj j|jj|jjd}| | | j|jj}| j|jj jD ]	}|jj| q{dS td| )z}Applies BundleElements to this FirestoreBundle instance as a part of
        deserializing a FirestoreBundle string.
        r   )Document_doc_metadata_mapNr*   
namedQuerydocumentMetadatadocument)mappingT)rY   )datar'   r+   r&   create_timeupdate_timez"Unexpected type of BundleElement: )(google.cloud.firestore_v1.types.documentrZ   getattrr[   r*   r    named_queryr   r   document_metadatar   DocumentReferenceValuer^   r   decode_dictfieldsr   collection_namedocument_idr&   ra   rb   r6   r   r-   r+   r,   r(   rK   r:   )	r!   rX   rY   r;   rZ   doc_ref_valuer%   rN   r8   r"   r"   r#   _add_bundle_element   sV   
z#FirestoreBundle._add_bundle_elementc              
   C   s   d}| j  D ]}|| t|d7 }qd}| j D ]}|| t|jd7 }|d7 }|| t|j jd7 }qt| j	pPt
| jt tj|t|ddd	}| | | S )
a  Iterates over the bundle's stored documents and queries and produces
        a single length-prefixed json string suitable for long-term storage.

        Example:

            from google.cloud import firestore

            db = firestore.Client()
            collection_ref = db.collection(u'users')

            bundle = firestore.FirestoreBundle('my bundle')
            bundle.add_named_query('app-users', collection_ref._query())

            serialized_bundle: str = bundle.build()

            # Now upload `serialized_bundle` to Google Cloud Storage, store it
            # in Memorystore, or any other storage solution.

        Returns:
            str: The length-prefixed string representation of this bundle'
                contents.
         )re   r   )rf   r   )r^   zutf-8)idra   versiontotal_documentstotal_bytes)r*   )r   values_compile_bundle_elementr   r   r*   r%   rT   rU   r    r   r   r   rV   r   r   lenencode)r!   bufferre   document_countrN   r*   r"   r"   r#   build"  s2   

zFirestoreBundle.buildc                 C   s"   t t|j}t| | S N)jsondumpsr   MessageToDictrU   ru   )r!   rX   serialized_ber"   r"   r#   rt   X  s   z'FirestoreBundle._compile_bundle_elementc                 C   s
   d| _ dS )zeHydrating bundles stores cached data we must reset anytime new
        queries or documents are addedN)r    )r!   r"   r"   r#   r1   \  s   
zFirestoreBundle._reset_metadata)r<   
__module____qualname____doc__r   int__annotations__strr$   r   r6   r   r@   rC   r=   r>   r
   rI   r   rO   r   r   r0   r   r   rm   ry   rt   r1   r"   r"   r"   r#   r   -   s^   
 5,




.6r   c                   @   s&   e Zd ZdZdededdfddZdS )r/   zcConvenience class to hold both the metadata and the actual content
    of a document to be bundled.r%   r*   r   Nc                 C   s   || _ || _d S rz   r)   )r!   r%   r*   r"   r"   r#   r$   f  s   
z_BundledDocument.__init__)r<   r   r   r   r   r   r$   r"   r"   r"   r#   r/   b  s    r/   )%r   rC   r{   *google.cloud.firestore_bundle.types.bundler   r   r   r   r   google.cloud._helpersr   r   &google.cloud.firestore_bundle._helpersr	   %google.cloud.firestore_v1.async_queryr
   %google.cloud.firestore_v1.base_clientr   'google.cloud.firestore_v1.base_documentr   $google.cloud.firestore_v1.base_queryr   "google.cloud.firestore_v1.documentr   google.cloud.firestore_v1r   google.protobuf.timestamp_pb2r   google.protobufr   typingr   r   r   r   r   r/   r"   r"   r"   r#   <module>   s&     7