Skip to content

Commit

Permalink
fix: Convert NDB keys to Datastore keys for serialization.
Browse files Browse the repository at this point in the history
See comments in code for design considerations. This is a compromise
solution.

Fixes googleapis#284.
  • Loading branch information
Chris Rossi committed Jan 9, 2020
1 parent 2fe5be3 commit 398c075
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
18 changes: 17 additions & 1 deletion google/cloud/ndb/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1687,7 +1687,23 @@ def _validate(self, value):
"""
methods = self._find_methods("_validate", "_to_base_type")
call = self._apply_list(methods)
return call(value)
value = call(value)

# Legacy NDB, because it didn't delegate to Datastore for serializing
# entities, would directly write a Key protocol buffer for a key. We,
# however, need to transform NDB keys to Datastore keys before
# delegating to Datastore to generate protocol buffers. You might be
# tempted to do this in KeyProperty._to_base_type, and that works great
# for properties of KeyProperty type. If, however, you're computing a
# key in a ComputedProperty, ComputedProperty doesn't know to call
# KeyProperty's base type. (Probably ComputedProperty should take
# another property type as a constructor argument for this purpose,
# but that wasn't part of the original design and adding it introduces
# backwards compatibility issues.) See: Issue #184
if isinstance(value, key_module.Key):
value = value._key # Datastore key

return value

def _call_shallow_validation(self, value):
"""Call the "initial" set of ``_validate()`` methods.
Expand Down
33 changes: 33 additions & 0 deletions tests/system/test_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,3 +1004,36 @@ class SomeKind(ndb.Model):

key.delete()
assert key.get() is None


@pytest.mark.usefixtures("client_context")
def test_computed_key_property(dispose_of):
"""Regression test for #284.
https://github.com/googleapis/python-ndb/issues/284
"""

class AModel(ndb.Model):
s_foo = ndb.StringProperty()

class BModel(ndb.Model):
s_bar = ndb.StringProperty()
key_a = ndb.KeyProperty(kind="AModel", indexed=True)

class CModel(ndb.Model):
s_foobar = ndb.StringProperty()
key_b = ndb.KeyProperty(kind="BModel", indexed=True)
key_a = ndb.ComputedProperty( # Issue here
lambda self: self.key_b.get().key_a if self.key_b else None,
)

key_a = AModel(s_foo="test").put()
dispose_of(key_a._key)
key_b = BModel(s_bar="test", key_a=key_a).put()
dispose_of(key_b._key)
key_c = CModel(s_foobar="test", key_b=key_b).put()
dispose_of(key_c._key)

entity = key_c.get()
assert entity.key_a == key_a
assert entity.key_b == key_b

0 comments on commit 398c075

Please sign in to comment.