diff --git a/api/client/src/main/java/org/projectnessie/client/api/ns/ClientSideGetMultipleNamespaces.java b/api/client/src/main/java/org/projectnessie/client/api/ns/ClientSideGetMultipleNamespaces.java index 6f5b6bb2667..a7e70a3d300 100644 --- a/api/client/src/main/java/org/projectnessie/client/api/ns/ClientSideGetMultipleNamespaces.java +++ b/api/client/src/main/java/org/projectnessie/client/api/ns/ClientSideGetMultipleNamespaces.java @@ -27,7 +27,6 @@ import org.projectnessie.client.builder.BaseGetMultipleNamespacesBuilder; import org.projectnessie.error.NessieNotFoundException; import org.projectnessie.error.NessieReferenceNotFoundException; -import org.projectnessie.model.Content; import org.projectnessie.model.ContentKey; import org.projectnessie.model.EntriesResponse; import org.projectnessie.model.GetMultipleContentsResponse; @@ -38,7 +37,7 @@ /** * Supports previous "get multiple namespaces" functionality of the java client over Nessie API v2. * - *

API v2 does not have methods dedicated to manging namespaces. Namespaces are expected to be + *

API v2 does not have methods dedicated to managing namespaces. Namespaces are expected to be * managed as ordinary content objects. */ public final class ClientSideGetMultipleNamespaces extends BaseGetMultipleNamespacesBuilder { @@ -61,33 +60,24 @@ public GetNamespacesResponse get() throws NessieReferenceNotFoundException { try { GetEntriesBuilder getEntries = api.getEntries().refName(refName).hashOnRef(hashOnRef); - String filter = null; + String filter = "entry.contentType == 'NAMESPACE'"; if (namespace != null && !namespace.isEmpty()) { String nsName = namespace.name(); - filter = + filter += onlyDirectChildren ? format( - "size(entry.keyElements) == %d && entry.encodedKey.startsWith('%s.')", + " && size(entry.keyElements) == %d && entry.encodedKey.startsWith('%s.')", namespace.getElementCount() + 1, nsName) : format( - "entry.encodedKey == '%s' || entry.encodedKey.startsWith('%s.')", + "&& (entry.encodedKey == '%s' || entry.encodedKey.startsWith('%s.'))", nsName, nsName); } else if (onlyDirectChildren) { - filter = "size(entry.keyElements) == 1"; - } - if (filter != null) { - getEntries.filter(filter); + filter += " && size(entry.keyElements) == 1"; } + getEntries.filter(filter); entries = - getEntries.stream() - .filter(e -> Content.Type.NAMESPACE.equals(e.getType())) - .map(EntriesResponse.Entry::getName) - .filter( - name -> - namespace == null - || Namespace.of(name.getElements()).isSameOrSubElementOf(namespace)) - .collect(Collectors.toList()); + getEntries.stream().map(EntriesResponse.Entry::getName).collect(Collectors.toList()); } catch (NessieNotFoundException e) { throw new NessieReferenceNotFoundException(e.getMessage(), e); } diff --git a/servers/jax-rs-tests/src/main/java/org/projectnessie/jaxrs/tests/BaseTestNessieApi.java b/servers/jax-rs-tests/src/main/java/org/projectnessie/jaxrs/tests/BaseTestNessieApi.java index 2302e9c1c50..e1f8d444830 100644 --- a/servers/jax-rs-tests/src/main/java/org/projectnessie/jaxrs/tests/BaseTestNessieApi.java +++ b/servers/jax-rs-tests/src/main/java/org/projectnessie/jaxrs/tests/BaseTestNessieApi.java @@ -1412,6 +1412,16 @@ public void namespaces() throws Exception { namespace4WithId = api().createNamespace().refName(mainName).namespace(namespace4).create(); } + // Add some non-namespace content to check that it is not returned by the namespace API + IcebergTable table = IcebergTable.of("irrelevant", 1, 2, 3, 4); + ContentKey table1 = ContentKey.of(namespace4, "table1"); + api() + .commitMultipleOperations() + .branch(main) + .commitMeta(CommitMeta.fromMessage("Add table1")) + .operation(Put.of(table1, table)) + .commit(); + for (Map.Entry> c : ImmutableMap.of( Namespace.EMPTY, @@ -1569,6 +1579,7 @@ public void namespaces() throws Exception { namespace1WithId, namespace2update2, namespace3WithId, namespace4WithId); if (isV2()) { + // contains other namespaces soft.assertThatThrownBy( () -> api().deleteNamespace().refName(mainName).namespace(namespace2).delete()) .isInstanceOf(NessieNamespaceNotEmptyException.class) @@ -1576,8 +1587,31 @@ public void namespaces() throws Exception { .extracting(NessieNamespaceNotEmptyException::getErrorDetails) .extracting(ContentKeyErrorDetails::contentKey) .isEqualTo(namespace2.toContentKey()); + // contains a table + soft.assertThatThrownBy( + () -> api().deleteNamespace().refName(mainName).namespace(namespace4).delete()) + .isInstanceOf(NessieNamespaceNotEmptyException.class) + .asInstanceOf(type(NessieNamespaceNotEmptyException.class)) + .extracting(NessieNamespaceNotEmptyException::getErrorDetails) + .extracting(ContentKeyErrorDetails::contentKey) + .isEqualTo(namespace4.toContentKey()); + } else { + soft.assertThatThrownBy( + () -> api().deleteNamespace().refName(mainName).namespace(namespace2).delete()) + .isInstanceOf(NessieNamespaceNotEmptyException.class); + soft.assertThatThrownBy( + () -> api().deleteNamespace().refName(mainName).namespace(namespace4).delete()) + .isInstanceOf(NessieNamespaceNotEmptyException.class); } + main = (Branch) api().getReference().refName(mainName).get(); + api() + .commitMultipleOperations() + .branch(main) + .commitMeta(CommitMeta.fromMessage("Delete table1")) + .operation(Delete.of(table1)) + .commit(); + if (isV2()) { main = (Branch) api().getReference().refName(mainName).get(); DeleteNamespaceResult response =