a
    !feG                     @   sh   d 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
 G dd deZG d	d
 d
eZdd ZdS )z0Create / interact with gcloud datastore queries.    N)_ensure_tuple_or_list)	query_pb2)helpers)Keyc                   @   s$  e Zd ZdZejjejjejjejj	ejj
dZd(ddZedd Zed	d
 Zejdd
 Zedd Zejdd Zedd Zejdd Zejdd Zedd Zdd Zedd Zejdd Zdd Zd)ddZedd  Zejd!d  Zed"d# Zejd$d# Zd*d&d'ZdS )+Querya  A Query against the Cloud Datastore.

    This class serves as an abstraction for creating a query over data
    stored in the Cloud Datastore.

    :type client: :class:`gcloud.datastore.client.Client`
    :param client: The client used to connect to datastore.

    :type kind: string
    :param kind: The kind to query.

    :type project: string
    :param project: The project associated with the query.  If not passed,
                    uses the client's value.

    :type namespace: string or None
    :param namespace: The namespace to which to restrict results.  If not
                      passed, uses the client's value.

    :type ancestor: :class:`gcloud.datastore.key.Key` or None
    :param ancestor: key of the ancestor to which this query's results are
                     restricted.

    :type filters: sequence of (property_name, operator, value) tuples
    :param filters: property filters applied by this query.

    :type projection: sequence of string
    :param projection:  fields returned as part of query results.

    :type order: sequence of string
    :param order:  field names used to order query results. Prepend '-'
                   to a field name to sort it in descending order.

    :type distinct_on: sequence of string
    :param distinct_on: field names used to group query results.

    :raises: ValueError if ``project`` is not passed and no implicit
             default is set.
    )z<=z>=<>=N c
                 C   sv   || _ || _|p|j| _|p |j| _|| _g | _|D ]\}
}}| |
|| q4t	d|| _
t	d|| _t	d|	| _d S )N
projectionorderdistinct_on)_client_kindproject_project	namespace
_namespace	_ancestor_filters
add_filterr   _projection_order_distinct_on)selfclientkindr   r   ancestorfiltersr   r   r   property_nameoperatorvaluer
   r
   W/var/www/html/python-backend/venv/lib/python3.9/site-packages/gcloud/datastore/query.py__init__K   s    zQuery.__init__c                 C   s   | j p| jjS )zjGet the project for this Query.

        :rtype: str
        :returns: The project for the query.
        )r   r   r   r   r
   r
   r"   r   c   s    zQuery.projectc                 C   s   | j p| jjS )zvThis query's namespace

        :rtype: string or None
        :returns: the namespace assigned to this query
        )r   r   r   r$   r
   r
   r"   r   l   s    zQuery.namespacec                 C   s   t |tstd|| _dS )zCUpdate the query's namespace.

        :type value: string
        zNamespace must be a stringN)
isinstancestr
ValueErrorr   r   r!   r
   r
   r"   r   u   s    
c                 C   s   | j S )zeGet the Kind of the Query.

        :rtype: string
        :returns: The kind for the query.
        )r   r$   r
   r
   r"   r      s    z
Query.kindc                 C   s   t |tstd|| _dS )a  Update the Kind of the Query.

        :type value: string
        :param value: updated kind for the query.

        .. note::

           The protobuf specification allows for ``kind`` to be repeated,
           but the current implementation returns an error if more than
           one value is passed.  If the back-end changes in the future to
           allow multiple values, this method will be updated to allow passing
           either a string or a sequence of strings.
        zKind must be a stringN)r%   r&   	TypeErrorr   r(   r
   r
   r"   r      s    
c                 C   s   | j S )zsThe ancestor key for the query.

        :rtype: Key or None
        :returns: The ancestor for the query.
        r   r$   r
   r
   r"   r      s    zQuery.ancestorc                 C   s   t |tstd|| _dS )zlSet the ancestor for the query

        :type value: Key
        :param value: the new ancestor key
        zAncestor must be a KeyN)r%   r   r)   r   r(   r
   r
   r"   r      s    
c                 C   s
   d| _ dS )z"Remove the ancestor for the query.Nr*   r$   r
   r
   r"   r      s    c                 C   s   | j dd S )zFilters set on the query.

        :rtype: sequence of (property_name, operator, value) tuples.
        :returns: The filters set on the query.
        N)r   r$   r
   r
   r"   r      s    zQuery.filtersc                 C   s\   | j |du r(d|f }d}t|||dkrFt|tsFtd| | j|||f dS )a  Filter the query based on a property name, operator and a value.

        Expressions take the form of::

          .add_filter('<property>', '<operator>', <value>)

        where property is a property stored on the entity in the datastore
        and operator is one of ``OPERATORS``
        (ie, ``=``, ``<``, ``<=``, ``>``, ``>=``)::

          >>> from gcloud import datastore
          >>> client = datastore.Client()
          >>> query = client.query(kind='Person')
          >>> query.add_filter('name', '=', 'James')
          >>> query.add_filter('age', '>', 50)

        :type property_name: string
        :param property_name: A property name.

        :type operator: string
        :param operator: One of ``=``, ``<``, ``<=``, ``>``, ``>=``.

        :type value: :class:`int`, :class:`str`, :class:`bool`,
                     :class:`float`, :class:`NoneType`,
                     :class:`datetime.datetime`,
                     :class:`gcloud.datastore.key.Key`
        :param value: The value to filter on.

        :raises: :class:`ValueError` if ``operation`` is not one of the
                 specified values, or if a filter names ``'__key__'`` but
                 passes an invalid value (a key is required).
        NzInvalid expression: "%s"z#Please use one of: =, <, <=, >, >=.__key__zInvalid key: "%s")	OPERATORSgetr'   r%   r   r   append)r   r   r    r!   error_messageZchoices_messager
   r
   r"   r      s    !

zQuery.add_filterc                 C   s   | j dd S )zFields names returned by the query.

        :rtype: sequence of string
        :returns: Names of fields in query results.
        Nr   r$   r
   r
   r"   r      s    zQuery.projectionc                 C   s"   t |tr|g}|| jdd< dS )zSet the fields returned the query.

        :type projection: string or sequence of strings
        :param projection: Each value is a string giving the name of a
                           property to be included in the projection query.
        N)r%   r&   r   )r   r   r
   r
   r"   r      s    
c                 C   s   dg| j dd< dS )z(Set the projection to include only keys.r+   Nr0   r$   r
   r
   r"   	keys_only   s    zQuery.keys_onlyr	   c                 C   s   |  d|| dS )a  Filter on a key.

        :type key: :class:`gcloud.datastore.key.Key`
        :param key: The key to filter on.

        :type operator: string
        :param operator: (Optional) One of ``=``, ``<``, ``<=``, ``>``, ``>=``.
                         Defaults to ``=``.
        r+   N)r   )r   keyr    r
   r
   r"   
key_filter  s    
zQuery.key_filterc                 C   s   | j dd S )zNames of fields used to sort query results.

        :rtype: sequence of string
        :returns: The order(s) set on the query.
        N)r   r$   r
   r
   r"   r     s    zQuery.orderc                 C   s"   t |tr|g}|| jdd< dS )a  Set the fields used to sort query results.

        Sort fields will be applied in the order specified.

        :type value: string or sequence of strings
        :param value: Each value is a string giving the name of the
                      property on which to sort, optionally preceded by a
                      hyphen (-) to specify descending order.
                      Omitting the hyphen implies ascending order.
        N)r%   r&   r   r(   r
   r
   r"   r     s    
c                 C   s   | j dd S )zNames of fields used to group query results.

        :rtype: sequence of string
        :returns: The "distinct on" fields set on the query.
        N)r   r$   r
   r
   r"   r   &  s    zQuery.distinct_onc                 C   s"   t |tr|g}|| jdd< dS )zSet fields used to group query results.

        :type value: string or sequence of strings
        :param value: Each value is a string giving the name of a
                      property to use to group results together.
        N)r%   r&   r   r(   r
   r
   r"   r   /  s    
r   c                 C   s    |du r| j }t| |||||S )a  Execute the Query; return an iterator for the matching entities.

        For example::

          >>> from gcloud import datastore
          >>> client = datastore.Client()
          >>> query = client.query(kind='Person')
          >>> query.add_filter('name', '=', 'Sally')
          >>> list(query.fetch())
          [<Entity object>, <Entity object>, ...]
          >>> list(query.fetch(1))
          [<Entity object>]

        :type limit: integer or None
        :param limit: An optional limit passed through to the iterator.

        :type offset: integer
        :param offset: An optional offset passed through to the iterator.

        :type start_cursor: bytes
        :param start_cursor: An optional cursor passed through to the iterator.

        :type end_cursor: bytes
        :param end_cursor: An optional cursor passed through to the iterator.

        :type client: :class:`gcloud.datastore.client.Client`
        :param client: client used to connect to datastore.
                       If not supplied, uses the query's value.

        :rtype: :class:`Iterator`
        :returns: The iterator for the query.
        :raises: ValueError if ``connection`` is not passed and no implicit
                 default has been set.
        N)r   Iterator)r   limitoffsetstart_cursor
end_cursorr   r
   r
   r"   fetch;  s
    $zQuery.fetch)NNNNr
   r
   r
   r
   )r	   )Nr   NNN)__name__
__module____qualname____doc__
_query_pb2PropertyFilterZLESS_THAN_OR_EQUALZGREATER_THAN_OR_EQUALZ	LESS_THANZGREATER_THANEQUALr,   r#   propertyr   r   setterr   r   deleterr   r   r   r1   r3   r   r   r9   r
   r
   r
   r"   r      sh   )        



	






+






  r   c                   @   sH   e Zd ZdZejjZejjejj	ejj
fZd	ddZdd Zdd ZdS )
r4   aI  Represent the state of a given execution of a Query.

    :type query: :class:`gcloud.datastore.query.Query`
    :param query: Query object holding permanent configuration (i.e.
                  things that don't change on with each page in
                  a results set).

    :type client: :class:`gcloud.datastore.client.Client`
    :param client: The client used to make a request.

    :type limit: integer
    :param limit: (Optional) Limit the number of results returned.

    :type offset: integer
    :param offset: (Optional) Offset used to begin a query.

    :type start_cursor: bytes
    :param start_cursor: (Optional) Cursor to begin paging through
                         query results.

    :type end_cursor: bytes
    :param end_cursor: (Optional) Cursor to end paging through
                       query results.
    Nc                 C   s:   || _ || _|| _|| _|| _|| _d  | _| _d | _d S )N)	_queryr   _limit_offset_start_cursor_end_cursor_page_more_results_skipped_results)r   queryr   r5   r6   r7   r8   r
   r
   r"   r#     s    zIterator.__init__c           	      C   s  t | j}| j}|dur$t||_| j}|dur>t||_| jdurR| j|j	_
| jdurd| j|_| jj}| jjj|| jj| jj|o|jd}|\}}}| _|dkrd| _nt|| _d| _|| jkrd| _n|| jv rd| _ntddd |D | _| j| j| jfS )	a  Fetch a single "page" of query results.

        Low-level API for fine control:  the more convenient API is
        to iterate on the current Iterator.

        :rtype: tuple, (entities, more_results, cursor)
        :returns: The next page of results.
        N)Zquery_pbr   r   Ztransaction_id    TFz-Unexpected value returned for `more_results`.c                 S   s   g | ]}t |qS r
   )r   Zentity_from_protobuf).0entityr
   r
   r"   
<listcomp>  s   z&Iterator.next_page.<locals>.<listcomp>)_pb_from_queryrD   rG   base64urlsafe_b64decoder7   rH   r8   rE   r5   r!   rF   r6   r   Zcurrent_transaction
connectionZ	run_queryr   r   idrK   urlsafe_b64encode_NOT_FINISHEDrJ   	_FINISHEDr'   rI   )	r   pbr7   r8   ZtransactionZquery_resultsZ
entity_pbsZcursor_as_bytesZmore_results_enumr
   r
   r"   	next_page  sD    	





zIterator.next_pagec                 c   sn   |    | jD ]
}|V  q| js"qjt| j}| jdurD|  j|8  _| jdur | jdur |  j| j8  _q dS )zGenerator yielding all results matching our query.

        :rtype: sequence of :class:`gcloud.datastore.entity.Entity`
        N)rZ   rI   rJ   lenrE   rF   rK   )r   rO   Znum_resultsr
   r
   r"   __iter__  s    


zIterator.__iter__)NNNN)r:   r;   r<   r=   r>   ZQueryResultBatchZNOT_FINISHEDrW   ZNO_MORE_RESULTSZMORE_RESULTS_AFTER_LIMITZMORE_RESULTS_AFTER_CURSORrX   r#   rZ   r\   r
   r
   r
   r"   r4   f  s     
6r4   c                 C   sf  t  }| jD ]}||j j_q| jr6| j|j _|jj}t j	j
|_| jr| j }|j j}d|j_t jj|_|jj| | jD ]^\}}}| j|}	|j j}
||
j_|	|
_|dkr| }|
jj| qt|
j| q|js|d | jD ]F}|j }|dr4|dd |j_|j|_n||j_|j|_q | jD ]}||j _qN|S )a  Convert a Query instance to the corresponding protobuf.

    :type query: :class:`Query`
    :param query: The source query.

    :rtype: :class:`gcloud.datastore._generated.query_pb2.Query`
    :returns: A protobuf that can be sent to the protobuf API.  N.b. that
              it does not contain "in-flight" fields for ongoing query
              executions (cursors, offset, limit).
    r+   filter-   N) r>   r   r   addrA   namer   r]   composite_filterZCompositeFilterANDopr   Zto_protobufr   property_filterr?   ZHAS_ANCESTORr!   	key_valueZCopyFromr,   r-   r   Z_set_protobuf_valueZ
ClearFieldr   
startswithZ
DESCENDING	directionZ	ASCENDINGr   )rL   rY   Zprojection_namerb   Zancestor_pbZancestor_filterr   r    r!   Z
pb_op_enumre   Zkey_pbpropZproperty_orderZdistinct_on_namer
   r
   r"   rQ     sD    








rQ   )r=   rR   Zgcloud._helpersr   Zgcloud.datastore._generatedr   r>   Zgcloud.datastorer   Zgcloud.datastore.keyr   objectr   r4   rQ   r
   r
   r
   r"   <module>   s     Ow