Skip to content

Commit 615f9a1

Browse files
author
Chris Rossi
authored
fix: Convert NDB keys to Datastore keys for serialization. (#287)
See comments in code for design considerations. This is a compromise solution. Fixes #284.
1 parent 51daf38 commit 615f9a1

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

packages/google-cloud-ndb/google/cloud/ndb/model.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1687,7 +1687,23 @@ def _validate(self, value):
16871687
"""
16881688
methods = self._find_methods("_validate", "_to_base_type")
16891689
call = self._apply_list(methods)
1690-
return call(value)
1690+
value = call(value)
1691+
1692+
# Legacy NDB, because it didn't delegate to Datastore for serializing
1693+
# entities, would directly write a Key protocol buffer for a key. We,
1694+
# however, need to transform NDB keys to Datastore keys before
1695+
# delegating to Datastore to generate protocol buffers. You might be
1696+
# tempted to do this in KeyProperty._to_base_type, and that works great
1697+
# for properties of KeyProperty type. If, however, you're computing a
1698+
# key in a ComputedProperty, ComputedProperty doesn't know to call
1699+
# KeyProperty's base type. (Probably ComputedProperty should take
1700+
# another property type as a constructor argument for this purpose,
1701+
# but that wasn't part of the original design and adding it introduces
1702+
# backwards compatibility issues.) See: Issue #184
1703+
if isinstance(value, key_module.Key):
1704+
value = value._key # Datastore key
1705+
1706+
return value
16911707

16921708
def _call_shallow_validation(self, value):
16931709
"""Call the "initial" set of ``_validate()`` methods.

packages/google-cloud-ndb/tests/system/test_crud.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,3 +1004,36 @@ class SomeKind(ndb.Model):
10041004

10051005
key.delete()
10061006
assert key.get() is None
1007+
1008+
1009+
@pytest.mark.usefixtures("client_context")
1010+
def test_computed_key_property(dispose_of):
1011+
"""Regression test for #284.
1012+
1013+
https://github.com/googleapis/python-ndb/issues/284
1014+
"""
1015+
1016+
class AModel(ndb.Model):
1017+
s_foo = ndb.StringProperty()
1018+
1019+
class BModel(ndb.Model):
1020+
s_bar = ndb.StringProperty()
1021+
key_a = ndb.KeyProperty(kind="AModel", indexed=True)
1022+
1023+
class CModel(ndb.Model):
1024+
s_foobar = ndb.StringProperty()
1025+
key_b = ndb.KeyProperty(kind="BModel", indexed=True)
1026+
key_a = ndb.ComputedProperty( # Issue here
1027+
lambda self: self.key_b.get().key_a if self.key_b else None,
1028+
)
1029+
1030+
key_a = AModel(s_foo="test").put()
1031+
dispose_of(key_a._key)
1032+
key_b = BModel(s_bar="test", key_a=key_a).put()
1033+
dispose_of(key_b._key)
1034+
key_c = CModel(s_foobar="test", key_b=key_b).put()
1035+
dispose_of(key_c._key)
1036+
1037+
entity = key_c.get()
1038+
assert entity.key_a == key_a
1039+
assert entity.key_b == key_b

0 commit comments

Comments
 (0)