Skip to content

Commit 891e94d

Browse files
authored
fix compressed and repeated properties (#290)
* fix compressed and repeated properties
1 parent 0587082 commit 891e94d

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2527,9 +2527,20 @@ def _to_datastore(self, entity, data, prefix="", repeated=False):
25272527
if isinstance(value, _CompressedValue):
25282528
value = value.z_val
25292529
data[self._name] = value
2530-
if value and not value.startswith(_ZLIB_COMPRESSION_MARKER):
2531-
value = zlib.compress(value)
2530+
2531+
if self._repeated:
2532+
compressed_value = []
2533+
for rval in value:
2534+
if rval and not rval.startswith(_ZLIB_COMPRESSION_MARKER):
2535+
rval = zlib.compress(rval)
2536+
compressed_value.append(rval)
2537+
value = compressed_value
25322538
data[self._name] = value
2539+
if not self._repeated:
2540+
if value and not value.startswith(_ZLIB_COMPRESSION_MARKER):
2541+
value = zlib.compress(value)
2542+
data[self._name] = value
2543+
25332544
if value:
25342545
data.setdefault("_meanings", {})[self._name] = (
25352546
_MEANING_COMPRESSED,

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,25 @@ class SomeKind(ndb.Model):
361361
assert retrieved.foo == foo
362362

363363

364+
@pytest.mark.usefixtures("client_context")
365+
def test_compressed_repeated_local_structured_property(dispose_of, ds_client):
366+
class Dog(ndb.Model):
367+
name = ndb.StringProperty()
368+
369+
class House(ndb.Model):
370+
dogs = ndb.LocalStructuredProperty(Dog, repeated=True, compressed=True)
371+
372+
entity = House()
373+
dogs = [Dog(name="Mika"), Dog(name="Mocha")]
374+
entity.dogs = dogs
375+
376+
key = entity.put()
377+
dispose_of(key._key)
378+
379+
retrieved = key.get()
380+
assert retrieved.dogs == dogs
381+
382+
364383
@pytest.mark.usefixtures("client_context")
365384
def test_retrieve_entity_with_legacy_compressed_property(
366385
ds_entity_with_meanings,

packages/google-cloud-ndb/tests/unit/test_model.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,25 @@ class ThisKind(model.Model):
18031803
assert ds_entity._meanings["foo"][0] == model._MEANING_COMPRESSED
18041804
assert ds_entity._meanings["foo"][1] == compressed_value
18051805

1806+
@staticmethod
1807+
@pytest.mark.usefixtures("in_context")
1808+
def test__to_datastore_compressed_repeated():
1809+
class ThisKind(model.Model):
1810+
foo = model.BlobProperty(compressed=True, repeated=True)
1811+
1812+
uncompressed_value_one = b"abc" * 1000
1813+
compressed_value_one = zlib.compress(uncompressed_value_one)
1814+
uncompressed_value_two = b"xyz" * 1000
1815+
compressed_value_two = zlib.compress(uncompressed_value_two)
1816+
entity = ThisKind(foo=[uncompressed_value_one, uncompressed_value_two])
1817+
ds_entity = model._entity_to_ds_entity(entity)
1818+
assert "foo" in ds_entity._meanings
1819+
assert ds_entity._meanings["foo"][0] == model._MEANING_COMPRESSED
1820+
assert ds_entity._meanings["foo"][1] == [
1821+
compressed_value_one,
1822+
compressed_value_two,
1823+
]
1824+
18061825
@staticmethod
18071826
@pytest.mark.usefixtures("in_context")
18081827
def test__to_datastore_compressed_uninitialized():
@@ -1861,6 +1880,33 @@ class ThisKind(model.Model):
18611880
ds_entity = model._entity_to_ds_entity(entity)
18621881
assert ds_entity["foo"] == compressed_value
18631882

1883+
@staticmethod
1884+
@pytest.mark.usefixtures("in_context")
1885+
def test__from_datastore_compressed_repeated_to_compressed():
1886+
class ThisKind(model.Model):
1887+
foo = model.BlobProperty(compressed=True, repeated=True)
1888+
1889+
key = datastore.Key("ThisKind", 123, project="testing")
1890+
datastore_entity = datastore.Entity(key=key)
1891+
uncompressed_value_one = b"abc" * 1000
1892+
compressed_value_one = zlib.compress(uncompressed_value_one)
1893+
uncompressed_value_two = b"xyz" * 1000
1894+
compressed_value_two = zlib.compress(uncompressed_value_two)
1895+
datastore_entity.update(
1896+
{"foo": [compressed_value_one, compressed_value_two]}
1897+
)
1898+
meanings = {
1899+
"foo": (
1900+
model._MEANING_COMPRESSED,
1901+
[compressed_value_one, compressed_value_two],
1902+
)
1903+
}
1904+
datastore_entity._meanings = meanings
1905+
protobuf = helpers.entity_to_protobuf(datastore_entity)
1906+
entity = model._entity_from_protobuf(protobuf)
1907+
ds_entity = model._entity_to_ds_entity(entity)
1908+
assert ds_entity["foo"] == [compressed_value_one, compressed_value_two]
1909+
18641910
@staticmethod
18651911
@pytest.mark.usefixtures("in_context")
18661912
def test__from_datastore_uncompressed_to_uncompressed():
@@ -1893,6 +1939,26 @@ class ThisKind(model.Model):
18931939
ds_entity = model._entity_to_ds_entity(entity)
18941940
assert ds_entity["foo"] == compressed_value
18951941

1942+
@staticmethod
1943+
@pytest.mark.usefixtures("in_context")
1944+
def test__from_datastore_uncompressed_repeated_to_compressed():
1945+
class ThisKind(model.Model):
1946+
foo = model.BlobProperty(compressed=True, repeated=True)
1947+
1948+
key = datastore.Key("ThisKind", 123, project="testing")
1949+
datastore_entity = datastore.Entity(key=key)
1950+
uncompressed_value_one = b"abc" * 1000
1951+
compressed_value_one = zlib.compress(uncompressed_value_one)
1952+
uncompressed_value_two = b"xyz" * 1000
1953+
compressed_value_two = zlib.compress(uncompressed_value_two)
1954+
datastore_entity.update(
1955+
{"foo": [uncompressed_value_one, uncompressed_value_two]}
1956+
)
1957+
protobuf = helpers.entity_to_protobuf(datastore_entity)
1958+
entity = model._entity_from_protobuf(protobuf)
1959+
ds_entity = model._entity_to_ds_entity(entity)
1960+
assert ds_entity["foo"] == [compressed_value_one, compressed_value_two]
1961+
18961962

18971963
class TestTextProperty:
18981964
@staticmethod

0 commit comments

Comments
 (0)