From 2225d6181f1ab02371612eedfb7baedf2fcdffc5 Mon Sep 17 00:00:00 2001 From: rohanshah18 Date: Thu, 19 Dec 2024 17:15:17 -0500 Subject: [PATCH 1/5] add index tags for serverless index --- .../helpers/TestResourcesManager.java | 6 ++++- .../CreateDescribeListAndDeleteIndexTest.java | 9 ++++--- .../serverless/DeletionProtectionTest.java | 14 ++++++++--- .../java/io/pinecone/clients/Pinecone.java | 14 ++++++++--- .../pinecone/PineconeIndexOperationsTest.java | 25 ++++++++++--------- 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/TestResourcesManager.java b/src/integration/java/io/pinecone/helpers/TestResourcesManager.java index 33c50c3e..8406a412 100644 --- a/src/integration/java/io/pinecone/helpers/TestResourcesManager.java +++ b/src/integration/java/io/pinecone/helpers/TestResourcesManager.java @@ -10,6 +10,8 @@ import org.slf4j.LoggerFactory; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import static io.pinecone.helpers.BuildUpsertRequest.buildRequiredUpsertRequestByDimension; @@ -315,9 +317,11 @@ public String getOrCreateServerlessIndex() throws InterruptedException, Pinecone } String indexName = RandomStringBuilder.build("serverless-index", 8); + HashMap tags = new HashMap<>(); + tags.put("env", "testing"); serverlessIndexModel = pineconeClient.createServerlessIndex(indexName, metric, dimension, cloud, - region, DeletionProtection.DISABLED); + region, DeletionProtection.DISABLED, tags); waitUntilIndexIsReady(pineconeClient, indexName); // Explicitly wait after ready to avoid the "no healthy upstream" issue diff --git a/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java index cf4c5faa..566eac58 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java @@ -10,6 +10,7 @@ import org.openapitools.db_control.client.model.*; import java.util.Arrays; +import java.util.Collections; import static org.junit.jupiter.api.Assertions.*; @@ -48,7 +49,7 @@ public void describeAndListIndex() { @Test public void createServerlessIndexWithInvalidName() { try { - controlPlaneClient.createServerlessIndex("Invalid-name", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED); + controlPlaneClient.createServerlessIndex("Invalid-name", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.emptyMap()); fail("Expected to throw PineconeBadRequestException"); } catch (PineconeBadRequestException expected) { @@ -59,7 +60,7 @@ public void createServerlessIndexWithInvalidName() { @Test public void createServerlessIndexWithInvalidDimension() { try { - controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED); + controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.emptyMap()); fail("Expected to throw PineconeValidationException"); } catch (PineconeValidationException expected) { assertTrue(expected.getLocalizedMessage().contains("Dimension must be greater than 0")); @@ -69,7 +70,7 @@ public void createServerlessIndexWithInvalidDimension() { @Test public void createServerlessIndexWithInvalidCloud() { try { - controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "blah", "us-west-2", DeletionProtection.DISABLED); + controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "blah", "us-west-2", DeletionProtection.DISABLED, Collections.emptyMap()); fail("Expected to throw PineconeValidationException"); } catch (PineconeValidationException expected) { assertTrue(expected.getLocalizedMessage().contains("Cloud cannot be null or empty. Must be one of " + Arrays.toString(ServerlessSpec.CloudEnum.values()))); @@ -79,7 +80,7 @@ public void createServerlessIndexWithInvalidCloud() { @Test public void createServerlessIndexWithInvalidRegion() { try { - controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "aws", "invalid-region", DeletionProtection.DISABLED); + controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "aws", "invalid-region", DeletionProtection.DISABLED, Collections.emptyMap()); fail("Expected to throw PineconeNotFoundException"); } catch (PineconeNotFoundException expected) { assertTrue(expected.getLocalizedMessage().contains("Resource cloud: aws region: invalid-region not found")); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java index af583ef6..98002705 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java @@ -7,6 +7,8 @@ import org.openapitools.db_control.client.model.DeletionProtection; import org.openapitools.db_control.client.model.IndexModel; +import java.util.HashMap; + public class DeletionProtectionTest { private static final Pinecone controlPlaneClient = new Pinecone .Builder(System.getenv("PINECONE_API_KEY")) @@ -16,8 +18,10 @@ public class DeletionProtectionTest { @Test public void createIndexWithDeletionProtectionEnabled() { String indexName = RandomStringBuilder.build("create-serv", 8); + HashMap tags = new HashMap<>(); + tags.put("test", "deletion-protection-enabled"); // Create serverless index with deletion protection enabled - controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.ENABLED); + controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.ENABLED, tags); // Describe index to verify deletion protection is enabled IndexModel indexModel = controlPlaneClient.describeIndex(indexName); DeletionProtection deletionProtection = indexModel.getDeletionProtection(); @@ -27,18 +31,20 @@ public void createIndexWithDeletionProtectionEnabled() { @Test public void createPodIndexWithDeletionProtectionDisabled() { String indexName = RandomStringBuilder.build("create-pod", 8); + HashMap tags = new HashMap<>(); + tags.put("test", "deletion-protection-disabled"); // Create serverless index with deletion protection disabled - controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED); + controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, tags); IndexModel indexModel = controlPlaneClient.describeIndex(indexName); DeletionProtection deletionProtection = indexModel.getDeletionProtection(); Assertions.assertEquals(deletionProtection, DeletionProtection.DISABLED); // Configure index to enable deletionProtection - controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.ENABLED); + controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.ENABLED, tags); indexModel = controlPlaneClient.describeIndex(indexName); deletionProtection = indexModel.getDeletionProtection(); Assertions.assertEquals(deletionProtection, DeletionProtection.ENABLED); // Configure index to disable deletionProtection - controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.DISABLED); + controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.DISABLED, tags); // Delete index controlPlaneClient.deleteIndex(indexName); } diff --git a/src/main/java/io/pinecone/clients/Pinecone.java b/src/main/java/io/pinecone/clients/Pinecone.java index b6d24aec..3d2a9628 100644 --- a/src/main/java/io/pinecone/clients/Pinecone.java +++ b/src/main/java/io/pinecone/clients/Pinecone.java @@ -14,6 +14,7 @@ import java.net.InetSocketAddress; import java.net.Proxy; import java.util.Arrays; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** @@ -70,6 +71,7 @@ PineconeConfig getConfig() { * @param cloud The cloud provider for the index. * @param region The cloud region for the index. * @param deletionProtection Enable or disable deletion protection for the index. + * @param tags A map of tags to associate with the Index. * @return {@link IndexModel} representing the created serverless index. * @throws PineconeException if the API encounters an error during index creation or if any of the arguments are invalid. */ @@ -78,7 +80,8 @@ public IndexModel createServerlessIndex(String indexName, int dimension, String cloud, String region, - DeletionProtection deletionProtection) throws PineconeException { + DeletionProtection deletionProtection, + Map tags) throws PineconeException { if (indexName == null || indexName.isEmpty()) { throw new PineconeValidationException("Index name cannot be null or empty"); } @@ -126,7 +129,8 @@ public IndexModel createServerlessIndex(String indexName, .metric(userMetric) .dimension(dimension) .spec(createServerlessIndexRequestSpec) - .deletionProtection(deletionProtection)); + .deletionProtection(deletionProtection)) + .tags(tags); } catch (ApiException apiException) { handleApiException(apiException); } @@ -626,13 +630,15 @@ public IndexModel configurePodsIndex(String indexName, DeletionProtection deleti * @return {@link IndexModel} representing the configured index. * @throws PineconeException if an error occurs during the operation, the index does not exist, or if any of the arguments are invalid. */ - public IndexModel configureServerlessIndex(String indexName, DeletionProtection deletionProtection) throws PineconeException { + public IndexModel configureServerlessIndex(String indexName, DeletionProtection deletionProtection, Map tags) throws PineconeException { if (indexName == null || indexName.isEmpty()) { throw new PineconeValidationException("indexName cannot be null or empty"); } // Build ConfigureIndexRequest object - ConfigureIndexRequest configureIndexRequest = new ConfigureIndexRequest().deletionProtection(deletionProtection); + ConfigureIndexRequest configureIndexRequest = new ConfigureIndexRequest() + .deletionProtection(deletionProtection) + .tags(tags); IndexModel indexModel = null; try { diff --git a/src/test/java/io/pinecone/PineconeIndexOperationsTest.java b/src/test/java/io/pinecone/PineconeIndexOperationsTest.java index 616779f4..7c224f6e 100644 --- a/src/test/java/io/pinecone/PineconeIndexOperationsTest.java +++ b/src/test/java/io/pinecone/PineconeIndexOperationsTest.java @@ -12,6 +12,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -64,55 +65,55 @@ public void testCreateServerlessIndex() throws IOException { Pinecone client = new Pinecone.Builder("testAPiKey").withOkHttpClient(mockClient).build(); - client.createServerlessIndex("testServerlessIndex", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED); + client.createServerlessIndex("testServerlessIndex", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP); verify(mockCall, times(1)).execute(); PineconeValidationException thrownEmptyIndexName = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Index name cannot be null or empty", thrownEmptyIndexName.getMessage()); PineconeValidationException thrownNullIndexName = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex(null, "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex(null, "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Index name cannot be null or empty", thrownNullIndexName.getMessage()); PineconeValidationException thrownEmptyMetric = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "", 3, "aws", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Metric cannot be null or empty. Must be one of " + Arrays.toString(IndexModel.MetricEnum.values()), thrownEmptyMetric.getMessage()); PineconeValidationException thrownInvalidMetric = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "blah", 3, "aws", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "blah", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals(String.format("Metric cannot be null or empty. Must be one of " + Arrays.toString(IndexModel.MetricEnum.values())), thrownInvalidMetric.getMessage()); PineconeValidationException thrownNullMetric = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", null, 3, "aws", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", null, 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Metric cannot be null or empty. Must be one of " + Arrays.toString(IndexModel.MetricEnum.values()), thrownNullMetric.getMessage()); PineconeValidationException thrownNegativeDimension = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Dimension must be greater than 0. See limits for more info: https://docs.pinecone.io/reference/limits", thrownNegativeDimension.getMessage()); PineconeValidationException thrownEmptyCloud = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Cloud cannot be null or empty. Must be one of " + Arrays.toString(ServerlessSpec.CloudEnum.values()), thrownEmptyCloud.getMessage()); PineconeValidationException thrownNullCloud = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, null, "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, null, "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Cloud cannot be null or empty. Must be one of " + Arrays.toString(ServerlessSpec.CloudEnum.values()), thrownNullCloud.getMessage()); PineconeValidationException thrownInvalidCloud = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "wooooo", "us-west-2", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "wooooo", "us-west-2", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Cloud cannot be null or empty. Must be one of " + Arrays.toString(ServerlessSpec.CloudEnum.values()), thrownInvalidCloud.getMessage()); PineconeValidationException thrownEmptyRegion = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "aws", "", DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "aws", "", DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Region cannot be null or empty", thrownEmptyRegion.getMessage()); PineconeValidationException thrownNullRegion = assertThrows(PineconeValidationException.class, - () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "aws", null, DeletionProtection.DISABLED)); + () -> client.createServerlessIndex("testServerlessIndex", "cosine", 3, "aws", null, DeletionProtection.DISABLED, Collections.EMPTY_MAP)); assertEquals("Region cannot be null or empty", thrownNullRegion.getMessage()); } From ea7ed9a5320d1dcbfb420d8b524e67761bc32bfc Mon Sep 17 00:00:00 2001 From: rohanshah18 Date: Fri, 3 Jan 2025 18:39:42 -0500 Subject: [PATCH 2/5] fix list vectors test and add tags for create serverless index --- .../CreateDescribeListAndDeleteIndexTest.java | 8 ++-- .../dataPlane/ListEndpointTest.java | 17 -------- .../java/io/pinecone/clients/Pinecone.java | 40 ++++++++++++------- .../pinecone/PineconeIndexOperationsTest.java | 3 +- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java index 566eac58..251fd853 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java @@ -49,7 +49,7 @@ public void describeAndListIndex() { @Test public void createServerlessIndexWithInvalidName() { try { - controlPlaneClient.createServerlessIndex("Invalid-name", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.emptyMap()); + controlPlaneClient.createServerlessIndex("Invalid-name", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, null); fail("Expected to throw PineconeBadRequestException"); } catch (PineconeBadRequestException expected) { @@ -60,7 +60,7 @@ public void createServerlessIndexWithInvalidName() { @Test public void createServerlessIndexWithInvalidDimension() { try { - controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED, Collections.emptyMap()); + controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED, null); fail("Expected to throw PineconeValidationException"); } catch (PineconeValidationException expected) { assertTrue(expected.getLocalizedMessage().contains("Dimension must be greater than 0")); @@ -70,7 +70,7 @@ public void createServerlessIndexWithInvalidDimension() { @Test public void createServerlessIndexWithInvalidCloud() { try { - controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "blah", "us-west-2", DeletionProtection.DISABLED, Collections.emptyMap()); + controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "blah", "us-west-2", DeletionProtection.DISABLED, null); fail("Expected to throw PineconeValidationException"); } catch (PineconeValidationException expected) { assertTrue(expected.getLocalizedMessage().contains("Cloud cannot be null or empty. Must be one of " + Arrays.toString(ServerlessSpec.CloudEnum.values()))); @@ -80,7 +80,7 @@ public void createServerlessIndexWithInvalidCloud() { @Test public void createServerlessIndexWithInvalidRegion() { try { - controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "aws", "invalid-region", DeletionProtection.DISABLED, Collections.emptyMap()); + controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "aws", "invalid-region", DeletionProtection.DISABLED, null); fail("Expected to throw PineconeNotFoundException"); } catch (PineconeNotFoundException expected) { assertTrue(expected.getLocalizedMessage().contains("Resource cloud: aws region: invalid-region not found")); diff --git a/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java b/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java index c4bff476..33868017 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java @@ -12,7 +12,6 @@ import static org.junit.jupiter.api.Assertions.*; - public class ListEndpointTest { private static final TestResourcesManager indexManager = TestResourcesManager.getInstance(); private static Index indexConnection; @@ -70,13 +69,6 @@ public void testSyncListEndpoint() throws InterruptedException { listResponseWithPaginationNoPrefix1.getPagination().getNext() ); assertEquals(listResponseWithPaginationNoPrefix2.getVectorsList().size(), 2); - ListResponse listResponseWithPaginationNoPrefix3 = indexConnection.list( - customNamespace, - 2, - listResponseWithPaginationNoPrefix2.getPagination().getNext() - ); - assertEquals(listResponseWithPaginationNoPrefix3.getVectorsList().size(), 0); - assertEquals(listResponseWithPaginationNoPrefix3.getPagination().getNext(), ""); } @Test @@ -122,14 +114,5 @@ public void testAsyncListEndpoint() throws InterruptedException { ); ListResponse asyncListResponseWithPaginationNoPrefix2 = Futures.getUnchecked(futureResponseWithPaginationNoPrefix2); assertEquals(asyncListResponseWithPaginationNoPrefix2.getVectorsList().size(), 2); - ListenableFuture futureResponseWithPaginationNoPrefix3 = asyncIndexConnection.list( - customNamespace, - 2, - asyncListResponseWithPaginationNoPrefix2.getPagination().getNext() - ); - ListResponse asyncListResponseWithPaginationNoPrefix3 = Futures.getUnchecked(futureResponseWithPaginationNoPrefix3); - assertEquals(asyncListResponseWithPaginationNoPrefix3.getVectorsList().size(), 0); - assertEquals(asyncListResponseWithPaginationNoPrefix3.getPagination().getNext(), ""); } - } diff --git a/src/main/java/io/pinecone/clients/Pinecone.java b/src/main/java/io/pinecone/clients/Pinecone.java index 3d2a9628..ddbbdf25 100644 --- a/src/main/java/io/pinecone/clients/Pinecone.java +++ b/src/main/java/io/pinecone/clients/Pinecone.java @@ -154,7 +154,7 @@ public IndexModel createServerlessIndex(String indexName, */ public IndexModel createPodsIndex(String indexName, Integer dimension, String environment, String podType) { return createPodsIndex(indexName, dimension, environment, podType, null, null, null, - null, null, null, DeletionProtection.DISABLED); + null, null, null, DeletionProtection.DISABLED, null); } /** @@ -179,7 +179,7 @@ public IndexModel createPodsIndex(String indexName, String podType, DeletionProtection deletionProtection) { return createPodsIndex(indexName, dimension, environment, podType, null, null, null, - null, null, null, deletionProtection); + null, null, null, deletionProtection, null); } /** @@ -201,7 +201,7 @@ public IndexModel createPodsIndex(String indexName, public IndexModel createPodsIndex(String indexName, Integer dimension, String environment, String podType, String metric) { return createPodsIndex(indexName, dimension, environment, podType, metric, null, null, - null, null, null, DeletionProtection.DISABLED); + null, null, null, DeletionProtection.DISABLED, null); } /** @@ -232,7 +232,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en public IndexModel createPodsIndex(String indexName, Integer dimension, String environment, String podType, String metric, PodSpecMetadataConfig metadataConfig) { return createPodsIndex(indexName, dimension, environment, podType, metric, null, null, null, - metadataConfig,null, DeletionProtection.DISABLED); + metadataConfig,null, DeletionProtection.DISABLED, null); } /** @@ -255,7 +255,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en public IndexModel createPodsIndex(String indexName, Integer dimension, String environment, String podType, String metric, String sourceCollection) { return createPodsIndex(indexName, dimension, environment, podType, metric, null, null, null, null, - sourceCollection, DeletionProtection.DISABLED); + sourceCollection, DeletionProtection.DISABLED, null); } /** @@ -277,7 +277,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en public IndexModel createPodsIndex(String indexName, Integer dimension, String environment, String podType, Integer pods) { return createPodsIndex(indexName, dimension, environment, podType, null, null, null, pods, - null, null, DeletionProtection.DISABLED); + null, null, DeletionProtection.DISABLED, null); } /** @@ -306,7 +306,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en String podType, Integer pods, PodSpecMetadataConfig metadataConfig) { return createPodsIndex(indexName, dimension, environment, podType, null, null, null, pods, metadataConfig, - null, DeletionProtection.DISABLED); + null, DeletionProtection.DISABLED, null); } /** @@ -330,7 +330,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en String podType, Integer replicas, Integer shards) { return createPodsIndex(indexName, dimension, environment, podType, null, replicas, shards, null, - null, null, DeletionProtection.DISABLED); + null, null, DeletionProtection.DISABLED, null); } /** @@ -362,7 +362,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en return createPodsIndex(indexName, dimension, environment, podType, null, replicas, shards, null, metadataConfig, - null, DeletionProtection.DISABLED); + null, DeletionProtection.DISABLED, null); } /** @@ -394,11 +394,18 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en * @return {@link IndexModel} representing the created serverless index. * @throws PineconeException if the API encounters an error during index creation or if any of the arguments are invalid. */ - public IndexModel createPodsIndex(String indexName, Integer dimension, String environment, - String podType, String metric, - Integer replicas, Integer shards, Integer pods, - PodSpecMetadataConfig metadataConfig, String sourceCollection, - DeletionProtection deletionProtection) throws PineconeException { + public IndexModel createPodsIndex(String indexName, + Integer dimension, + String environment, + String podType, + String metric, + Integer replicas, + Integer shards, + Integer pods, + PodSpecMetadataConfig metadataConfig, + String sourceCollection, + DeletionProtection deletionProtection, + Map tags) throws PineconeException { validatePodIndexParams(indexName, dimension, environment, podType, metric, replicas, shards, pods); PodSpec podSpec = new PodSpec().environment(environment) @@ -416,6 +423,10 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en .spec(createIndexRequestSpec) .deletionProtection(deletionProtection); + if (tags != null && !tags.isEmpty()) { + createIndexRequest.tags(tags); + } + IndexModel indexModel = null; try { indexModel = manageIndexesApi.createIndex(createIndexRequest); @@ -425,7 +436,6 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en return indexModel; } - public static void validatePodIndexParams(String indexName, Integer dimension, String environment, String podType, String metric, Integer replicas, Integer shards, Integer pods) { diff --git a/src/test/java/io/pinecone/PineconeIndexOperationsTest.java b/src/test/java/io/pinecone/PineconeIndexOperationsTest.java index 7c224f6e..cf23a15f 100644 --- a/src/test/java/io/pinecone/PineconeIndexOperationsTest.java +++ b/src/test/java/io/pinecone/PineconeIndexOperationsTest.java @@ -146,7 +146,8 @@ public void testCreatePodsIndex() throws IOException { 2, new PodSpecMetadataConfig(), "some-source-collection", - DeletionProtection.DISABLED); + DeletionProtection.DISABLED, + null); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(Request.class); From 54f98904c833e14d9fd209dfce82542d278214fc Mon Sep 17 00:00:00 2001 From: rohanshah18 Date: Wed, 8 Jan 2025 17:43:17 -0500 Subject: [PATCH 3/5] add index tags for configurePodIndex() --- .../java/io/pinecone/clients/Pinecone.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/pinecone/clients/Pinecone.java b/src/main/java/io/pinecone/clients/Pinecone.java index ddbbdf25..7642d3ba 100644 --- a/src/main/java/io/pinecone/clients/Pinecone.java +++ b/src/main/java/io/pinecone/clients/Pinecone.java @@ -391,6 +391,7 @@ public IndexModel createPodsIndex(String indexName, Integer dimension, String en * when metadataConfig is present, only specified metadata fields are indexed. * @param sourceCollection The name of the collection to be used as the source for the index. Collections are snapshots of an index at a point in time. * @param deletionProtection Enable or disable deletion protection for the index. + * @param tags A map of tags to associate with the Index. * @return {@link IndexModel} representing the created serverless index. * @throws PineconeException if the API encounters an error during index creation or if any of the arguments are invalid. */ @@ -525,10 +526,15 @@ public IndexModel describeIndex(String indexName) throws PineconeException { * @param podType The new podType for the index. Can be null if not changing the pod type. * @param replicas The desired number of replicas for the index, lowest value is 0. Can be null if not changing the number of replicas. * @param deletionProtection Enable or disable deletion protection for the index. + * @param tags A map of tags to associate with the Index. * @return {@link IndexModel} representing the configured index. * @throws PineconeException if an error occurs during the operation, the index does not exist, or if any of the arguments are invalid. */ - public IndexModel configurePodsIndex(String indexName, String podType, Integer replicas, DeletionProtection deletionProtection) throws PineconeException { + public IndexModel configurePodsIndex(String indexName, + String podType, + Integer replicas, + DeletionProtection deletionProtection, + Map tags) throws PineconeException { if (indexName == null || indexName.isEmpty()) { throw new PineconeValidationException("indexName cannot be null or empty"); } @@ -549,6 +555,10 @@ public IndexModel configurePodsIndex(String indexName, String podType, Integer r ) ).deletionProtection(deletionProtection); + if(tags != null && !tags.isEmpty()) { + configureIndexRequest.tags(tags); + } + IndexModel indexModel = null; try { indexModel = manageIndexesApi.configureIndex(indexName, configureIndexRequest); @@ -576,7 +586,7 @@ public IndexModel configurePodsIndex(String indexName, String podType, Integer r * @throws PineconeException if an error occurs during the operation, the index does not exist, or if the number of replicas is invalid. */ public IndexModel configurePodsIndex(String indexName, Integer replicas, DeletionProtection deletionProtection) throws PineconeException { - return configurePodsIndex(indexName, null, replicas, deletionProtection); + return configurePodsIndex(indexName, null, replicas, deletionProtection, null); } /** @@ -597,7 +607,7 @@ public IndexModel configurePodsIndex(String indexName, Integer replicas, Deletio */ public IndexModel configurePodsIndex(String indexName, String podType) throws PineconeException { DeletionProtection deletionProtection = describeIndex(indexName).getDeletionProtection(); - return configurePodsIndex(indexName, podType, null, deletionProtection); + return configurePodsIndex(indexName, podType, null, deletionProtection, null); } /** @@ -617,7 +627,7 @@ public IndexModel configurePodsIndex(String indexName, String podType) throws Pi * @throws PineconeException if an error occurs during the operation, the index does not exist, or if the podType is invalid. */ public IndexModel configurePodsIndex(String indexName, DeletionProtection deletionProtection) throws PineconeException { - return configurePodsIndex(indexName, null, null, deletionProtection); + return configurePodsIndex(indexName, null, null, deletionProtection, null); } /** @@ -637,6 +647,7 @@ public IndexModel configurePodsIndex(String indexName, DeletionProtection deleti * * @param indexName The name of the index to configure. * @param deletionProtection Enable or disable deletion protection for the index. + * @param tags A map of tags to associate with the Index. * @return {@link IndexModel} representing the configured index. * @throws PineconeException if an error occurs during the operation, the index does not exist, or if any of the arguments are invalid. */ @@ -647,8 +658,11 @@ public IndexModel configureServerlessIndex(String indexName, DeletionProtection // Build ConfigureIndexRequest object ConfigureIndexRequest configureIndexRequest = new ConfigureIndexRequest() - .deletionProtection(deletionProtection) - .tags(tags); + .deletionProtection(deletionProtection); + + if(tags != null && !tags.isEmpty()) { + configureIndexRequest.tags(tags); + } IndexModel indexModel = null; try { From 5bde9ddfaf9804ac986571785b7e6b3f4a1d2d45 Mon Sep 17 00:00:00 2001 From: rohanshah18 Date: Thu, 9 Jan 2025 10:51:30 -0500 Subject: [PATCH 4/5] update readme --- README.md | 11 +++++++++-- .../io/pinecone/helpers/TestResourcesManager.java | 1 - 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b9cffc01..5c33f801 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ serverless and regional availability, see [Understanding indexes](https://docs.p import io.pinecone.clients.Pinecone; import org.openapitools.db_control.client.model.IndexModel; import org.openapitools.db_control.client.model.DeletionProtection; +import java.util.HashMap; ... Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build(); @@ -180,8 +181,10 @@ String similarityMetric = "cosine"; int dimension = 1538; String cloud = "aws"; String region = "us-west-2"; +HashMap tags = new HashMap<>(); +tags.put("env", "test"); -IndexModel indexModel = pinecone.createServerlessIndex(indexName, similarityMetric, dimension, cloud, region, DeletionProtection.ENABLED); +IndexModel indexModel = pinecone.createServerlessIndex(indexName, similarityMetric, dimension, cloud, region, DeletionProtection.ENABLED, tags); ``` ### Create a pod index @@ -309,12 +312,16 @@ The following example enables deletion protection for a serverless index. ```java import io.pinecone.clients.Pinecone; import org.openapitools.db_control.client.model.DeletionProtection; +import java.util.HashMap; ... Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build(); String indexName = "example-index"; -pinecone.configureServerlessIndex(indexName, DeletionProtection.ENABLED); +HashMap tags = new HashMap<>(); +tags.put("env", "test"); + +pinecone.configureServerlessIndex(indexName, DeletionProtection.ENABLED, tags); ``` ## Describe index statistics diff --git a/src/integration/java/io/pinecone/helpers/TestResourcesManager.java b/src/integration/java/io/pinecone/helpers/TestResourcesManager.java index 8406a412..e5079d3a 100644 --- a/src/integration/java/io/pinecone/helpers/TestResourcesManager.java +++ b/src/integration/java/io/pinecone/helpers/TestResourcesManager.java @@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; From d45381b9d6d116f04c1308a6eb4d56f6ad164b06 Mon Sep 17 00:00:00 2001 From: rohanshah18 Date: Fri, 10 Jan 2025 11:47:14 -0500 Subject: [PATCH 5/5] clean up createServerlessIndex() and address code review comments --- .../serverless/DeletionProtectionTest.java | 21 ++++++++++++------- .../java/io/pinecone/clients/Pinecone.java | 11 +++++++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java index 98002705..dbabbb22 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/serverless/DeletionProtectionTest.java @@ -8,6 +8,7 @@ import org.openapitools.db_control.client.model.IndexModel; import java.util.HashMap; +import java.util.Map; public class DeletionProtectionTest { private static final Pinecone controlPlaneClient = new Pinecone @@ -18,33 +19,37 @@ public class DeletionProtectionTest { @Test public void createIndexWithDeletionProtectionEnabled() { String indexName = RandomStringBuilder.build("create-serv", 8); - HashMap tags = new HashMap<>(); - tags.put("test", "deletion-protection-enabled"); + HashMap expectedTags = new HashMap<>(); + expectedTags.put("test", "deletion-protection-enabled"); // Create serverless index with deletion protection enabled - controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.ENABLED, tags); + controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.ENABLED, expectedTags); // Describe index to verify deletion protection is enabled IndexModel indexModel = controlPlaneClient.describeIndex(indexName); DeletionProtection deletionProtection = indexModel.getDeletionProtection(); Assertions.assertEquals(deletionProtection, DeletionProtection.ENABLED); + Map actualTags = indexModel.getTags(); + Assertions.assertEquals(expectedTags, actualTags); } @Test public void createPodIndexWithDeletionProtectionDisabled() { String indexName = RandomStringBuilder.build("create-pod", 8); - HashMap tags = new HashMap<>(); - tags.put("test", "deletion-protection-disabled"); + HashMap expectedTags = new HashMap<>(); + expectedTags.put("test", "deletion-protection-disabled"); // Create serverless index with deletion protection disabled - controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, tags); + controlPlaneClient.createServerlessIndex(indexName, "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED, expectedTags); IndexModel indexModel = controlPlaneClient.describeIndex(indexName); DeletionProtection deletionProtection = indexModel.getDeletionProtection(); Assertions.assertEquals(deletionProtection, DeletionProtection.DISABLED); + Map actualTags = indexModel.getTags(); + Assertions.assertEquals(expectedTags, actualTags); // Configure index to enable deletionProtection - controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.ENABLED, tags); + controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.ENABLED, expectedTags); indexModel = controlPlaneClient.describeIndex(indexName); deletionProtection = indexModel.getDeletionProtection(); Assertions.assertEquals(deletionProtection, DeletionProtection.ENABLED); // Configure index to disable deletionProtection - controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.DISABLED, tags); + controlPlaneClient.configureServerlessIndex(indexName, DeletionProtection.DISABLED, expectedTags); // Delete index controlPlaneClient.deleteIndex(indexName); } diff --git a/src/main/java/io/pinecone/clients/Pinecone.java b/src/main/java/io/pinecone/clients/Pinecone.java index 7642d3ba..7e4e7117 100644 --- a/src/main/java/io/pinecone/clients/Pinecone.java +++ b/src/main/java/io/pinecone/clients/Pinecone.java @@ -124,13 +124,18 @@ public IndexModel createServerlessIndex(String indexName, IndexModel indexModel = null; try { - indexModel = manageIndexesApi.createIndex(new CreateIndexRequest() + CreateIndexRequest createIndexRequest = new CreateIndexRequest() .name(indexName) .metric(userMetric) .dimension(dimension) .spec(createServerlessIndexRequestSpec) - .deletionProtection(deletionProtection)) - .tags(tags); + .deletionProtection(deletionProtection); + + if(tags != null && !tags.isEmpty()) { + createIndexRequest.tags(tags); + } + + indexModel = manageIndexesApi.createIndex(createIndexRequest); } catch (ApiException apiException) { handleApiException(apiException); }