U
    >i-0                     @  s   d Z ddlmZ ddlZddlmZ ddlmZmZ dZ	dZ
dZd	Zd
Zed ZdZee ZedZedZdddgZddd eD ZeeZddddZddddZddddZdd d!d"ZeZdd#d$d%d&ZG d'd( d(eZdS ))zBUtilities for managing / converting field paths to / from strings.    )annotationsN)abc)Iterablecastz!{!r} is not contained in the dataz2{!r} is not contained in the data for the key {!r}zGThe data at {!r} is not a dictionary, so it cannot contain the key {!r}.\   `z^[_a-zA-Z][_a-zA-Z0-9]*$z ^[_a-zA-Z][_a-zA-Z0-9]*[~*/\[\]])ZSIMPLEz[_a-zA-Z][_a-zA-Z0-9]*)ZQUOTEDz`(?:\\`|[^`])*?`)DOTz\.|c                 c  s   | ]}d j | V  qdS )z
(?P<{}>{})N)format).0pair r   H/tmp/pip-unpacked-wheel-599y42ri/google/cloud/firestore_v1/field_path.py	<genexpr>(   s     r   str)pathc                 c  sr   d}t j}|| }|dk	rJtt|j}||}|V  | }|| |}q|t| krntd	| | |d dS )zLex a field path into tokens (including dots).

    Args:
        path (str): field path to be lexed.
    Returns:
        List(str): tokens
    r   Nz!Path {} not consumed, residue: {})
TOKENS_REGEXmatchr   r   	lastgroupgroupendlen
ValueErrorr   )r   pos	get_tokenr   type_valuer   r   r   _tokenize_field_path,   s    
r   z
str | Nonec                 C  s~   | sg S g }d}t | D ]J}|r>|dkr8td| qbd}q|dkrTtd| || d}q|rl|sztd| |S )a  Split a field path into valid elements (without dots).

    Args:
        path (str): field path to be lexed.
    Returns:
        List(str): tokens
    Raises:
        ValueError: if the path does not match the elements-interspersed-
                    with-dots pattern.
    Fr   zInvalid path: {}T)r   r   r   append)r   elementsZwant_dotelementr   r   r   split_field_pathA   s     
r#   api_reprc                 C  s\   g }t | D ]J}|d dkrL|d dkrL|dd }|tt}|tt}|| q|S )a;  Parse a **field path** from into a list of nested field names.

    See :func:`field_path` for more on **field paths**.

    Args:
        api_repr (str):
            The unique Firestore api representation which consists of
            either simple or UTF-8 field names. It cannot exceed
            1500 bytes, and cannot be empty. Simple field names match
            ``'^[_a-zA-Z][_a-zA-Z0-9]*$'``. All other field names are
            escaped by surrounding them with backticks.

    Returns:
        List[str, ...]: The list of field names in the field path.
    r   r	      )r#   replace_ESCAPED_BACKTICK	_BACKTICK_ESCAPED_BACKSLASH
_BACKSLASHr    )r%   field_names
field_namer   r   r   parse_field_pathd   s    r/   zIterable[str])r-   c                 C  sf   g }| D ]R}t |}|r4|d|kr4|| q|tttt}|t| t  qt	
|S )aC  Create a **field path** from a list of nested field names.

    A **field path** is a ``.``-delimited concatenation of the field
    names. It is used to represent a nested field. For example,
    in the data

    .. code-block:: python

       data = {
          'aa': {
              'bb': {
                  'cc': 10,
              },
          },
       }

    the field path ``'aa.bb.cc'`` represents that data stored in
    ``data['aa']['bb']['cc']``.

    Args:
        field_names: The list of field names.

    Returns:
        str: The ``.``-delimited field path.
    r   )_SIMPLE_FIELD_NAMEr   r   r    r(   r,   r+   r*   r)   _FIELD_PATH_DELIMITERjoin)r-   resultr.   r   Zreplacedr   r   r   render_field_path   s    
 r4   dict)
field_pathdatac                 C  s   t | }|}t|D ]\}}t|tjr|||kr:|| }q|dkrVt|}t|qt|d| }t	||}t|qt|d| }t
||}t|q|S )a  Get a (potentially nested) value from a dictionary.

    If the data is nested, for example:

    .. code-block:: python

       >>> data
       {
           'top1': {
               'middle2': {
                   'bottom3': 20,
                   'bottom4': 22,
               },
               'middle5': True,
           },
           'top6': b'  foo',
       }

    a **field path** can be used to access the nested data. For
    example:

    .. code-block:: python

       >>> get_nested_value('top1', data)
       {
           'middle2': {
               'bottom3': 20,
               'bottom4': 22,
           },
           'middle5': True,
       }
       >>> get_nested_value('top1.middle2', data)
       {
           'bottom3': 20,
           'bottom4': 22,
       }
       >>> get_nested_value('top1.middle2.bottom3', data)
       20

    See :meth:`~google.cloud.firestore_v1.client.Client.field_path` for
    more information on **field paths**.

    Args:
        field_path (str): A field path (``.``-delimited list of
            field names).
        data (Dict[str, Any]): The (possibly nested) data.

    Returns:
        Any: (A copy of) the value stored for the ``field_path``.

    Raises:
        KeyError: If the ``field_path`` does not match nested data.
    r   N)r/   	enumerate
isinstancer   Mapping_FIELD_PATH_MISSING_TOPr   KeyErrorr4   _FIELD_PATH_MISSING_KEY_FIELD_PATH_WRONG_TYPE)r6   r7   r-   Znested_dataindexr.   msgpartialr   r   r   get_nested_value   s     6




rB   c                   @  s   e Zd ZdZdd ZeddddZeddd	d
Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zedd ZdS )	FieldPatha  Field Path object for client use.

    A field path is a sequence of element keys, separated by periods.
    Each element key can be either a simple identifier, or a full unicode
    string.

    In the string representation of a field path, non-identifier elements
    must be quoted using backticks, with internal backticks and backslashes
    escaped with a backslash.

    Args:
        parts: (one or more strings)
            Indicating path of the key to be used.
    c                 G  s2   |D ]}t |tr|sd}t|qt|| _d S )Nz3One or more components is not a string or is empty.)r9   r   r   tupleparts)selfrE   parterrorr   r   r   __init__
  s
    
zFieldPath.__init__r   r$   c                 C  s    |  }|std| t| S )a  Factory: create a FieldPath from the string formatted per the API.

        Args:
            api_repr (str): a string path, with non-identifier elements quoted
            It cannot exceed 1500 characters, and cannot be empty.
        Returns:
            (:class:`FieldPath`) An instance parsed from ``api_repr``.
        Raises:
            ValueError if the parsing fails
        z.Field path API representation cannot be empty.)stripr   r/   )clsr%   r   r   r   from_api_repr  s    zFieldPath.from_api_repr)path_stringc                 C  sf   z|  |W S  tk
r`   |d}|D ](}|s:tdt|r*td|q*t|  Y S X dS )a  Factory: create a FieldPath from a unicode string representation.

        This method splits on the character `.` and disallows the
        characters `~*/[]`. To create a FieldPath whose components have
        those characters, call the constructor.

        Args:
            path_string (str): A unicode string which cannot contain
            `~*/[]` characters, cannot exceed 1500 bytes, and cannot be empty.

        Returns:
            (:class:`FieldPath`) An instance parsed from ``path_string``.
        r   zEmpty elementz.Invalid char in element with leading alpha: {}N)rL   r   split_LEADING_ALPHA_INVALIDr   r   rC   )rK   rM   r!   r"   r   r   r   from_string"  s    

zFieldPath.from_stringc                 C  s6   d}| j D ]}|d| d 7 }q
|d d }d|S )N 'z',r&   zFieldPath({}))rE   r   )rF   pathsrG   r   r   r   __repr__>  s
    
zFieldPath.__repr__c                 C  s   t |  S N)hashto_api_reprrF   r   r   r   __hash__E  s    zFieldPath.__hash__c                 C  s   t |tr| j|jkS tS rU   r9   rC   rE   NotImplementedrF   otherr   r   r   __eq__H  s    
zFieldPath.__eq__c                 C  s   t |tr| j|jk S tS rU   rZ   r\   r   r   r   __lt__M  s    
zFieldPath.__lt__c                 C  sJ   t |tr| j|j }t| S t |trB| jt|j }t| S tS dS )zAdds `other` field path to end of this field path.

        Args:
            other (~google.cloud.firestore_v1._helpers.FieldPath, str):
                The field path to add to the end of this `FieldPath`.
        N)r9   rC   rE   r   rP   r[   )rF   r]   rE   r   r   r   __add__R  s    

zFieldPath.__add__c                 C  s
   t | jS )zRender a quoted string representation of the FieldPath

        Returns:
            (str) Quoted string representation of the path stored
            within this FieldPath.
        )r4   rE   rX   r   r   r   rW   b  s    zFieldPath.to_api_reprc                 C  s(   | j dt|j  |j dt| j  kS )zCheck whether ``other`` is an ancestor.

        Returns:
            (bool) True IFF ``other`` is an ancestor or equal to ``self``,
            else False.
        N)rE   r   r\   r   r   r   eq_or_parentk  s    zFieldPath.eq_or_parentc                   s"   t dt j} fdd|D S )zVReturn field paths for all parents.

        Returns: Set[:class:`FieldPath`]
        r'   c                   s   h | ]}t  jd |  qS rU   )rC   rE   )r   r?   rX   r   r   	<setcomp>z  s     z$FieldPath.lineage.<locals>.<setcomp>)ranger   rE   )rF   Zindexesr   rX   r   lineaget  s    zFieldPath.lineagec                   C  s   dS )zA special FieldPath value to refer to the ID of a document. It can be used
           in queries to sort or filter by the document ID.

        Returns: A special sentinel value to refer to the ID of a document.
        __name__r   r   r   r   r   document_id|  s    zFieldPath.document_idN)re   
__module____qualname____doc__rI   classmethodrL   rP   rT   rY   r^   r_   r`   rW   ra   rd   staticmethodrf   r   r   r   r   rC      s    		rC   ) ri   
__future__r   recollectionsr   typingr   r   r;   r=   r>   r1   r,   r+   r*   r)   compiler0   rO   ZPATH_ELEMENT_TOKENSr2   ZTOKENS_PATTERNr   r   r#   r/   r4   Zget_field_pathrB   objectrC   r   r   r   r   <module>   s8   


#)M