Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firestore: add Watch Support #6191

Merged
merged 164 commits into from
Nov 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
164 commits
Select commit Hold shift + click to select a range
4c51dac
groundwork for firestore
crwilcox Jun 12, 2018
972b62f
Use chemelnucfin sample (pythonification of nodejs) as base
crwilcox Jun 18, 2018
a66ce73
syntactic and style fixes
crwilcox Jun 18, 2018
b06c55b
Merge branch 'master' of github.com:GoogleCloudPlatform/google-cloud-…
crwilcox Jun 27, 2018
1390eb8
hold work
crwilcox Jun 27, 2018
45f48d6
use helper for_document
crwilcox Jun 27, 2018
4758b6b
Staging changes to firestore for watch. still incomplete but returnin…
crwilcox Jul 3, 2018
ff7aad7
returning watch result now
crwilcox Jul 10, 2018
c597669
broken currently, but nearing handling of multiple documents in colle…
crwilcox Jul 10, 2018
048b5fa
small fixes. seems mostly working
crwilcox Jul 11, 2018
a2fdd18
fix variable name, remove things from doc map on remove
crwilcox Jul 11, 2018
421b841
merge crwilcox firestore-watch branch into a recent branch from master
mcdonc Aug 14, 2018
6a0294e
improve doc strings and comment out yet to be done methods
crwilcox Aug 14, 2018
fd889d5
remove fstrings for 2.7 compat
mcdonc Aug 14, 2018
83755b8
be more specific on snapshot type
crwilcox Aug 14, 2018
eb8a48c
Merge remote-tracking branch 'crwilcox/firestore-watch' into firestor…
mcdonc Aug 14, 2018
a327dfe
unit tests for watch module
mcdonc Aug 20, 2018
a26699d
these must be staticmethods; improve performance in _affects_target
mcdonc Aug 20, 2018
cf85c92
make system test for watch pass
mcdonc Aug 20, 2018
9b0a4c2
containment check instead of iteration
mcdonc Aug 20, 2018
5bd6374
fix filter update test
mcdonc Aug 20, 2018
481ae83
tests for various helper methods
mcdonc Aug 21, 2018
a5c78a2
Improve rpc_done and add early query support
crwilcox Aug 21, 2018
4ce2939
Merge branch 'firestore-watch' of github.com:mcdonc/google-cloud-pyth…
crwilcox Aug 21, 2018
4301130
add more tests
mcdonc Aug 21, 2018
e00884b
Merge remote-tracking branch 'crwilcox/firestore-watch' into firestor…
mcdonc Aug 21, 2018
623e635
add tests for close
mcdonc Aug 21, 2018
27de7be
not reraising in except broke tests
mcdonc Aug 21, 2018
c665d73
compute_snapshot_ordering test still fails but fails later than it us…
mcdonc Aug 21, 2018
86628fd
remove incorrect comment
mcdonc Aug 21, 2018
23eaad5
parent is a fq path
crwilcox Aug 21, 2018
065e988
Merge branch 'firestore-watch' of github.com:mcdonc/google-cloud-pyth…
crwilcox Aug 21, 2018
9db3d18
Merge remote-tracking branch 'crwilcox/firestore-watch' into firestor…
mcdonc Aug 21, 2018
0d9de3c
fix and add test for _reset_docs
mcdonc Aug 21, 2018
199aaf1
Merge branch 'firestore-watch' of github.com:mcdonc/google-cloud-pyth…
crwilcox Aug 21, 2018
2a0723a
undo mistaken push
mcdonc Aug 22, 2018
f2b7c13
Merge remote-tracking branch 'crwilcox/firestore-watch' into firestor…
mcdonc Aug 22, 2018
889f350
appease the linter
mcdonc Aug 22, 2018
698e512
idiom
mcdonc Aug 22, 2018
3a70102
enable collection watches
crwilcox Aug 22, 2018
ed329dd
Merge branch 'firestore-watch' of github.com:mcdonc/google-cloud-pyth…
crwilcox Aug 22, 2018
2301a0e
undo spurious changes
mcdonc Aug 22, 2018
cca772e
add unfinished test
mcdonc Aug 22, 2018
48fac6d
modify the way we compute document references to support query and co…
crwilcox Aug 23, 2018
66b6071
add system tests for each variety of watch
crwilcox Aug 24, 2018
67a609f
fix most unit tests, 3 still fail
mcdonc Aug 24, 2018
d598f32
merge and apply
crwilcox Aug 24, 2018
c6ae725
expected time of test was not the same as read time, so false failure
crwilcox Aug 24, 2018
87ccc87
tests passing
crwilcox Aug 24, 2018
725f4a4
make the datetime.datetime returned non-naive and assume it's in UTC
mcdonc Aug 25, 2018
ee12608
depends directly on pytz now
mcdonc Aug 25, 2018
6aac664
100pct statement coverage for watch and test_watch
mcdonc Aug 28, 2018
97368c9
just cutnpaste this i guess
mcdonc Aug 28, 2018
53d6745
coverage for collection and bidi modules
mcdonc Aug 28, 2018
1e73ab7
coverage for document and query methods added
mcdonc Aug 28, 2018
6ade323
100 percent branch coverage
mcdonc Aug 29, 2018
2ee71fe
appease linter
mcdonc Aug 29, 2018
92e98d7
should return object on snapshot watching. This is needed to unsubscribe
crwilcox Sep 19, 2018
cf52f51
Merge branch 'master' into firestore-watch
crwilcox Sep 19, 2018
213169e
Remove use of deprecated assert
crwilcox Sep 20, 2018
abd5c97
Fix bug in deletion of document from map (using wrong key)
crwilcox Sep 20, 2018
3ed821e
startings of ordering
crwilcox Sep 28, 2018
2f3cbc7
update tests
crwilcox Oct 5, 2018
9290511
complete implementation of order
crwilcox Oct 8, 2018
f5734e9
remove commented code areas in order
crwilcox Oct 8, 2018
78a62a6
refactor order
crwilcox Oct 8, 2018
925495c
refactor order compare_objects
crwilcox Oct 8, 2018
4316fd1
add system test for ordering (currently failing for non-ordering
crwilcox Oct 8, 2018
220ba99
add system test for query and verify order
crwilcox Oct 10, 2018
30972d9
Improve test for order
crwilcox Oct 10, 2018
d549145
Add comparator to kw creation of dummyquery, fix old test, move compa…
crwilcox Oct 10, 2018
1abc70d
flake8 fixes
crwilcox Oct 10, 2018
ab862d7
coverage + tests
crwilcox Oct 10, 2018
be3584f
Properly decode document snapshot data and fix tests
crwilcox Oct 11, 2018
abdfe40
coverage
crwilcox Oct 11, 2018
2af7db7
noxfile from master
crwilcox Oct 11, 2018
a11f8eb
Merge branch 'master' into firestore-watch
crwilcox Oct 11, 2018
4c52c55
Delete Untitled-1
crwilcox Oct 11, 2018
dd9a15f
Merge branch 'master' into firestore-watch
crwilcox Oct 16, 2018
17cd042
modify to use bidi in api-core. one test has started to fail
crwilcox Oct 16, 2018
f1d079d
get tests passing (intermittently) on 2.7,3.5,3.6
mcdonc Oct 18, 2018
e0cbda4
fix failing test_order tests when left and right were dictionaries of…
mcdonc Oct 19, 2018
fb8142c
groundwork for firestore
crwilcox Jun 12, 2018
a5dbe62
Use chemelnucfin sample (pythonification of nodejs) as base
crwilcox Jun 18, 2018
8a5bd5f
syntactic and style fixes
crwilcox Jun 18, 2018
e296b22
hold work
crwilcox Jun 27, 2018
9499c89
use helper for_document
crwilcox Jun 27, 2018
e9855fd
Staging changes to firestore for watch. still incomplete but returnin…
crwilcox Jul 3, 2018
82a4a06
returning watch result now
crwilcox Jul 10, 2018
a83ebde
broken currently, but nearing handling of multiple documents in colle…
crwilcox Jul 10, 2018
1d1be53
small fixes. seems mostly working
crwilcox Jul 11, 2018
80c6bea
fix variable name, remove things from doc map on remove
crwilcox Jul 11, 2018
799fac9
improve doc strings and comment out yet to be done methods
crwilcox Aug 14, 2018
77eea6a
remove fstrings for 2.7 compat
mcdonc Aug 14, 2018
0db6a9d
be more specific on snapshot type
crwilcox Aug 14, 2018
374775b
unit tests for watch module
mcdonc Aug 20, 2018
36e431b
these must be staticmethods; improve performance in _affects_target
mcdonc Aug 20, 2018
4f08ac3
make system test for watch pass
mcdonc Aug 20, 2018
d0bffa9
containment check instead of iteration
mcdonc Aug 20, 2018
3de5310
fix filter update test
mcdonc Aug 20, 2018
40e8b0b
tests for various helper methods
mcdonc Aug 21, 2018
1853297
Improve rpc_done and add early query support
crwilcox Aug 21, 2018
1e77943
add more tests
mcdonc Aug 21, 2018
2724132
add tests for close
mcdonc Aug 21, 2018
d7258c8
not reraising in except broke tests
mcdonc Aug 21, 2018
1396b74
compute_snapshot_ordering test still fails but fails later than it us…
mcdonc Aug 21, 2018
1465bc2
remove incorrect comment
mcdonc Aug 21, 2018
39b97db
parent is a fq path
crwilcox Aug 21, 2018
39e429f
fix and add test for _reset_docs
mcdonc Aug 21, 2018
397c6d6
undo mistaken push
mcdonc Aug 22, 2018
95a485a
appease the linter
mcdonc Aug 22, 2018
3424284
idiom
mcdonc Aug 22, 2018
429f86e
enable collection watches
crwilcox Aug 22, 2018
00de5d3
undo spurious changes
mcdonc Aug 22, 2018
4b96582
add unfinished test
mcdonc Aug 22, 2018
bcecb25
modify the way we compute document references to support query and co…
crwilcox Aug 23, 2018
05db07c
add system tests for each variety of watch
crwilcox Aug 24, 2018
dfaacc7
fix most unit tests, 3 still fail
mcdonc Aug 24, 2018
b59b12b
merge and apply
crwilcox Aug 24, 2018
2a19765
expected time of test was not the same as read time, so false failure
crwilcox Aug 24, 2018
299fd94
tests passing
crwilcox Aug 24, 2018
9081664
make the datetime.datetime returned non-naive and assume it's in UTC
mcdonc Aug 25, 2018
9489ec1
depends directly on pytz now
mcdonc Aug 25, 2018
be51be8
100pct statement coverage for watch and test_watch
mcdonc Aug 28, 2018
854d051
just cutnpaste this i guess
mcdonc Aug 28, 2018
1059f2c
coverage for collection and bidi modules
mcdonc Aug 28, 2018
346e5d6
coverage for document and query methods added
mcdonc Aug 28, 2018
6cb3e85
100 percent branch coverage
mcdonc Aug 29, 2018
7c73721
appease linter
mcdonc Aug 29, 2018
7019fd5
should return object on snapshot watching. This is needed to unsubscribe
crwilcox Sep 19, 2018
6f36b6f
Fix bug in deletion of document from map (using wrong key)
crwilcox Sep 20, 2018
23d467d
startings of ordering
crwilcox Sep 28, 2018
c8e293a
update tests
crwilcox Oct 5, 2018
6cd0ac6
complete implementation of order
crwilcox Oct 8, 2018
41ef649
remove commented code areas in order
crwilcox Oct 8, 2018
6be3422
refactor order
crwilcox Oct 8, 2018
b1c42e9
refactor order compare_objects
crwilcox Oct 8, 2018
59f725b
add system test for ordering (currently failing for non-ordering
crwilcox Oct 8, 2018
6888e8a
add system test for query and verify order
crwilcox Oct 10, 2018
f77616c
Improve test for order
crwilcox Oct 10, 2018
cc445f1
Add comparator to kw creation of dummyquery, fix old test, move compa…
crwilcox Oct 10, 2018
85c199b
flake8 fixes
crwilcox Oct 10, 2018
f75a49c
coverage + tests
crwilcox Oct 10, 2018
0125c87
Properly decode document snapshot data and fix tests
crwilcox Oct 11, 2018
cdc6594
coverage
crwilcox Oct 11, 2018
36e8772
noxfile from master
crwilcox Oct 11, 2018
738d938
Delete Untitled-1
crwilcox Oct 11, 2018
9c2ff84
modify to use bidi in api-core. one test has started to fail
crwilcox Oct 16, 2018
3f8e0c8
get tests passing (intermittently) on 2.7,3.5,3.6
mcdonc Oct 18, 2018
4a892a7
fix failing test_order tests when left and right were dictionaries of…
mcdonc Oct 19, 2018
cb74bf7
fix transports layer use in watch
crwilcox Oct 19, 2018
d42f8c5
try adding wait before doc setting. System tests failing on CI but no…
crwilcox Oct 19, 2018
138a6f1
merge from crwilcox/firestore-watch and fix conflicts
mcdonc Oct 20, 2018
3add82d
linting
mcdonc Oct 20, 2018
b484098
make a bit more idiomatic
mcdonc Oct 20, 2018
e14421b
more idiomatic, and remove special casing of -0.0 and 0.0 in compare_…
mcdonc Oct 20, 2018
e089dac
lint fixes
crwilcox Oct 22, 2018
6e588f3
Merge branch 'firestore-watch' of github.com:mcdonc/google-cloud-pyth…
crwilcox Oct 22, 2018
136a881
Start using self.close where previously using self._consumer.stop
crwilcox Oct 26, 2018
195814b
lint
crwilcox Oct 26, 2018
34b4da3
clean up comments
crwilcox Nov 7, 2018
5622f3c
alias unsubscribe to close
crwilcox Nov 7, 2018
67c9a47
move rpc to internal attr
crwilcox Nov 7, 2018
8900be2
Merge branch 'master' into firestore-watch
crwilcox Nov 9, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api_core/google/api_core/bidi.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ def on_response(response):
print(response)

consumer = BackgroundConsumer(rpc, on_response)
consume.start()
consumer.start()

Note that error handling *must* be done by using the provided
``bidi_rpc``'s ``add_done_callback``. This helper will automatically exit
Expand Down
2 changes: 2 additions & 0 deletions firestore/google/cloud/firestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from google.cloud.firestore_v1beta1 import Transaction
from google.cloud.firestore_v1beta1 import transactional
from google.cloud.firestore_v1beta1 import types
from google.cloud.firestore_v1beta1 import Watch
from google.cloud.firestore_v1beta1 import WriteBatch
from google.cloud.firestore_v1beta1 import WriteOption

Expand All @@ -52,6 +53,7 @@
'Transaction',
'transactional',
'types',
'Watch',
'WriteBatch',
'WriteOption',
]
2 changes: 2 additions & 0 deletions firestore/google/cloud/firestore_v1beta1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from google.cloud.firestore_v1beta1.query import Query
from google.cloud.firestore_v1beta1.transaction import Transaction
from google.cloud.firestore_v1beta1.transaction import transactional
from google.cloud.firestore_v1beta1.watch import Watch


__all__ = [
Expand All @@ -53,6 +54,7 @@
'Transaction',
'transactional',
'types',
'Watch',
'WriteBatch',
'WriteOption',
]
8 changes: 6 additions & 2 deletions firestore/google/cloud/firestore_v1beta1/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
"""Common helpers shared across Google Cloud Firestore modules."""


import collections
try:
from collections import abc
except ImportError: # python 2.7
import collections as abc

import datetime
import re

Expand Down Expand Up @@ -745,7 +749,7 @@ def get_nested_value(field_path, data):

nested_data = data
for index, field_name in enumerate(field_names):
if isinstance(nested_data, collections.Mapping):
if isinstance(nested_data, abc.Mapping):
if field_name in nested_data:
nested_data = nested_data[field_name]
else:
Expand Down
34 changes: 33 additions & 1 deletion firestore/google/cloud/firestore_v1beta1/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
from google.cloud.firestore_v1beta1 import _helpers
from google.cloud.firestore_v1beta1 import query as query_mod
from google.cloud.firestore_v1beta1.proto import document_pb2

from google.cloud.firestore_v1beta1.watch import Watch
from google.cloud.firestore_v1beta1 import document

_AUTO_ID_CHARS = (
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
Expand Down Expand Up @@ -371,6 +372,37 @@ def get(self, transaction=None):
query = query_mod.Query(self)
return query.get(transaction=transaction)

def on_snapshot(self, callback):
"""Monitor the documents in this collection.

This starts a watch on this collection using a background thread. The
provided callback is run on the snapshot of the documents.

Args:
callback(~.firestore.collection.CollectionSnapshot): a callback
to run when a change occurs.

Example:
from google.cloud import firestore

db = firestore.Client()
collection_ref = db.collection(u'users')

def on_snapshot(collection_snapshot):
for doc in collection_snapshot.documents:
print(u'{} => {}'.format(doc.id, doc.to_dict()))

# Watch this collection
collection_watch = collection_ref.on_snapshot(on_snapshot)

# Terminate this watch
collection_watch.unsubscribe()
"""
return Watch.for_query(query_mod.Query(self),
callback,
document.DocumentSnapshot,
document.DocumentReference)


def _auto_id():
"""Generate a "random" automatically generated ID.
Expand Down
33 changes: 33 additions & 0 deletions firestore/google/cloud/firestore_v1beta1/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import six

from google.cloud.firestore_v1beta1 import _helpers
from google.cloud.firestore_v1beta1.watch import Watch


class DocumentReference(object):
Expand Down Expand Up @@ -445,6 +446,38 @@ def collections(self, page_size=None):
iterator.item_to_value = _item_to_collection_ref
return iterator

def on_snapshot(self, callback):
"""Watch this document.

This starts a watch on this document using a background thread. The
provided callback is run on the snapshot.

Args:
callback(~.firestore.document.DocumentSnapshot):a callback to run
when a change occurs

Example:
from google.cloud import firestore

db = firestore.Client()
collection_ref = db.collection(u'users')

def on_snapshot(document_snapshot):
doc = document_snapshot
print(u'{} => {}'.format(doc.id, doc.to_dict()))

doc_ref = db.collection(u'users').document(
u'alovelace' + unique_resource_id())

# Watch this document
doc_watch = doc_ref.on_snapshot(on_snapshot)

# Terminate this watch
doc_watch.unsubscribe()
"""
return Watch.for_document(self, callback, DocumentSnapshot,
DocumentReference)


class DocumentSnapshot(object):
"""A snapshot of document data in a Firestore database.
Expand Down
211 changes: 211 additions & 0 deletions firestore/google/cloud/firestore_v1beta1/order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
# Copyright 2017 Google LLC All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from enum import Enum
from google.cloud.firestore_v1beta1._helpers import decode_value
import math


class TypeOrder(Enum):
# NOTE: This order is defined by the backend and cannot be changed.
NULL = 0
BOOLEAN = 1
NUMBER = 2
TIMESTAMP = 3
STRING = 4
BLOB = 5
REF = 6
GEO_POINT = 7
ARRAY = 8
OBJECT = 9

@staticmethod
def from_value(value):
v = value.WhichOneof('value_type')

lut = {
'null_value': TypeOrder.NULL,
'boolean_value': TypeOrder.BOOLEAN,
'integer_value': TypeOrder.NUMBER,
'double_value': TypeOrder.NUMBER,
'timestamp_value': TypeOrder.TIMESTAMP,
'string_value': TypeOrder.STRING,
'bytes_value': TypeOrder.BLOB,
'reference_value': TypeOrder.REF,
'geo_point_value': TypeOrder.GEO_POINT,
'array_value': TypeOrder.ARRAY,
'map_value': TypeOrder.OBJECT,
}

if v not in lut:
raise ValueError(
"Could not detect value type for " + v)
return lut[v]


class Order(object):
'''
Order implements the ordering semantics of the backend.
'''

@classmethod
def compare(cls, left, right):
'''
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.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('Unknown ``value_type``', str(value_type))

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

return Order._compare_to(left_bytes, right_bytes)

@staticmethod
def compare_timestamps(left, right):
left = left.timestamp_value
right = right.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):
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):
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):
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):
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):
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):
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):
# 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)
Loading