a
    !fN?                     @   s   d Z ddlZddlZddlmZ ddlmZ ddl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
Zd"ddZdd Zdd Zdd Zd#ddZdd Zdd Zdd Zdd Zdd ZG d d! d!eZdS )$zrHelper functions for dealing with Cloud Datastore's Protobuf API.

The non-private functions are part of the API.
    N)
struct_pb2)
latlng_pb2)_datetime_to_pb_timestamp)_pb_timestamp_to_datetime)
entity_pb2)Entity)Key)entity_from_protobufkey_from_protobufFc                 C   sb   d}|rRt | jjdkrdS dd | jjD }t|}t |dkrL| }q^|}n| jr^| j}|S )at  Get the meaning from a protobuf value.

    :type value_pb: :class:`gcloud.datastore._generated.entity_pb2.Value`
    :param value_pb: The protobuf value to be checked for an
                     associated meaning.

    :type is_list: bool
    :param is_list: Boolean indicating if the ``value_pb`` contains
                    a list value.

    :rtype: int
    :returns: The meaning for the ``value_pb`` if one is set, else
              :data:`None`. For a list value, if there are disagreeing
              means it just returns a list of meanings. If all the
              list meanings agree, it just condenses them.
    Nr   c                 S   s   g | ]}t |qS  )_get_meaning).0sub_value_pbr   r   Y/var/www/html/python-backend/venv/lib/python3.9/site-packages/gcloud/datastore/helpers.py
<listcomp>>   s   z _get_meaning.<locals>.<listcomp>   )lenarray_valuevaluessetpopmeaning)value_pbis_listr   Zall_meaningsZunique_meaningsr   r   r   r   $   s    
r   c                 C   s   | j |S )a  Add (by name) a new ``Value`` protobuf to an entity protobuf.

    :type entity_pb: :class:`gcloud.datastore._generated.entity_pb2.Entity`
    :param entity_pb: An entity protobuf to add a new property to.

    :type name: string
    :param name: The name of the new property.

    :rtype: :class:`gcloud.datastore._generated.entity_pb2.Value`
    :returns: The new ``Value`` protobuf that was added to the entity.
    )
propertiesZget_or_create)	entity_pbnamer   r   r   _new_value_pbM   s    r   c                 C   s   t | jS )am  Iterator of name, ``Value`` tuples from entity properties.

    :type entity_pb: :class:`gcloud.datastore._generated.entity_pb2.Entity`
    :param entity_pb: An entity protobuf to add a new property to.

    :rtype: :class:`generator`
    :returns: An iterator that yields tuples of a name and ``Value``
              corresponding to properties on the entity.
    )six	iteritemsr   )r   r   r   r   _property_tuples\   s    
r    c                 C   s   d}|  drt| j}i }i }g }t| D ]\}}t|}|||< t|t}t||d}	|	durn|	|f||< |rtdd |j	j
D }
t|
dkrtd|
 r|| q,|jr,|| q,t||d}|| |j| |S )	aw  Factory method for creating an entity based on a protobuf.

    The protobuf should be one returned from the Cloud Datastore
    Protobuf API.

    :type pb: :class:`gcloud.datastore._generated.entity_pb2.Entity`
    :param pb: The Protobuf representing the entity.

    :rtype: :class:`gcloud.datastore.entity.Entity`
    :returns: The entity derived from the protobuf.
    Nkeyr   c                 s   s   | ]}|j V  qd S N)exclude_from_indexes)r   r   r   r   r   	<genexpr>   s   z'entity_from_protobuf.<locals>.<genexpr>r   zVFor an array_value, subvalues must either all be indexed or all excluded from indexes.)r!   r$   )ZHasFieldr
   r!   r    _get_value_from_value_pb
isinstancelistr   r   r   r   r   
ValueErrorr   appendr$   r   update	_meanings)pbr!   Zentity_propsZentity_meaningsr$   Z	prop_namer   valuer   r   Zexclude_valuesentityr   r   r   r	   i   s6    



r	   c           
      C   sz   || j vrdS | j | \}}||ur(dS |rpt|ts@t|}tj|jj	|}|D ]\}}	|	durV|	|_
qVn||_
dS )ab  Add meaning information (from an entity) to a protobuf.

    :type entity: :class:`gcloud.datastore.entity.Entity`
    :param entity: The entity to be turned into a protobuf.

    :type name: string
    :param name: The name of the property.

    :type value: object
    :param value: The current value stored as property ``name``.

    :type value_pb: :class:`gcloud.datastore._generated.entity_pb2.Value`
    :param value_pb: The protobuf value to add meaning / meanings to.

    :type is_list: bool
    :param is_list: (Optional) Boolean indicating if the ``value`` is
                    a list value.
    N)r,   r'   r(   	itertoolsrepeatr   moveszipr   r   r   )
r/   r   r.   r   r   r   Z
orig_valueZval_iterr   Zsub_meaningr   r   r   _set_pb_meaning_from_entity   s    



r4   c                 C   s   t  }| jdur(| j }|j| |  D ]r\}}t|t}|rTt|dkrTq0t	||}t
|| || jv r|s|d|_|jjD ]
}d|_qt| ||||d q0|S )a  Converts an entity into a protobuf.

    :type entity: :class:`gcloud.datastore.entity.Entity`
    :param entity: The entity to be turned into a protobuf.

    :rtype: :class:`gcloud.datastore._generated.entity_pb2.Entity`
    :returns: The protobuf representing the entity.
    Nr   Tr"   )_entity_pb2r   r!   to_protobufCopyFromitemsr'   r(   r   r   _set_protobuf_valuer$   r   r   r4   )r/   r   Zkey_pbr   r.   Zvalue_is_listr   Z	sub_valuer   r   r   entity_to_protobuf   s&    	






r:   c                 C   sx   g }| j D ]4}||j |jr,||j |jr
||j q
d}| jjrT| jj}d}| jjrh| jj}t|||dS )aV  Factory method for creating a key based on a protobuf.

    The protobuf should be one returned from the Cloud Datastore
    Protobuf API.

    :type pb: :class:`gcloud.datastore._generated.entity_pb2.Key`
    :param pb: The Protobuf representing the key.

    :rtype: :class:`gcloud.datastore.key.Key`
    :returns: a new `Key` instance
    N)	namespaceproject)	pathr*   kindidr   Zpartition_idZ
project_idZnamespace_idr   )r-   Z	path_argselementr<   r;   r   r   r   r
      s    
r
   c                 C   s(  t | tjrd}t| }n t | tr6d|   }}nt | trLd|  }}nt | trbd|  }}nt | tjrzd|  }}nt | tj	rd|  }}nt | t
tfrd|  }}npt | trd|  }}nZt | trd	|  }}nDt | t rd
|   }}n(| du rdtj }}ntdt|  |d |fS )a  Given a value, return the protobuf attribute name and proper value.

    The Protobuf API uses different attribute names based on value types
    rather than inferring the type.  This function simply determines the
    proper attribute name based on the type of the value provided and
    returns the attribute name as well as a properly formatted value.

    Certain value types need to be coerced into a different type (such
    as a `datetime.datetime` into an integer timestamp, or a
    `gcloud.datastore.key.Key` into a Protobuf representation.  This
    function handles that for you.

    .. note::
       Values which are "text" ('unicode' in Python2, 'str' in Python3) map
       to 'string_value' in the datastore;  values which are "bytes"
       ('str' in Python2, 'bytes' in Python3) map to 'blob_value'.

    For example:

    >>> _pb_attr_value(1234)
    ('integer_value', 1234)
    >>> _pb_attr_value('my_string')
    ('string_value', 'my_string')

    :type val: `datetime.datetime`, :class:`gcloud.datastore.key.Key`,
               bool, float, integer, string
    :param val: The value to be scrutinized.

    :rtype: tuple
    :returns: A tuple of the attribute name and proper value type.
    	timestampr!   booleandoubleintegerstringZblobr/   arrayZ	geo_pointNnullzUnknown protobuf attr type %s_value)r'   datetimer   r   r6   boolfloatr   integer_types	text_typebytesstrr   r(   GeoPointr   Z
NULL_VALUEr)   type)valr   r.   r   r   r   _pb_attr_value  s2    !





rS   c                 C   s   |  d}|dkrt| j}n|dkr2t| j}n|dkrB| j}n|dkrR| j}n|dkrb| j}n|dkrr| j}nr|dkr| j	}nb|d	krt
| j}nN|d
krdd | jjD }n2|dkrt| jj| jj}n|dkrd}ntd|S )a  Given a protobuf for a Value, get the correct value.

    The Cloud Datastore Protobuf API returns a Property Protobuf which
    has one value set and the rest blank.  This function retrieves the
    the one value provided.

    Some work is done to coerce the return value into a more useful type
    (particularly in the case of a timestamp value, or a key value).

    :type value_pb: :class:`gcloud.datastore._generated.entity_pb2.Value`
    :param value_pb: The Value Protobuf.

    :rtype: object
    :returns: The value provided by the Protobuf.
    :raises: :class:`ValueError <exceptions.ValueError>` if no value type
             has been set.
    
value_typetimestamp_value	key_valueboolean_valuedouble_valueinteger_valuestring_value
blob_valueentity_valuer   c                 S   s   g | ]}t |qS r   )r&   )r   r.   r   r   r   r   y  s   z,_get_value_from_value_pb.<locals>.<listcomp>geo_point_valueZ
null_valueNz)Value protobuf did not have any value set)Z
WhichOneofr   rU   r
   rV   rW   rX   rY   rZ   r[   r	   r\   r   r   rP   r]   latitude	longituder)   )r   rT   resultr   r   r   r&   L  s:    
r&   c                 C   s   t |\}}|dkr"| j| n|dkr8| j| nn|dkrVt|}| j| nP|dkr| jj}|D ]}| }t	|| qjn"|dkr| j
| nt| || dS )a  Assign 'val' to the correct subfield of 'value_pb'.

    The Protobuf API uses different attribute names based on value types
    rather than inferring the type.

    Some value types (entities, keys, lists) cannot be directly
    assigned; this function handles them correctly.

    :type value_pb: :class:`gcloud.datastore._generated.entity_pb2.Value`
    :param value_pb: The value protobuf to which the value is being assigned.

    :type val: :class:`datetime.datetime`, boolean, float, integer, string,
               :class:`gcloud.datastore.key.Key`,
               :class:`gcloud.datastore.entity.Entity`
    :param val: The value to be assigned.
    rV   rU   r\   r   r]   N)rS   rV   r7   rU   r:   r\   r   r   addr9   r]   setattr)r   rR   attrr   Zl_pbitemZi_pbr   r   r   r9     s     r9   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )rP   zSimple container for a geo point value.

    :type latitude: float
    :param latitude: Latitude of a point.

    :type longitude: float
    :param longitude: Longitude of a point.
    c                 C   s   || _ || _d S r#   r^   r_   )selfr^   r_   r   r   r   __init__  s    zGeoPoint.__init__c                 C   s   t j| j| jdS )zConvert the current object to protobuf.

        :rtype: :class:`google.type.latlng_pb2.LatLng`.
        :returns: The current point as a protobuf.
        re   )r   ZLatLngr^   r_   )rf   r   r   r   r6     s    zGeoPoint.to_protobufc                 C   s&   t |tsdS | j|jko$| j|jkS )zCompare two geo points for equality.

        :rtype: boolean
        :returns: True if the points compare equal, else False.
        F)r'   rP   r^   r_   rf   otherr   r   r   __eq__  s
    

zGeoPoint.__eq__c                 C   s   |  | S )zCompare two geo points for inequality.

        :rtype: boolean
        :returns: False if the points compare equal, else True.
        )rj   rh   r   r   r   __ne__  s    zGeoPoint.__ne__N)__name__
__module____qualname____doc__rg   r6   rj   rk   r   r   r   r   rP     s
   		rP   )F)F)ro   rI   r0   Zgoogle.protobufr   Zgoogle.typer   r   Zgcloud._helpersr   r   Zgcloud.datastore._generatedr   r5   Zgcloud.datastore.entityr   Zgcloud.datastore.keyr   __all__r   r   r    r	   r4   r:   r
   rS   r&   r9   objectrP   r   r   r   r   <module>   s.   
)6 
*& >=$