From 455f860343ff1b71232dad98cf91415492a899ca Mon Sep 17 00:00:00 2001 From: ventice11o <159263040+ventice11o@users.noreply.github.com> Date: Thu, 29 Feb 2024 20:16:14 +0400 Subject: [PATCH] fix: repeated structured property containing blob property with legacy_data (#817) (#946) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix issue 817 * Fix issue 817 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: venticello Co-authored-by: Owl Bot Co-authored-by: Jim Morrison --- google/cloud/ndb/model.py | 13 +++++++---- tests/unit/test_model.py | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/google/cloud/ndb/model.py b/google/cloud/ndb/model.py index 3ede1952..51d082f7 100644 --- a/google/cloud/ndb/model.py +++ b/google/cloud/ndb/model.py @@ -2662,11 +2662,16 @@ def _to_datastore(self, entity, data, prefix="", repeated=False): value = compressed_value data[key] = value if not self._repeated: - if value and not value.startswith(_ZLIB_COMPRESSION_MARKERS): - value = zlib.compress(value) - data[key] = value + values = [ + zlib.compress(v) + if v and not v.startswith(_ZLIB_COMPRESSION_MARKERS) + else v + for v in (value if repeated else [value]) + ] + value = values if repeated else values[0] + data[key] = value - if value: + if value and not repeated: data.setdefault("_meanings", {})[key] = ( _MEANING_COMPRESSED, value, diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py index 82e4324c..b57a6040 100644 --- a/tests/unit/test_model.py +++ b/tests/unit/test_model.py @@ -1816,6 +1816,52 @@ class ThisKind(model.Model): compressed_value_two, ] + @staticmethod + def test__to_datastore_legacy_compressed_repeated_in_parent(in_context): + class ThisKind(model.Model): + bar = model.BlobProperty(compressed=True, repeated=False) + + class ParentKind(model.Model): + foo = model.StructuredProperty(ThisKind, repeated=True) + + with in_context.new(legacy_data=True).use(): + uncompressed_value_one = b"abc" * 1000 + compressed_value_one = zlib.compress(uncompressed_value_one) + uncompressed_value_two = b"xyz" * 1000 + compressed_value_two = zlib.compress(uncompressed_value_two) + entity = ParentKind( + foo=[ + ThisKind(bar=uncompressed_value_one), + ThisKind(bar=uncompressed_value_two), + ] + ) + ds_entity = model._entity_to_ds_entity(entity) + assert "foo.bar" not in ds_entity._meanings + assert "foo.bar" in ds_entity.keys() + assert ds_entity.get("foo.bar") == [ + compressed_value_one, + compressed_value_two, + ] + + @staticmethod + def test__to_datastore_legacy_compressed_repeated_in_parent_uninitialized( + in_context, + ): + class ThisKind(model.Model): + bar = model.BlobProperty(compressed=True, repeated=False) + + class ParentKind(model.Model): + foo = model.StructuredProperty(ThisKind, repeated=True) + + with in_context.new(legacy_data=True).use(): + uncompressed_value = b"abc" * 1000 + compressed_value = zlib.compress(uncompressed_value) + entity = ParentKind(foo=[ThisKind(), ThisKind(bar=uncompressed_value)]) + ds_entity = model._entity_to_ds_entity(entity) + assert "foo.bar" not in ds_entity._meanings + assert "foo.bar" in ds_entity.keys() + assert ds_entity.get("foo.bar") == [None, compressed_value] + @staticmethod @pytest.mark.usefixtures("in_context") def test__to_datastore_compressed_uninitialized():