示例#1
0
    def test_paths(self):
        from google.cloud.firestore_v1.types import common

        field_paths = ["a.b", "c"]
        result = self._call_fut(field_paths)
        expected = common.DocumentMask(field_paths=field_paths)
        self.assertEqual(result, expected)
    def _prep_batch_get(
        self,
        field_paths: Iterable[str] = None,
        transaction=None,
        retry: retries.Retry = None,
        timeout: float = None,
    ) -> Tuple[dict, dict]:
        """Shared setup for async/sync :meth:`get`."""
        if isinstance(field_paths, str):
            raise ValueError(
                "'field_paths' must be a sequence of paths, not a string.")

        if field_paths is not None:
            mask = common.DocumentMask(field_paths=sorted(field_paths))
        else:
            mask = None

        request = {
            "database": self._client._database_string,
            "documents": [self._document_path],
            "mask": mask,
            "transaction": _helpers.get_transaction_id(transaction),
        }
        kwargs = _helpers.make_retry_timeout_kwargs(retry, timeout)

        return request, kwargs
def test_basewritebatch_update():
    from google.cloud.firestore_v1.types import common
    from google.cloud.firestore_v1.types import document
    from google.cloud.firestore_v1.types import write

    client = _make_client()
    batch = _make_derived_write_batch(client)
    assert batch._write_pbs == []

    reference = client.document("cats", "cradle")
    field_path = "head.foot"
    value = u"knees toes shoulders"
    field_updates = {field_path: value}

    ret_val = batch.update(reference, field_updates)
    assert ret_val is None

    map_pb = document.MapValue(fields={"foot": _value_pb(string_value=value)})
    new_write_pb = write.Write(
        update=document.Document(
            name=reference._document_path, fields={"head": _value_pb(map_value=map_pb)},
        ),
        update_mask=common.DocumentMask(field_paths=[field_path]),
        current_document=common.Precondition(exists=True),
    )
    assert batch._write_pbs == [new_write_pb]
示例#4
0
    def _get_update_mask(self, allow_empty_mask=False) -> types.common.DocumentMask:
        mask_paths = []
        for field_path in self.top_level_paths:
            if field_path not in self.transform_paths:
                mask_paths.append(field_path.to_api_repr())

        return common.DocumentMask(field_paths=mask_paths)
示例#5
0
def test__get_doc_mask_w_paths():
    from google.cloud.firestore_v1.types import common
    from google.cloud.firestore_v1.base_client import _get_doc_mask

    field_paths = ["a.b", "c"]
    result = _get_doc_mask(field_paths)
    expected = common.DocumentMask(field_paths=field_paths)
    assert result == expected
示例#6
0
    def _get_update_mask(
            self,
            allow_empty_mask=False) -> Optional[types.common.DocumentMask]:
        # Mask uses dotted / quoted paths.
        mask_paths = [
            field_path.to_api_repr() for field_path in self.merge
            if field_path not in self.transform_merge
        ]

        return common.DocumentMask(field_paths=mask_paths)
示例#7
0
def _write_pb_for_update(document_path, update_values, field_paths):
    from google.cloud.firestore_v1.types import common
    from google.cloud.firestore_v1.types import document
    from google.cloud.firestore_v1.types import write
    from google.cloud.firestore_v1 import _helpers

    return write.Write(
        update=document.Document(name=document_path,
                                 fields=_helpers.encode_dict(update_values)),
        update_mask=common.DocumentMask(field_paths=field_paths),
        current_document=common.Precondition(exists=True),
    )
示例#8
0
    def _write_pb_for_set(document_path, document_data, merge):
        from google.cloud.firestore_v1.types import common
        from google.cloud.firestore_v1.types import document
        from google.cloud.firestore_v1.types import write
        from google.cloud.firestore_v1 import _helpers

        write_pbs = write.Write(update=document.Document(
            name=document_path, fields=_helpers.encode_dict(document_data)))
        if merge:
            field_paths = [
                field_path for field_path, value in _helpers.extract_fields(
                    document_data, _helpers.FieldPath())
            ]
            field_paths = [
                field_path.to_api_repr() for field_path in sorted(field_paths)
            ]
            mask = common.DocumentMask(field_paths=sorted(field_paths))
            write_pbs._pb.update_mask.CopyFrom(mask._pb)
        return write_pbs
    async def test_get_all(self):
        from google.cloud.firestore_v1.types import common
        from google.cloud.firestore_v1.async_document import DocumentSnapshot

        data1 = {"a": u"cheese"}
        data2 = {"b": True, "c": 18}
        info = self._info_for_get_all(data1, data2)
        client, document1, document2, response1, response2 = info

        # Exercise the mocked ``batch_get_documents``.
        field_paths = ["a", "b"]
        snapshots = await self._get_all_helper(
            client,
            [document1, document2],
            [response1, response2],
            field_paths=field_paths,
        )
        self.assertEqual(len(snapshots), 2)

        snapshot1 = snapshots[0]
        self.assertIsInstance(snapshot1, DocumentSnapshot)
        self.assertIs(snapshot1._reference, document1)
        self.assertEqual(snapshot1._data, data1)

        snapshot2 = snapshots[1]
        self.assertIsInstance(snapshot2, DocumentSnapshot)
        self.assertIs(snapshot2._reference, document2)
        self.assertEqual(snapshot2._data, data2)

        # Verify the call to the mock.
        doc_paths = [document1._document_path, document2._document_path]
        mask = common.DocumentMask(field_paths=field_paths)
        client._firestore_api.batch_get_documents.assert_called_once_with(
            request={
                "database": client._database_string,
                "documents": doc_paths,
                "mask": mask,
                "transaction": None,
            },
            metadata=client._rpc_metadata,
        )
示例#10
0
    def _get_helper(
        self,
        field_paths=None,
        use_transaction=False,
        not_found=False,
        # This should be an impossible case, but we test against it for
        # completeness
        return_empty=False,
        retry=None,
        timeout=None,
    ):
        from google.cloud.firestore_v1 import _helpers
        from google.cloud.firestore_v1.types import common
        from google.cloud.firestore_v1.types import document
        from google.cloud.firestore_v1.types import firestore
        from google.cloud.firestore_v1.transaction import Transaction

        # Create a minimal fake GAPIC with a dummy response.
        create_time = 123
        update_time = 234
        read_time = 345
        firestore_api = mock.Mock(spec=["batch_get_documents"])
        response = mock.create_autospec(firestore.BatchGetDocumentsResponse)
        response.read_time = read_time
        response.found = mock.create_autospec(document.Document)
        response.found.fields = {}
        response.found.create_time = create_time
        response.found.update_time = update_time

        client = _make_client("donut-base")
        client._firestore_api_internal = firestore_api
        document_reference = self._make_one("where", "we-are", client=client)

        response.found.name = None if not_found else document_reference._document_path
        response.missing = document_reference._document_path if not_found else None

        def WhichOneof(val):
            return "missing" if not_found else "found"

        response._pb = response
        response._pb.WhichOneof = WhichOneof
        firestore_api.batch_get_documents.return_value = iter(
            [response] if not return_empty else [])

        if use_transaction:
            transaction = Transaction(client)
            transaction_id = transaction._id = b"asking-me-2"
        else:
            transaction = None

        kwargs = _helpers.make_retry_timeout_kwargs(retry, timeout)

        snapshot = document_reference.get(field_paths=field_paths,
                                          transaction=transaction,
                                          **kwargs)

        self.assertIs(snapshot.reference, document_reference)
        if not_found or return_empty:
            self.assertIsNone(snapshot._data)
            self.assertFalse(snapshot.exists)
            self.assertIsNotNone(snapshot.read_time)
            self.assertIsNone(snapshot.create_time)
            self.assertIsNone(snapshot.update_time)
        else:
            self.assertEqual(snapshot.to_dict(), {})
            self.assertTrue(snapshot.exists)
            self.assertIs(snapshot.read_time, read_time)
            self.assertIs(snapshot.create_time, create_time)
            self.assertIs(snapshot.update_time, update_time)

        # Verify the request made to the API
        if field_paths is not None:
            mask = common.DocumentMask(field_paths=sorted(field_paths))
        else:
            mask = None

        if use_transaction:
            expected_transaction_id = transaction_id
        else:
            expected_transaction_id = None

        firestore_api.batch_get_documents.assert_called_once_with(
            request={
                "database": client._database_string,
                "documents": [document_reference._document_path],
                "mask": mask,
                "transaction": expected_transaction_id,
            },
            metadata=client._rpc_metadata,
            **kwargs,
        )
示例#11
0
    async def _get_all_helper(
        self, num_snapshots=2, txn_id=None, retry=None, timeout=None
    ):
        from google.cloud.firestore_v1 import _helpers
        from google.cloud.firestore_v1.types import common
        from google.cloud.firestore_v1.async_document import DocumentSnapshot

        client = self._make_default_one()

        data1 = {"a": "cheese"}
        document1 = client.document("pineapple", "lamp1")
        document_pb1, read_time = _doc_get_info(document1._document_path, data1)
        response1 = _make_batch_response(found=document_pb1, read_time=read_time)

        data2 = {"b": True, "c": 18}
        document2 = client.document("pineapple", "lamp2")
        document, read_time = _doc_get_info(document2._document_path, data2)
        response2 = _make_batch_response(found=document, read_time=read_time)

        document3 = client.document("pineapple", "lamp3")
        response3 = _make_batch_response(missing=document3._document_path)

        expected_data = [data1, data2, None][:num_snapshots]
        documents = [document1, document2, document3][:num_snapshots]
        responses = [response1, response2, response3][:num_snapshots]
        field_paths = [
            field_path for field_path in ["a", "b", None][:num_snapshots] if field_path
        ]
        kwargs = _helpers.make_retry_timeout_kwargs(retry, timeout)

        if txn_id is not None:
            transaction = client.transaction()
            transaction._id = txn_id
            kwargs["transaction"] = transaction

        snapshots = await self._invoke_get_all(
            client, documents, responses, field_paths=field_paths, **kwargs,
        )

        self.assertEqual(len(snapshots), num_snapshots)

        for data, document, snapshot in zip(expected_data, documents, snapshots):
            self.assertIsInstance(snapshot, DocumentSnapshot)
            self.assertIs(snapshot._reference, document)
            if data is None:
                self.assertFalse(snapshot.exists)
            else:
                self.assertEqual(snapshot._data, data)

        # Verify the call to the mock.
        doc_paths = [document._document_path for document in documents]
        mask = common.DocumentMask(field_paths=field_paths)

        kwargs.pop("transaction", None)

        client._firestore_api.batch_get_documents.assert_called_once_with(
            request={
                "database": client._database_string,
                "documents": doc_paths,
                "mask": mask,
                "transaction": txn_id,
            },
            metadata=client._rpc_metadata,
            **kwargs,
        )
示例#12
0
    def get(self, field_paths=None, transaction=None) -> DocumentSnapshot:
        """Retrieve a snapshot of the current document.

        See :meth:`~google.cloud.firestore_v1.base_client.BaseClient.field_path` for
        more information on **field paths**.

        If a ``transaction`` is used and it already has write operations
        added, this method cannot be used (i.e. read-after-write is not
        allowed).

        Args:
            field_paths (Optional[Iterable[str, ...]]): An iterable of field
                paths (``.``-delimited list of field names) to use as a
                projection of document fields in the returned results. If
                no value is provided, all fields will be returned.
            transaction (Optional[:class:`~google.cloud.firestore_v1.transaction.Transaction`]):
                An existing transaction that this reference
                will be retrieved in.

        Returns:
            :class:`~google.cloud.firestore_v1.base_document.DocumentSnapshot`:
                A snapshot of the current document. If the document does not
                exist at the time of the snapshot is taken, the snapshot's
                :attr:`reference`, :attr:`data`, :attr:`update_time`, and
                :attr:`create_time` attributes will all be ``None`` and
                its :attr:`exists` attribute will be ``False``.
        """
        if isinstance(field_paths, str):
            raise ValueError("'field_paths' must be a sequence of paths, not a string.")

        if field_paths is not None:
            mask = common.DocumentMask(field_paths=sorted(field_paths))
        else:
            mask = None

        firestore_api = self._client._firestore_api
        try:
            document_pb = firestore_api.get_document(
                request={
                    "name": self._document_path,
                    "mask": mask,
                    "transaction": _helpers.get_transaction_id(transaction),
                },
                metadata=self._client._rpc_metadata,
            )
        except exceptions.NotFound:
            data = None
            exists = False
            create_time = None
            update_time = None
        else:
            data = _helpers.decode_dict(document_pb.fields, self._client)
            exists = True
            create_time = document_pb.create_time
            update_time = document_pb.update_time

        return DocumentSnapshot(
            reference=self,
            data=data,
            exists=exists,
            read_time=None,  # No server read_time available
            create_time=create_time,
            update_time=update_time,
        )
    async def _get_helper(
        self,
        field_paths=None,
        use_transaction=False,
        not_found=False,
        retry=None,
        timeout=None,
    ):
        from google.api_core.exceptions import NotFound
        from google.cloud.firestore_v1 import _helpers
        from google.cloud.firestore_v1.types import common
        from google.cloud.firestore_v1.types import document
        from google.cloud.firestore_v1.transaction import Transaction

        # Create a minimal fake GAPIC with a dummy response.
        create_time = 123
        update_time = 234
        firestore_api = AsyncMock(spec=["get_document"])
        response = mock.create_autospec(document.Document)
        response.fields = {}
        response.create_time = create_time
        response.update_time = update_time

        if not_found:
            firestore_api.get_document.side_effect = NotFound("testing")
        else:
            firestore_api.get_document.return_value = response

        client = _make_client("donut-base")
        client._firestore_api_internal = firestore_api

        document = self._make_one("where", "we-are", client=client)

        if use_transaction:
            transaction = Transaction(client)
            transaction_id = transaction._id = b"asking-me-2"
        else:
            transaction = None

        kwargs = _helpers.make_retry_timeout_kwargs(retry, timeout)

        snapshot = await document.get(
            field_paths=field_paths,
            transaction=transaction,
            **kwargs,
        )

        self.assertIs(snapshot.reference, document)
        if not_found:
            self.assertIsNone(snapshot._data)
            self.assertFalse(snapshot.exists)
            self.assertIsNone(snapshot.read_time)
            self.assertIsNone(snapshot.create_time)
            self.assertIsNone(snapshot.update_time)
        else:
            self.assertEqual(snapshot.to_dict(), {})
            self.assertTrue(snapshot.exists)
            self.assertIsNone(snapshot.read_time)
            self.assertIs(snapshot.create_time, create_time)
            self.assertIs(snapshot.update_time, update_time)

        # Verify the request made to the API
        if field_paths is not None:
            mask = common.DocumentMask(field_paths=sorted(field_paths))
        else:
            mask = None

        if use_transaction:
            expected_transaction_id = transaction_id
        else:
            expected_transaction_id = None

        firestore_api.get_document.assert_called_once_with(
            request={
                "name": document._document_path,
                "mask": mask,
                "transaction": expected_transaction_id,
            },
            metadata=client._rpc_metadata,
            **kwargs,
        )