@functional-systems/lambdadb 0.3.0-dev.2 → 0.3.0-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -13
- package/dist/commonjs/client.d.ts +108 -18
- package/dist/commonjs/client.d.ts.map +1 -1
- package/dist/commonjs/client.js +220 -2
- package/dist/commonjs/client.js.map +1 -1
- package/dist/commonjs/index.d.ts +16 -1
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +10 -2
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/lib/queryInput.d.ts +30 -0
- package/dist/commonjs/lib/queryInput.d.ts.map +1 -0
- package/dist/commonjs/lib/queryInput.js +18 -0
- package/dist/commonjs/lib/queryInput.js.map +1 -0
- package/dist/commonjs/types/errors.d.ts +34 -0
- package/dist/commonjs/types/errors.d.ts.map +1 -0
- package/dist/commonjs/types/errors.js +27 -0
- package/dist/commonjs/types/errors.js.map +1 -0
- package/dist/commonjs/types/public.d.ts +26 -0
- package/dist/commonjs/types/public.d.ts.map +1 -0
- package/dist/commonjs/types/public.js +7 -0
- package/dist/commonjs/types/public.js.map +1 -0
- package/dist/esm/client.d.ts +108 -18
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +221 -3
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +16 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +6 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/queryInput.d.ts +30 -0
- package/dist/esm/lib/queryInput.d.ts.map +1 -0
- package/dist/esm/lib/queryInput.js +15 -0
- package/dist/esm/lib/queryInput.js.map +1 -0
- package/dist/esm/types/errors.d.ts +34 -0
- package/dist/esm/types/errors.d.ts.map +1 -0
- package/dist/esm/types/errors.js +8 -0
- package/dist/esm/types/errors.js.map +1 -0
- package/dist/esm/types/public.d.ts +26 -0
- package/dist/esm/types/public.d.ts.map +1 -0
- package/dist/esm/types/public.js +6 -0
- package/dist/esm/types/public.js.map +1 -0
- package/examples/collectionScoped.example.ts +9 -3
- package/examples/collectionsList.example.ts +5 -2
- package/package.json +1 -1
- package/src/client.ts +410 -19
- package/src/index.ts +25 -1
- package/src/lib/queryInput.ts +33 -0
- package/src/types/errors.ts +97 -0
- package/src/types/public.ts +45 -0
package/src/client.ts
CHANGED
|
@@ -26,15 +26,73 @@ import { collectionsDocsListDocs } from "./funcs/collectionsDocsListDocs.js";
|
|
|
26
26
|
import { collectionsDocsUpdate } from "./funcs/collectionsDocsUpdate.js";
|
|
27
27
|
import { collectionsDocsUpsert } from "./funcs/collectionsDocsUpsert.js";
|
|
28
28
|
import type { RequestOptions } from "./lib/sdks.js";
|
|
29
|
+
import { unwrapAsync, OK, ERR } from "./types/fp.js";
|
|
30
|
+
import type { Result } from "./types/fp.js";
|
|
29
31
|
import type * as operations from "./models/operations/index.js";
|
|
30
32
|
import type * as models from "./models/index.js";
|
|
31
|
-
import {
|
|
33
|
+
import type {
|
|
34
|
+
CreateCollectionInput,
|
|
35
|
+
UpdateCollectionInput,
|
|
36
|
+
QueryCollectionInput,
|
|
37
|
+
QueryCollectionResponse,
|
|
38
|
+
QueryCollectionDoc,
|
|
39
|
+
ListDocsInput,
|
|
40
|
+
ListDocsResponse,
|
|
41
|
+
UpsertDocsInput,
|
|
42
|
+
UpdateDocsInput,
|
|
43
|
+
DeleteDocsInput,
|
|
44
|
+
FetchDocsInput,
|
|
45
|
+
FetchDocsResponse,
|
|
46
|
+
FetchDocsDoc,
|
|
47
|
+
BulkUpsertInput,
|
|
48
|
+
MessageResponse,
|
|
49
|
+
ListCollectionsResponse,
|
|
50
|
+
CreateCollectionResponse,
|
|
51
|
+
GetCollectionResponse,
|
|
52
|
+
UpdateCollectionResponse,
|
|
53
|
+
GetBulkUpsertDocsResponse,
|
|
54
|
+
} from "./types/public.js";
|
|
55
|
+
import type {
|
|
56
|
+
ListCollectionsError,
|
|
57
|
+
CreateCollectionError,
|
|
58
|
+
GetCollectionError,
|
|
59
|
+
UpdateCollectionError,
|
|
60
|
+
DeleteCollectionError,
|
|
61
|
+
QueryCollectionError,
|
|
62
|
+
ListDocsError,
|
|
63
|
+
UpsertDocsError,
|
|
64
|
+
UpdateDocsError,
|
|
65
|
+
DeleteDocsError,
|
|
66
|
+
FetchDocsError,
|
|
67
|
+
GetBulkUpsertDocsError,
|
|
68
|
+
BulkUpsertDocsError,
|
|
69
|
+
} from "./types/errors.js";
|
|
32
70
|
|
|
33
71
|
export type { RequestOptions };
|
|
34
72
|
|
|
35
|
-
// Re-export
|
|
73
|
+
// Re-export public API types (request-body–level inputs and method return types)
|
|
74
|
+
export type * from "./types/public.js";
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @deprecated Use types from the package root (e.g. CreateCollectionInput, QueryCollectionResponse, ListDocsInput). Will be removed in the next major version.
|
|
78
|
+
*/
|
|
36
79
|
export type { operations, models };
|
|
37
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Fetches documents from a presigned docsUrl. Response must be { docs: [...] }.
|
|
83
|
+
*/
|
|
84
|
+
async function fetchDocsFromUrl<T>(docsUrl: string): Promise<T[]> {
|
|
85
|
+
const res = await fetch(docsUrl);
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
const text = await res.text();
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Failed to fetch documents from URL: ${res.status} ${res.statusText}${text ? ` - ${text}` : ""}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const json = (await res.json()) as { docs?: T[] };
|
|
93
|
+
return json.docs ?? [];
|
|
94
|
+
}
|
|
95
|
+
|
|
38
96
|
/** Default base URL for the LambdaDB API. */
|
|
39
97
|
export const DEFAULT_BASE_URL = "https://api.lambdadb.ai";
|
|
40
98
|
/** Default project name when not specified. */
|
|
@@ -103,15 +161,34 @@ export class LambdaDBClient extends LambdaDBCore {
|
|
|
103
161
|
return unwrapAsync(collectionsList(this, options));
|
|
104
162
|
}
|
|
105
163
|
|
|
164
|
+
/**
|
|
165
|
+
* List all collections (Safe: returns Result instead of throwing).
|
|
166
|
+
*/
|
|
167
|
+
async listCollectionsSafe(
|
|
168
|
+
options?: RequestOptions,
|
|
169
|
+
): Promise<Result<ListCollectionsResponse, ListCollectionsError>> {
|
|
170
|
+
return await collectionsList(this, options);
|
|
171
|
+
}
|
|
172
|
+
|
|
106
173
|
/**
|
|
107
174
|
* Create a new collection.
|
|
108
175
|
*/
|
|
109
176
|
async createCollection(
|
|
110
|
-
request:
|
|
177
|
+
request: CreateCollectionInput,
|
|
111
178
|
options?: RequestOptions,
|
|
112
179
|
) {
|
|
113
180
|
return unwrapAsync(collectionsCreate(this, request, options));
|
|
114
181
|
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Create a new collection (Safe: returns Result instead of throwing).
|
|
185
|
+
*/
|
|
186
|
+
async createCollectionSafe(
|
|
187
|
+
request: CreateCollectionInput,
|
|
188
|
+
options?: RequestOptions,
|
|
189
|
+
): Promise<Result<CreateCollectionResponse, CreateCollectionError>> {
|
|
190
|
+
return await collectionsCreate(this, request, options);
|
|
191
|
+
}
|
|
115
192
|
}
|
|
116
193
|
|
|
117
194
|
/**
|
|
@@ -132,11 +209,20 @@ export class CollectionHandle {
|
|
|
132
209
|
);
|
|
133
210
|
}
|
|
134
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Get metadata of this collection (Safe: returns Result instead of throwing).
|
|
214
|
+
*/
|
|
215
|
+
async getSafe(
|
|
216
|
+
options?: RequestOptions,
|
|
217
|
+
): Promise<Result<GetCollectionResponse, GetCollectionError>> {
|
|
218
|
+
return await collectionsGet(this.client, { collectionName: this.collectionName }, options);
|
|
219
|
+
}
|
|
220
|
+
|
|
135
221
|
/**
|
|
136
222
|
* Configure (update) this collection.
|
|
137
223
|
*/
|
|
138
224
|
async update(
|
|
139
|
-
requestBody:
|
|
225
|
+
requestBody: UpdateCollectionInput,
|
|
140
226
|
options?: RequestOptions,
|
|
141
227
|
) {
|
|
142
228
|
return unwrapAsync(
|
|
@@ -151,6 +237,20 @@ export class CollectionHandle {
|
|
|
151
237
|
);
|
|
152
238
|
}
|
|
153
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Configure (update) this collection (Safe: returns Result instead of throwing).
|
|
242
|
+
*/
|
|
243
|
+
async updateSafe(
|
|
244
|
+
requestBody: UpdateCollectionInput,
|
|
245
|
+
options?: RequestOptions,
|
|
246
|
+
): Promise<Result<UpdateCollectionResponse, UpdateCollectionError>> {
|
|
247
|
+
return await collectionsUpdate(
|
|
248
|
+
this.client,
|
|
249
|
+
{ collectionName: this.collectionName, requestBody },
|
|
250
|
+
options,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
154
254
|
/**
|
|
155
255
|
* Delete this collection.
|
|
156
256
|
*/
|
|
@@ -164,14 +264,29 @@ export class CollectionHandle {
|
|
|
164
264
|
);
|
|
165
265
|
}
|
|
166
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Delete this collection (Safe: returns Result instead of throwing).
|
|
269
|
+
*/
|
|
270
|
+
async deleteSafe(
|
|
271
|
+
options?: RequestOptions,
|
|
272
|
+
): Promise<Result<MessageResponse, DeleteCollectionError>> {
|
|
273
|
+
return await collectionsDelete(
|
|
274
|
+
this.client,
|
|
275
|
+
{ collectionName: this.collectionName },
|
|
276
|
+
options,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
167
280
|
/**
|
|
168
281
|
* Search this collection with a query.
|
|
282
|
+
* When the API returns docs via docsUrl (isDocsInline false), documents are
|
|
283
|
+
* fetched from the presigned URL automatically so the response always has docs.
|
|
169
284
|
*/
|
|
170
285
|
async query(
|
|
171
|
-
requestBody:
|
|
286
|
+
requestBody: QueryCollectionInput,
|
|
172
287
|
options?: RequestOptions,
|
|
173
|
-
) {
|
|
174
|
-
|
|
288
|
+
): Promise<QueryCollectionResponse> {
|
|
289
|
+
const result = await unwrapAsync(
|
|
175
290
|
collectionsQuery(
|
|
176
291
|
this.client,
|
|
177
292
|
{
|
|
@@ -181,6 +296,38 @@ export class CollectionHandle {
|
|
|
181
296
|
options,
|
|
182
297
|
),
|
|
183
298
|
);
|
|
299
|
+
if (!result.isDocsInline && result.docsUrl) {
|
|
300
|
+
const docs = await fetchDocsFromUrl<QueryCollectionDoc>(
|
|
301
|
+
result.docsUrl,
|
|
302
|
+
);
|
|
303
|
+
return { ...result, docs, isDocsInline: true };
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Search this collection with a query (Safe: returns Result instead of throwing).
|
|
310
|
+
* When the API returns docs via docsUrl, documents are fetched from the presigned URL automatically.
|
|
311
|
+
*/
|
|
312
|
+
async querySafe(
|
|
313
|
+
requestBody: QueryCollectionInput,
|
|
314
|
+
options?: RequestOptions,
|
|
315
|
+
): Promise<Result<QueryCollectionResponse, QueryCollectionError>> {
|
|
316
|
+
const result = await collectionsQuery(
|
|
317
|
+
this.client,
|
|
318
|
+
{ collectionName: this.collectionName, requestBody },
|
|
319
|
+
options,
|
|
320
|
+
);
|
|
321
|
+
if (!result.ok) return result;
|
|
322
|
+
if (!result.value.isDocsInline && result.value.docsUrl) {
|
|
323
|
+
try {
|
|
324
|
+
const docs = await fetchDocsFromUrl<QueryCollectionDoc>(result.value.docsUrl);
|
|
325
|
+
return OK({ ...result.value, docs, isDocsInline: true });
|
|
326
|
+
} catch (e) {
|
|
327
|
+
return ERR(e as QueryCollectionError);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return result;
|
|
184
331
|
}
|
|
185
332
|
|
|
186
333
|
readonly docs: CollectionDocs = new CollectionDocs(this.client, this.collectionName);
|
|
@@ -199,7 +346,7 @@ class CollectionDocs {
|
|
|
199
346
|
* List documents in the collection.
|
|
200
347
|
*/
|
|
201
348
|
async list(
|
|
202
|
-
params?:
|
|
349
|
+
params?: ListDocsInput,
|
|
203
350
|
options?: RequestOptions,
|
|
204
351
|
) {
|
|
205
352
|
return unwrapAsync(
|
|
@@ -211,13 +358,72 @@ class CollectionDocs {
|
|
|
211
358
|
);
|
|
212
359
|
}
|
|
213
360
|
|
|
361
|
+
/**
|
|
362
|
+
* List documents in the collection (Safe: returns Result instead of throwing).
|
|
363
|
+
*/
|
|
364
|
+
async listSafe(
|
|
365
|
+
params?: ListDocsInput,
|
|
366
|
+
options?: RequestOptions,
|
|
367
|
+
): Promise<Result<ListDocsResponse, ListDocsError>> {
|
|
368
|
+
return await collectionsDocsListDocs(
|
|
369
|
+
this.client,
|
|
370
|
+
{ collectionName: this.collectionName, ...params },
|
|
371
|
+
options,
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Iterate over all pages of documents. Yields one page per API response (with docs and nextPageToken).
|
|
377
|
+
* Use this to process large result sets without loading everything into memory.
|
|
378
|
+
*
|
|
379
|
+
* Note: The API limits response size by payload, not by document count. The number of docs per page
|
|
380
|
+
* may be less than the requested `size` and can vary from page to page.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* for await (const page of collection.docs.listPages({ size: 50 })) {
|
|
384
|
+
* console.log(page.docs.length, page.nextPageToken ?? "last page");
|
|
385
|
+
* }
|
|
386
|
+
*/
|
|
387
|
+
async *listPages(
|
|
388
|
+
params?: ListDocsInput,
|
|
389
|
+
options?: RequestOptions,
|
|
390
|
+
): AsyncGenerator<ListDocsResponse> {
|
|
391
|
+
let pageToken: string | undefined = params?.pageToken;
|
|
392
|
+
const baseParams: ListDocsInput = { size: params?.size, pageToken };
|
|
393
|
+
while (true) {
|
|
394
|
+
const page = await this.list({ ...baseParams, pageToken }, options);
|
|
395
|
+
yield page;
|
|
396
|
+
pageToken = page.nextPageToken;
|
|
397
|
+
if (pageToken == null || pageToken === "") break;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Fetch all documents across pages and return a single list. Uses listPages internally.
|
|
403
|
+
* For large collections, prefer listPages() to avoid high memory use.
|
|
404
|
+
*
|
|
405
|
+
* Note: Page size is constrained by API payload limits, so the number of docs per page may vary.
|
|
406
|
+
*/
|
|
407
|
+
async listAll(
|
|
408
|
+
params?: ListDocsInput,
|
|
409
|
+
options?: RequestOptions,
|
|
410
|
+
): Promise<{ docs: Array<Record<string, unknown>>; total: number }> {
|
|
411
|
+
const docs: Array<Record<string, unknown>> = [];
|
|
412
|
+
let total = 0;
|
|
413
|
+
for await (const page of this.listPages(params, options)) {
|
|
414
|
+
docs.push(...page.docs);
|
|
415
|
+
total = page.total;
|
|
416
|
+
}
|
|
417
|
+
return { docs, total };
|
|
418
|
+
}
|
|
419
|
+
|
|
214
420
|
/**
|
|
215
421
|
* Upsert documents. Max payload 6MB.
|
|
216
422
|
*/
|
|
217
423
|
async upsert(
|
|
218
|
-
body:
|
|
424
|
+
body: UpsertDocsInput,
|
|
219
425
|
options?: RequestOptions,
|
|
220
|
-
): Promise<
|
|
426
|
+
): Promise<MessageResponse> {
|
|
221
427
|
return unwrapAsync(
|
|
222
428
|
collectionsDocsUpsert(
|
|
223
429
|
this.client,
|
|
@@ -230,13 +436,27 @@ class CollectionDocs {
|
|
|
230
436
|
);
|
|
231
437
|
}
|
|
232
438
|
|
|
439
|
+
/**
|
|
440
|
+
* Upsert documents (Safe: returns Result instead of throwing). Max payload 6MB.
|
|
441
|
+
*/
|
|
442
|
+
async upsertSafe(
|
|
443
|
+
body: UpsertDocsInput,
|
|
444
|
+
options?: RequestOptions,
|
|
445
|
+
): Promise<Result<MessageResponse, UpsertDocsError>> {
|
|
446
|
+
return await collectionsDocsUpsert(
|
|
447
|
+
this.client,
|
|
448
|
+
{ collectionName: this.collectionName, requestBody: body },
|
|
449
|
+
options,
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
233
453
|
/**
|
|
234
454
|
* Update documents (each doc must have id). Max payload 6MB.
|
|
235
455
|
*/
|
|
236
456
|
async update(
|
|
237
|
-
body:
|
|
457
|
+
body: UpdateDocsInput,
|
|
238
458
|
options?: RequestOptions,
|
|
239
|
-
): Promise<
|
|
459
|
+
): Promise<MessageResponse> {
|
|
240
460
|
return unwrapAsync(
|
|
241
461
|
collectionsDocsUpdate(
|
|
242
462
|
this.client,
|
|
@@ -249,13 +469,27 @@ class CollectionDocs {
|
|
|
249
469
|
);
|
|
250
470
|
}
|
|
251
471
|
|
|
472
|
+
/**
|
|
473
|
+
* Update documents (Safe: returns Result instead of throwing). Max payload 6MB.
|
|
474
|
+
*/
|
|
475
|
+
async updateSafe(
|
|
476
|
+
body: UpdateDocsInput,
|
|
477
|
+
options?: RequestOptions,
|
|
478
|
+
): Promise<Result<MessageResponse, UpdateDocsError>> {
|
|
479
|
+
return await collectionsDocsUpdate(
|
|
480
|
+
this.client,
|
|
481
|
+
{ collectionName: this.collectionName, requestBody: body },
|
|
482
|
+
options,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
252
486
|
/**
|
|
253
487
|
* Delete documents by ids and/or filter.
|
|
254
488
|
*/
|
|
255
489
|
async delete(
|
|
256
|
-
body:
|
|
490
|
+
body: DeleteDocsInput,
|
|
257
491
|
options?: RequestOptions,
|
|
258
|
-
): Promise<
|
|
492
|
+
): Promise<MessageResponse> {
|
|
259
493
|
return unwrapAsync(
|
|
260
494
|
collectionsDocsDelete(
|
|
261
495
|
this.client,
|
|
@@ -268,14 +502,30 @@ class CollectionDocs {
|
|
|
268
502
|
);
|
|
269
503
|
}
|
|
270
504
|
|
|
505
|
+
/**
|
|
506
|
+
* Delete documents by ids and/or filter (Safe: returns Result instead of throwing).
|
|
507
|
+
*/
|
|
508
|
+
async deleteSafe(
|
|
509
|
+
body: DeleteDocsInput,
|
|
510
|
+
options?: RequestOptions,
|
|
511
|
+
): Promise<Result<MessageResponse, DeleteDocsError>> {
|
|
512
|
+
return await collectionsDocsDelete(
|
|
513
|
+
this.client,
|
|
514
|
+
{ collectionName: this.collectionName, requestBody: body },
|
|
515
|
+
options,
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
271
519
|
/**
|
|
272
520
|
* Fetch documents by IDs (max 100).
|
|
521
|
+
* When the API returns docs via docsUrl (isDocsInline false), documents are
|
|
522
|
+
* fetched from the presigned URL automatically so the response always has docs.
|
|
273
523
|
*/
|
|
274
524
|
async fetch(
|
|
275
|
-
body:
|
|
525
|
+
body: FetchDocsInput,
|
|
276
526
|
options?: RequestOptions,
|
|
277
|
-
) {
|
|
278
|
-
|
|
527
|
+
): Promise<FetchDocsResponse> {
|
|
528
|
+
const result = await unwrapAsync(
|
|
279
529
|
collectionsDocsFetch(
|
|
280
530
|
this.client,
|
|
281
531
|
{
|
|
@@ -285,6 +535,38 @@ class CollectionDocs {
|
|
|
285
535
|
options,
|
|
286
536
|
),
|
|
287
537
|
);
|
|
538
|
+
if (!result.isDocsInline && result.docsUrl) {
|
|
539
|
+
const docs = await fetchDocsFromUrl<FetchDocsDoc>(
|
|
540
|
+
result.docsUrl,
|
|
541
|
+
);
|
|
542
|
+
return { ...result, docs, isDocsInline: true };
|
|
543
|
+
}
|
|
544
|
+
return result;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Fetch documents by IDs (Safe: returns Result instead of throwing).
|
|
549
|
+
* When the API returns docs via docsUrl, documents are fetched from the presigned URL automatically.
|
|
550
|
+
*/
|
|
551
|
+
async fetchSafe(
|
|
552
|
+
body: FetchDocsInput,
|
|
553
|
+
options?: RequestOptions,
|
|
554
|
+
): Promise<Result<FetchDocsResponse, FetchDocsError>> {
|
|
555
|
+
const result = await collectionsDocsFetch(
|
|
556
|
+
this.client,
|
|
557
|
+
{ collectionName: this.collectionName, requestBody: body },
|
|
558
|
+
options,
|
|
559
|
+
);
|
|
560
|
+
if (!result.ok) return result;
|
|
561
|
+
if (!result.value.isDocsInline && result.value.docsUrl) {
|
|
562
|
+
try {
|
|
563
|
+
const docs = await fetchDocsFromUrl<FetchDocsDoc>(result.value.docsUrl);
|
|
564
|
+
return OK({ ...result.value, docs, isDocsInline: true });
|
|
565
|
+
} catch (e) {
|
|
566
|
+
return ERR(e as FetchDocsError);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return result;
|
|
288
570
|
}
|
|
289
571
|
|
|
290
572
|
/**
|
|
@@ -300,13 +582,26 @@ class CollectionDocs {
|
|
|
300
582
|
);
|
|
301
583
|
}
|
|
302
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Get presigned URL and metadata for bulk upload (Safe: returns Result instead of throwing).
|
|
587
|
+
*/
|
|
588
|
+
async getBulkUpsertSafe(
|
|
589
|
+
options?: RequestOptions,
|
|
590
|
+
): Promise<Result<GetBulkUpsertDocsResponse, GetBulkUpsertDocsError>> {
|
|
591
|
+
return await collectionsDocsGetBulkUpsert(
|
|
592
|
+
this.client,
|
|
593
|
+
{ collectionName: this.collectionName },
|
|
594
|
+
options,
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
|
|
303
598
|
/**
|
|
304
599
|
* Trigger bulk upsert with an object key from getBulkUpsert().
|
|
305
600
|
*/
|
|
306
601
|
async bulkUpsert(
|
|
307
|
-
body:
|
|
602
|
+
body: BulkUpsertInput,
|
|
308
603
|
options?: RequestOptions,
|
|
309
|
-
): Promise<
|
|
604
|
+
): Promise<MessageResponse> {
|
|
310
605
|
return unwrapAsync(
|
|
311
606
|
collectionsDocsBulkUpsert(
|
|
312
607
|
this.client,
|
|
@@ -318,4 +613,100 @@ class CollectionDocs {
|
|
|
318
613
|
),
|
|
319
614
|
);
|
|
320
615
|
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Trigger bulk upsert (Safe: returns Result instead of throwing).
|
|
619
|
+
*/
|
|
620
|
+
async bulkUpsertSafe(
|
|
621
|
+
body: BulkUpsertInput,
|
|
622
|
+
options?: RequestOptions,
|
|
623
|
+
): Promise<Result<MessageResponse, BulkUpsertDocsError>> {
|
|
624
|
+
return await collectionsDocsBulkUpsert(
|
|
625
|
+
this.client,
|
|
626
|
+
{ collectionName: this.collectionName, requestBody: body },
|
|
627
|
+
options,
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Bulk upsert documents in one call (up to 200MB). Abstracts getBulkUpsert,
|
|
633
|
+
* S3 upload via presigned URL, and bulkUpsert. Use this for better DX when
|
|
634
|
+
* you have a document list; use getBulkUpsert + bulkUpsert for low-level control.
|
|
635
|
+
*/
|
|
636
|
+
async bulkUpsertDocs(
|
|
637
|
+
body: UpsertDocsInput,
|
|
638
|
+
options?: RequestOptions,
|
|
639
|
+
): Promise<MessageResponse> {
|
|
640
|
+
const { url, type, httpMethod, objectKey, sizeLimitBytes } = await this.getBulkUpsert(options);
|
|
641
|
+
|
|
642
|
+
const payload = { docs: body.docs };
|
|
643
|
+
const jsonString = JSON.stringify(payload);
|
|
644
|
+
const sizeBytes = new TextEncoder().encode(jsonString).length;
|
|
645
|
+
if (sizeBytes > sizeLimitBytes) {
|
|
646
|
+
throw new Error(
|
|
647
|
+
`Bulk upsert payload size (${sizeBytes} bytes) exceeds limit (${sizeLimitBytes} bytes)`,
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const putResponse = await fetch(url, {
|
|
652
|
+
method: httpMethod,
|
|
653
|
+
headers: { "Content-Type": type },
|
|
654
|
+
body: jsonString,
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
if (!putResponse.ok) {
|
|
658
|
+
const text = await putResponse.text();
|
|
659
|
+
throw new Error(
|
|
660
|
+
`Bulk upsert upload failed: ${putResponse.status} ${putResponse.statusText}${text ? ` - ${text}` : ""}`,
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
return this.bulkUpsert({ objectKey }, options);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Bulk upsert documents in one call (Safe: returns Result instead of throwing).
|
|
669
|
+
* May return Error for local failures (payload size, upload). API errors use GetBulkUpsertDocsError or BulkUpsertDocsError.
|
|
670
|
+
*/
|
|
671
|
+
async bulkUpsertDocsSafe(
|
|
672
|
+
body: UpsertDocsInput,
|
|
673
|
+
options?: RequestOptions,
|
|
674
|
+
): Promise<
|
|
675
|
+
Result<
|
|
676
|
+
MessageResponse,
|
|
677
|
+
GetBulkUpsertDocsError | BulkUpsertDocsError | Error
|
|
678
|
+
>
|
|
679
|
+
> {
|
|
680
|
+
const getResult = await this.getBulkUpsertSafe(options);
|
|
681
|
+
if (!getResult.ok) return getResult;
|
|
682
|
+
const { url, type, httpMethod, objectKey, sizeLimitBytes } = getResult.value;
|
|
683
|
+
|
|
684
|
+
const payload = { docs: body.docs };
|
|
685
|
+
const jsonString = JSON.stringify(payload);
|
|
686
|
+
const sizeBytes = new TextEncoder().encode(jsonString).length;
|
|
687
|
+
if (sizeBytes > sizeLimitBytes) {
|
|
688
|
+
return ERR(
|
|
689
|
+
new Error(
|
|
690
|
+
`Bulk upsert payload size (${sizeBytes} bytes) exceeds limit (${sizeLimitBytes} bytes)`,
|
|
691
|
+
),
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const putResponse = await fetch(url, {
|
|
696
|
+
method: httpMethod,
|
|
697
|
+
headers: { "Content-Type": type },
|
|
698
|
+
body: jsonString,
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
if (!putResponse.ok) {
|
|
702
|
+
const text = await putResponse.text();
|
|
703
|
+
return ERR(
|
|
704
|
+
new Error(
|
|
705
|
+
`Bulk upsert upload failed: ${putResponse.status} ${putResponse.statusText}${text ? ` - ${text}` : ""}`,
|
|
706
|
+
),
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return this.bulkUpsertSafe({ objectKey }, options);
|
|
711
|
+
}
|
|
321
712
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { HTTPClient } from "./lib/http.js";
|
|
|
8
8
|
export type { Fetcher, HTTPClientOptions } from "./lib/http.js";
|
|
9
9
|
export * from "./sdk/sdk.js";
|
|
10
10
|
|
|
11
|
-
/** Collection-scoped client (recommended). See docs/
|
|
11
|
+
/** Collection-scoped client (recommended). See docs/REFACTORING_STATUS.md */
|
|
12
12
|
export {
|
|
13
13
|
LambdaDBClient,
|
|
14
14
|
CollectionHandle,
|
|
@@ -17,3 +17,27 @@ export {
|
|
|
17
17
|
type RequestOptions as ClientRequestOptions,
|
|
18
18
|
type LambdaDBClientOptions,
|
|
19
19
|
} from "./client.js";
|
|
20
|
+
|
|
21
|
+
/** Public API types (inputs and responses for the collection-scoped client). */
|
|
22
|
+
export type * from "./types/public.js";
|
|
23
|
+
|
|
24
|
+
/** Result type and helpers for Safe methods. */
|
|
25
|
+
export type { Result } from "./types/fp.js";
|
|
26
|
+
export { OK, ERR } from "./types/fp.js";
|
|
27
|
+
|
|
28
|
+
/** Error classes and per-operation error unions for Safe methods and instanceof checks. */
|
|
29
|
+
export * from "./types/errors.js";
|
|
30
|
+
|
|
31
|
+
/** Query input helper for collection.query() / collection.querySafe(). */
|
|
32
|
+
export {
|
|
33
|
+
createQueryInput,
|
|
34
|
+
type CreateQueryInputOptions,
|
|
35
|
+
} from "./lib/queryInput.js";
|
|
36
|
+
|
|
37
|
+
/** Retry config type for LambdaDBClientOptions and RequestOptions. */
|
|
38
|
+
export type { RetryConfig } from "./lib/retries.js";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated Use types from the package root (e.g. CreateCollectionInput, QueryCollectionResponse). Will be removed in the next major version.
|
|
42
|
+
*/
|
|
43
|
+
export type { operations, models } from "./client.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to build QueryCollectionInput for collection.query() / collection.querySafe().
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { FieldsSelectorUnion, PartitionFilter } from "../models/index.js";
|
|
6
|
+
import type { QueryCollectionInput } from "../types/public.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Options for createQueryInput (all optional except query).
|
|
10
|
+
*/
|
|
11
|
+
export type CreateQueryInputOptions = {
|
|
12
|
+
size?: number;
|
|
13
|
+
consistentRead?: boolean;
|
|
14
|
+
includeVectors?: boolean;
|
|
15
|
+
sort?: Array<{ [k: string]: unknown }>;
|
|
16
|
+
fields?: FieldsSelectorUnion;
|
|
17
|
+
partitionFilter?: PartitionFilter;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build a query input object for collection.query() or collection.querySafe().
|
|
22
|
+
* Pass the required query object (e.g. text search or vector search params) and optional options.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const input = createQueryInput({ text: "hello" }, { size: 10 });
|
|
26
|
+
* const result = await collection.query(input);
|
|
27
|
+
*/
|
|
28
|
+
export function createQueryInput(
|
|
29
|
+
query: { [k: string]: unknown },
|
|
30
|
+
options?: CreateQueryInputOptions,
|
|
31
|
+
): QueryCollectionInput {
|
|
32
|
+
return { query, ...options };
|
|
33
|
+
}
|