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+ }
0 commit comments