_GRPC_ERROR_MAPPING: dict
BAD_PATH_TEMPLATE = "A path element must be a string. Received {}, which is a {}."
DOCUMENT_PATH_DELIMITER = "/"
INACTIVE_TXN = "Transaction not in progress, cannot be used in API requests."
READ_AFTER_WRITE_ERROR = "Attempted read after write in a transaction."
BAD_REFERENCE_ERROR = (
    "Reference value {!r} in unexpected format, expected to be of the form "
    "``projects/{{project}}/databases/{{database}}/"
    "documents/{{document_path}}``."
)
WRONG_APP_REFERENCE = (
    "Document {!r} does not correspond to the same database " "({!r}) as the client."
)
REQUEST_TIME_ENUM = DocumentTransform.FieldTransform.ServerValue.REQUEST_TIME
_GRPC_ERROR_MAPPING = {
    grpc.StatusCode.ALREADY_EXISTS: exceptions.Conflict,
    grpc.StatusCode.NOT_FOUND: exceptions.NotFound,
}
class GeoPoint(object):
class DocumentReferenceValue:
class DocumentExtractor(object):
class DocumentExtractorForMerge(DocumentExtractor):
class DocumentExtractorForUpdate(DocumentExtractor):
class ReadAfterWriteError(Exception):
class WriteOption(object):
class LastUpdateOption(WriteOption):
class ExistsOption(WriteOption):
    def __init__(self, latitude, longitude) -> None:
    def to_protobuf(self) -> latlng_pb2.LatLng:
    def __eq__(self, other):
    def __ne__(self, other):
def verify_path(path, is_collection) -> None:
def encode_value(value) -> types.document.Value:
def encode_dict(values_dict) -> dict:
def document_snapshot_to_protobuf(snapshot: "google.cloud.firestore_v1.base_document.DocumentSnapshot") -> Optional["google.cloud.firestore_v1.types.Document"]:  # type: ignore
    def __init__(self, reference_value: str):
    def full_key(self) -> str:
    def full_path(self) -> str:
def reference_value_to_document(reference_value, client) -> Any:
def decode_value(
    value, client
) -> Union[None, bool, int, float, list, datetime.datetime, str, bytes, dict, GeoPoint]:
def decode_dict(value_fields, client) -> dict:
def get_doc_id(document_pb, expected_prefix) -> str:
def extract_fields(
    document_data, prefix_path: FieldPath, expand_dots=False
) -> Generator[Tuple[Any, Any], Any, None]:
def set_field_value(document_data, field_path, value) -> None:
def get_field_value(document_data, field_path) -> Any:
    def __init__(self, document_data) -> None:
    def _get_document_iterator(
        self, prefix_path: FieldPath
    ) -> Generator[Tuple[Any, Any], Any, None]:
    def has_transforms(self):
    def transform_paths(self):
    def _get_update_mask(self, allow_empty_mask=False) -> None:
    def get_update_pb(
        self, document_path, exists=None, allow_empty_mask=False
    ) -> types.write.Write:
    def get_field_transform_pbs(
        self, document_path
    ) -> List[types.write.DocumentTransform.FieldTransform]:
        def make_array_value(values):
    def get_transform_pb(self, document_path, exists=None) -> types.write.Write:
def pbs_for_create(document_path, document_data) -> List[types.write.Write]:
def pbs_for_set_no_merge(document_path, document_data) -> List[types.write.Write]:
    def __init__(self, document_data) -> None:
    def _apply_merge_all(self) -> None:
    def _construct_merge_paths(self, merge) -> Generator[Any, Any, None]:
    def _normalize_merge_paths(self, merge) -> list:
    def _apply_merge_paths(self, merge) -> None:
    def apply_merge(self, merge) -> None:
    def _get_update_mask(
        self, allow_empty_mask=False
    ) -> Optional[types.common.DocumentMask]:
def pbs_for_set_with_merge(
    document_path, document_data, merge
) -> List[types.write.Write]:
    def __init__(self, document_data) -> None:
    def _get_document_iterator(
        self, prefix_path: FieldPath
    ) -> Generator[Tuple[Any, Any], Any, None]:
    def _get_update_mask(self, allow_empty_mask=False) -> types.common.DocumentMask:
def pbs_for_update(document_path, field_updates, option) -> List[types.write.Write]:
def pb_for_delete(document_path, option) -> types.write.Write:
def get_transaction_id(transaction, read_operation=True) -> Union[bytes, None]:
def metadata_with_prefix(prefix: str, **kw) -> List[Tuple[str, str]]:
    def modify_write(self, write, no_create_msg=None) -> NoReturn:
    def __init__(self, last_update_time) -> None:
    def __eq__(self, other):
    def modify_write(self, write, **unused_kwargs) -> None:
    def __init__(self, exists) -> None:
    def __eq__(self, other):
    def modify_write(self, write, **unused_kwargs) -> None:
def make_retry_timeout_kwargs(retry, timeout) -> dict:
def build_timestamp(
    dt: Optional[Union[DatetimeWithNanoseconds, datetime.datetime]] = None
) -> Timestamp:
def compare_timestamps(
    ts1: Union[Timestamp, datetime.datetime], ts2: Union[Timestamp, datetime.datetime],
) -> int:
def deserialize_bundle(
    serialized: Union[str, bytes],
    client: "google.cloud.firestore_v1.client.BaseClient",  # type: ignore
) -> "google.cloud.firestore_bundle.FirestoreBundle":  # type: ignore
def _parse_bundle_elements_data(serialized: Union[str, bytes]) -> Generator[Dict, None, None]:  # type: ignore
def _get_documents_from_bundle(
    bundle, *, query_name: Optional[str] = None
) -> Generator["google.cloud.firestore.DocumentSnapshot", None, None]:  # type: ignore
def _get_document_from_bundle(
    bundle, *, document_id: str,
) -> Optional["google.cloud.firestore.DocumentSnapshot"]:  # type: ignore class DocumentReference(BaseDocumentReference):
    def __init__(self, *path, **kwargs) -> None:
    def create(
        self,
        document_data: dict,
        retry: retries.Retry = gapic_v1.method.DEFAULT,
        timeout: float = None,
    ) -> write.WriteResult:
    def set(
        self,
        document_data: dict,
        merge: bool = False,
        retry: retries.Retry = gapic_v1.method.DEFAULT,
        timeout: float = None,
    ) -> write.WriteResult:
    def update(
        self,
        field_updates: dict,
        option: _helpers.WriteOption = None,
        retry: retries.Retry = gapic_v1.method.DEFAULT,
        timeout: float = None,
    ) -> write.WriteResult:
    def delete(
        self,
        option: _helpers.WriteOption = None,
        retry: retries.Retry = gapic_v1.method.DEFAULT,
        timeout: float = None,
    ) -> Timestamp:
    def get(
        self,
        field_paths: Iterable[str] = None,
        transaction=None,
        retry: retries.Retry = gapic_v1.method.DEFAULT,
        timeout: float = None,
    ) -> DocumentSnapshot:
    def collections(
        self,
        page_size: int = None,
        retry: retries.Retry = gapic_v1.method.DEFAULT,
        timeout: float = None,
    ) -> Generator[Any, Any, None]:
    def on_snapshot(self, callback: Callable) -> Watch: _FIELD_PATH_MISSING_TOP = "{!r} is not contained in the data"
_FIELD_PATH_MISSING_KEY = "{!r} is not contained in the data for the key {!r}"
_FIELD_PATH_WRONG_TYPE = (
    "The data at {!r} is not a dictionary, so it cannot contain the key {!r}"
)
_FIELD_PATH_DELIMITER = "."
_BACKSLASH = "\\"
_ESCAPED_BACKSLASH = _BACKSLASH * 2
_BACKTICK = "`"
_ESCAPED_BACKTICK = _BACKSLASH + _BACKTICK
_SIMPLE_FIELD_NAME = re.compile("^[_a-zA-Z][_a-zA-Z0-9]*$")
_LEADING_ALPHA_INVALID = re.compile("^[_a-zA-Z][_a-zA-Z0-9]*[^_a-zA-Z0-9]")
PATH_ELEMENT_TOKENS = [
    ("SIMPLE", r"[_a-zA-Z][_a-zA-Z0-9]*"),  # unquoted elements
    ("QUOTED", r"`(?:\\`|[^`])*?`"),  # quoted elements, unquoted
    ("DOT", r"\."),  # separator
]
TOKENS_PATTERN = "|".join("(?P<{}>{})".format(*pair) for pair in PATH_ELEMENT_TOKENS)
TOKENS_REGEX = re.compile(TOKENS_PATTERN)
def _tokenize_field_path(path: str):
def split_field_path(path: str):
def parse_field_path(api_repr: str):
def render_field_path(field_names: Iterable[str]):
def get_nested_value(field_path: str, data: dict):
    def __init__(self, *parts):
    def from_api_repr(cls, api_repr: str):
    def from_string(cls, path_string: str):
    def __repr__(self):
    def __hash__(self):
    def __eq__(self, other):
    def __lt__(self, other):
    def __add__(self, other):
    def to_api_repr(self):
    def eq_or_parent(self, other):
    def lineage(self):
    def document_id():
class FieldPath(object): class Sentinel(object):
class _ValueList(object):
class ArrayUnion(_ValueList):
class ArrayRemove(_ValueList):
class _NumericValue(object):
class Increment(_NumericValue):
class Maximum(_NumericValue):
class Minimum(_NumericValue):
    def __init__(self, description) -> None:
    def __repr__(self):
    def __init__(self, values) -> None:
    def __eq__(self, other):
    def values(self):
    def __init__(self, value) -> None:
    def value(self):
    def __eq__(self, other):
DELETE_FIELD = Sentinel("Value used to delete a field in a document.")
SERVER_TIMESTAMP = Sentinel(
    "Value used to set a document field to the server timestamp."
) class StructuredQuery(proto.Message):
    r"""A Firestore query.

    Attributes:
        select (google.cloud.firestore_v1.types.StructuredQuery.Projection):
            The projection to return.
        from_ (Sequence[google.cloud.firestore_v1.types.StructuredQuery.CollectionSelector]):
            The collections to query.
        where (google.cloud.firestore_v1.types.StructuredQuery.Filter):
            The filter to apply.
        order_by (Sequence[google.cloud.firestore_v1.types.StructuredQuery.Order]):
            The order to apply to the query results.

            Firestore guarantees a stable ordering through the following
            rules:

            -  Any field required to appear in ``order_by``, that is not
               already specified in ``order_by``, is appended to the
               order in field name order by default.
            -  If an order on ``__name__`` is not specified, it is
               appended by default.

            Fields are appended with the same sort direction as the last
            order specified, or 'ASCENDING' if no order was specified.
            For example:

            -  ``SELECT * FROM Foo ORDER BY A`` becomes
               ``SELECT * FROM Foo ORDER BY A, __name__``
            -  ``SELECT * FROM Foo ORDER BY A DESC`` becomes
               ``SELECT * FROM Foo ORDER BY A DESC, __name__ DESC``
            -  ``SELECT * FROM Foo WHERE A > 1`` becomes
               ``SELECT * FROM Foo WHERE A > 1 ORDER BY A, __name__``
        start_at (google.cloud.firestore_v1.types.Cursor):
            A starting point for the query results.
        end_at (google.cloud.firestore_v1.types.Cursor):
            A end point for the query results.
        offset (int):
            The number of results to skip.
            Applies before limit, but after all other
            constraints. Must be >= 0 if specified.
        limit (google.protobuf.wrappers_pb2.Int32Value):
            The maximum number of results to return.
            Applies after all other constraints.
            Must be >= 0 if specified.
    """

    class Direction(proto.Enum):
        r"""A sort direction."""
        DIRECTION_UNSPECIFIED = 0
        ASCENDING = 1
        DESCENDING = 2

    class CollectionSelector(proto.Message):
        r"""A selection of a collection, such as ``messages as m1``.

        Attributes:
            collection_id (str):
                The collection ID.
                When set, selects only collections with this ID.
            all_descendants (bool):
                When false, selects only collections that are immediate
                children of the ``parent`` specified in the containing
                ``RunQueryRequest``. When true, selects all descendant
                collections.
        """

        collection_id = proto.Field(proto.STRING, number=2,)
        all_descendants = proto.Field(proto.BOOL, number=3,)

    class Filter(proto.Message):
        r"""A filter.

        This message has `oneof`_ fields (mutually exclusive fields).
        For each oneof, at most one member field can be set at the same time.
        Setting any member of the oneof automatically clears all other
        members.

        .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields

        Attributes:
            composite_filter (google.cloud.firestore_v1.types.StructuredQuery.CompositeFilter):
                A composite filter.

                This field is a member of `oneof`_ ``filter_type``.
            field_filter (google.cloud.firestore_v1.types.StructuredQuery.FieldFilter):
                A filter on a document field.

                This field is a member of `oneof`_ ``filter_type``.
            unary_filter (google.cloud.firestore_v1.types.StructuredQuery.UnaryFilter):
                A filter that takes exactly one argument.

                This field is a member of `oneof`_ ``filter_type``.
        """

        composite_filter = proto.Field(
            proto.MESSAGE,
            number=1,
            oneof="filter_type",
            message="StructuredQuery.CompositeFilter",
        )
        field_filter = proto.Field(
            proto.MESSAGE,
            number=2,
            oneof="filter_type",
            message="StructuredQuery.FieldFilter",
        )
        unary_filter = proto.Field(
            proto.MESSAGE,
            number=3,
            oneof="filter_type",
            message="StructuredQuery.UnaryFilter",
        )

    class CompositeFilter(proto.Message):
        r"""A filter that merges multiple other filters using the given
        operator.

        Attributes:
            op (google.cloud.firestore_v1.types.StructuredQuery.CompositeFilter.Operator):
                The operator for combining multiple filters.
            filters (Sequence[google.cloud.firestore_v1.types.StructuredQuery.Filter]):
                The list of filters to combine.
                Must contain at least one filter.
        """

        class Operator(proto.Enum):
            r"""A composite filter operator."""
            OPERATOR_UNSPECIFIED = 0
            AND = 1

        op = proto.Field(
            proto.ENUM, number=1, enum="StructuredQuery.CompositeFilter.Operator",
        )
        filters = proto.RepeatedField(
            proto.MESSAGE, number=2, message="StructuredQuery.Filter",
        )

    class FieldFilter(proto.Message):
        r"""A filter on a specific field.

        Attributes:
            field (google.cloud.firestore_v1.types.StructuredQuery.FieldReference):
                The field to filter by.
            op (google.cloud.firestore_v1.types.StructuredQuery.FieldFilter.Operator):
                The operator to filter by.
            value (google.cloud.firestore_v1.types.Value):
                The value to compare to.
        """

        class Operator(proto.Enum):
            r"""A field filter operator."""
            OPERATOR_UNSPECIFIED = 0
            LESS_THAN = 1
            LESS_THAN_OR_EQUAL = 2
            GREATER_THAN = 3
            GREATER_THAN_OR_EQUAL = 4
            EQUAL = 5
            NOT_EQUAL = 6
            ARRAY_CONTAINS = 7
            IN = 8
            ARRAY_CONTAINS_ANY = 9
            NOT_IN = 10

        field = proto.Field(
            proto.MESSAGE, number=1, message="StructuredQuery.FieldReference",
        )
        op = proto.Field(
            proto.ENUM, number=2, enum="StructuredQuery.FieldFilter.Operator",
        )
        value = proto.Field(proto.MESSAGE, number=3, message=document.Value,)

    class UnaryFilter(proto.Message):
        r"""A filter with a single operand.

        .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields

        Attributes:
            op (google.cloud.firestore_v1.types.StructuredQuery.UnaryFilter.Operator):
                The unary operator to apply.
            field (google.cloud.firestore_v1.types.StructuredQuery.FieldReference):
                The field to which to apply the operator.

                This field is a member of `oneof`_ ``operand_type``.
        """

        class Operator(proto.Enum):
            r"""A unary operator."""
            OPERATOR_UNSPECIFIED = 0
            IS_NAN = 2
            IS_NULL = 3
            IS_NOT_NAN = 4
            IS_NOT_NULL = 5

        op = proto.Field(
            proto.ENUM, number=1, enum="StructuredQuery.UnaryFilter.Operator",
        )
        field = proto.Field(
            proto.MESSAGE,
            number=2,
            oneof="operand_type",
            message="StructuredQuery.FieldReference",
        )

    class Order(proto.Message):
        r"""An order on a field.

        Attributes:
            field (google.cloud.firestore_v1.types.StructuredQuery.FieldReference):
                The field to order by.
            direction (google.cloud.firestore_v1.types.StructuredQuery.Direction):
                The direction to order by. Defaults to ``ASCENDING``.
        """

        field = proto.Field(
            proto.MESSAGE, number=1, message="StructuredQuery.FieldReference",
        )
        direction = proto.Field(proto.ENUM, number=2, enum="StructuredQuery.Direction",)

    class FieldReference(proto.Message):
        r"""A reference to a field, such as ``max(messages.time) as max_time``.

        Attributes:
            field_path (str):

        """

        field_path = proto.Field(proto.STRING, number=2,)

    class Projection(proto.Message):
        r"""The projection of document's fields to return.

        Attributes:
            fields (Sequence[google.cloud.firestore_v1.types.StructuredQuery.FieldReference]):
                The fields to return.

                If empty, all fields are returned. To only return the name
                of the document, use ``['__name__']``.
        """

        fields = proto.RepeatedField(
            proto.MESSAGE, number=2, message="StructuredQuery.FieldReference",
        )

    select = proto.Field(proto.MESSAGE, number=1, message=Projection,)
    from_ = proto.RepeatedField(proto.MESSAGE, number=2, message=CollectionSelector,)
    where = proto.Field(proto.MESSAGE, number=3, message=Filter,)
    order_by = proto.RepeatedField(proto.MESSAGE, number=4, message=Order,)
    start_at = proto.Field(proto.MESSAGE, number=7, message="Cursor",)
    end_at = proto.Field(proto.MESSAGE, number=8, message="Cursor",)
    offset = proto.Field(proto.INT32, number=6,)
    limit = proto.Field(proto.MESSAGE, number=5, message=wrappers_pb2.Int32Value,) class StructuredQuery(proto.Message):
    class Direction(proto.Enum):
    class CollectionSelector(proto.Message):
    class Filter(proto.Message):
    class CompositeFilter(proto.Message):
        class Operator(proto.Enum):
    class FieldFilter(proto.Message):
        class Operator(proto.Enum):
    class UnaryFilter(proto.Message):
        class Operator(proto.Enum):
    class Order(proto.Message):
    class FieldReference(proto.Message):
    class Projection(proto.Message):
class Cursor(proto.Message):
        DIRECTION_UNSPECIFIED = 0
        ASCENDING = 1
        DESCENDING = 2
            OPERATOR_UNSPECIFIED = 0
            AND = 1
            OPERATOR_UNSPECIFIED = 0
            LESS_THAN = 1
            LESS_THAN_OR_EQUAL = 2
            GREATER_THAN = 3
            GREATER_THAN_OR_EQUAL = 4
            EQUAL = 5
            NOT_EQUAL = 6
            ARRAY_CONTAINS = 7
            IN = 8
            ARRAY_CONTAINS_ANY = 9
            NOT_IN = 10
            OPERATOR_UNSPECIFIED = 0
            IS_NAN = 2
            IS_NULL = 3
            IS_NOT_NAN = 4
            IS_NOT_NULL = 5 class Cursor(proto.Message):
    r"""A position in a query result set.

    Attributes:
        values (Sequence[google.cloud.firestore_v1.types.Value]):
            The values that represent a position, in the
            order they appear in the order by clause of a
            query.
            Can contain fewer values than specified in the
            order by clause.
        before (bool):
            If the position is just before or just after
            the given values, relative to the sort order
            defined by the query.
    """

    values = proto.RepeatedField(proto.MESSAGE, number=1, message=document.Value,)
    before = proto.Field(proto.BOOL, number=2,) class RunQueryResponse(proto.Message):
    r"""The response for
    [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery].

    Attributes:
        transaction (bytes):
            The transaction that was started as part of this request.
            Can only be set in the first response, and only if
            [RunQueryRequest.new_transaction][google.firestore.v1.RunQueryRequest.new_transaction]
            was set in the request. If set, no other fields will be set
            in this response.
        document (google.cloud.firestore_v1.types.Document):
            A query result, not set when reporting
            partial progress.
        read_time (google.protobuf.timestamp_pb2.Timestamp):
            The time at which the document was read. This may be
            monotonically increasing; in this case, the previous
            documents in the result stream are guaranteed not to have
            changed between their ``read_time`` and this one.

            If the query returns no results, a response with
            ``read_time`` and no ``document`` will be sent, and this
            represents the time at which the query was run.
        skipped_results (int):
            The number of results that have been skipped
            due to an offset between the last response and
            the current response.
    """

    transaction = proto.Field(proto.BYTES, number=2,)
    document = proto.Field(proto.MESSAGE, number=1, message=gf_document.Document,)
    read_time = proto.Field(proto.MESSAGE, number=3, message=timestamp_pb2.Timestamp,)
    skipped_results = proto.Field(proto.INT32, number=4,) class Order(object):
    """
    Order implements the ordering semantics of the backend.
    """

    @classmethod
    def compare(cls, left, right) -> int:
        """
        Main comparison function for all Firestore types.
        @return -1 is left < right, 0 if left == right, otherwise 1
        """
        # First compare the types.
        leftType = TypeOrder.from_value(left).value
        rightType = TypeOrder.from_value(right).value

        if leftType != rightType:
            if leftType < rightType:
                return -1
            return 1

        value_type = left._pb.WhichOneof("value_type")

        if value_type == "null_value":
            return 0  # nulls are all equal
        elif value_type == "boolean_value":
            return cls._compare_to(left.boolean_value, right.boolean_value)
        elif value_type == "integer_value":
            return cls.compare_numbers(left, right)
        elif value_type == "double_value":
            return cls.compare_numbers(left, right)
        elif value_type == "timestamp_value":
            return cls.compare_timestamps(left, right)
        elif value_type == "string_value":
            return cls._compare_to(left.string_value, right.string_value)
        elif value_type == "bytes_value":
            return cls.compare_blobs(left, right)
        elif value_type == "reference_value":
            return cls.compare_resource_paths(left, right)
        elif value_type == "geo_point_value":
            return cls.compare_geo_points(left, right)
        elif value_type == "array_value":
            return cls.compare_arrays(left, right)
        elif value_type == "map_value":
            return cls.compare_objects(left, right)
        else:
            raise ValueError(f"Unknown ``value_type`` {value_type}")

    @staticmethod
    def compare_blobs(left, right) -> int:
        left_bytes = left.bytes_value
        right_bytes = right.bytes_value

        return Order._compare_to(left_bytes, right_bytes)

    @staticmethod
    def compare_timestamps(left, right) -> Any:
        left = left._pb.timestamp_value
        right = right._pb.timestamp_value

        seconds = Order._compare_to(left.seconds or 0, right.seconds or 0)
        if seconds != 0:
            return seconds

        return Order._compare_to(left.nanos or 0, right.nanos or 0)

    @staticmethod
    def compare_geo_points(left, right) -> Any:
        left_value = decode_value(left, None)
        right_value = decode_value(right, None)
        cmp = (left_value.latitude > right_value.latitude) - (
            left_value.latitude < right_value.latitude
        )

        if cmp != 0:
            return cmp
        return (left_value.longitude > right_value.longitude) - (
            left_value.longitude < right_value.longitude
        )

    @staticmethod
    def compare_resource_paths(left, right) -> int:
        left = left.reference_value
        right = right.reference_value

        left_segments = left.split("/")
        right_segments = right.split("/")
        shorter = min(len(left_segments), len(right_segments))
        # compare segments
        for i in range(shorter):
            if left_segments[i] < right_segments[i]:
                return -1
            if left_segments[i] > right_segments[i]:
                return 1

        left_length = len(left)
        right_length = len(right)
        return (left_length > right_length) - (left_length < right_length)

    @staticmethod
    def compare_arrays(left, right) -> int:
        l_values = left.array_value.values
        r_values = right.array_value.values

        length = min(len(l_values), len(r_values))
        for i in range(length):
            cmp = Order.compare(l_values[i], r_values[i])
            if cmp != 0:
                return cmp

        return Order._compare_to(len(l_values), len(r_values))

    @staticmethod
    def compare_objects(left, right) -> int:
        left_fields = left.map_value.fields
        right_fields = right.map_value.fields

        for left_key, right_key in zip(sorted(left_fields), sorted(right_fields)):
            keyCompare = Order._compare_to(left_key, right_key)
            if keyCompare != 0:
                return keyCompare

            value_compare = Order.compare(
                left_fields[left_key], right_fields[right_key]
            )
            if value_compare != 0:
                return value_compare

        return Order._compare_to(len(left_fields), len(right_fields))

    @staticmethod
    def compare_numbers(left, right) -> int:
        left_value = decode_value(left, None)
        right_value = decode_value(right, None)
        return Order.compare_doubles(left_value, right_value)

    @staticmethod
    def compare_doubles(left, right) -> int:
        if math.isnan(left):
            if math.isnan(right):
                return 0
            return -1
        if math.isnan(right):
            return 1

        return Order._compare_to(left, right)

    @staticmethod
    def _compare_to(left, right) -> int:
        # We can't just use cmp(left, right) because cmp doesn't exist
        # in Python 3, so this is an equivalent suggested by
        # https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons
        return (left > right) - (left < right) class DocumentSnapshot(object):
    """A snapshot of document data in a Firestore database.

    This represents data retrieved at a specific time and may not contain
    all fields stored for the document (i.e. a hand-picked selection of
    fields may have been retrieved).

    Instances of this class are not intended to be constructed by hand,
    rather they'll be returned as responses to various methods, such as
    :meth:`~google.cloud.DocumentReference.get`.

    Args:
        reference (:class:`~google.cloud.firestore_v1.document.DocumentReference`):
            A document reference corresponding to the document that contains
            the data in this snapshot.
        data (Dict[str, Any]):
            The data retrieved in the snapshot.
        exists (bool):
            Indicates if the document existed at the time the snapshot was
            retrieved.
        read_time (:class:`proto.datetime_helpers.DatetimeWithNanoseconds`):
            The time that this snapshot was read from the server.
        create_time (:class:`proto.datetime_helpers.DatetimeWithNanoseconds`):
            The time that this document was created.
        update_time (:class:`proto.datetime_helpers.DatetimeWithNanoseconds`):
            The time that this document was last updated.
    """

    def __init__(
        self, reference, data, exists, read_time, create_time, update_time
    ) -> None:
        self._reference = reference
        # We want immutable data, so callers can't modify this value
        # out from under us.
        self._data = copy.deepcopy(data)
        self._exists = exists
        self.read_time = read_time
        self.create_time = create_time
        self.update_time = update_time

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self._reference == other._reference and self._data == other._data

    def __hash__(self):
        return hash(self._reference) + hash(self.update_time)

    @property
    def _client(self):
        """The client that owns the document reference for this snapshot.

        Returns:
            :class:`~google.cloud.firestore_v1.client.Client`:
            The client that owns this document.
        """
        return self._reference._client

    @property
    def exists(self):
        """Existence flag.

        Indicates if the document existed at the time this snapshot
        was retrieved.

        Returns:
            bool: The existence flag.
        """
        return self._exists

    @property
    def id(self):
        """The document identifier (within its collection).

        Returns:
            str: The last component of the path of the document.
        """
        return self._reference.id

    @property
    def reference(self):
        """Document reference corresponding to document that owns this data.

        Returns:
            :class:`~google.cloud.firestore_v1.document.DocumentReference`:
            A document reference corresponding to this document.
        """
        return self._reference

    def get(self, field_path: str) -> Any:
        """Get a value from the snapshot data.

        If the data is nested, for example:

        .. code-block:: python

           >>> snapshot.to_dict()
           {
               'top1': {
                   'middle2': {
                       'bottom3': 20,
                       'bottom4': 22,
                   },
                   'middle5': True,
               },
               'top6': b'\x00\x01 foo',
           }

        a **field path** can be used to access the nested data. For
        example:

        .. code-block:: python

           >>> snapshot.get('top1')
           {
               'middle2': {
                   'bottom3': 20,
                   'bottom4': 22,
               },
               'middle5': True,
           }
           >>> snapshot.get('top1.middle2')
           {
               'bottom3': 20,
               'bottom4': 22,
           }
           >>> snapshot.get('top1.middle2.bottom3')
           20

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

        A copy is returned since the data may contain mutable values,
        but the data stored in the snapshot must remain immutable.

        Args:
            field_path (str): A field path (``.``-delimited list of
                field names).

        Returns:
            Any or None:
                (A copy of) the value stored for the ``field_path`` or
                None if snapshot document does not exist.

        Raises:
            KeyError: If the ``field_path`` does not match nested data
                in the snapshot.
        """
        if not self._exists:
            return None
        nested_data = field_path_module.get_nested_value(field_path, self._data)
        return copy.deepcopy(nested_data)

    def to_dict(self) -> Union[Dict[str, Any], None]:
        """Retrieve the data contained in this snapshot.

        A copy is returned since the data may contain mutable values,
        but the data stored in the snapshot must remain immutable.

        Returns:
            Dict[str, Any] or None:
                The data in the snapshot.  Returns None if reference
                does not exist.
        """
        if not self._exists:
            return None
        return copy.deepcopy(self._data)

    def _to_protobuf(self) -> Optional[Document]:
        return _helpers.document_snapshot_to_protobuf(self)
import copy
import math
from google.api_core import retry as retries
from google.protobuf import wrappers_pb2
from google.cloud.firestore_v1 import _helpers
from google.cloud.firestore_v1 import document
from google.cloud.firestore_v1 import field_path as field_path_module
from google.cloud.firestore_v1 import transforms
from google.cloud.firestore_v1.types import StructuredQuery
from google.cloud.firestore_v1.types import query
from google.cloud.firestore_v1.types import Cursor
from google.cloud.firestore_v1.types import RunQueryResponse
from google.cloud.firestore_v1.order import Order
from typing import (
    Any,
    Dict,
    Generator,
    Iterable,
    NoReturn,
    Optional,
    Tuple,
    Type,
    Union,
)
from google.cloud.firestore_v1.base_document import DocumentSnapshot
        return 0


def _enum_from_op_string(op_string: str) -> int:
    """Convert a string representation of a binary operator to an enum.

    These enums come from the protobuf message definition
    ``StructuredQuery.FieldFilter.Operator``.

    Args:
        op_string (str): A comparison operation in the form of a string.
            Acceptable values are ``<``, ``<=``, ``==``, ``!=``, ``>=``
            and ``>``.

    Returns:
        int: The enum corresponding to ``op_string``.

    Raises:
        ValueError: If ``op_string`` is not a valid operator.
    """
    try:
        return _COMPARISON_OPERATORS[op_string]
    except KeyError:
        choices = ", ".join(sorted(_COMPARISON_OPERATORS.keys()))
        msg = _BAD_OP_STRING.format(op_string, choices)
        raise ValueError(msg)


def _isnan(value) -> bool:
    """Check if a value is NaN.

    This differs from ``math.isnan`` in that **any** input type is
    allowed.

    Args:
        value (Any): A value to check for NaN-ness.

    Returns:
        bool: Indicates if the value is the NaN float.
    """
    if isinstance(value, float):
        return math.isnan(value)
    else:
        return False


def _enum_from_direction(direction: str) -> int:
    """Convert a string representation of a direction to an enum.

    Args:
        direction (str): A direction to order by. Must be one of
            :attr:`~google.cloud.firestore.BaseQuery.ASCENDING` or
            :attr:`~google.cloud.firestore.BaseQuery.DESCENDING`.

    Returns:
        int: The enum corresponding to ``direction``.

    Raises:
        ValueError: If ``direction`` is not a valid direction.
    """
    if isinstance(direction, int):
        return direction

    if direction == BaseQuery.ASCENDING:
        return StructuredQuery.Direction.ASCENDING
    elif direction == BaseQuery.DESCENDING:
        return StructuredQuery.Direction.DESCENDING
    else:
        msg = _BAD_DIR_STRING.format(
            direction, BaseQuery.ASCENDING, BaseQuery.DESCENDING
        )
        raise ValueError(msg)


def _filter_pb(field_or_unary) -> StructuredQuery.Filter:
    """Convert a specific protobuf filter to the generic filter type.

    Args:
        field_or_unary (Union[google.cloud.proto.firestore.v1.\
            query.StructuredQuery.FieldFilter, google.cloud.proto.\
            firestore.v1.query.StructuredQuery.FieldFilter]): A
            field or unary filter to convert to a generic filter.

    Returns:
        google.cloud.firestore_v1.types.\
        StructuredQuery.Filter: A "generic" filter.

    Raises:
        ValueError: If ``field_or_unary`` is not a field or unary filter.
    """
    if isinstance(field_or_unary, query.StructuredQuery.FieldFilter):
        return query.StructuredQuery.Filter(field_filter=field_or_unary)
    elif isinstance(field_or_unary, query.StructuredQuery.UnaryFilter):
        return query.StructuredQuery.Filter(unary_filter=field_or_unary)
    else:
        raise ValueError("Unexpected filter type", type(field_or_unary), field_or_unary)


def _cursor_pb(cursor_pair: Tuple[list, bool]) -> Optional[Cursor]:
    """Convert a cursor pair to a protobuf.

    If ``cursor_pair`` is :data:`None`, just returns :data:`None`.

    Args:
        cursor_pair (Optional[Tuple[list, bool]]): Two-tuple of

            * a list of field values.
            * a ``before`` flag

    Returns:
        Optional[google.cloud.firestore_v1.types.Cursor]: A
        protobuf cursor corresponding to the values.
    """
    if cursor_pair is not None:
        data, before = cursor_pair
        value_pbs = [_helpers.encode_value(value) for value in data]
        return query.Cursor(values=value_pbs, before=before)


def _query_response_to_snapshot(

    response_pb: RunQueryResponse, collection, expected_prefix: str