Skip to content

Commit fd06f16

Browse files
committed
Merge pull request #792 from dhermes/non-fuzzy-app-id-isolated
Adding one-time RPC to find unaliased / true dataset ID.
2 parents 3af46b1 + 01d0354 commit fd06f16

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

gcloud/datastore/helpers.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,46 @@
3333
INT_VALUE_CHECKER = Int64ValueChecker()
3434

3535

36+
def find_true_dataset_id(dataset_id, connection):
37+
"""Find the true (unaliased) dataset ID.
38+
39+
If the given ID already has a 's~' or 'e~' prefix, does nothing.
40+
Otherwise, looks up a bogus Key('__MissingLookupKind', 1) and reads the
41+
true prefixed dataset ID from the response (either from found or from
42+
missing).
43+
44+
For some context, see:
45+
github.com/GoogleCloudPlatform/gcloud-python/pull/528
46+
github.com/GoogleCloudPlatform/google-cloud-datastore/issues/59
47+
48+
:type dataset_id: string
49+
:param dataset_id: The dataset ID to un-alias / prefix.
50+
51+
:type connection: :class:`gcloud.datastore.connection.Connection`
52+
:param connection: A connection provided to connection to the dataset.
53+
54+
:rtype: string
55+
:returns: The true / prefixed / un-aliased dataset ID.
56+
"""
57+
if dataset_id.startswith('s~') or dataset_id.startswith('e~'):
58+
return dataset_id
59+
60+
# Create the bogus Key protobuf to be looked up and remove
61+
# the dataset ID so the backend won't complain.
62+
bogus_key_pb = Key('__MissingLookupKind', 1,
63+
dataset_id=dataset_id).to_protobuf()
64+
bogus_key_pb.partition_id.ClearField('dataset_id')
65+
66+
found_pbs, missing_pbs, _ = connection.lookup(dataset_id, [bogus_key_pb])
67+
# By not passing in `deferred`, lookup will continue until
68+
# all results are `found` or `missing`.
69+
all_pbs = missing_pbs + found_pbs
70+
# We only asked for one, so should only receive one.
71+
returned_pb, = all_pbs
72+
73+
return returned_pb.key.partition_id.dataset_id
74+
75+
3676
def entity_from_protobuf(pb):
3777
"""Factory method for creating an entity based on a protobuf.
3878

gcloud/datastore/test_helpers.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,96 @@ def test_prepare_dataset_id_unset(self):
574574
key = datastore_pb.Key()
575575
new_key = self._callFUT(key)
576576
self.assertTrue(new_key is key)
577+
578+
579+
class Test_find_true_dataset_id(unittest2.TestCase):
580+
581+
def setUp(self):
582+
from gcloud.datastore._testing import _setup_defaults
583+
_setup_defaults(self)
584+
585+
def tearDown(self):
586+
from gcloud.datastore._testing import _tear_down_defaults
587+
_tear_down_defaults(self)
588+
589+
def _callFUT(self, dataset_id, connection):
590+
from gcloud.datastore.helpers import find_true_dataset_id
591+
return find_true_dataset_id(dataset_id, connection)
592+
593+
def test_prefixed(self):
594+
PREFIXED = 's~DATASET'
595+
result = self._callFUT(PREFIXED, object())
596+
self.assertEqual(PREFIXED, result)
597+
598+
def test_unprefixed_bogus_key_miss(self):
599+
UNPREFIXED = 'DATASET'
600+
PREFIX = 's~'
601+
CONNECTION = _Connection(PREFIX, from_missing=False)
602+
result = self._callFUT(UNPREFIXED, CONNECTION)
603+
604+
self.assertEqual(CONNECTION._called_dataset_id, UNPREFIXED)
605+
606+
self.assertEqual(len(CONNECTION._lookup_result), 1)
607+
608+
# Make sure just one.
609+
called_key_pb, = CONNECTION._called_key_pbs
610+
path_element = called_key_pb.path_element
611+
self.assertEqual(len(path_element), 1)
612+
self.assertEqual(path_element[0].kind, '__MissingLookupKind')
613+
self.assertEqual(path_element[0].id, 1)
614+
self.assertFalse(path_element[0].HasField('name'))
615+
616+
PREFIXED = PREFIX + UNPREFIXED
617+
self.assertEqual(result, PREFIXED)
618+
619+
def test_unprefixed_bogus_key_hit(self):
620+
UNPREFIXED = 'DATASET'
621+
PREFIX = 'e~'
622+
CONNECTION = _Connection(PREFIX, from_missing=True)
623+
result = self._callFUT(UNPREFIXED, CONNECTION)
624+
625+
self.assertEqual(CONNECTION._called_dataset_id, UNPREFIXED)
626+
self.assertEqual(CONNECTION._lookup_result, [])
627+
628+
# Make sure just one.
629+
called_key_pb, = CONNECTION._called_key_pbs
630+
path_element = called_key_pb.path_element
631+
self.assertEqual(len(path_element), 1)
632+
self.assertEqual(path_element[0].kind, '__MissingLookupKind')
633+
self.assertEqual(path_element[0].id, 1)
634+
self.assertFalse(path_element[0].HasField('name'))
635+
636+
PREFIXED = PREFIX + UNPREFIXED
637+
self.assertEqual(result, PREFIXED)
638+
639+
640+
class _Connection(object):
641+
642+
_called_dataset_id = _called_key_pbs = _lookup_result = None
643+
644+
def __init__(self, prefix, from_missing=False):
645+
self.prefix = prefix
646+
self.from_missing = from_missing
647+
648+
def lookup(self, dataset_id, key_pbs):
649+
from gcloud.datastore import _datastore_v1_pb2 as datastore_pb
650+
651+
# Store the arguments called with.
652+
self._called_dataset_id = dataset_id
653+
self._called_key_pbs = key_pbs
654+
655+
key_pb, = key_pbs
656+
657+
response = datastore_pb.Entity()
658+
response.key.CopyFrom(key_pb)
659+
response.key.partition_id.dataset_id = self.prefix + dataset_id
660+
661+
missing = []
662+
deferred = []
663+
if self.from_missing:
664+
missing[:] = [response]
665+
self._lookup_result = []
666+
else:
667+
self._lookup_result = [response]
668+
669+
return self._lookup_result, missing, deferred

0 commit comments

Comments
 (0)