Skip to content

Commit 2121660

Browse files
tazarovclaude
andcommitted
fix: update v2 API to use correct /api/v2 endpoints
- Update all v2 API endpoints from /api/v1 to /api/v2 - Update ChromaClient to use correct v2 paths for all operations - Fix Collection basePath to use full v2 path format - Update default tenant to default_tenant and database to default_database - Fix collections_count endpoint response parsing - Update tests to use ChromaDB 1.1.0 which supports v2 API - Add database creation in test setup as required by v2 API Co-Authored-By: Claude <[email protected]>
1 parent 2b3beac commit 2121660

Some content is hidden

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

44 files changed

+964
-694
lines changed

src/main/java/tech/amikos/chromadb/v2/model/AddRecordsRequest.java renamed to src/main/java/tech/amikos/chromadb/v2/AddRecordsRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.model;
1+
package tech.amikos.chromadb.v2;
22

33
import com.google.gson.annotations.SerializedName;
44

src/main/java/tech/amikos/chromadb/v2/auth/AuthProvider.java renamed to src/main/java/tech/amikos/chromadb/v2/AuthProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
package tech.amikos.chromadb.v2.auth;
1+
package tech.amikos.chromadb.v2;
22

33
import okhttp3.Request;
44

55
public interface AuthProvider {
66
Request.Builder authenticate(Request.Builder requestBuilder);
77

88
static AuthProvider none() {
9-
return new NoAuthProvider();
9+
return NoAuthProvider.INSTANCE;
1010
}
1111

1212
static AuthProvider token(String token) {

src/main/java/tech/amikos/chromadb/v2/auth/BasicAuthProvider.java renamed to src/main/java/tech/amikos/chromadb/v2/BasicAuthProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.auth;
1+
package tech.amikos.chromadb.v2;
22

33
import okhttp3.Credentials;
44
import okhttp3.Request;

src/main/java/tech/amikos/chromadb/v2/exception/ChromaBadRequestException.java renamed to src/main/java/tech/amikos/chromadb/v2/ChromaBadRequestException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.exception;
1+
package tech.amikos.chromadb.v2;
22

33
public class ChromaBadRequestException extends ChromaV2Exception {
44
public ChromaBadRequestException(String message) {
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
package tech.amikos.chromadb.v2;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.UUID;
7+
import java.util.stream.Collectors;
8+
9+
/**
10+
* Simplified ChromaDB client with single approach for configuration.
11+
* Follows radical simplicity principles: flat package, single client, builder-only patterns.
12+
*/
13+
public class ChromaClient {
14+
private final HttpClient httpClient;
15+
private final String defaultTenant;
16+
private final String defaultDatabase;
17+
18+
private ChromaClient(Builder builder) {
19+
this.httpClient = HttpClient.builder()
20+
.baseUrl(builder.baseUrl)
21+
.auth(builder.authProvider)
22+
.connectTimeout(builder.connectTimeout)
23+
.readTimeout(builder.readTimeout)
24+
.writeTimeout(builder.writeTimeout)
25+
.build();
26+
this.defaultTenant = builder.defaultTenant;
27+
this.defaultDatabase = builder.defaultDatabase;
28+
}
29+
30+
public static Builder builder() {
31+
return new Builder();
32+
}
33+
34+
// Heartbeat and version
35+
@SuppressWarnings("unchecked")
36+
public String heartbeat() {
37+
Map<String, Object> response = httpClient.get("/api/v2/heartbeat", Map.class);
38+
return response.get("nanosecond heartbeat").toString();
39+
}
40+
41+
public String version() {
42+
String response = httpClient.get("/api/v2/version", String.class);
43+
return response.replace("\"", "");
44+
}
45+
46+
public void reset() {
47+
httpClient.post("/api/v2/reset", null, Void.class);
48+
}
49+
50+
// Tenant operations
51+
public Tenant createTenant(String name) {
52+
Map<String, String> request = new HashMap<>();
53+
request.put("name", name);
54+
return httpClient.post("/api/v2/tenants", request, Tenant.class);
55+
}
56+
57+
public Tenant getTenant(String name) {
58+
return httpClient.get("/api/v2/tenants/" + name, Tenant.class);
59+
}
60+
61+
// Database operations
62+
public Database createDatabase(String name) {
63+
return createDatabase(defaultTenant, name);
64+
}
65+
66+
public Database createDatabase(String tenant, String name) {
67+
Map<String, String> request = new HashMap<>();
68+
request.put("name", name);
69+
return httpClient.post("/api/v2/tenants/" + tenant + "/databases", request, Database.class);
70+
}
71+
72+
public Database getDatabase(String name) {
73+
return getDatabase(defaultTenant, name);
74+
}
75+
76+
public Database getDatabase(String tenant, String name) {
77+
return httpClient.get("/api/v2/tenants/" + tenant + "/databases/" + name, Database.class);
78+
}
79+
80+
public List<Database> listDatabases() {
81+
return listDatabases(defaultTenant);
82+
}
83+
84+
@SuppressWarnings("unchecked")
85+
public List<Database> listDatabases(String tenant) {
86+
return httpClient.get("/api/v2/tenants/" + tenant + "/databases", List.class);
87+
}
88+
89+
public void deleteDatabase(String name) {
90+
deleteDatabase(defaultTenant, name);
91+
}
92+
93+
public void deleteDatabase(String tenant, String name) {
94+
httpClient.delete("/api/v2/tenants/" + tenant + "/databases/" + name, Void.class);
95+
}
96+
97+
// Collection operations - simplified overloads
98+
public Collection createCollection(String name) {
99+
return createCollection(defaultTenant, defaultDatabase, name, null);
100+
}
101+
102+
public Collection createCollection(String name, Map<String, Object> metadata) {
103+
CreateCollectionRequest request = new CreateCollectionRequest.Builder(name)
104+
.metadata(metadata)
105+
.build();
106+
return createCollectionWithRequest(defaultTenant, defaultDatabase, request);
107+
}
108+
109+
public Collection getCollection(String nameOrId) {
110+
return getCollection(defaultTenant, defaultDatabase, nameOrId);
111+
}
112+
113+
@SuppressWarnings("unchecked")
114+
public Collection getCollection(String tenant, String database, String nameOrId) {
115+
// Try as ID first
116+
try {
117+
UUID.fromString(nameOrId);
118+
CollectionModel model = httpClient.get(
119+
"/api/v2/tenants/" + tenant + "/databases/" + database + "/collections/" + nameOrId,
120+
CollectionModel.class
121+
);
122+
return new Collection(httpClient, model);
123+
} catch (IllegalArgumentException e) {
124+
// Not a UUID, try as name
125+
List<CollectionModel> collections = httpClient.get(
126+
"/api/v2/tenants/" + tenant + "/databases/" + database + "/collections?name=" + nameOrId,
127+
List.class
128+
);
129+
if (collections.isEmpty()) {
130+
throw new ChromaNotFoundException("Collection not found: " + nameOrId);
131+
}
132+
return new Collection(httpClient, collections.get(0));
133+
}
134+
}
135+
136+
public Collection getOrCreateCollection(String name) {
137+
return getOrCreateCollection(name, null);
138+
}
139+
140+
public Collection getOrCreateCollection(String name, Map<String, Object> metadata) {
141+
try {
142+
return getCollection(name);
143+
} catch (ChromaNotFoundException e) {
144+
return createCollection(name, metadata);
145+
}
146+
}
147+
148+
public List<Collection> listCollections() {
149+
return listCollections(defaultTenant, defaultDatabase);
150+
}
151+
152+
@SuppressWarnings("unchecked")
153+
public List<Collection> listCollections(String tenant, String database) {
154+
List<CollectionModel> models = httpClient.get(
155+
"/api/v2/tenants/" + tenant + "/databases/" + database + "/collections",
156+
List.class
157+
);
158+
return models.stream()
159+
.map(model -> new Collection(httpClient, model))
160+
.collect(Collectors.toList());
161+
}
162+
163+
public void deleteCollection(String nameOrId) {
164+
deleteCollection(defaultTenant, defaultDatabase, nameOrId);
165+
}
166+
167+
public void deleteCollection(String tenant, String database, String nameOrId) {
168+
Collection collection = getCollection(tenant, database, nameOrId);
169+
httpClient.delete("/api/v2/tenants/" + tenant + "/databases/" + database +
170+
"/collections/" + collection.getId(), Void.class);
171+
}
172+
173+
public int countCollections() {
174+
return countCollections(defaultTenant, defaultDatabase);
175+
}
176+
177+
public int countCollections(String tenant, String database) {
178+
Integer count = httpClient.get(
179+
"/api/v2/tenants/" + tenant + "/databases/" + database + "/collections_count",
180+
Integer.class
181+
);
182+
return count;
183+
}
184+
185+
// Private helpers
186+
private Collection createCollectionWithRequest(String tenant, String database, CreateCollectionRequest request) {
187+
CollectionModel model = httpClient.post(
188+
"/api/v2/tenants/" + tenant + "/databases/" + database + "/collections",
189+
request,
190+
CollectionModel.class
191+
);
192+
return new Collection(httpClient, model);
193+
}
194+
195+
private Collection createCollection(String tenant, String database, String name, Map<String, Object> metadata) {
196+
CreateCollectionRequest request = new CreateCollectionRequest.Builder(name)
197+
.metadata(metadata)
198+
.build();
199+
return createCollectionWithRequest(tenant, database, request);
200+
}
201+
202+
public static class Builder {
203+
private String baseUrl = "http://localhost:8000";
204+
private AuthProvider authProvider = NoAuthProvider.INSTANCE;
205+
private String defaultTenant = "default_tenant";
206+
private String defaultDatabase = "default_database";
207+
private int connectTimeout = 60;
208+
private int readTimeout = 60;
209+
private int writeTimeout = 60;
210+
211+
// Server mode configuration
212+
public Builder serverUrl(String url) {
213+
this.baseUrl = url;
214+
return this;
215+
}
216+
217+
// Cloud mode configuration (syntactic sugar)
218+
public Builder cloudUrl(String url) {
219+
this.baseUrl = url;
220+
return this;
221+
}
222+
223+
public Builder apiKey(String apiKey) {
224+
this.authProvider = new TokenAuthProvider(apiKey);
225+
return this;
226+
}
227+
228+
public Builder auth(AuthProvider authProvider) {
229+
this.authProvider = authProvider;
230+
return this;
231+
}
232+
233+
public Builder tenant(String tenant) {
234+
this.defaultTenant = tenant;
235+
return this;
236+
}
237+
238+
public Builder database(String database) {
239+
this.defaultDatabase = database;
240+
return this;
241+
}
242+
243+
public Builder connectTimeout(int seconds) {
244+
this.connectTimeout = seconds;
245+
return this;
246+
}
247+
248+
public Builder readTimeout(int seconds) {
249+
this.readTimeout = seconds;
250+
return this;
251+
}
252+
253+
public Builder writeTimeout(int seconds) {
254+
this.writeTimeout = seconds;
255+
return this;
256+
}
257+
258+
public ChromaClient build() {
259+
if (baseUrl == null) {
260+
throw new IllegalStateException("Base URL is required");
261+
}
262+
return new ChromaClient(this);
263+
}
264+
}
265+
}

src/main/java/tech/amikos/chromadb/v2/exception/ChromaNotFoundException.java renamed to src/main/java/tech/amikos/chromadb/v2/ChromaNotFoundException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.exception;
1+
package tech.amikos.chromadb.v2;
22

33
public class ChromaNotFoundException extends ChromaV2Exception {
44
public ChromaNotFoundException(String message) {

src/main/java/tech/amikos/chromadb/v2/exception/ChromaServerException.java renamed to src/main/java/tech/amikos/chromadb/v2/ChromaServerException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.exception;
1+
package tech.amikos.chromadb.v2;
22

33
public class ChromaServerException extends ChromaV2Exception {
44
public ChromaServerException(String message) {

src/main/java/tech/amikos/chromadb/v2/auth/ChromaTokenAuthProvider.java renamed to src/main/java/tech/amikos/chromadb/v2/ChromaTokenAuthProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.auth;
1+
package tech.amikos.chromadb.v2;
22

33
import okhttp3.Request;
44

src/main/java/tech/amikos/chromadb/v2/exception/ChromaUnauthorizedException.java renamed to src/main/java/tech/amikos/chromadb/v2/ChromaUnauthorizedException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.exception;
1+
package tech.amikos.chromadb.v2;
22

33
public class ChromaUnauthorizedException extends ChromaV2Exception {
44
public ChromaUnauthorizedException(String message) {

src/main/java/tech/amikos/chromadb/v2/exception/ChromaV2Exception.java renamed to src/main/java/tech/amikos/chromadb/v2/ChromaV2Exception.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tech.amikos.chromadb.v2.exception;
1+
package tech.amikos.chromadb.v2;
22

33
public class ChromaV2Exception extends RuntimeException {
44
private final int statusCode;

0 commit comments

Comments
 (0)