U
    $FZhj6                     @   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< eddddZe	d dd	d
Z
eed dddZeeejdddZeeejddddZeeejdddZeeejedddZeejef ddddZeeedddZed d!d"Zeed#d$d%Zd&d' ZdS )(FirestoreBundleam  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:

    .. code-block:: python

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

        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),
        )
        serialized: str = bundle.build()

        # Store somewhere like a Google Cloud Storage bucket for retrieval by
        # a client SDK.

    Args:
        name (str): The Id of the bundle.
       BUNDLE_SCHEMA_VERSIONN)namereturnc                 C   s*   || _ i | _i | _tddd| _d | _d S )Nr   )secondsZnanos)r   	documentsnamed_queriesr   latest_read_time_deserialized_metadata)selfr    r!   k/home/aprabhat/apps/x.techxrdev.in/venv/lib/python3.8/site-packages/google/cloud/firestore_bundle/bundle.py__init__M   s
    zFirestoreBundle.__init__)snapshotr   c                 C   s   g }|j j}| j|}|r$|jj}|dkp@t|j|j	jdk}|rht
|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:

        .. code-block:: python

            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$   Zoriginal_queriesZfull_document_pathZoriginal_documentZshould_use_snaphotr!   r!   r"   add_documentT   s4    
zFirestoreBundle.add_document)r   queryr   c                 C   sb   t |ts tdt|j d|| jk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:

        .. code-block:: python

            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_queryr0   )r    r   r2   
_read_timer!   r!   r"   add_named_query   s    

zFirestoreBundle.add_named_query)r2   r3   r   c                 C   s|   t j jjtd}t|tr<dd l}| }|| 	||S |
 D ]2}| | | j|jj}|jj| |j}qD|S )Ntzinfor   )datetimeminreplacer   r4   r
   asyncioZget_event_loopZrun_until_complete_process_async_querystreamr1   r   r,   r*   r+   r)   r'   appendr%   )r    r2   r3   r:   rA   loopdocbundled_documentr!   r!   r"   r8      s    

z*FirestoreBundle._save_documents_from_query)r   r2   r%   r   c                 C   s$   | j |||d| j|< | | d S )N)r   r$   r%   )_build_named_queryr   r/   )r    r   r2   r%   r!   r!   r"   r9      s    z!FirestoreBundle._save_named_query)r$   r3   r   c                    sZ   t j jjtd}| 2 z:3 d H W }| | | j|jj	}|j
j| |j}q6 |S )Nr<   )r>   r?   r@   r   rC   r1   r   r,   r*   r+   r)   r'   rD   r%   )r    r$   r3   r:   rF   rG   r!   r!   r"   rB      s    

z$FirestoreBundle._process_async_query)r   r$   r%   r   c                 C   s(   t |t|| jt|dt|dS )N)parentZstructured_queryZ
limit_type)r   Zbundled_queryr%   )r   r   _to_protobuf_pbr	   r   build_timestamp)r    r   r$   r%   r!   r!   r"   rH      s    z"FirestoreBundle._build_named_query)r%   r   c                 C   s2   t |tr|nt|}t|| jdkr.|| _d S )Nr   )r4   r   r   r   r-   r   )r    r%   Z_tsr!   r!   r"   r/      s    z&FirestoreBundle._update_last_read_time)bundle_elementclientr6   c          	      C   s  ddl m} t| dddkr"i | _|dkr4|j| _n|dkrN|j| j|jj< n|dkrh|j	| j|j	j< n|dkrt
|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| qntd| dS )z}Applies BundleElements to this FirestoreBundle instance as a part of
        deserializing a FirestoreBundle string.
        r   )Document_doc_metadata_mapNr)   Z
namedQueryZdocumentMetadatadocument)mappingT)rN   )datar&   r*   r%   create_timeupdate_timez"Unexpected type of BundleElement: )Z(google.cloud.firestore_v1.types.documentrO   getattrrP   r)   r   named_queryr   r   document_metadatar   ZDocumentReferenceValuerQ   r   Zdecode_dictfieldsr   Zcollection_nameZdocument_idr%   rT   rU   r1   r   r,   r*   r+   r'   rD   r5   )	r    rM   rN   r6   rO   Zdoc_ref_valuer$   rG   r3   r!   r!   r"   _add_bundle_element  sP    

 

z#FirestoreBundle._add_bundle_element)r   c              
   C   s   d}| j  D ]}|| t|d7 }qd}| j D ]>}|| t|jd7 }|d7 }|| t|j jd7 }q6t| j	pt
| 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:

        .. code-block:: python

            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.
         )rW   r   )rX   r   )rQ   zutf-8)idrT   versionZtotal_documentstotal_bytes)r)   )r   values_compile_bundle_elementr   r   r)   r$   rJ   rK   r   r   r   r   rL   r   r   lenencode)r    bufferrW   Zdocument_countrG   r)   r!   r!   r"   build3  s6    


zFirestoreBundle.build)rM   r   c                 C   s"   t t|j}t| | S N)jsondumpsr   ZMessageToDictrK   ra   )r    rM   Zserialized_ber!   r!   r"   r`   m  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"   r0   q  s    zFirestoreBundle._reset_metadata)r7   
__module____qualname____doc__r   int__annotations__strr#   r   r1   r   r;   r>   r8   r9   r
   rB   r   rH   r   r   r/   r   r   rZ   rd   r`   r0   r!   r!   r!   r"   r   -   s<   
8/ .:r   c                   @   s"   e Zd ZdZeeddddZdS )r.   zcConvenience class to hold both the metadata and the actual content
    of a document to be bundled.N)r$   r)   r   c                 C   s   || _ || _d S re   r(   )r    r$   r)   r!   r!   r"   r#   {  s    z_BundledDocument.__init__)r7   rh   ri   rj   r   r   r#   r!   r!   r!   r"   r.   w  s
   r.   )%rj   r>   rf   Z*google.cloud.firestore_bundle.types.bundler   r   r   r   r   Zgoogle.cloud._helpersr   r   Z&google.cloud.firestore_bundle._helpersr	   Z%google.cloud.firestore_v1.async_queryr
   Z%google.cloud.firestore_v1.base_clientr   Z'google.cloud.firestore_v1.base_documentr   Z$google.cloud.firestore_v1.base_queryr   Z"google.cloud.firestore_v1.documentr   Zgoogle.cloud.firestore_v1r   Zgoogle.protobuf.timestamp_pb2r   Zgoogle.protobufr   typingr   r   r   r   r   r.   r!   r!   r!   r"   <module>   s$     L