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]): Deprecated. 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 This argument will be removed in the next major version of this library.
171 scopes (Optional(Sequence[str])): A list of scopes. This argument is
172 ignored if a ``channel`` instance is provided.
173 channel (Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]]):
174 A ``Channel`` instance through which to make calls, or a Callable
175 that constructs and returns one. If set to None, ``self.create_channel``
176 is used to create the channel. If a Callable is given, it will be called
177 with the same arguments as used in ``self.create_channel``.
178 api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint.
179 If provided, it overrides the ``host`` argument and tries to create
180 a mutual TLS channel with client SSL credentials from
181 ``client_cert_source`` or application default SSL credentials.
182 client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]):
183 Deprecated. A callback to provide client SSL certificate bytes and
184 private key bytes, both in PEM format. It is ignored if
185 ``api_mtls_endpoint`` is None.
186 ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
187 for the grpc channel. It is ignored if a ``channel`` instance is provided.
188 client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
189 A callback to provide client certificate bytes and private key bytes,
190 both in PEM format. It is used to configure a mutual TLS channel. It is
191 ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided.
192 quota_project_id (Optional[str]): An optional project to use for billing
193 and quota.
194 client_info (google.api_core.gapic_v1.client_info.ClientInfo):
195 The client info used to send a user-agent string along with
196 API requests. If ``None``, then default info will be used.
197 Generally, you only need to set this if you're developing
198 your own client library.
199 always_use_jwt_access (Optional[bool]): Whether self signed JWT should
200 be used for service account credentials.
201
202 Raises:
203 google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
204 creation failed for any reason.
205 google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials``
206 and ``credentials_file`` are passed.
207 """
208 self._grpc_channel = None
209 self._ssl_channel_credentials = ssl_channel_credentials
210 self._stubs: Dict[str, Callable] = {}
211
212 if api_mtls_endpoint:
213 warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
214 if client_cert_source:
215 warnings.warn("client_cert_source is deprecated", DeprecationWarning)
216
217 if isinstance(channel, grpc.Channel):
218 # Ignore credentials if a channel was passed.
219 credentials = None
220 self._ignore_credentials = True
221 # If a channel was explicitly provided, set it.
222 self._grpc_channel = channel
223 self._ssl_channel_credentials = None
224
225 else:
226 if api_mtls_endpoint:
227 host = api_mtls_endpoint
228
229 # Create SSL credentials with client_cert_source or application
230 # default SSL credentials.
231 if client_cert_source:
232 cert, key = client_cert_source()
233 self._ssl_channel_credentials = grpc.ssl_channel_credentials(
234 certificate_chain=cert, private_key=key
235 )
236 else:
237 self._ssl_channel_credentials = SslCredentials().ssl_credentials
238
239 else:
240 if client_cert_source_for_mtls and not ssl_channel_credentials:
241 cert, key = client_cert_source_for_mtls()
242 self._ssl_channel_credentials = grpc.ssl_channel_credentials(
243 certificate_chain=cert, private_key=key
244 )
245
246 # The base transport sets the host, credentials and scopes
247 super().__init__(
248 host=host,
249 credentials=credentials,
250 credentials_file=credentials_file,
251 scopes=scopes,
252 quota_project_id=quota_project_id,
253 client_info=client_info,
254 always_use_jwt_access=always_use_jwt_access,
255 api_audience=api_audience,
256 )
257
258 if not self._grpc_channel:
259 # initialize with the provided callable or the default channel
260 channel_init = channel or type(self).create_channel
261 self._grpc_channel = channel_init(
262 self._host,
263 # use the credentials which are saved
264 credentials=self._credentials,
265 # Set ``credentials_file`` to ``None`` here as
266 # the credentials that we saved earlier should be used.
267 credentials_file=None,
268 scopes=self._scopes,
269 ssl_credentials=self._ssl_channel_credentials,
270 quota_project_id=quota_project_id,
271 options=[
272 ("grpc.max_send_message_length", -1),
273 ("grpc.max_receive_message_length", -1),
274 ],
275 )
276
277 self._interceptor = _LoggingClientInterceptor()
278 self._logged_channel = grpc.intercept_channel(
279 self._grpc_channel, self._interceptor
280 )
281
282 # Wrap messages. This must be done after self._logged_channel exists
283 self._prep_wrapped_messages(client_info)
284
285 @classmethod
286 def create_channel(
287 cls,
288 host: str = "firestore.googleapis.com",
289 credentials: Optional[ga_credentials.Credentials] = None,
290 credentials_file: Optional[str] = None,
291 scopes: Optional[Sequence[str]] = None,
292 quota_project_id: Optional[str] = None,
293 **kwargs,
294 ) -> grpc.Channel:
295 """Create and return a gRPC channel object.
296 Args:
297 host (Optional[str]): The host for the channel to use.
298 credentials (Optional[~.Credentials]): The
299 authorization credentials to attach to requests. These
300 credentials identify this application to the service. If
301 none are specified, the client will attempt to ascertain
302 the credentials from the environment.
303 credentials_file (Optional[str]): Deprecated. A file with credentials that can
304 be loaded with :func:`google.auth.load_credentials_from_file`.
305 This argument is mutually exclusive with credentials. This argument will be
306 removed in the next major version of this library.
307 scopes (Optional[Sequence[str]]): A optional list of scopes needed for this
308 service. These are only used when credentials are not specified and
309 are passed to :func:`google.auth.default`.
310 quota_project_id (Optional[str]): An optional project to use for billing
311 and quota.
312 kwargs (Optional[dict]): Keyword arguments, which are passed to the
313 channel creation.
314 Returns:
315 grpc.Channel: A gRPC channel object.
316
317 Raises:
318 google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials``
319 and ``credentials_file`` are passed.
320 """
321
322 return grpc_helpers.create_channel(
323 host,
324 credentials=credentials,
325 credentials_file=credentials_file,
326 quota_project_id=quota_project_id,
327 default_scopes=cls.AUTH_SCOPES,
328 scopes=scopes,
329 default_host=cls.DEFAULT_HOST,
330 **kwargs,
331 )
332
333 @property
334 def grpc_channel(self) -> grpc.Channel:
335 """Return the channel designed to connect to this service."""
336 return self._grpc_channel
337
338 @property
339 def get_document(
340 self,
341 ) -> Callable[[firestore.GetDocumentRequest], document.Document]:
342 r"""Return a callable for the get document method over gRPC.
343
344 Gets a single document.
345
346 Returns:
347 Callable[[~.GetDocumentRequest],
348 ~.Document]:
349 A function that, when called, will call the underlying RPC
350 on the server.
351 """
352 # Generate a "stub function" on-the-fly which will actually make
353 # the request.
354 # gRPC handles serialization and deserialization, so we just need
355 # to pass in the functions for each.
356 if "get_document" not in self._stubs:
357 self._stubs["get_document"] = self._logged_channel.unary_unary(
358 "/google.firestore.v1.Firestore/GetDocument",
359 request_serializer=firestore.GetDocumentRequest.serialize,
360 response_deserializer=document.Document.deserialize,
361 )
362 return self._stubs["get_document"]
363
364 @property
365 def list_documents(
366 self,
367 ) -> Callable[[firestore.ListDocumentsRequest], firestore.ListDocumentsResponse]:
368 r"""Return a callable for the list documents method over gRPC.
369
370 Lists documents.
371
372 Returns:
373 Callable[[~.ListDocumentsRequest],
374 ~.ListDocumentsResponse]:
375 A function that, when called, will call the underlying RPC
376 on the server.
377 """
378 # Generate a "stub function" on-the-fly which will actually make
379 # the request.
380 # gRPC handles serialization and deserialization, so we just need
381 # to pass in the functions for each.
382 if "list_documents" not in self._stubs:
383 self._stubs["list_documents"] = self._logged_channel.unary_unary(
384 "/google.firestore.v1.Firestore/ListDocuments",
385 request_serializer=firestore.ListDocumentsRequest.serialize,
386 response_deserializer=firestore.ListDocumentsResponse.deserialize,
387 )
388 return self._stubs["list_documents"]
389
390 @property
391 def update_document(
392 self,
393 ) -> Callable[[firestore.UpdateDocumentRequest], gf_document.Document]:
394 r"""Return a callable for the update document method over gRPC.
395
396 Updates or inserts a document.
397
398 Returns:
399 Callable[[~.UpdateDocumentRequest],
400 ~.Document]:
401 A function that, when called, will call the underlying RPC
402 on the server.
403 """
404 # Generate a "stub function" on-the-fly which will actually make
405 # the request.
406 # gRPC handles serialization and deserialization, so we just need
407 # to pass in the functions for each.
408 if "update_document" not in self._stubs:
409 self._stubs["update_document"] = self._logged_channel.unary_unary(
410 "/google.firestore.v1.Firestore/UpdateDocument",
411 request_serializer=firestore.UpdateDocumentRequest.serialize,
412 response_deserializer=gf_document.Document.deserialize,
413 )
414 return self._stubs["update_document"]
415
416 @property
417 def delete_document(
418 self,
419 ) -> Callable[[firestore.DeleteDocumentRequest], empty_pb2.Empty]:
420 r"""Return a callable for the delete document method over gRPC.
421
422 Deletes a document.
423
424 Returns:
425 Callable[[~.DeleteDocumentRequest],
426 ~.Empty]:
427 A function that, when called, will call the underlying RPC
428 on the server.
429 """
430 # Generate a "stub function" on-the-fly which will actually make
431 # the request.
432 # gRPC handles serialization and deserialization, so we just need
433 # to pass in the functions for each.
434 if "delete_document" not in self._stubs:
435 self._stubs["delete_document"] = self._logged_channel.unary_unary(
436 "/google.firestore.v1.Firestore/DeleteDocument",
437 request_serializer=firestore.DeleteDocumentRequest.serialize,
438 response_deserializer=empty_pb2.Empty.FromString,
439 )
440 return self._stubs["delete_document"]
441
442 @property
443 def batch_get_documents(
444 self,
445 ) -> Callable[
446 [firestore.BatchGetDocumentsRequest], firestore.BatchGetDocumentsResponse
447 ]:
448 r"""Return a callable for the batch get documents method over gRPC.
449
450 Gets multiple documents.
451
452 Documents returned by this method are not guaranteed to
453 be returned in the same order that they were requested.
454
455 Returns:
456 Callable[[~.BatchGetDocumentsRequest],
457 ~.BatchGetDocumentsResponse]:
458 A function that, when called, will call the underlying RPC
459 on the server.
460 """
461 # Generate a "stub function" on-the-fly which will actually make
462 # the request.
463 # gRPC handles serialization and deserialization, so we just need
464 # to pass in the functions for each.
465 if "batch_get_documents" not in self._stubs:
466 self._stubs["batch_get_documents"] = self._logged_channel.unary_stream(
467 "/google.firestore.v1.Firestore/BatchGetDocuments",
468 request_serializer=firestore.BatchGetDocumentsRequest.serialize,
469 response_deserializer=firestore.BatchGetDocumentsResponse.deserialize,
470 )
471 return self._stubs["batch_get_documents"]
472
473 @property
474 def begin_transaction(
475 self,
476 ) -> Callable[
477 [firestore.BeginTransactionRequest], firestore.BeginTransactionResponse
478 ]:
479 r"""Return a callable for the begin transaction method over gRPC.
480
481 Starts a new transaction.
482
483 Returns:
484 Callable[[~.BeginTransactionRequest],
485 ~.BeginTransactionResponse]:
486 A function that, when called, will call the underlying RPC
487 on the server.
488 """
489 # Generate a "stub function" on-the-fly which will actually make
490 # the request.
491 # gRPC handles serialization and deserialization, so we just need
492 # to pass in the functions for each.
493 if "begin_transaction" not in self._stubs:
494 self._stubs["begin_transaction"] = self._logged_channel.unary_unary(
495 "/google.firestore.v1.Firestore/BeginTransaction",
496 request_serializer=firestore.BeginTransactionRequest.serialize,
497 response_deserializer=firestore.BeginTransactionResponse.deserialize,
498 )
499 return self._stubs["begin_transaction"]
500
501 @property
502 def commit(self) -> Callable[[firestore.CommitRequest], firestore.CommitResponse]:
503 r"""Return a callable for the commit method over gRPC.
504
505 Commits a transaction, while optionally updating
506 documents.
507
508 Returns:
509 Callable[[~.CommitRequest],
510 ~.CommitResponse]:
511 A function that, when called, will call the underlying RPC
512 on the server.
513 """
514 # Generate a "stub function" on-the-fly which will actually make
515 # the request.
516 # gRPC handles serialization and deserialization, so we just need
517 # to pass in the functions for each.
518 if "commit" not in self._stubs:
519 self._stubs["commit"] = self._logged_channel.unary_unary(
520 "/google.firestore.v1.Firestore/Commit",
521 request_serializer=firestore.CommitRequest.serialize,
522 response_deserializer=firestore.CommitResponse.deserialize,
523 )
524 return self._stubs["commit"]
525
526 @property
527 def rollback(self) -> Callable[[firestore.RollbackRequest], empty_pb2.Empty]:
528 r"""Return a callable for the rollback method over gRPC.
529
530 Rolls back a transaction.
531
532 Returns:
533 Callable[[~.RollbackRequest],
534 ~.Empty]:
535 A function that, when called, will call the underlying RPC
536 on the server.
537 """
538 # Generate a "stub function" on-the-fly which will actually make
539 # the request.
540 # gRPC handles serialization and deserialization, so we just need
541 # to pass in the functions for each.
542 if "rollback" not in self._stubs:
543 self._stubs["rollback"] = self._logged_channel.unary_unary(
544 "/google.firestore.v1.Firestore/Rollback",
545 request_serializer=firestore.RollbackRequest.serialize,
546 response_deserializer=empty_pb2.Empty.FromString,
547 )
548 return self._stubs["rollback"]
549
550 @property
551 def run_query(
552 self,
553 ) -> Callable[[firestore.RunQueryRequest], firestore.RunQueryResponse]:
554 r"""Return a callable for the run query method over gRPC.
555
556 Runs a query.
557
558 Returns:
559 Callable[[~.RunQueryRequest],
560 ~.RunQueryResponse]:
561 A function that, when called, will call the underlying RPC
562 on the server.
563 """
564 # Generate a "stub function" on-the-fly which will actually make
565 # the request.
566 # gRPC handles serialization and deserialization, so we just need
567 # to pass in the functions for each.
568 if "run_query" not in self._stubs:
569 self._stubs["run_query"] = self._logged_channel.unary_stream(
570 "/google.firestore.v1.Firestore/RunQuery",
571 request_serializer=firestore.RunQueryRequest.serialize,
572 response_deserializer=firestore.RunQueryResponse.deserialize,
573 )
574 return self._stubs["run_query"]
575
576 @property
577 def run_aggregation_query(
578 self,
579 ) -> Callable[
580 [firestore.RunAggregationQueryRequest], firestore.RunAggregationQueryResponse
581 ]:
582 r"""Return a callable for the run aggregation query method over gRPC.
583
584 Runs an aggregation query.
585
586 Rather than producing [Document][google.firestore.v1.Document]
587 results like
588 [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery],
589 this API allows running an aggregation to produce a series of
590 [AggregationResult][google.firestore.v1.AggregationResult]
591 server-side.
592
593 High-Level Example:
594
595 ::
596
597 -- Return the number of documents in table given a filter.
598 SELECT COUNT(*) FROM ( SELECT * FROM k where a = true );
599
600 Returns:
601 Callable[[~.RunAggregationQueryRequest],
602 ~.RunAggregationQueryResponse]:
603 A function that, when called, will call the underlying RPC
604 on the server.
605 """
606 # Generate a "stub function" on-the-fly which will actually make
607 # the request.
608 # gRPC handles serialization and deserialization, so we just need
609 # to pass in the functions for each.
610 if "run_aggregation_query" not in self._stubs:
611 self._stubs["run_aggregation_query"] = self._logged_channel.unary_stream(
612 "/google.firestore.v1.Firestore/RunAggregationQuery",
613 request_serializer=firestore.RunAggregationQueryRequest.serialize,
614 response_deserializer=firestore.RunAggregationQueryResponse.deserialize,
615 )
616 return self._stubs["run_aggregation_query"]
617
618 @property
619 def partition_query(
620 self,
621 ) -> Callable[[firestore.PartitionQueryRequest], firestore.PartitionQueryResponse]:
622 r"""Return a callable for the partition query method over gRPC.
623
624 Partitions a query by returning partition cursors
625 that can be used to run the query in parallel. The
626 returned partition cursors are split points that can be
627 used by RunQuery as starting/end points for the query
628 results.
629
630 Returns:
631 Callable[[~.PartitionQueryRequest],
632 ~.PartitionQueryResponse]:
633 A function that, when called, will call the underlying RPC
634 on the server.
635 """
636 # Generate a "stub function" on-the-fly which will actually make
637 # the request.
638 # gRPC handles serialization and deserialization, so we just need
639 # to pass in the functions for each.
640 if "partition_query" not in self._stubs:
641 self._stubs["partition_query"] = self._logged_channel.unary_unary(
642 "/google.firestore.v1.Firestore/PartitionQuery",
643 request_serializer=firestore.PartitionQueryRequest.serialize,
644 response_deserializer=firestore.PartitionQueryResponse.deserialize,
645 )
646 return self._stubs["partition_query"]
647
648 @property
649 def write(self) -> Callable[[firestore.WriteRequest], firestore.WriteResponse]:
650 r"""Return a callable for the write method over gRPC.
651
652 Streams batches of document updates and deletes, in
653 order. This method is only available via gRPC or
654 WebChannel (not REST).
655
656 Returns:
657 Callable[[~.WriteRequest],
658 ~.WriteResponse]:
659 A function that, when called, will call the underlying RPC
660 on the server.
661 """
662 # Generate a "stub function" on-the-fly which will actually make
663 # the request.
664 # gRPC handles serialization and deserialization, so we just need
665 # to pass in the functions for each.
666 if "write" not in self._stubs:
667 self._stubs["write"] = self._logged_channel.stream_stream(
668 "/google.firestore.v1.Firestore/Write",
669 request_serializer=firestore.WriteRequest.serialize,
670 response_deserializer=firestore.WriteResponse.deserialize,
671 )
672 return self._stubs["write"]
673
674 @property
675 def listen(self) -> Callable[[firestore.ListenRequest], firestore.ListenResponse]:
676 r"""Return a callable for the listen method over gRPC.
677
678 Listens to changes. This method is only available via
679 gRPC or WebChannel (not REST).
680
681 Returns:
682 Callable[[~.ListenRequest],
683 ~.ListenResponse]:
684 A function that, when called, will call the underlying RPC
685 on the server.
686 """
687 # Generate a "stub function" on-the-fly which will actually make
688 # the request.
689 # gRPC handles serialization and deserialization, so we just need
690 # to pass in the functions for each.
691 if "listen" not in self._stubs:
692 self._stubs["listen"] = self._logged_channel.stream_stream(
693 "/google.firestore.v1.Firestore/Listen",
694 request_serializer=firestore.ListenRequest.serialize,
695 response_deserializer=firestore.ListenResponse.deserialize,
696 )
697 return self._stubs["listen"]
698
699 @property
700 def list_collection_ids(
701 self,
702 ) -> Callable[
703 [firestore.ListCollectionIdsRequest], firestore.ListCollectionIdsResponse
704 ]:
705 r"""Return a callable for the list collection ids method over gRPC.
706
707 Lists all the collection IDs underneath a document.
708
709 Returns:
710 Callable[[~.ListCollectionIdsRequest],
711 ~.ListCollectionIdsResponse]:
712 A function that, when called, will call the underlying RPC
713 on the server.
714 """
715 # Generate a "stub function" on-the-fly which will actually make
716 # the request.
717 # gRPC handles serialization and deserialization, so we just need
718 # to pass in the functions for each.
719 if "list_collection_ids" not in self._stubs:
720 self._stubs["list_collection_ids"] = self._logged_channel.unary_unary(
721 "/google.firestore.v1.Firestore/ListCollectionIds",
722 request_serializer=firestore.ListCollectionIdsRequest.serialize,
723 response_deserializer=firestore.ListCollectionIdsResponse.deserialize,
724 )
725 return self._stubs["list_collection_ids"]
726
727 @property
728 def batch_write(
729 self,
730 ) -> Callable[[firestore.BatchWriteRequest], firestore.BatchWriteResponse]:
731 r"""Return a callable for the batch write method over gRPC.
732
733 Applies a batch of write operations.
734
735 The BatchWrite method does not apply the write operations
736 atomically and can apply them out of order. Method does not
737 allow more than one write per document. Each write succeeds or
738 fails independently. See the
739 [BatchWriteResponse][google.firestore.v1.BatchWriteResponse] for
740 the success status of each write.
741
742 If you require an atomically applied set of writes, use
743 [Commit][google.firestore.v1.Firestore.Commit] instead.
744
745 Returns:
746 Callable[[~.BatchWriteRequest],
747 ~.BatchWriteResponse]:
748 A function that, when called, will call the underlying RPC
749 on the server.
750 """
751 # Generate a "stub function" on-the-fly which will actually make
752 # the request.
753 # gRPC handles serialization and deserialization, so we just need
754 # to pass in the functions for each.
755 if "batch_write" not in self._stubs:
756 self._stubs["batch_write"] = self._logged_channel.unary_unary(
757 "/google.firestore.v1.Firestore/BatchWrite",
758 request_serializer=firestore.BatchWriteRequest.serialize,
759 response_deserializer=firestore.BatchWriteResponse.deserialize,
760 )
761 return self._stubs["batch_write"]
762
763 @property
764 def create_document(
765 self,
766 ) -> Callable[[firestore.CreateDocumentRequest], document.Document]:
767 r"""Return a callable for the create document method over gRPC.
768
769 Creates a new document.
770
771 Returns:
772 Callable[[~.CreateDocumentRequest],
773 ~.Document]:
774 A function that, when called, will call the underlying RPC
775 on the server.
776 """
777 # Generate a "stub function" on-the-fly which will actually make
778 # the request.
779 # gRPC handles serialization and deserialization, so we just need
780 # to pass in the functions for each.
781 if "create_document" not in self._stubs:
782 self._stubs["create_document"] = self._logged_channel.unary_unary(
783 "/google.firestore.v1.Firestore/CreateDocument",
784 request_serializer=firestore.CreateDocumentRequest.serialize,
785 response_deserializer=document.Document.deserialize,
786 )
787 return self._stubs["create_document"]
788
789 def close(self):
790 self._logged_channel.close()
791
792 @property
793 def delete_operation(
794 self,
795 ) -> Callable[[operations_pb2.DeleteOperationRequest], None]:
796 r"""Return a callable for the delete_operation method over gRPC."""
797 # Generate a "stub function" on-the-fly which will actually make
798 # the request.
799 # gRPC handles serialization and deserialization, so we just need
800 # to pass in the functions for each.
801 if "delete_operation" not in self._stubs:
802 self._stubs["delete_operation"] = self._logged_channel.unary_unary(
803 "/google.longrunning.Operations/DeleteOperation",
804 request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString,
805 response_deserializer=None,
806 )
807 return self._stubs["delete_operation"]
808
809 @property
810 def cancel_operation(
811 self,
812 ) -> Callable[[operations_pb2.CancelOperationRequest], None]:
813 r"""Return a callable for the cancel_operation method over gRPC."""
814 # Generate a "stub function" on-the-fly which will actually make
815 # the request.
816 # gRPC handles serialization and deserialization, so we just need
817 # to pass in the functions for each.
818 if "cancel_operation" not in self._stubs:
819 self._stubs["cancel_operation"] = self._logged_channel.unary_unary(
820 "/google.longrunning.Operations/CancelOperation",
821 request_serializer=operations_pb2.CancelOperationRequest.SerializeToString,
822 response_deserializer=None,
823 )
824 return self._stubs["cancel_operation"]
825
826 @property
827 def get_operation(
828 self,
829 ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]:
830 r"""Return a callable for the get_operation method over gRPC."""
831 # Generate a "stub function" on-the-fly which will actually make
832 # the request.
833 # gRPC handles serialization and deserialization, so we just need
834 # to pass in the functions for each.
835 if "get_operation" not in self._stubs:
836 self._stubs["get_operation"] = self._logged_channel.unary_unary(
837 "/google.longrunning.Operations/GetOperation",
838 request_serializer=operations_pb2.GetOperationRequest.SerializeToString,
839 response_deserializer=operations_pb2.Operation.FromString,
840 )
841 return self._stubs["get_operation"]
842
843 @property
844 def list_operations(
845 self,
846 ) -> Callable[
847 [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse
848 ]:
849 r"""Return a callable for the list_operations method over gRPC."""
850 # Generate a "stub function" on-the-fly which will actually make
851 # the request.
852 # gRPC handles serialization and deserialization, so we just need
853 # to pass in the functions for each.
854 if "list_operations" not in self._stubs:
855 self._stubs["list_operations"] = self._logged_channel.unary_unary(
856 "/google.longrunning.Operations/ListOperations",
857 request_serializer=operations_pb2.ListOperationsRequest.SerializeToString,
858 response_deserializer=operations_pb2.ListOperationsResponse.FromString,
859 )
860 return self._stubs["list_operations"]
861
862 @property
863 def kind(self) -> str:
864 return "grpc"
865
866
867__all__ = ("FirestoreGrpcTransport",)