Skip to content

Commit cb00bc3

Browse files
authored
Generate code for 2025-04, automate ndjson handling, add backups, restore, and namespaces. (#183)
## Problem 1. Generate code for 2025-04 and automate ndjson handling. 2. Add support for backups and restore. 3. Add support for namespaces ## Solution 1. Generated code using the 2025-04 open api spec and added sed command to automate the process of handling ndjson which is currently not handled by the open api genearted code in ApiClient.java of data.yaml module. 2. Added support for backups and restore 3. Added support for namespaces ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [X] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [ ] None of the above: (explain here) ## Test Plan Integration tests were added for new features.
1 parent ee5d882 commit cb00bc3

File tree

217 files changed

+13913
-829
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

217 files changed

+13913
-829
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
[comment]: <> (When bumping [pc:VERSION_LATEST_RELEASE] create a new entry below)
44
### Unreleased version
5+
### 5.0.0
6+
- Add support for backups and restore
7+
- Add support for list, describe, and delete namespaces
8+
- Generate code based on 2025-04 api spec
9+
- Automate ndjson handling
10+
511
### 4.0.1
612
- Create a new config per index connection
713

README.md

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ Maven:
1515
<dependency>
1616
<groupId>io.pinecone</groupId>
1717
<artifactId>pinecone-client</artifactId>
18-
<version>4.0.0</version>
18+
<version>5.0.0</version>
1919
</dependency>
2020
```
2121

2222
[comment]: <> (^ [pc:VERSION_LATEST_RELEASE])
2323

2424
Gradle:
2525
```
26-
implementation "io.pinecone:pinecone-client:4.0.0"
26+
implementation "io.pinecone:pinecone-client:5.0.0"
2727
```
2828

2929
[comment]: <> (^ [pc:VERSION_LATEST_RELEASE])
3030

31-
Alternatively, you can use our standalone uberjar [pinecone-client-4.0.0-all.jar](https://repo1.maven.org/maven2/io/pinecone/pinecone-client/4.0.0/pinecone-client-4.0.0-all.jar), which bundles the Pinecone
31+
Alternatively, you can use our standalone uberjar [pinecone-client-5.0.0-all.jar](https://repo1.maven.org/maven2/io/pinecone/pinecone-client/5.0.0/pinecone-client-5.0.0-all.jar), which bundles the Pinecone
3232
SDK and all dependencies together. You can include this in your classpath like you do with any 3rd party JAR without
3333
having to obtain the *pinecone-client* dependencies separately.
3434

@@ -521,6 +521,74 @@ List<Float> values = Arrays.asList(1F, 2F, 3F);
521521
UpdateResponse updateResponse = index.update("v1", values, "example-namespace");
522522
```
523523

524+
## List namespaces
525+
526+
The following example shows various methods to list namespaces.
527+
528+
```java
529+
import io.pinecone.clients.AsyncIndex;
530+
import io.pinecone.clients.Index;
531+
import io.pinecone.clients.Pinecone;
532+
import io.pinecone.proto.ListNamespacesResponse;
533+
534+
import java.util.concurrent.ExecutionException;
535+
...
536+
537+
String indexName = "PINECONE_INDEX_NAME";
538+
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
539+
Index index = pinecone.getIndexConnection(indexName);
540+
541+
// list namespaces without pagination token and limit (if no limit is passed, it'll default to 100)
542+
ListNamespacesResponse listNamespacesResponse = index.listNamespaces();
543+
544+
// list namespaces with pagination token
545+
listNamespacesResponse = index.listNamespaces("some-pagination-token");
546+
547+
// list namespaces with pagination token and a custom limit of 5
548+
listNamespacesResponse = index.listNamespaces("some-pagination-token", 5);
549+
```
550+
551+
## Describe namespace
552+
553+
The following example shows how to describe a namespace.
554+
555+
```java
556+
import io.pinecone.clients.AsyncIndex;
557+
import io.pinecone.clients.Index;
558+
import io.pinecone.clients.Pinecone;
559+
import io.pinecone.proto.NamespaceDescription;
560+
561+
import java.util.concurrent.ExecutionException;
562+
...
563+
564+
String indexName = "PINECONE_INDEX_NAME";
565+
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
566+
Index index = pinecone.getIndexConnection(indexName);
567+
568+
// describe a namespace
569+
NamespaceDescription namespaceDescription = index.describeName("some-namespace");
570+
```
571+
572+
## Delete namespace
573+
574+
The following example shows how to describe a namespace.
575+
576+
```java
577+
import io.pinecone.clients.AsyncIndex;
578+
import io.pinecone.clients.Index;
579+
import io.pinecone.clients.Pinecone;
580+
581+
import java.util.concurrent.ExecutionException;
582+
...
583+
584+
String indexName = "PINECONE_INDEX_NAME";
585+
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
586+
Index index = pinecone.getIndexConnection(indexName);
587+
588+
// delete a namespace
589+
index.deleteName("some-namespace");
590+
```
591+
524592
# Collections
525593

526594
Collections fall under control plane operations.
@@ -766,6 +834,65 @@ AsyncIndex asyncIndex = pinecone.getAsyncIndexConnection("PINECONE_INDEX_NAME");
766834
// Cancel import
767835
asyncIndex.cancelImport("2");
768836
```
837+
# Backups and restore
838+
839+
The following example shows how to backup and restore from a serverless index.
840+
841+
```java
842+
import io.pinecone.clients.Pinecone;
843+
import org.openapitools.db_control.client.ApiException;
844+
import org.openapitools.db_control.client.model.*;
845+
846+
...
847+
848+
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
849+
850+
String indexName1 = "test-index-1";
851+
String indexName2 = "test-index-2";
852+
853+
// create a backup from index
854+
BackupModel backupModel1 = pinecone.createBackup(indexName1, "backup-id-1", "description-for-backup-1");
855+
System.out.println("backupModel1: " + backupModel1);
856+
857+
BackupModel backupModel2 = pinecone.createBackup(indexName2, "backup-id-2", "description-for-backup-2");
858+
System.out.println("backupModel2: " + backupModel2);
859+
860+
// list all backups for an index
861+
BackupList backupList = pinecone.listIndexBackups(indexName1);
862+
System.out.println("backupList for index1: " + backupList);
863+
864+
// list all backups for a project
865+
backupList = pinecone.listProjectBackups();
866+
System.out.println("backupList for project: " + backupList);
867+
868+
// describe backup
869+
backupModel1 = pinecone.describeBackup(backupModel1.getBackupId());
870+
System.out.println("describe backup for index1: " + backupModel1);
871+
872+
backupModel2 = pinecone.describeBackup(backupModel2.getBackupId());
873+
System.out.println("describe backup index2: " + backupModel2);
874+
875+
// delete backup
876+
pinecone.deleteBackup(backupModel1.getBackupId());
877+
878+
// wait for the backup to be ready
879+
Thread.sleep(10000);
880+
881+
// create index from a backup
882+
CreateIndexFromBackupResponse backupResponse = pinecone.createIndexFromBackup(backupModel1.getBackupId(), "test-index-3");
883+
System.out.println(backupResponse.getRestoreJobId());
884+
885+
// wait for index to be created
886+
Thread.sleep(5000);
887+
888+
// describeRestoreJob
889+
RestoreJobModel restoreJobModel = pinecone.describeRestoreJob(backupResponse.getRestoreJobId());
890+
System.out.println("restore model: " + restoreJobModel);
891+
892+
// listRestoreJobs
893+
RestoreJobList restoreJobList = pinecone.listRestoreJobs(2);
894+
System.out.println("restore job list: " + restoreJobList);
895+
```
769896

770897
## Examples
771898

codegen/apis

Submodule apis updated from 63e97dc to daf808c

codegen/buf.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ breaking:
99
deps:
1010
- buf.build/googleapis/googleapis
1111
modules:
12-
- path: apis/_build/2025-01
12+
- path: apis/_build/2025-04

codegen/build-grpc.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,8 @@ rm -rf "${dest}*.java"
4545
# Copy the new generated files to dest directory
4646
cp codegen/gen/java/io/pinecone/proto/*.java ${dest}
4747

48+
# Update version reference in PineconeConnection.java
49+
sed -i '' "s/[0-9][0-9][0-9][0-9]-[0-1][0-9]/${version}/g" src/main/java/io/pinecone/configs/PineconeConnection.java
50+
4851
# Cleanup the intermediate files that were generated
4952
rm -rf codegen/gen

codegen/build-oas.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,27 @@ generate_client() {
7474
find "${destination}/${module_name}" -name "*.java" | while IFS= read -r file; do
7575
sed -i '' "s/org\.openapitools\.client/org\.openapitools\.${module_name}\.client/g" "$file"
7676
done
77+
78+
# Add NDJSON block to ApiClient.java in the db_data module
79+
if [ "$module_name" == "db_data" ]; then
80+
echo "Adding NDJSON handler block to ApiClient.java"
81+
82+
# Use sed to insert the NDJSON block into ApiClient.java
83+
sed -i '' '/return RequestBody.create((File) obj, MediaType.parse(contentType));/a \
84+
} else if ("application/x-ndjson".equals(contentType)) { \
85+
// Handle NDJSON (Newline Delimited JSON) \
86+
if (obj instanceof Iterable) { \
87+
StringBuilder ndjsonContent = new StringBuilder(); \
88+
for (Object item : (Iterable<?>) obj) { \
89+
String json = JSON.serialize(item); \
90+
ndjsonContent.append(json).append("\\n"); \
91+
} \
92+
return RequestBody.create(ndjsonContent.toString(), MediaType.parse(contentType)); \
93+
} else { \
94+
throw new ApiException("NDJSON content requires a collection of objects."); \
95+
} \
96+
' src/main/java/org/openapitools/db_data/client/ApiClient.java
97+
fi
7798
}
7899

79100
update_apis_repo

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pineconeClientVersion = 4.0.1
1+
pineconeClientVersion = 5.0.0
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package io.pinecone.integration.dataPlane;
2+
3+
import io.pinecone.clients.AsyncIndex;
4+
import io.pinecone.clients.Index;
5+
import io.pinecone.helpers.RandomStringBuilder;
6+
import io.pinecone.helpers.TestResourcesManager;
7+
import io.pinecone.proto.ListNamespacesResponse;
8+
import org.junit.jupiter.api.AfterAll;
9+
import org.junit.jupiter.api.Test;
10+
11+
import java.util.concurrent.ExecutionException;
12+
13+
import static io.pinecone.helpers.BuildUpsertRequest.generateVectorValuesByDimension;
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
16+
public class NamespacesTest {
17+
private static final TestResourcesManager indexManager = TestResourcesManager.getInstance();
18+
private static Index index;
19+
private static AsyncIndex asyncIndex;
20+
private static final int dimension = indexManager.getDimension();
21+
22+
@AfterAll
23+
public static void cleanUp() {
24+
index.close();
25+
asyncIndex.close();
26+
}
27+
28+
@Test
29+
public void namespacesSyncTest() throws InterruptedException {
30+
String[] namespaces = new String[3];
31+
index = indexManager.getOrCreateServerlessIndexConnection();
32+
ListNamespacesResponse listNamespacesResponse = index.listNamespaces();
33+
int namespaceCount = listNamespacesResponse.getNamespacesCount();
34+
35+
for(int i=0; i<3; i++) {
36+
namespaces[i] = RandomStringBuilder.build("namespace-", 3);
37+
index.upsert("v"+i, generateVectorValuesByDimension(dimension), namespaces[i]);
38+
}
39+
40+
// wait for vectors to be upserted
41+
Thread.sleep(5000);
42+
listNamespacesResponse = index.listNamespaces();
43+
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 3);
44+
45+
index.describeNamespace(namespaces[0]);
46+
index.deleteNamespace(namespaces[0]);
47+
48+
// wait for namespace to be deleted
49+
Thread.sleep(3000);
50+
listNamespacesResponse = index.listNamespaces();
51+
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 2);
52+
}
53+
54+
@Test
55+
public void namespacesAsyncTest() throws InterruptedException, ExecutionException {
56+
String[] namespaces = new String[3];
57+
asyncIndex = indexManager.getOrCreateServerlessAsyncIndexConnection();
58+
59+
ListNamespacesResponse listNamespacesResponse = asyncIndex.listNamespaces().get();
60+
int namespaceCount = listNamespacesResponse.getNamespacesCount();
61+
62+
for(int i=0; i<3; i++) {
63+
namespaces[i] = RandomStringBuilder.build("namespace-", 3);
64+
asyncIndex.upsert("v"+i, generateVectorValuesByDimension(dimension), namespaces[i]);
65+
}
66+
67+
// wait for vectors to be upserted
68+
Thread.sleep(5000);
69+
listNamespacesResponse = asyncIndex.listNamespaces().get();
70+
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 3);
71+
72+
asyncIndex.describeNamespace(namespaces[0]);
73+
asyncIndex.deleteNamespace(namespaces[0]);
74+
75+
// wait for namespace to be deleted
76+
Thread.sleep(3000);
77+
listNamespacesResponse = asyncIndex.listNamespaces().get();
78+
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 2);
79+
}
80+
}

0 commit comments

Comments
 (0)