Skip to content

Commit

Permalink
Implement _prepare_for_put for StructuredProperty and `LocalStruc…
Browse files Browse the repository at this point in the history
…turedProperty`. (#221)

This was in the original code, but was overlooked when porting. Fixes #216.
  • Loading branch information
Chris Rossi authored Oct 17, 2019
1 parent eb34c8d commit dfd403f
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
16 changes: 16 additions & 0 deletions google/cloud/ndb/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4035,6 +4035,14 @@ def _to_datastore(self, entity, data, prefix="", repeated=False):

return set(keys)

def _prepare_for_put(self, entity):
values = self._get_user_value(entity)
if not self._repeated:
values = [values]
for value in values:
if value is not None:
value._prepare_for_put()


class LocalStructuredProperty(BlobProperty):
"""A property that contains ndb.Model value.
Expand Down Expand Up @@ -4130,6 +4138,14 @@ def _from_base_type(self, value):
value.key = None
return _entity_from_ds_entity(value, model_class=self._model_class)

def _prepare_for_put(self, entity):
values = self._get_user_value(entity)
if not self._repeated:
values = [values]
for value in values:
if value is not None:
value._prepare_for_put()


class GenericProperty(Property):
"""A Property whose value can be (almost) any basic type.
Expand Down
20 changes: 20 additions & 0 deletions tests/system/test_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,26 @@ class SomeKind(ndb.Model):
dispose_of(key._key)


@pytest.mark.usefixtures("client_context")
def test_insert_nested_autonow_property(dispose_of):
class OtherKind(ndb.Model):
created_at = ndb.DateTimeProperty(indexed=True, auto_now_add=True)
updated_at = ndb.DateTimeProperty(indexed=True, auto_now=True)

class SomeKind(ndb.Model):
other = ndb.StructuredProperty(OtherKind)

entity = SomeKind(other=OtherKind())
key = entity.put()

retrieved = key.get()

assert isinstance(retrieved.other.created_at, datetime.datetime)
assert isinstance(retrieved.other.updated_at, datetime.datetime)

dispose_of(key._key)


@pytest.mark.usefixtures("client_context")
def test_uninitialized_property(dispose_of):
class SomeKind(ndb.Model):
Expand Down
78 changes: 78 additions & 0 deletions tests/unit/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3295,6 +3295,45 @@ class SomeKind(model.Model):
assert SomeKind.foo._to_datastore(entity, data) == {"foo.bar"}
assert data == {"foo.bar": ["baz", "boz"]}

@staticmethod
def test__prepare_for_put():
class SubKind(model.Model):
bar = model.Property()

class SomeKind(model.Model):
foo = model.StructuredProperty(SubKind)

entity = SomeKind(foo=SubKind())
entity.foo._prepare_for_put = unittest.mock.Mock()
SomeKind.foo._prepare_for_put(entity)
entity.foo._prepare_for_put.assert_called_once_with()

@staticmethod
def test__prepare_for_put_repeated():
class SubKind(model.Model):
bar = model.Property()

class SomeKind(model.Model):
foo = model.StructuredProperty(SubKind, repeated=True)

entity = SomeKind(foo=[SubKind(), SubKind()])
entity.foo[0]._prepare_for_put = unittest.mock.Mock()
entity.foo[1]._prepare_for_put = unittest.mock.Mock()
SomeKind.foo._prepare_for_put(entity)
entity.foo[0]._prepare_for_put.assert_called_once_with()
entity.foo[1]._prepare_for_put.assert_called_once_with()

@staticmethod
def test__prepare_for_put_repeated_None():
class SubKind(model.Model):
bar = model.Property()

class SomeKind(model.Model):
foo = model.StructuredProperty(SubKind)

entity = SomeKind()
SomeKind.foo._prepare_for_put(entity) # noop


class TestLocalStructuredProperty:
@staticmethod
Expand Down Expand Up @@ -3397,6 +3436,45 @@ class Simple(model.Model):
expected = Simple()
assert prop._from_base_type(entity) == expected

@staticmethod
def test__prepare_for_put():
class SubKind(model.Model):
bar = model.Property()

class SomeKind(model.Model):
foo = model.LocalStructuredProperty(SubKind)

entity = SomeKind(foo=SubKind())
entity.foo._prepare_for_put = unittest.mock.Mock()
SomeKind.foo._prepare_for_put(entity)
entity.foo._prepare_for_put.assert_called_once_with()

@staticmethod
def test__prepare_for_put_repeated():
class SubKind(model.Model):
bar = model.Property()

class SomeKind(model.Model):
foo = model.LocalStructuredProperty(SubKind, repeated=True)

entity = SomeKind(foo=[SubKind(), SubKind()])
entity.foo[0]._prepare_for_put = unittest.mock.Mock()
entity.foo[1]._prepare_for_put = unittest.mock.Mock()
SomeKind.foo._prepare_for_put(entity)
entity.foo[0]._prepare_for_put.assert_called_once_with()
entity.foo[1]._prepare_for_put.assert_called_once_with()

@staticmethod
def test__prepare_for_put_repeated_None():
class SubKind(model.Model):
bar = model.Property()

class SomeKind(model.Model):
foo = model.LocalStructuredProperty(SubKind)

entity = SomeKind()
SomeKind.foo._prepare_for_put(entity) # noop


class TestGenericProperty:
@staticmethod
Expand Down

0 comments on commit dfd403f

Please sign in to comment.