1# -*- coding: utf-8 -*- 
    2# Copyright 2025 Google LLC 
    3# 
    4# Licensed under the Apache License, Version 2.0 (the "License"); 
    5# you may not use this file except in compliance with the License. 
    6# You may obtain a copy of the License at 
    7# 
    8#     http://www.apache.org/licenses/LICENSE-2.0 
    9# 
    10# Unless required by applicable law or agreed to in writing, software 
    11# distributed under the License is distributed on an "AS IS" BASIS, 
    12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13# See the License for the specific language governing permissions and 
    14# limitations under the License. 
    15# 
    16import json 
    17import logging as std_logging 
    18import pickle 
    19import warnings 
    20from typing import Callable, Dict, Optional, Sequence, Tuple, Union 
    21 
    22from google.api_core import grpc_helpers 
    23from google.api_core import gapic_v1 
    24import google.auth  # type: ignore 
    25from google.auth import credentials as ga_credentials  # type: ignore 
    26from google.auth.transport.grpc import SslCredentials  # type: ignore 
    27from google.protobuf.json_format import MessageToJson 
    28import google.protobuf.message 
    29 
    30import grpc  # type: ignore 
    31import proto  # type: ignore 
    32 
    33from google.cloud.firestore_v1.types import document 
    34from google.cloud.firestore_v1.types import document as gf_document 
    35from google.cloud.firestore_v1.types import firestore 
    36from google.cloud.location import locations_pb2  # type: ignore 
    37from google.longrunning import operations_pb2  # type: ignore 
    38from google.protobuf import empty_pb2  # type: ignore 
    39from .base import FirestoreTransport, DEFAULT_CLIENT_INFO 
    40 
    41try: 
    42    from google.api_core import client_logging  # type: ignore 
    43 
    44    CLIENT_LOGGING_SUPPORTED = True  # pragma: NO COVER 
    45except ImportError:  # pragma: NO COVER 
    46    CLIENT_LOGGING_SUPPORTED = False 
    47 
    48_LOGGER = std_logging.getLogger(__name__) 
    49 
    50 
    51class _LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor):  # pragma: NO COVER 
    52    def intercept_unary_unary(self, continuation, client_call_details, request): 
    53        logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( 
    54            std_logging.DEBUG 
    55        ) 
    56        if logging_enabled:  # pragma: NO COVER 
    57            request_metadata = client_call_details.metadata 
    58            if isinstance(request, proto.Message): 
    59                request_payload = type(request).to_json(request) 
    60            elif isinstance(request, google.protobuf.message.Message): 
    61                request_payload = MessageToJson(request) 
    62            else: 
    63                request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" 
    64 
    65            request_metadata = { 
    66                key: value.decode("utf-8") if isinstance(value, bytes) else value 
    67                for key, value in request_metadata 
    68            } 
    69            grpc_request = { 
    70                "payload": request_payload, 
    71                "requestMethod": "grpc", 
    72                "metadata": dict(request_metadata), 
    73            } 
    74            _LOGGER.debug( 
    75                f"Sending request for {client_call_details.method}", 
    76                extra={ 
    77                    "serviceName": "google.firestore.v1.Firestore", 
    78                    "rpcName": str(client_call_details.method), 
    79                    "request": grpc_request, 
    80                    "metadata": grpc_request["metadata"], 
    81                }, 
    82            ) 
    83        response = continuation(client_call_details, request) 
    84        if logging_enabled:  # pragma: NO COVER 
    85            response_metadata = response.trailing_metadata() 
    86            # Convert gRPC metadata `<class 'grpc.aio._metadata.Metadata'>` to list of tuples 
    87            metadata = ( 
    88                dict([(k, str(v)) for k, v in response_metadata]) 
    89                if response_metadata 
    90                else None 
    91            ) 
    92            result = response.result() 
    93            if isinstance(result, proto.Message): 
    94                response_payload = type(result).to_json(result) 
    95            elif isinstance(result, google.protobuf.message.Message): 
    96                response_payload = MessageToJson(result) 
    97            else: 
    98                response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" 
    99            grpc_response = { 
    100                "payload": response_payload, 
    101                "metadata": metadata, 
    102                "status": "OK", 
    103            } 
    104            _LOGGER.debug( 
    105                f"Received response for {client_call_details.method}.", 
    106                extra={ 
    107                    "serviceName": "google.firestore.v1.Firestore", 
    108                    "rpcName": client_call_details.method, 
    109                    "response": grpc_response, 
    110                    "metadata": grpc_response["metadata"], 
    111                }, 
    112            ) 
    113        return response 
    114 
    115 
    116class FirestoreGrpcTransport(FirestoreTransport): 
    117    """gRPC backend transport for Firestore. 
    118 
    119    The Cloud Firestore service. 
    120 
    121    Cloud Firestore is a fast, fully managed, serverless, 
    122    cloud-native NoSQL document database that simplifies storing, 
    123    syncing, and querying data for your mobile, web, and IoT apps at 
    124    global scale. Its client libraries provide live synchronization 
    125    and offline support, while its security features and 
    126    integrations with Firebase and Google Cloud Platform accelerate 
    127    building truly serverless apps. 
    128 
    129    This class defines the same methods as the primary client, so the 
    130    primary client can load the underlying transport implementation 
    131    and call it. 
    132 
    133    It sends protocol buffers over the wire using gRPC (which is built on 
    134    top of HTTP/2); the ``grpcio`` package must be installed. 
    135    """ 
    136 
    137    _stubs: Dict[str, Callable] 
    138 
    139    def __init__( 
    140        self, 
    141        *, 
    142        host: str = "firestore.googleapis.com", 
    143        credentials: Optional[ga_credentials.Credentials] = None, 
    144        credentials_file: Optional[str] = None, 
    145        scopes: Optional[Sequence[str]] = None, 
    146        channel: Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]] = None, 
    147        api_mtls_endpoint: Optional[str] = None, 
    148        client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, 
    149        ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, 
    150        client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, 
    151        quota_project_id: Optional[str] = None, 
    152        client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, 
    153        always_use_jwt_access: Optional[bool] = False, 
    154        api_audience: Optional[str] = None, 
    155    ) -> None: 
    156        """Instantiate the transport. 
    157 
    158        Args: 
    159            host (Optional[str]): 
    160                 The hostname to connect to (default: 'firestore.googleapis.com'). 
    161            credentials (Optional[google.auth.credentials.Credentials]): The 
    162                authorization credentials to attach to requests. These 
    163                credentials identify the application to the service; if none 
    164                are specified, the client will attempt to ascertain the 
    165                credentials from the environment. 
    166                This argument is ignored if a ``channel`` instance is provided. 
    167            credentials_file (Optional[str]): A file with credentials that can 
    168                be loaded with :func:`google.auth.load_credentials_from_file`. 
    169                This argument is ignored if a ``channel`` instance is provided. 
    170            scopes (Optional(Sequence[str])): A list of scopes. This argument is 
    171                ignored if a ``channel`` instance is provided. 
    172            channel (Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]]): 
    173                A ``Channel`` instance through which to make calls, or a Callable 
    174                that constructs and returns one. If set to None, ``self.create_channel`` 
    175                is used to create the channel. If a Callable is given, it will be called 
    176                with the same arguments as used in ``self.create_channel``. 
    177            api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. 
    178                If provided, it overrides the ``host`` argument and tries to create 
    179                a mutual TLS channel with client SSL credentials from 
    180                ``client_cert_source`` or application default SSL credentials. 
    181            client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): 
    182                Deprecated. A callback to provide client SSL certificate bytes and 
    183                private key bytes, both in PEM format. It is ignored if 
    184                ``api_mtls_endpoint`` is None. 
    185            ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials 
    186                for the grpc channel. It is ignored if a ``channel`` instance is provided. 
    187            client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): 
    188                A callback to provide client certificate bytes and private key bytes, 
    189                both in PEM format. It is used to configure a mutual TLS channel. It is 
    190                ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided. 
    191            quota_project_id (Optional[str]): An optional project to use for billing 
    192                and quota. 
    193            client_info (google.api_core.gapic_v1.client_info.ClientInfo): 
    194                The client info used to send a user-agent string along with 
    195                API requests. If ``None``, then default info will be used. 
    196                Generally, you only need to set this if you're developing 
    197                your own client library. 
    198            always_use_jwt_access (Optional[bool]): Whether self signed JWT should 
    199                be used for service account credentials. 
    200 
    201        Raises: 
    202          google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport 
    203              creation failed for any reason. 
    204          google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` 
    205              and ``credentials_file`` are passed. 
    206        """ 
    207        self._grpc_channel = None 
    208        self._ssl_channel_credentials = ssl_channel_credentials 
    209        self._stubs: Dict[str, Callable] = {} 
    210 
    211        if api_mtls_endpoint: 
    212            warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) 
    213        if client_cert_source: 
    214            warnings.warn("client_cert_source is deprecated", DeprecationWarning) 
    215 
    216        if isinstance(channel, grpc.Channel): 
    217            # Ignore credentials if a channel was passed. 
    218            credentials = None 
    219            self._ignore_credentials = True 
    220            # If a channel was explicitly provided, set it. 
    221            self._grpc_channel = channel 
    222            self._ssl_channel_credentials = None 
    223 
    224        else: 
    225            if api_mtls_endpoint: 
    226                host = api_mtls_endpoint 
    227 
    228                # Create SSL credentials with client_cert_source or application 
    229                # default SSL credentials. 
    230                if client_cert_source: 
    231                    cert, key = client_cert_source() 
    232                    self._ssl_channel_credentials = grpc.ssl_channel_credentials( 
    233                        certificate_chain=cert, private_key=key 
    234                    ) 
    235                else: 
    236                    self._ssl_channel_credentials = SslCredentials().ssl_credentials 
    237 
    238            else: 
    239                if client_cert_source_for_mtls and not ssl_channel_credentials: 
    240                    cert, key = client_cert_source_for_mtls() 
    241                    self._ssl_channel_credentials = grpc.ssl_channel_credentials( 
    242                        certificate_chain=cert, private_key=key 
    243                    ) 
    244 
    245        # The base transport sets the host, credentials and scopes 
    246        super().__init__( 
    247            host=host, 
    248            credentials=credentials, 
    249            credentials_file=credentials_file, 
    250            scopes=scopes, 
    251            quota_project_id=quota_project_id, 
    252            client_info=client_info, 
    253            always_use_jwt_access=always_use_jwt_access, 
    254            api_audience=api_audience, 
    255        ) 
    256 
    257        if not self._grpc_channel: 
    258            # initialize with the provided callable or the default channel 
    259            channel_init = channel or type(self).create_channel 
    260            self._grpc_channel = channel_init( 
    261                self._host, 
    262                # use the credentials which are saved 
    263                credentials=self._credentials, 
    264                # Set ``credentials_file`` to ``None`` here as 
    265                # the credentials that we saved earlier should be used. 
    266                credentials_file=None, 
    267                scopes=self._scopes, 
    268                ssl_credentials=self._ssl_channel_credentials, 
    269                quota_project_id=quota_project_id, 
    270                options=[ 
    271                    ("grpc.max_send_message_length", -1), 
    272                    ("grpc.max_receive_message_length", -1), 
    273                ], 
    274            ) 
    275 
    276        self._interceptor = _LoggingClientInterceptor() 
    277        self._logged_channel = grpc.intercept_channel( 
    278            self._grpc_channel, self._interceptor 
    279        ) 
    280 
    281        # Wrap messages. This must be done after self._logged_channel exists 
    282        self._prep_wrapped_messages(client_info) 
    283 
    284    @classmethod 
    285    def create_channel( 
    286        cls, 
    287        host: str = "firestore.googleapis.com", 
    288        credentials: Optional[ga_credentials.Credentials] = None, 
    289        credentials_file: Optional[str] = None, 
    290        scopes: Optional[Sequence[str]] = None, 
    291        quota_project_id: Optional[str] = None, 
    292        **kwargs, 
    293    ) -> grpc.Channel: 
    294        """Create and return a gRPC channel object. 
    295        Args: 
    296            host (Optional[str]): The host for the channel to use. 
    297            credentials (Optional[~.Credentials]): The 
    298                authorization credentials to attach to requests. These 
    299                credentials identify this application to the service. If 
    300                none are specified, the client will attempt to ascertain 
    301                the credentials from the environment. 
    302            credentials_file (Optional[str]): A file with credentials that can 
    303                be loaded with :func:`google.auth.load_credentials_from_file`. 
    304                This argument is mutually exclusive with credentials. 
    305            scopes (Optional[Sequence[str]]): A optional list of scopes needed for this 
    306                service. These are only used when credentials are not specified and 
    307                are passed to :func:`google.auth.default`. 
    308            quota_project_id (Optional[str]): An optional project to use for billing 
    309                and quota. 
    310            kwargs (Optional[dict]): Keyword arguments, which are passed to the 
    311                channel creation. 
    312        Returns: 
    313            grpc.Channel: A gRPC channel object. 
    314 
    315        Raises: 
    316            google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` 
    317              and ``credentials_file`` are passed. 
    318        """ 
    319 
    320        return grpc_helpers.create_channel( 
    321            host, 
    322            credentials=credentials, 
    323            credentials_file=credentials_file, 
    324            quota_project_id=quota_project_id, 
    325            default_scopes=cls.AUTH_SCOPES, 
    326            scopes=scopes, 
    327            default_host=cls.DEFAULT_HOST, 
    328            **kwargs, 
    329        ) 
    330 
    331    @property 
    332    def grpc_channel(self) -> grpc.Channel: 
    333        """Return the channel designed to connect to this service.""" 
    334        return self._grpc_channel 
    335 
    336    @property 
    337    def get_document( 
    338        self, 
    339    ) -> Callable[[firestore.GetDocumentRequest], document.Document]: 
    340        r"""Return a callable for the get document method over gRPC. 
    341 
    342        Gets a single document. 
    343 
    344        Returns: 
    345            Callable[[~.GetDocumentRequest], 
    346                    ~.Document]: 
    347                A function that, when called, will call the underlying RPC 
    348                on the server. 
    349        """ 
    350        # Generate a "stub function" on-the-fly which will actually make 
    351        # the request. 
    352        # gRPC handles serialization and deserialization, so we just need 
    353        # to pass in the functions for each. 
    354        if "get_document" not in self._stubs: 
    355            self._stubs["get_document"] = self._logged_channel.unary_unary( 
    356                "/google.firestore.v1.Firestore/GetDocument", 
    357                request_serializer=firestore.GetDocumentRequest.serialize, 
    358                response_deserializer=document.Document.deserialize, 
    359            ) 
    360        return self._stubs["get_document"] 
    361 
    362    @property 
    363    def list_documents( 
    364        self, 
    365    ) -> Callable[[firestore.ListDocumentsRequest], firestore.ListDocumentsResponse]: 
    366        r"""Return a callable for the list documents method over gRPC. 
    367 
    368        Lists documents. 
    369 
    370        Returns: 
    371            Callable[[~.ListDocumentsRequest], 
    372                    ~.ListDocumentsResponse]: 
    373                A function that, when called, will call the underlying RPC 
    374                on the server. 
    375        """ 
    376        # Generate a "stub function" on-the-fly which will actually make 
    377        # the request. 
    378        # gRPC handles serialization and deserialization, so we just need 
    379        # to pass in the functions for each. 
    380        if "list_documents" not in self._stubs: 
    381            self._stubs["list_documents"] = self._logged_channel.unary_unary( 
    382                "/google.firestore.v1.Firestore/ListDocuments", 
    383                request_serializer=firestore.ListDocumentsRequest.serialize, 
    384                response_deserializer=firestore.ListDocumentsResponse.deserialize, 
    385            ) 
    386        return self._stubs["list_documents"] 
    387 
    388    @property 
    389    def update_document( 
    390        self, 
    391    ) -> Callable[[firestore.UpdateDocumentRequest], gf_document.Document]: 
    392        r"""Return a callable for the update document method over gRPC. 
    393 
    394        Updates or inserts a document. 
    395 
    396        Returns: 
    397            Callable[[~.UpdateDocumentRequest], 
    398                    ~.Document]: 
    399                A function that, when called, will call the underlying RPC 
    400                on the server. 
    401        """ 
    402        # Generate a "stub function" on-the-fly which will actually make 
    403        # the request. 
    404        # gRPC handles serialization and deserialization, so we just need 
    405        # to pass in the functions for each. 
    406        if "update_document" not in self._stubs: 
    407            self._stubs["update_document"] = self._logged_channel.unary_unary( 
    408                "/google.firestore.v1.Firestore/UpdateDocument", 
    409                request_serializer=firestore.UpdateDocumentRequest.serialize, 
    410                response_deserializer=gf_document.Document.deserialize, 
    411            ) 
    412        return self._stubs["update_document"] 
    413 
    414    @property 
    415    def delete_document( 
    416        self, 
    417    ) -> Callable[[firestore.DeleteDocumentRequest], empty_pb2.Empty]: 
    418        r"""Return a callable for the delete document method over gRPC. 
    419 
    420        Deletes a document. 
    421 
    422        Returns: 
    423            Callable[[~.DeleteDocumentRequest], 
    424                    ~.Empty]: 
    425                A function that, when called, will call the underlying RPC 
    426                on the server. 
    427        """ 
    428        # Generate a "stub function" on-the-fly which will actually make 
    429        # the request. 
    430        # gRPC handles serialization and deserialization, so we just need 
    431        # to pass in the functions for each. 
    432        if "delete_document" not in self._stubs: 
    433            self._stubs["delete_document"] = self._logged_channel.unary_unary( 
    434                "/google.firestore.v1.Firestore/DeleteDocument", 
    435                request_serializer=firestore.DeleteDocumentRequest.serialize, 
    436                response_deserializer=empty_pb2.Empty.FromString, 
    437            ) 
    438        return self._stubs["delete_document"] 
    439 
    440    @property 
    441    def batch_get_documents( 
    442        self, 
    443    ) -> Callable[ 
    444        [firestore.BatchGetDocumentsRequest], firestore.BatchGetDocumentsResponse 
    445    ]: 
    446        r"""Return a callable for the batch get documents method over gRPC. 
    447 
    448        Gets multiple documents. 
    449 
    450        Documents returned by this method are not guaranteed to 
    451        be returned in the same order that they were requested. 
    452 
    453        Returns: 
    454            Callable[[~.BatchGetDocumentsRequest], 
    455                    ~.BatchGetDocumentsResponse]: 
    456                A function that, when called, will call the underlying RPC 
    457                on the server. 
    458        """ 
    459        # Generate a "stub function" on-the-fly which will actually make 
    460        # the request. 
    461        # gRPC handles serialization and deserialization, so we just need 
    462        # to pass in the functions for each. 
    463        if "batch_get_documents" not in self._stubs: 
    464            self._stubs["batch_get_documents"] = self._logged_channel.unary_stream( 
    465                "/google.firestore.v1.Firestore/BatchGetDocuments", 
    466                request_serializer=firestore.BatchGetDocumentsRequest.serialize, 
    467                response_deserializer=firestore.BatchGetDocumentsResponse.deserialize, 
    468            ) 
    469        return self._stubs["batch_get_documents"] 
    470 
    471    @property 
    472    def begin_transaction( 
    473        self, 
    474    ) -> Callable[ 
    475        [firestore.BeginTransactionRequest], firestore.BeginTransactionResponse 
    476    ]: 
    477        r"""Return a callable for the begin transaction method over gRPC. 
    478 
    479        Starts a new transaction. 
    480 
    481        Returns: 
    482            Callable[[~.BeginTransactionRequest], 
    483                    ~.BeginTransactionResponse]: 
    484                A function that, when called, will call the underlying RPC 
    485                on the server. 
    486        """ 
    487        # Generate a "stub function" on-the-fly which will actually make 
    488        # the request. 
    489        # gRPC handles serialization and deserialization, so we just need 
    490        # to pass in the functions for each. 
    491        if "begin_transaction" not in self._stubs: 
    492            self._stubs["begin_transaction"] = self._logged_channel.unary_unary( 
    493                "/google.firestore.v1.Firestore/BeginTransaction", 
    494                request_serializer=firestore.BeginTransactionRequest.serialize, 
    495                response_deserializer=firestore.BeginTransactionResponse.deserialize, 
    496            ) 
    497        return self._stubs["begin_transaction"] 
    498 
    499    @property 
    500    def commit(self) -> Callable[[firestore.CommitRequest], firestore.CommitResponse]: 
    501        r"""Return a callable for the commit method over gRPC. 
    502 
    503        Commits a transaction, while optionally updating 
    504        documents. 
    505 
    506        Returns: 
    507            Callable[[~.CommitRequest], 
    508                    ~.CommitResponse]: 
    509                A function that, when called, will call the underlying RPC 
    510                on the server. 
    511        """ 
    512        # Generate a "stub function" on-the-fly which will actually make 
    513        # the request. 
    514        # gRPC handles serialization and deserialization, so we just need 
    515        # to pass in the functions for each. 
    516        if "commit" not in self._stubs: 
    517            self._stubs["commit"] = self._logged_channel.unary_unary( 
    518                "/google.firestore.v1.Firestore/Commit", 
    519                request_serializer=firestore.CommitRequest.serialize, 
    520                response_deserializer=firestore.CommitResponse.deserialize, 
    521            ) 
    522        return self._stubs["commit"] 
    523 
    524    @property 
    525    def rollback(self) -> Callable[[firestore.RollbackRequest], empty_pb2.Empty]: 
    526        r"""Return a callable for the rollback method over gRPC. 
    527 
    528        Rolls back a transaction. 
    529 
    530        Returns: 
    531            Callable[[~.RollbackRequest], 
    532                    ~.Empty]: 
    533                A function that, when called, will call the underlying RPC 
    534                on the server. 
    535        """ 
    536        # Generate a "stub function" on-the-fly which will actually make 
    537        # the request. 
    538        # gRPC handles serialization and deserialization, so we just need 
    539        # to pass in the functions for each. 
    540        if "rollback" not in self._stubs: 
    541            self._stubs["rollback"] = self._logged_channel.unary_unary( 
    542                "/google.firestore.v1.Firestore/Rollback", 
    543                request_serializer=firestore.RollbackRequest.serialize, 
    544                response_deserializer=empty_pb2.Empty.FromString, 
    545            ) 
    546        return self._stubs["rollback"] 
    547 
    548    @property 
    549    def run_query( 
    550        self, 
    551    ) -> Callable[[firestore.RunQueryRequest], firestore.RunQueryResponse]: 
    552        r"""Return a callable for the run query method over gRPC. 
    553 
    554        Runs a query. 
    555 
    556        Returns: 
    557            Callable[[~.RunQueryRequest], 
    558                    ~.RunQueryResponse]: 
    559                A function that, when called, will call the underlying RPC 
    560                on the server. 
    561        """ 
    562        # Generate a "stub function" on-the-fly which will actually make 
    563        # the request. 
    564        # gRPC handles serialization and deserialization, so we just need 
    565        # to pass in the functions for each. 
    566        if "run_query" not in self._stubs: 
    567            self._stubs["run_query"] = self._logged_channel.unary_stream( 
    568                "/google.firestore.v1.Firestore/RunQuery", 
    569                request_serializer=firestore.RunQueryRequest.serialize, 
    570                response_deserializer=firestore.RunQueryResponse.deserialize, 
    571            ) 
    572        return self._stubs["run_query"] 
    573 
    574    @property 
    575    def run_aggregation_query( 
    576        self, 
    577    ) -> Callable[ 
    578        [firestore.RunAggregationQueryRequest], firestore.RunAggregationQueryResponse 
    579    ]: 
    580        r"""Return a callable for the run aggregation query method over gRPC. 
    581 
    582        Runs an aggregation query. 
    583 
    584        Rather than producing [Document][google.firestore.v1.Document] 
    585        results like 
    586        [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery], 
    587        this API allows running an aggregation to produce a series of 
    588        [AggregationResult][google.firestore.v1.AggregationResult] 
    589        server-side. 
    590 
    591        High-Level Example: 
    592 
    593        :: 
    594 
    595           -- Return the number of documents in table given a filter. 
    596           SELECT COUNT(*) FROM ( SELECT * FROM k where a = true ); 
    597 
    598        Returns: 
    599            Callable[[~.RunAggregationQueryRequest], 
    600                    ~.RunAggregationQueryResponse]: 
    601                A function that, when called, will call the underlying RPC 
    602                on the server. 
    603        """ 
    604        # Generate a "stub function" on-the-fly which will actually make 
    605        # the request. 
    606        # gRPC handles serialization and deserialization, so we just need 
    607        # to pass in the functions for each. 
    608        if "run_aggregation_query" not in self._stubs: 
    609            self._stubs["run_aggregation_query"] = self._logged_channel.unary_stream( 
    610                "/google.firestore.v1.Firestore/RunAggregationQuery", 
    611                request_serializer=firestore.RunAggregationQueryRequest.serialize, 
    612                response_deserializer=firestore.RunAggregationQueryResponse.deserialize, 
    613            ) 
    614        return self._stubs["run_aggregation_query"] 
    615 
    616    @property 
    617    def partition_query( 
    618        self, 
    619    ) -> Callable[[firestore.PartitionQueryRequest], firestore.PartitionQueryResponse]: 
    620        r"""Return a callable for the partition query method over gRPC. 
    621 
    622        Partitions a query by returning partition cursors 
    623        that can be used to run the query in parallel. The 
    624        returned partition cursors are split points that can be 
    625        used by RunQuery as starting/end points for the query 
    626        results. 
    627 
    628        Returns: 
    629            Callable[[~.PartitionQueryRequest], 
    630                    ~.PartitionQueryResponse]: 
    631                A function that, when called, will call the underlying RPC 
    632                on the server. 
    633        """ 
    634        # Generate a "stub function" on-the-fly which will actually make 
    635        # the request. 
    636        # gRPC handles serialization and deserialization, so we just need 
    637        # to pass in the functions for each. 
    638        if "partition_query" not in self._stubs: 
    639            self._stubs["partition_query"] = self._logged_channel.unary_unary( 
    640                "/google.firestore.v1.Firestore/PartitionQuery", 
    641                request_serializer=firestore.PartitionQueryRequest.serialize, 
    642                response_deserializer=firestore.PartitionQueryResponse.deserialize, 
    643            ) 
    644        return self._stubs["partition_query"] 
    645 
    646    @property 
    647    def write(self) -> Callable[[firestore.WriteRequest], firestore.WriteResponse]: 
    648        r"""Return a callable for the write method over gRPC. 
    649 
    650        Streams batches of document updates and deletes, in 
    651        order. This method is only available via gRPC or 
    652        WebChannel (not REST). 
    653 
    654        Returns: 
    655            Callable[[~.WriteRequest], 
    656                    ~.WriteResponse]: 
    657                A function that, when called, will call the underlying RPC 
    658                on the server. 
    659        """ 
    660        # Generate a "stub function" on-the-fly which will actually make 
    661        # the request. 
    662        # gRPC handles serialization and deserialization, so we just need 
    663        # to pass in the functions for each. 
    664        if "write" not in self._stubs: 
    665            self._stubs["write"] = self._logged_channel.stream_stream( 
    666                "/google.firestore.v1.Firestore/Write", 
    667                request_serializer=firestore.WriteRequest.serialize, 
    668                response_deserializer=firestore.WriteResponse.deserialize, 
    669            ) 
    670        return self._stubs["write"] 
    671 
    672    @property 
    673    def listen(self) -> Callable[[firestore.ListenRequest], firestore.ListenResponse]: 
    674        r"""Return a callable for the listen method over gRPC. 
    675 
    676        Listens to changes. This method is only available via 
    677        gRPC or WebChannel (not REST). 
    678 
    679        Returns: 
    680            Callable[[~.ListenRequest], 
    681                    ~.ListenResponse]: 
    682                A function that, when called, will call the underlying RPC 
    683                on the server. 
    684        """ 
    685        # Generate a "stub function" on-the-fly which will actually make 
    686        # the request. 
    687        # gRPC handles serialization and deserialization, so we just need 
    688        # to pass in the functions for each. 
    689        if "listen" not in self._stubs: 
    690            self._stubs["listen"] = self._logged_channel.stream_stream( 
    691                "/google.firestore.v1.Firestore/Listen", 
    692                request_serializer=firestore.ListenRequest.serialize, 
    693                response_deserializer=firestore.ListenResponse.deserialize, 
    694            ) 
    695        return self._stubs["listen"] 
    696 
    697    @property 
    698    def list_collection_ids( 
    699        self, 
    700    ) -> Callable[ 
    701        [firestore.ListCollectionIdsRequest], firestore.ListCollectionIdsResponse 
    702    ]: 
    703        r"""Return a callable for the list collection ids method over gRPC. 
    704 
    705        Lists all the collection IDs underneath a document. 
    706 
    707        Returns: 
    708            Callable[[~.ListCollectionIdsRequest], 
    709                    ~.ListCollectionIdsResponse]: 
    710                A function that, when called, will call the underlying RPC 
    711                on the server. 
    712        """ 
    713        # Generate a "stub function" on-the-fly which will actually make 
    714        # the request. 
    715        # gRPC handles serialization and deserialization, so we just need 
    716        # to pass in the functions for each. 
    717        if "list_collection_ids" not in self._stubs: 
    718            self._stubs["list_collection_ids"] = self._logged_channel.unary_unary( 
    719                "/google.firestore.v1.Firestore/ListCollectionIds", 
    720                request_serializer=firestore.ListCollectionIdsRequest.serialize, 
    721                response_deserializer=firestore.ListCollectionIdsResponse.deserialize, 
    722            ) 
    723        return self._stubs["list_collection_ids"] 
    724 
    725    @property 
    726    def batch_write( 
    727        self, 
    728    ) -> Callable[[firestore.BatchWriteRequest], firestore.BatchWriteResponse]: 
    729        r"""Return a callable for the batch write method over gRPC. 
    730 
    731        Applies a batch of write operations. 
    732 
    733        The BatchWrite method does not apply the write operations 
    734        atomically and can apply them out of order. Method does not 
    735        allow more than one write per document. Each write succeeds or 
    736        fails independently. See the 
    737        [BatchWriteResponse][google.firestore.v1.BatchWriteResponse] for 
    738        the success status of each write. 
    739 
    740        If you require an atomically applied set of writes, use 
    741        [Commit][google.firestore.v1.Firestore.Commit] instead. 
    742 
    743        Returns: 
    744            Callable[[~.BatchWriteRequest], 
    745                    ~.BatchWriteResponse]: 
    746                A function that, when called, will call the underlying RPC 
    747                on the server. 
    748        """ 
    749        # Generate a "stub function" on-the-fly which will actually make 
    750        # the request. 
    751        # gRPC handles serialization and deserialization, so we just need 
    752        # to pass in the functions for each. 
    753        if "batch_write" not in self._stubs: 
    754            self._stubs["batch_write"] = self._logged_channel.unary_unary( 
    755                "/google.firestore.v1.Firestore/BatchWrite", 
    756                request_serializer=firestore.BatchWriteRequest.serialize, 
    757                response_deserializer=firestore.BatchWriteResponse.deserialize, 
    758            ) 
    759        return self._stubs["batch_write"] 
    760 
    761    @property 
    762    def create_document( 
    763        self, 
    764    ) -> Callable[[firestore.CreateDocumentRequest], document.Document]: 
    765        r"""Return a callable for the create document method over gRPC. 
    766 
    767        Creates a new document. 
    768 
    769        Returns: 
    770            Callable[[~.CreateDocumentRequest], 
    771                    ~.Document]: 
    772                A function that, when called, will call the underlying RPC 
    773                on the server. 
    774        """ 
    775        # Generate a "stub function" on-the-fly which will actually make 
    776        # the request. 
    777        # gRPC handles serialization and deserialization, so we just need 
    778        # to pass in the functions for each. 
    779        if "create_document" not in self._stubs: 
    780            self._stubs["create_document"] = self._logged_channel.unary_unary( 
    781                "/google.firestore.v1.Firestore/CreateDocument", 
    782                request_serializer=firestore.CreateDocumentRequest.serialize, 
    783                response_deserializer=document.Document.deserialize, 
    784            ) 
    785        return self._stubs["create_document"] 
    786 
    787    def close(self): 
    788        self._logged_channel.close() 
    789 
    790    @property 
    791    def delete_operation( 
    792        self, 
    793    ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: 
    794        r"""Return a callable for the delete_operation method over gRPC.""" 
    795        # Generate a "stub function" on-the-fly which will actually make 
    796        # the request. 
    797        # gRPC handles serialization and deserialization, so we just need 
    798        # to pass in the functions for each. 
    799        if "delete_operation" not in self._stubs: 
    800            self._stubs["delete_operation"] = self._logged_channel.unary_unary( 
    801                "/google.longrunning.Operations/DeleteOperation", 
    802                request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, 
    803                response_deserializer=None, 
    804            ) 
    805        return self._stubs["delete_operation"] 
    806 
    807    @property 
    808    def cancel_operation( 
    809        self, 
    810    ) -> Callable[[operations_pb2.CancelOperationRequest], None]: 
    811        r"""Return a callable for the cancel_operation method over gRPC.""" 
    812        # Generate a "stub function" on-the-fly which will actually make 
    813        # the request. 
    814        # gRPC handles serialization and deserialization, so we just need 
    815        # to pass in the functions for each. 
    816        if "cancel_operation" not in self._stubs: 
    817            self._stubs["cancel_operation"] = self._logged_channel.unary_unary( 
    818                "/google.longrunning.Operations/CancelOperation", 
    819                request_serializer=operations_pb2.CancelOperationRequest.SerializeToString, 
    820                response_deserializer=None, 
    821            ) 
    822        return self._stubs["cancel_operation"] 
    823 
    824    @property 
    825    def get_operation( 
    826        self, 
    827    ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: 
    828        r"""Return a callable for the get_operation method over gRPC.""" 
    829        # Generate a "stub function" on-the-fly which will actually make 
    830        # the request. 
    831        # gRPC handles serialization and deserialization, so we just need 
    832        # to pass in the functions for each. 
    833        if "get_operation" not in self._stubs: 
    834            self._stubs["get_operation"] = self._logged_channel.unary_unary( 
    835                "/google.longrunning.Operations/GetOperation", 
    836                request_serializer=operations_pb2.GetOperationRequest.SerializeToString, 
    837                response_deserializer=operations_pb2.Operation.FromString, 
    838            ) 
    839        return self._stubs["get_operation"] 
    840 
    841    @property 
    842    def list_operations( 
    843        self, 
    844    ) -> Callable[ 
    845        [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse 
    846    ]: 
    847        r"""Return a callable for the list_operations method over gRPC.""" 
    848        # Generate a "stub function" on-the-fly which will actually make 
    849        # the request. 
    850        # gRPC handles serialization and deserialization, so we just need 
    851        # to pass in the functions for each. 
    852        if "list_operations" not in self._stubs: 
    853            self._stubs["list_operations"] = self._logged_channel.unary_unary( 
    854                "/google.longrunning.Operations/ListOperations", 
    855                request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, 
    856                response_deserializer=operations_pb2.ListOperationsResponse.FromString, 
    857            ) 
    858        return self._stubs["list_operations"] 
    859 
    860    @property 
    861    def kind(self) -> str: 
    862        return "grpc" 
    863 
    864 
    865__all__ = ("FirestoreGrpcTransport",)