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",)