Context
Record operations are the core of the client. PR #80 had a good instinct with inner builders on Collection (.query().nResults(10).execute()), but we need to finalize the exact API shape with type safety and alignment with the Go client.
Requirements
Include Enum
public enum Include {
EMBEDDINGS("embeddings"),
DOCUMENTS("documents"),
METADATAS("metadatas"),
DISTANCES("distances"),
URIS("uris");
}
AddBuilder
collection.add()
.ids("id1", "id2") // varargs
.ids(List.of("id1", "id2")) // list form
.documents("doc1", "doc2") // varargs
.documents(List.of("doc1", "doc2")) // list form
.embeddings(vec1, vec2) // varargs of float[]
.embeddings(List.of(vec1, vec2)) // list form
.metadatas(meta1, meta2) // varargs of Map
.metadatas(List.of(meta1, meta2)) // list form
.uris("uri1", "uri2") // varargs
.execute(); // void, throws on error
Key: both varargs and List overloads for each field. IDs are required (validated at execute()).
QueryBuilder
QueryResult result = collection.query()
.queryTexts("machine learning") // varargs
.queryTexts(List.of("machine learning", "AI")) // list form
// OR
.queryEmbeddings(vec1) // varargs
.queryEmbeddings(List.of(vec1, vec2)) // list form
.nResults(10)
.where(Where.eq("type", "article"))
.whereDocument(WhereDocument.contains("tech"))
.include(Include.DOCUMENTS, Include.DISTANCES)
.execute(); // QueryResult
Validation: exactly one of queryTexts/queryEmbeddings must be set.
GetBuilder
GetResult result = collection.get()
.ids("id1", "id2") // optional
.where(Where.eq("status", "published")) // optional
.whereDocument(WhereDocument.contains("ML")) // optional
.include(Include.DOCUMENTS, Include.METADATAS)
.limit(100)
.offset(0)
.execute(); // GetResult
UpdateBuilder
collection.update()
.ids("id1", "id2") // required
.documents("updated doc1", "updated doc2") // optional
.embeddings(newVec1, newVec2) // optional
.metadatas(newMeta1, newMeta2) // optional
.execute(); // void
UpsertBuilder
Same shape as AddBuilder (ids + embeddings/documents/metadatas/uris), different endpoint.
DeleteBuilder
collection.delete()
.ids("id1", "id2") // optional
.where(Where.eq("status", "archived")) // optional
.whereDocument(WhereDocument.contains("OLD")) // optional
.execute(); // void
Validation: at least one of ids/where/whereDocument must be set.
Result Types
QueryResult
public interface QueryResult {
List<List<String>> getIds();
List<List<String>> getDocuments();
List<List<Map<String, Object>>> getMetadatas();
List<List<float[]>> getEmbeddings();
List<List<Float>> getDistances();
}
GetResult
public interface GetResult {
List<String> getIds();
List<String> getDocuments();
List<Map<String, Object>> getMetadatas();
List<float[]> getEmbeddings();
}
Design Decisions
- Varargs AND List overloads —
ids("a", "b") for inline, ids(myList) for dynamic
- Validation at
execute() time — not in setters, to allow any build order
- Builders are non-static inner classes of the Collection implementation (they need access to the HTTP client and base path)
- Builder interfaces are public (defined alongside Collection interface) — implementations are package-private
execute() is the terminal operation — returns the result or throws
Acceptance Criteria
Depends On
Supersedes
Context
Record operations are the core of the client. PR #80 had a good instinct with inner builders on Collection (
.query().nResults(10).execute()), but we need to finalize the exact API shape with type safety and alignment with the Go client.Requirements
Include Enum
AddBuilder
Key: both varargs and List overloads for each field. IDs are required (validated at
execute()).QueryBuilder
Validation: exactly one of queryTexts/queryEmbeddings must be set.
GetBuilder
UpdateBuilder
UpsertBuilder
Same shape as AddBuilder (ids + embeddings/documents/metadatas/uris), different endpoint.
DeleteBuilder
Validation: at least one of ids/where/whereDocument must be set.
Result Types
QueryResult
GetResult
Design Decisions
ids("a", "b")for inline,ids(myList)for dynamicexecute()time — not in setters, to allow any build orderexecute()is the terminal operation — returns the result or throwsAcceptance Criteria
Depends On
Supersedes