diff --git a/google/cloud/ndb/query.py b/google/cloud/ndb/query.py index 6eba8bd3..161ea092 100644 --- a/google/cloud/ndb/query.py +++ b/google/cloud/ndb/query.py @@ -1392,7 +1392,13 @@ def __init__( else: project = ancestor.app() if namespace is not None: - if namespace != ancestor.namespace(): + # if namespace is the empty string, that means default + # namespace, but after a put, if the ancestor is using + # the default namespace, its namespace will be None, + # so skip the test to avoid a false mismatch error. + if namespace == "" and ancestor.namespace() is None: + pass + elif namespace != ancestor.namespace(): raise TypeError("ancestor/namespace mismatch") else: namespace = ancestor.namespace() diff --git a/tests/system/test_query.py b/tests/system/test_query.py index 96838206..7e57f139 100644 --- a/tests/system/test_query.py +++ b/tests/system/test_query.py @@ -161,6 +161,56 @@ class SomeKind(ndb.Model): assert [entity.foo for entity in results] == [-1, 0, 1, 2, 3, 4] +def test_ancestor_query_with_namespace(client_context, dispose_of, other_namespace): + class Dummy(ndb.Model): + foo = ndb.StringProperty(default="") + + entity1 = Dummy(foo="bar", namespace="xyz") + parent_key = entity1.put() + dispose_of(entity1.key._key) + + entity2 = Dummy(foo="child", parent=parent_key, namespace=None) + entity2.put() + dispose_of(entity2.key._key) + + entity3 = Dummy(foo="childless", namespace="xyz") + entity3.put() + dispose_of(entity3.key._key) + + with client_context.new(namespace=other_namespace).use(): + query = Dummy.query(ancestor=parent_key, namespace="xyz") + results = eventually(query.fetch, length_equals(2)) + + assert results[0].foo == "bar" + assert results[1].foo == "child" + + +def test_ancestor_query_with_default_namespace( + client_context, dispose_of, other_namespace +): + class Dummy(ndb.Model): + foo = ndb.StringProperty(default="") + + entity1 = Dummy(foo="bar", namespace="") + parent_key = entity1.put() + dispose_of(entity1.key._key) + + entity2 = Dummy(foo="child", parent=parent_key, namespace=None) + entity2.put() + dispose_of(entity2.key._key) + + entity3 = Dummy(foo="childless", namespace="") + entity3.put() + dispose_of(entity3.key._key) + + with client_context.new(namespace=other_namespace).use(): + query = Dummy.query(ancestor=parent_key, namespace="") + results = eventually(query.fetch, length_equals(2)) + + assert results[0].foo == "bar" + assert results[1].foo == "child" + + @pytest.mark.usefixtures("client_context") def test_projection(ds_entity): entity_id = test_utils.system.unique_resource_id() diff --git a/tests/unit/test_query.py b/tests/unit/test_query.py index 7e4966a2..672bce7a 100644 --- a/tests/unit/test_query.py +++ b/tests/unit/test_query.py @@ -1244,6 +1244,13 @@ def test_constructor_with_ancestor_and_namespace(): query = query_module.Query(ancestor=key, namespace="space") assert query.namespace == "space" + @staticmethod + @pytest.mark.usefixtures("in_context") + def test_constructor_with_ancestor_and_default_namespace(): + key = key_module.Key("a", "b", namespace=None) + query = query_module.Query(ancestor=key, namespace="") + assert query.namespace == "" + @staticmethod @pytest.mark.usefixtures("in_context") def test_constructor_with_ancestor_parameterized_thing():