ai-database 2.1.1 → 2.3.0
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/CHANGELOG.md +47 -1
- package/README.md +1063 -186
- package/dist/actions.d.ts +2 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/ai-promise-db.d.ts +52 -23
- package/dist/ai-promise-db.d.ts.map +1 -1
- package/dist/ai-promise-db.js +185 -164
- package/dist/ai-promise-db.js.map +1 -1
- package/dist/authorization.d.ts.map +1 -1
- package/dist/authorization.js +38 -30
- package/dist/authorization.js.map +1 -1
- package/dist/cascade-orchestrator.d.ts +404 -0
- package/dist/cascade-orchestrator.d.ts.map +1 -0
- package/dist/cascade-orchestrator.js +828 -0
- package/dist/cascade-orchestrator.js.map +1 -0
- package/dist/cascade-write-strategy.d.ts +584 -0
- package/dist/cascade-write-strategy.d.ts.map +1 -0
- package/dist/cascade-write-strategy.js +590 -0
- package/dist/cascade-write-strategy.js.map +1 -0
- package/dist/ch-adapter.d.ts +358 -0
- package/dist/ch-adapter.d.ts.map +1 -0
- package/dist/ch-adapter.js +929 -0
- package/dist/ch-adapter.js.map +1 -0
- package/dist/client/index.d.ts +42 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +43 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client.d.ts +266 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +81 -0
- package/dist/client.js.map +1 -0
- package/dist/constants.d.ts +64 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +52 -2
- package/dist/constants.js.map +1 -1
- package/dist/dataloader.d.ts +99 -0
- package/dist/dataloader.d.ts.map +1 -0
- package/dist/dataloader.js +225 -0
- package/dist/dataloader.js.map +1 -0
- package/dist/db-provider-port.d.ts +501 -0
- package/dist/db-provider-port.d.ts.map +1 -0
- package/dist/db-provider-port.js +113 -0
- package/dist/db-provider-port.js.map +1 -0
- package/dist/digital-objects-provider.d.ts +49 -0
- package/dist/digital-objects-provider.d.ts.map +1 -0
- package/dist/digital-objects-provider.js +55 -0
- package/dist/digital-objects-provider.js.map +1 -0
- package/dist/do-sqlite-adapter.d.ts +402 -0
- package/dist/do-sqlite-adapter.d.ts.map +1 -0
- package/dist/do-sqlite-adapter.js +745 -0
- package/dist/do-sqlite-adapter.js.map +1 -0
- package/dist/docs-rels/custom-types.d.ts +134 -0
- package/dist/docs-rels/custom-types.d.ts.map +1 -0
- package/dist/docs-rels/custom-types.js +70 -0
- package/dist/docs-rels/custom-types.js.map +1 -0
- package/dist/docs-rels/index.d.ts +16 -0
- package/dist/docs-rels/index.d.ts.map +1 -0
- package/dist/docs-rels/index.js +16 -0
- package/dist/docs-rels/index.js.map +1 -0
- package/dist/docs-rels/migrations/index.d.ts +30 -0
- package/dist/docs-rels/migrations/index.d.ts.map +1 -0
- package/dist/docs-rels/migrations/index.js +128 -0
- package/dist/docs-rels/migrations/index.js.map +1 -0
- package/dist/docs-rels/schema.d.ts +2961 -0
- package/dist/docs-rels/schema.d.ts.map +1 -0
- package/dist/docs-rels/schema.js +244 -0
- package/dist/docs-rels/schema.js.map +1 -0
- package/dist/durable-clickhouse.d.ts.map +1 -1
- package/dist/durable-clickhouse.js +16 -13
- package/dist/durable-clickhouse.js.map +1 -1
- package/dist/durable-promise.d.ts.map +1 -1
- package/dist/durable-promise.js +34 -15
- package/dist/durable-promise.js.map +1 -1
- package/dist/errors.d.ts +127 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +210 -0
- package/dist/errors.js.map +1 -0
- package/dist/eventbridge.d.ts +117 -0
- package/dist/eventbridge.d.ts.map +1 -0
- package/dist/eventbridge.js +238 -0
- package/dist/eventbridge.js.map +1 -0
- package/dist/events.d.ts +2 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +1 -1
- package/dist/events.js.map +1 -1
- package/dist/execution-queue.d.ts.map +1 -1
- package/dist/execution-queue.js +4 -5
- package/dist/execution-queue.js.map +1 -1
- package/dist/index.d.ts +37 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +112 -6
- package/dist/index.js.map +1 -1
- package/dist/linguistic.d.ts +3 -108
- package/dist/linguistic.d.ts.map +1 -1
- package/dist/linguistic.js +3 -372
- package/dist/linguistic.js.map +1 -1
- package/dist/logger.d.ts +132 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +137 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory-provider.d.ts +129 -0
- package/dist/memory-provider.d.ts.map +1 -1
- package/dist/memory-provider.js +592 -257
- package/dist/memory-provider.js.map +1 -1
- package/dist/pg-adapter.d.ts +424 -0
- package/dist/pg-adapter.d.ts.map +1 -0
- package/dist/pg-adapter.js +921 -0
- package/dist/pg-adapter.js.map +1 -0
- package/dist/pipelines-iceberg-emitter.d.ts +327 -0
- package/dist/pipelines-iceberg-emitter.d.ts.map +1 -0
- package/dist/pipelines-iceberg-emitter.js +351 -0
- package/dist/pipelines-iceberg-emitter.js.map +1 -0
- package/dist/provider-capabilities.d.ts +146 -0
- package/dist/provider-capabilities.d.ts.map +1 -0
- package/dist/provider-capabilities.js +214 -0
- package/dist/provider-capabilities.js.map +1 -0
- package/dist/rdb-provider-adapter.d.ts +195 -0
- package/dist/rdb-provider-adapter.d.ts.map +1 -0
- package/dist/rdb-provider-adapter.js +291 -0
- package/dist/rdb-provider-adapter.js.map +1 -0
- package/dist/schema/cascade.d.ts +49 -10
- package/dist/schema/cascade.d.ts.map +1 -1
- package/dist/schema/cascade.js +491 -273
- package/dist/schema/cascade.js.map +1 -1
- package/dist/schema/definition-caches.d.ts +24 -0
- package/dist/schema/definition-caches.d.ts.map +1 -0
- package/dist/schema/definition-caches.js +26 -0
- package/dist/schema/definition-caches.js.map +1 -0
- package/dist/schema/dependency-graph.d.ts +45 -0
- package/dist/schema/dependency-graph.d.ts.map +1 -0
- package/dist/schema/dependency-graph.js +47 -0
- package/dist/schema/dependency-graph.js.map +1 -0
- package/dist/schema/diff.d.ts +103 -0
- package/dist/schema/diff.d.ts.map +1 -0
- package/dist/schema/diff.js +329 -0
- package/dist/schema/diff.js.map +1 -0
- package/dist/schema/entity-operations.d.ts +99 -0
- package/dist/schema/entity-operations.d.ts.map +1 -0
- package/dist/schema/entity-operations.js +818 -0
- package/dist/schema/entity-operations.js.map +1 -0
- package/dist/schema/generation-context.d.ts +202 -0
- package/dist/schema/generation-context.d.ts.map +1 -0
- package/dist/schema/generation-context.js +393 -0
- package/dist/schema/generation-context.js.map +1 -0
- package/dist/schema/index.d.ts +32 -34
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +462 -519
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/migration.d.ts +205 -0
- package/dist/schema/migration.d.ts.map +1 -0
- package/dist/schema/migration.js +327 -0
- package/dist/schema/migration.js.map +1 -0
- package/dist/schema/nl-query-generator.d.ts +68 -0
- package/dist/schema/nl-query-generator.d.ts.map +1 -0
- package/dist/schema/nl-query-generator.js +362 -0
- package/dist/schema/nl-query-generator.js.map +1 -0
- package/dist/schema/nl-query.d.ts +65 -0
- package/dist/schema/nl-query.d.ts.map +1 -0
- package/dist/schema/nl-query.js +178 -0
- package/dist/schema/nl-query.js.map +1 -0
- package/dist/schema/parse.d.ts.map +1 -1
- package/dist/schema/parse.js +152 -89
- package/dist/schema/parse.js.map +1 -1
- package/dist/schema/provider.d.ts +38 -0
- package/dist/schema/provider.d.ts.map +1 -1
- package/dist/schema/provider.js +15 -7
- package/dist/schema/provider.js.map +1 -1
- package/dist/schema/resolve.d.ts +46 -5
- package/dist/schema/resolve.d.ts.map +1 -1
- package/dist/schema/resolve.js +334 -117
- package/dist/schema/resolve.js.map +1 -1
- package/dist/schema/search-utils.d.ts +76 -0
- package/dist/schema/search-utils.d.ts.map +1 -0
- package/dist/schema/search-utils.js +86 -0
- package/dist/schema/search-utils.js.map +1 -0
- package/dist/schema/seed.d.ts +53 -0
- package/dist/schema/seed.d.ts.map +1 -0
- package/dist/schema/seed.js +94 -0
- package/dist/schema/seed.js.map +1 -0
- package/dist/schema/semantic.d.ts +11 -0
- package/dist/schema/semantic.d.ts.map +1 -1
- package/dist/schema/semantic.js +262 -68
- package/dist/schema/semantic.js.map +1 -1
- package/dist/schema/sub-apis.d.ts +52 -0
- package/dist/schema/sub-apis.d.ts.map +1 -0
- package/dist/schema/sub-apis.js +216 -0
- package/dist/schema/sub-apis.js.map +1 -0
- package/dist/schema/system-entities.d.ts +42 -0
- package/dist/schema/system-entities.d.ts.map +1 -0
- package/dist/schema/system-entities.js +101 -0
- package/dist/schema/system-entities.js.map +1 -0
- package/dist/schema/types.d.ts +91 -9
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/union-fallback.d.ts +219 -0
- package/dist/schema/union-fallback.d.ts.map +1 -0
- package/dist/schema/union-fallback.js +331 -0
- package/dist/schema/union-fallback.js.map +1 -0
- package/dist/schema/value-generators/ai.d.ts +54 -0
- package/dist/schema/value-generators/ai.d.ts.map +1 -0
- package/dist/schema/value-generators/ai.js +136 -0
- package/dist/schema/value-generators/ai.js.map +1 -0
- package/dist/schema/value-generators/index.d.ts +126 -0
- package/dist/schema/value-generators/index.d.ts.map +1 -0
- package/dist/schema/value-generators/index.js +219 -0
- package/dist/schema/value-generators/index.js.map +1 -0
- package/dist/schema/value-generators/placeholder.d.ts +52 -0
- package/dist/schema/value-generators/placeholder.d.ts.map +1 -0
- package/dist/schema/value-generators/placeholder.js +328 -0
- package/dist/schema/value-generators/placeholder.js.map +1 -0
- package/dist/schema/value-generators/types.d.ts +116 -0
- package/dist/schema/value-generators/types.d.ts.map +1 -0
- package/dist/schema/value-generators/types.js +11 -0
- package/dist/schema/value-generators/types.js.map +1 -0
- package/dist/schema/verb-derivation.d.ts +167 -0
- package/dist/schema/verb-derivation.d.ts.map +1 -0
- package/dist/schema/verb-derivation.js +281 -0
- package/dist/schema/verb-derivation.js.map +1 -0
- package/dist/schema/version.d.ts +111 -0
- package/dist/schema/version.d.ts.map +1 -0
- package/dist/schema/version.js +190 -0
- package/dist/schema/version.js.map +1 -0
- package/dist/schema.d.ts +1095 -23
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2854 -38
- package/dist/schema.js.map +1 -1
- package/dist/semantic-vectors.d.ts +39 -0
- package/dist/semantic-vectors.d.ts.map +1 -0
- package/dist/semantic-vectors.js +334 -0
- package/dist/semantic-vectors.js.map +1 -0
- package/dist/semantic.d.ts +29 -1
- package/dist/semantic.d.ts.map +1 -1
- package/dist/semantic.js +26 -16
- package/dist/semantic.js.map +1 -1
- package/dist/telemetry.d.ts +128 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +305 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tests.d.ts.map +1 -1
- package/dist/tests.js +30 -22
- package/dist/tests.js.map +1 -1
- package/dist/type-guards.d.ts +212 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +318 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types.d.ts +33 -245
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +62 -72
- package/dist/types.js.map +1 -1
- package/dist/validation.d.ts +165 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +639 -0
- package/dist/validation.js.map +1 -0
- package/dist/worker/db-provider.d.ts +168 -0
- package/dist/worker/db-provider.d.ts.map +1 -0
- package/dist/worker/db-provider.js +277 -0
- package/dist/worker/db-provider.js.map +1 -0
- package/dist/worker/index.d.ts +35 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +37 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker.d.ts +779 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +2786 -0
- package/dist/worker.js.map +1 -0
- package/package.json +38 -8
- package/src/docs-rels/migrations/0001-init.sql +125 -0
package/dist/ai-promise-db.js
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
* @packageDocumentation
|
|
22
22
|
*/
|
|
23
23
|
import { Semaphore } from './memory-provider.js';
|
|
24
|
+
import { isEntityArray, extractEntityId, extractMarkerType, isPlainObject, hasRelationElements, asCallback, asPredicate, asComparator, getSymbolProperty, asItem, } from './type-guards.js';
|
|
25
|
+
import { EntityNotFoundError } from './errors.js';
|
|
24
26
|
// Provider resolver - will be set by schema.ts
|
|
25
27
|
let providerResolver = null;
|
|
26
28
|
/**
|
|
@@ -146,7 +148,7 @@ export class DBPromise {
|
|
|
146
148
|
map(callback) {
|
|
147
149
|
const parentPromise = this;
|
|
148
150
|
return new DBPromise({
|
|
149
|
-
type: this._options.type,
|
|
151
|
+
...(this._options.type !== undefined && { type: this._options.type }),
|
|
150
152
|
executor: async () => {
|
|
151
153
|
// Resolve the parent array
|
|
152
154
|
const items = await parentPromise.resolve();
|
|
@@ -165,8 +167,9 @@ export class DBPromise {
|
|
|
165
167
|
// Create a recording proxy for this item
|
|
166
168
|
const recordingProxy = createRecordingProxy(item, recording);
|
|
167
169
|
// Execute callback with recording proxy to discover accesses
|
|
170
|
+
// Use asCallback to convert the callback to accept unknown items
|
|
168
171
|
try {
|
|
169
|
-
callback(recordingProxy, i);
|
|
172
|
+
asCallback(callback)(recordingProxy, i);
|
|
170
173
|
}
|
|
171
174
|
catch {
|
|
172
175
|
// Ignore errors during recording phase - they'll surface in Phase 3
|
|
@@ -182,9 +185,11 @@ export class DBPromise {
|
|
|
182
185
|
enrichedItems.push(enrichItemWithLoadedRelations(items[i], loadedRelations));
|
|
183
186
|
}
|
|
184
187
|
// Execute callback again with enriched data
|
|
188
|
+
// Use asCallback to convert the callback to accept unknown items
|
|
185
189
|
const results = [];
|
|
190
|
+
const typedCallback = asCallback(callback);
|
|
186
191
|
for (let i = 0; i < enrichedItems.length; i++) {
|
|
187
|
-
results.push(
|
|
192
|
+
results.push(typedCallback(enrichedItems[i], i));
|
|
188
193
|
}
|
|
189
194
|
return results;
|
|
190
195
|
},
|
|
@@ -196,13 +201,14 @@ export class DBPromise {
|
|
|
196
201
|
filter(predicate) {
|
|
197
202
|
const parentPromise = this;
|
|
198
203
|
return new DBPromise({
|
|
199
|
-
type: this._options.type,
|
|
204
|
+
...(this._options.type !== undefined && { type: this._options.type }),
|
|
200
205
|
executor: async () => {
|
|
201
206
|
const items = await parentPromise.resolve();
|
|
202
207
|
if (!Array.isArray(items)) {
|
|
203
208
|
return items;
|
|
204
209
|
}
|
|
205
|
-
|
|
210
|
+
// Use asPredicate to convert the predicate to accept unknown items
|
|
211
|
+
return items.filter(asPredicate(predicate));
|
|
206
212
|
},
|
|
207
213
|
});
|
|
208
214
|
}
|
|
@@ -212,13 +218,14 @@ export class DBPromise {
|
|
|
212
218
|
sort(compareFn) {
|
|
213
219
|
const parentPromise = this;
|
|
214
220
|
return new DBPromise({
|
|
215
|
-
type: this._options.type,
|
|
221
|
+
...(this._options.type !== undefined && { type: this._options.type }),
|
|
216
222
|
executor: async () => {
|
|
217
223
|
const items = await parentPromise.resolve();
|
|
218
224
|
if (!Array.isArray(items)) {
|
|
219
225
|
return items;
|
|
220
226
|
}
|
|
221
|
-
|
|
227
|
+
// Use asComparator to convert the compareFn to accept unknown items
|
|
228
|
+
return [...items].sort(asComparator(compareFn));
|
|
222
229
|
},
|
|
223
230
|
});
|
|
224
231
|
}
|
|
@@ -228,7 +235,7 @@ export class DBPromise {
|
|
|
228
235
|
limit(n) {
|
|
229
236
|
const parentPromise = this;
|
|
230
237
|
return new DBPromise({
|
|
231
|
-
type: this._options.type,
|
|
238
|
+
...(this._options.type !== undefined && { type: this._options.type }),
|
|
232
239
|
executor: async () => {
|
|
233
240
|
const items = await parentPromise.resolve();
|
|
234
241
|
if (!Array.isArray(items)) {
|
|
@@ -244,7 +251,7 @@ export class DBPromise {
|
|
|
244
251
|
first() {
|
|
245
252
|
const parentPromise = this;
|
|
246
253
|
return new DBPromise({
|
|
247
|
-
type: this._options.type,
|
|
254
|
+
...(this._options.type !== undefined && { type: this._options.type }),
|
|
248
255
|
executor: async () => {
|
|
249
256
|
const items = await parentPromise.resolve();
|
|
250
257
|
if (Array.isArray(items)) {
|
|
@@ -300,7 +307,7 @@ export class DBPromise {
|
|
|
300
307
|
// Persistence state
|
|
301
308
|
let processedIds = new Set();
|
|
302
309
|
let persistCounter = 0;
|
|
303
|
-
const getItemId = (item) => item
|
|
310
|
+
const getItemId = (item) => extractEntityId(item) ?? String(item);
|
|
304
311
|
// Get actions API from options (injected by wrapEntityOperations)
|
|
305
312
|
const actionsAPI = this._options.actionsAPI;
|
|
306
313
|
// Initialize persistence if enabled
|
|
@@ -319,7 +326,7 @@ export class DBPromise {
|
|
|
319
326
|
await actionsAPI.update(actionId, { status: 'active' });
|
|
320
327
|
}
|
|
321
328
|
else {
|
|
322
|
-
throw new
|
|
329
|
+
throw new EntityNotFoundError('Action', resume, 'resume');
|
|
323
330
|
}
|
|
324
331
|
}
|
|
325
332
|
else {
|
|
@@ -355,7 +362,7 @@ export class DBPromise {
|
|
|
355
362
|
skipped,
|
|
356
363
|
current,
|
|
357
364
|
elapsed,
|
|
358
|
-
remaining,
|
|
365
|
+
...(remaining !== undefined && { remaining }),
|
|
359
366
|
rate,
|
|
360
367
|
};
|
|
361
368
|
};
|
|
@@ -377,10 +384,10 @@ export class DBPromise {
|
|
|
377
384
|
const getRetryDelay = (attempt) => {
|
|
378
385
|
return typeof retryDelay === 'function' ? retryDelay(attempt) : retryDelay;
|
|
379
386
|
};
|
|
380
|
-
// Helper to handle error
|
|
387
|
+
// Helper to handle error - use asItem for type conversion
|
|
381
388
|
const handleError = async (error, item, attempt) => {
|
|
382
389
|
if (typeof onError === 'function') {
|
|
383
|
-
return onError(error, item, attempt);
|
|
390
|
+
return onError(error, asItem(item), attempt);
|
|
384
391
|
}
|
|
385
392
|
return onError;
|
|
386
393
|
};
|
|
@@ -399,24 +406,25 @@ export class DBPromise {
|
|
|
399
406
|
let attempt = 0;
|
|
400
407
|
while (true) {
|
|
401
408
|
try {
|
|
402
|
-
// Create timeout wrapper if needed
|
|
409
|
+
// Create timeout wrapper if needed - use asCallback for type conversion
|
|
403
410
|
let result;
|
|
411
|
+
const typedCallback = asCallback(callback);
|
|
404
412
|
if (timeout) {
|
|
405
413
|
const timeoutPromise = new Promise((_, reject) => {
|
|
406
414
|
setTimeout(() => reject(new Error(`Timeout after ${timeout}ms`)), timeout);
|
|
407
415
|
});
|
|
408
416
|
result = await Promise.race([
|
|
409
|
-
Promise.resolve(
|
|
417
|
+
Promise.resolve(typedCallback(item, index)),
|
|
410
418
|
timeoutPromise,
|
|
411
419
|
]);
|
|
412
420
|
}
|
|
413
421
|
else {
|
|
414
|
-
result = await
|
|
422
|
+
result = await typedCallback(item, index);
|
|
415
423
|
}
|
|
416
424
|
// Success
|
|
417
425
|
completed++;
|
|
418
426
|
await persistProgress(itemId);
|
|
419
|
-
await onComplete?.(item, result, index);
|
|
427
|
+
await onComplete?.(asItem(item), result, index);
|
|
420
428
|
onProgress?.(getProgress(index, item));
|
|
421
429
|
return;
|
|
422
430
|
}
|
|
@@ -504,13 +512,21 @@ export class DBPromise {
|
|
|
504
512
|
cancelled,
|
|
505
513
|
actionId,
|
|
506
514
|
};
|
|
507
|
-
|
|
515
|
+
const updatePayload = {
|
|
508
516
|
status: cancelled ? 'failed' : 'completed',
|
|
509
517
|
progress: completed + failed + skipped,
|
|
510
518
|
data: { processedIds: Array.from(processedIds) },
|
|
511
519
|
result: finalResult,
|
|
512
|
-
|
|
513
|
-
|
|
520
|
+
};
|
|
521
|
+
const errorMessage = cancelled
|
|
522
|
+
? 'Cancelled'
|
|
523
|
+
: errors.length > 0
|
|
524
|
+
? `${errors.length} items failed`
|
|
525
|
+
: undefined;
|
|
526
|
+
if (errorMessage !== undefined) {
|
|
527
|
+
updatePayload.error = errorMessage;
|
|
528
|
+
}
|
|
529
|
+
await actionsAPI.update(actionId, updatePayload);
|
|
514
530
|
}
|
|
515
531
|
}
|
|
516
532
|
return {
|
|
@@ -521,11 +537,14 @@ export class DBPromise {
|
|
|
521
537
|
elapsed: Date.now() - startTime,
|
|
522
538
|
errors,
|
|
523
539
|
cancelled,
|
|
524
|
-
actionId,
|
|
540
|
+
...(actionId !== undefined && { actionId }),
|
|
525
541
|
};
|
|
526
542
|
}
|
|
527
543
|
/**
|
|
528
544
|
* Async iteration
|
|
545
|
+
*
|
|
546
|
+
* The yield casts use a local type alias because TypeScript cannot narrow
|
|
547
|
+
* the conditional type `T extends (infer I)[] ? I : T` at runtime.
|
|
529
548
|
*/
|
|
530
549
|
async *[Symbol.asyncIterator]() {
|
|
531
550
|
const items = await this.resolve();
|
|
@@ -579,9 +598,50 @@ export class DBPromise {
|
|
|
579
598
|
// =============================================================================
|
|
580
599
|
// Proxy Handlers
|
|
581
600
|
// =============================================================================
|
|
601
|
+
/**
|
|
602
|
+
* Known DBPromise methods that need proxy handling.
|
|
603
|
+
*/
|
|
604
|
+
const DBPROMISE_METHODS = new Set([
|
|
605
|
+
'map',
|
|
606
|
+
'filter',
|
|
607
|
+
'sort',
|
|
608
|
+
'limit',
|
|
609
|
+
'first',
|
|
610
|
+
'forEach',
|
|
611
|
+
'resolve',
|
|
612
|
+
'then',
|
|
613
|
+
'catch',
|
|
614
|
+
'finally',
|
|
615
|
+
]);
|
|
616
|
+
/**
|
|
617
|
+
* Known internal properties that need proxy handling.
|
|
618
|
+
*/
|
|
619
|
+
const INTERNAL_PROPS = new Set(['accessedProps', 'path', 'isResolved']);
|
|
620
|
+
/**
|
|
621
|
+
* Access a property on DBPromise by name, with type safety.
|
|
622
|
+
*/
|
|
623
|
+
function getDBPromiseProperty(target, prop) {
|
|
624
|
+
return target[prop];
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Get and bind a method from DBPromise by name.
|
|
628
|
+
*/
|
|
629
|
+
function bindDBPromiseMethod(target, prop) {
|
|
630
|
+
const method = getDBPromiseProperty(target, prop);
|
|
631
|
+
if (typeof method === 'function') {
|
|
632
|
+
return method.bind(target);
|
|
633
|
+
}
|
|
634
|
+
throw new Error(`${prop} is not a method on DBPromise`);
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Proxy handlers for DBPromise property access tracking.
|
|
638
|
+
*
|
|
639
|
+
* Uses type-safe helper functions to access class methods and properties
|
|
640
|
+
* from within the ProxyHandler where the target type is DBPromise<unknown>.
|
|
641
|
+
*/
|
|
582
642
|
const DB_PROXY_HANDLERS = {
|
|
583
|
-
get(target, prop
|
|
584
|
-
// Handle symbols
|
|
643
|
+
get(target, prop) {
|
|
644
|
+
// Handle symbols - access internal symbol-keyed properties
|
|
585
645
|
if (typeof prop === 'symbol') {
|
|
586
646
|
if (prop === DB_PROMISE_SYMBOL)
|
|
587
647
|
return true;
|
|
@@ -589,25 +649,24 @@ const DB_PROXY_HANDLERS = {
|
|
|
589
649
|
return target;
|
|
590
650
|
if (prop === Symbol.asyncIterator)
|
|
591
651
|
return target[Symbol.asyncIterator].bind(target);
|
|
592
|
-
|
|
652
|
+
// Use getSymbolProperty for type-safe symbol access
|
|
653
|
+
return getSymbolProperty(target, prop);
|
|
593
654
|
}
|
|
594
|
-
// Handle promise methods
|
|
595
|
-
if (prop
|
|
596
|
-
return target
|
|
655
|
+
// Handle promise and DBPromise methods
|
|
656
|
+
if (DBPROMISE_METHODS.has(prop)) {
|
|
657
|
+
return bindDBPromiseMethod(target, prop);
|
|
597
658
|
}
|
|
598
|
-
// Handle
|
|
599
|
-
if (
|
|
600
|
-
return target
|
|
601
|
-
}
|
|
602
|
-
// Handle internal properties
|
|
603
|
-
if (prop.startsWith('_') || ['accessedProps', 'path', 'isResolved'].includes(prop)) {
|
|
604
|
-
return target[prop];
|
|
659
|
+
// Handle internal properties - private properties and getters
|
|
660
|
+
if (prop.startsWith('_') || INTERNAL_PROPS.has(prop)) {
|
|
661
|
+
return getDBPromiseProperty(target, prop);
|
|
605
662
|
}
|
|
606
663
|
// Track property access
|
|
607
664
|
target.accessedProps.add(prop);
|
|
608
665
|
// Return a new DBPromise for the property path
|
|
666
|
+
const internals = target;
|
|
667
|
+
const typeValue = internals._options?.type;
|
|
609
668
|
return new DBPromise({
|
|
610
|
-
type:
|
|
669
|
+
...(typeValue !== undefined && { type: typeValue }),
|
|
611
670
|
parent: target,
|
|
612
671
|
propertyPath: [...target.path, prop],
|
|
613
672
|
executor: async () => {
|
|
@@ -651,9 +710,11 @@ function getNestedValue(obj, path) {
|
|
|
651
710
|
function createBatchLoadingArray(items) {
|
|
652
711
|
// Create a new array with all the original items
|
|
653
712
|
const batchArray = [...items];
|
|
654
|
-
// Override the map method to do batch loading
|
|
713
|
+
// Override the map method to do batch loading only when needed
|
|
714
|
+
// Returns synchronously when no relations are accessed (preserving native Array behavior)
|
|
715
|
+
// Returns a Promise when relations need to be batch-loaded
|
|
655
716
|
Object.defineProperty(batchArray, 'map', {
|
|
656
|
-
value:
|
|
717
|
+
value: function (callback) {
|
|
657
718
|
const items = this;
|
|
658
719
|
// Phase 1: Record what the callback accesses using placeholder proxies
|
|
659
720
|
const recordings = [];
|
|
@@ -674,20 +735,33 @@ function createBatchLoadingArray(items) {
|
|
|
674
735
|
}
|
|
675
736
|
recordings.push(recording);
|
|
676
737
|
}
|
|
677
|
-
//
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
for (let i = 0; i < enrichedItems.length; i++) {
|
|
688
|
-
results.push(callback(enrichedItems[i], i));
|
|
738
|
+
// Check if any relations were accessed
|
|
739
|
+
const hasRelations = recordings.some((r) => r.relations.size > 0);
|
|
740
|
+
// If no relations were accessed, run synchronously like native Array.map
|
|
741
|
+
if (!hasRelations) {
|
|
742
|
+
try {
|
|
743
|
+
return Array.prototype.map.call(items, (item, i) => callback(item, i));
|
|
744
|
+
}
|
|
745
|
+
catch (error) {
|
|
746
|
+
return Promise.reject(error);
|
|
747
|
+
}
|
|
689
748
|
}
|
|
690
|
-
|
|
749
|
+
// Phase 2 & 3: Async batch loading path (returns a Promise)
|
|
750
|
+
return (async () => {
|
|
751
|
+
const batchLoads = analyzeBatchLoads(recordings, items);
|
|
752
|
+
const loadedRelations = await executeBatchLoads(batchLoads, recordings);
|
|
753
|
+
// Re-run callback with enriched items that have loaded relations
|
|
754
|
+
const enrichedItems = [];
|
|
755
|
+
for (let i = 0; i < items.length; i++) {
|
|
756
|
+
enrichedItems.push(enrichItemWithLoadedRelations(items[i], loadedRelations));
|
|
757
|
+
}
|
|
758
|
+
// Execute callback again with enriched data
|
|
759
|
+
const results = [];
|
|
760
|
+
for (let i = 0; i < enrichedItems.length; i++) {
|
|
761
|
+
results.push(callback(enrichedItems[i], i));
|
|
762
|
+
}
|
|
763
|
+
return results;
|
|
764
|
+
})();
|
|
691
765
|
},
|
|
692
766
|
writable: true,
|
|
693
767
|
configurable: true,
|
|
@@ -779,14 +853,15 @@ function createRecordingProxy(item, recording) {
|
|
|
779
853
|
return new Proxy(item, {
|
|
780
854
|
get(target, prop) {
|
|
781
855
|
if (typeof prop === 'symbol') {
|
|
782
|
-
|
|
856
|
+
// Use getSymbolProperty for type-safe symbol access
|
|
857
|
+
return getSymbolProperty(target, prop);
|
|
783
858
|
}
|
|
784
859
|
recording.paths.add(prop);
|
|
785
860
|
const value = target[prop];
|
|
786
861
|
// If accessing a relation (identified by $type marker from hydration)
|
|
787
862
|
// Note: proxies may not expose $type in 'has' trap, so check via property access
|
|
788
|
-
const maybeType = value
|
|
789
|
-
if (maybeType
|
|
863
|
+
const maybeType = extractMarkerType(value);
|
|
864
|
+
if (maybeType) {
|
|
790
865
|
const relationType = maybeType;
|
|
791
866
|
// Get or create the relation recording
|
|
792
867
|
let relationRecording = recording.relations.get(prop);
|
|
@@ -805,16 +880,17 @@ function createRecordingProxy(item, recording) {
|
|
|
805
880
|
// Handle arrays with potential relation elements (like members: ['->User'])
|
|
806
881
|
if (Array.isArray(value)) {
|
|
807
882
|
// Check if the array itself is a relation array (has $type marker from thenableArray)
|
|
808
|
-
const
|
|
809
|
-
const
|
|
883
|
+
const arrayMarker = isEntityArray(value) ? value : null;
|
|
884
|
+
const arrayType = arrayMarker?.$type;
|
|
885
|
+
const isArrayRelationFlag = arrayMarker !== null;
|
|
810
886
|
// Also check if array contains relation proxies (for backwards compatibility)
|
|
811
|
-
const
|
|
812
|
-
if (
|
|
887
|
+
const hasRelationElementsFlag = !isArrayRelationFlag && hasRelationElements(value);
|
|
888
|
+
if (isArrayRelationFlag || hasRelationElementsFlag) {
|
|
813
889
|
// Get the type from the array $type or first element
|
|
814
890
|
let relationType = arrayType;
|
|
815
891
|
if (!relationType) {
|
|
816
|
-
const firstRelation = value.find(v => v
|
|
817
|
-
relationType = firstRelation ? firstRelation
|
|
892
|
+
const firstRelation = value.find((v) => extractMarkerType(v) !== undefined);
|
|
893
|
+
relationType = firstRelation ? extractMarkerType(firstRelation) ?? 'unknown' : 'unknown';
|
|
818
894
|
}
|
|
819
895
|
let relationRecording = recording.relations.get(prop);
|
|
820
896
|
if (!relationRecording) {
|
|
@@ -852,7 +928,7 @@ function createRecordingProxy(item, recording) {
|
|
|
852
928
|
return createRelationRecordingProxy(relationRecording);
|
|
853
929
|
}
|
|
854
930
|
return Reflect.get(arrayTarget, arrayProp);
|
|
855
|
-
}
|
|
931
|
+
},
|
|
856
932
|
});
|
|
857
933
|
}
|
|
858
934
|
// Regular array - wrap for recording
|
|
@@ -889,36 +965,17 @@ function analyzeBatchLoads(recordings, items) {
|
|
|
889
965
|
// Handle array relations (e.g., members: ['id1', 'id2'])
|
|
890
966
|
if (Array.isArray(relationValue)) {
|
|
891
967
|
for (const element of relationValue) {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
else if (element && typeof element === 'object') {
|
|
896
|
-
// Try valueOf() for thenable proxies
|
|
897
|
-
if (typeof element.valueOf === 'function') {
|
|
898
|
-
const val = element.valueOf();
|
|
899
|
-
if (typeof val === 'string') {
|
|
900
|
-
ids.push(val);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
else if (element.$id) {
|
|
904
|
-
ids.push(element.$id);
|
|
905
|
-
}
|
|
968
|
+
const elementId = extractEntityId(element);
|
|
969
|
+
if (elementId) {
|
|
970
|
+
ids.push(elementId);
|
|
906
971
|
}
|
|
907
972
|
}
|
|
908
973
|
}
|
|
909
|
-
else
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if (typeof relationValue.valueOf === 'function') {
|
|
915
|
-
const val = relationValue.valueOf();
|
|
916
|
-
if (typeof val === 'string') {
|
|
917
|
-
ids.push(val);
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
else if (relationValue.$id) {
|
|
921
|
-
ids.push(relationValue.$id);
|
|
974
|
+
else {
|
|
975
|
+
// Handle single relations - string ID or proxy object
|
|
976
|
+
const relationId = extractEntityId(relationValue);
|
|
977
|
+
if (relationId) {
|
|
978
|
+
ids.push(relationId);
|
|
922
979
|
}
|
|
923
980
|
}
|
|
924
981
|
}
|
|
@@ -983,12 +1040,12 @@ async function executeBatchLoads(batchLoads, recordings) {
|
|
|
983
1040
|
// Deduplicate IDs
|
|
984
1041
|
const uniqueIds = [...new Set(ids)];
|
|
985
1042
|
// Fetch all entities in parallel
|
|
986
|
-
const entities = await Promise.all(uniqueIds.map(id => provider.get(type, id)));
|
|
1043
|
+
const entities = await Promise.all(uniqueIds.map((id) => provider.get(type, id)));
|
|
987
1044
|
// Map results by ID
|
|
988
1045
|
for (let i = 0; i < uniqueIds.length; i++) {
|
|
989
1046
|
const entity = entities[i];
|
|
990
1047
|
if (entity) {
|
|
991
|
-
const entityId = (entity
|
|
1048
|
+
const entityId = (entity['$id'] || entity['id']);
|
|
992
1049
|
relationResults.set(entityId, entity);
|
|
993
1050
|
}
|
|
994
1051
|
}
|
|
@@ -1004,7 +1061,7 @@ async function executeBatchLoads(batchLoads, recordings) {
|
|
|
1004
1061
|
let nestedType;
|
|
1005
1062
|
for (const entity of relationResults.values()) {
|
|
1006
1063
|
const entityObj = entity;
|
|
1007
|
-
const entityType = entityObj
|
|
1064
|
+
const entityType = entityObj['$type'];
|
|
1008
1065
|
const nestedValue = entityObj[nestedPath];
|
|
1009
1066
|
if (typeof nestedValue === 'string') {
|
|
1010
1067
|
// It's a string - could be an ID
|
|
@@ -1022,17 +1079,15 @@ async function executeBatchLoads(batchLoads, recordings) {
|
|
|
1022
1079
|
}
|
|
1023
1080
|
}
|
|
1024
1081
|
}
|
|
1025
|
-
else if (nestedValue
|
|
1082
|
+
else if (isPlainObject(nestedValue)) {
|
|
1026
1083
|
// Check if it has a $type marker (for already-hydrated proxies)
|
|
1027
|
-
const valueType = nestedValue
|
|
1028
|
-
if (valueType
|
|
1084
|
+
const valueType = extractMarkerType(nestedValue);
|
|
1085
|
+
if (valueType) {
|
|
1029
1086
|
nestedType = valueType;
|
|
1030
|
-
// Try to get the ID
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
nestedIds.push(val);
|
|
1035
|
-
}
|
|
1087
|
+
// Try to get the ID via valueOf or $id
|
|
1088
|
+
const nestedId = extractEntityId(nestedValue);
|
|
1089
|
+
if (nestedId) {
|
|
1090
|
+
nestedIds.push(nestedId);
|
|
1036
1091
|
}
|
|
1037
1092
|
}
|
|
1038
1093
|
}
|
|
@@ -1044,11 +1099,13 @@ async function executeBatchLoads(batchLoads, recordings) {
|
|
|
1044
1099
|
// Recursively load nested relations
|
|
1045
1100
|
if (nestedBatchLoads.size > 0) {
|
|
1046
1101
|
// Create nested recordings for the next level if available
|
|
1102
|
+
// The key must be the field name (not the type) so that nestedRelationInfo
|
|
1103
|
+
// lookups in the recursive call match by relation field name
|
|
1047
1104
|
const nestedRecordings = [];
|
|
1048
|
-
for (const nestedRecording of nestedInfo.nestedRelations
|
|
1105
|
+
for (const [nestedFieldName, nestedRecording] of nestedInfo.nestedRelations) {
|
|
1049
1106
|
nestedRecordings.push({
|
|
1050
1107
|
paths: new Set(),
|
|
1051
|
-
relations: new Map([[
|
|
1108
|
+
relations: new Map([[nestedFieldName, nestedRecording]]),
|
|
1052
1109
|
});
|
|
1053
1110
|
}
|
|
1054
1111
|
const nestedResults = await executeBatchLoads(nestedBatchLoads, nestedRecordings.length > 0 ? nestedRecordings : undefined);
|
|
@@ -1076,22 +1133,7 @@ function enrichItemWithLoadedRelations(item, loadedRelations) {
|
|
|
1076
1133
|
if (Array.isArray(relationValue)) {
|
|
1077
1134
|
const loadedArray = [];
|
|
1078
1135
|
for (const element of relationValue) {
|
|
1079
|
-
|
|
1080
|
-
if (typeof element === 'string') {
|
|
1081
|
-
idStr = element;
|
|
1082
|
-
}
|
|
1083
|
-
else if (element && typeof element === 'object') {
|
|
1084
|
-
// Try valueOf for thenable proxies
|
|
1085
|
-
if (typeof element.valueOf === 'function') {
|
|
1086
|
-
const val = element.valueOf();
|
|
1087
|
-
if (typeof val === 'string') {
|
|
1088
|
-
idStr = val;
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
if (!idStr && element.$id) {
|
|
1092
|
-
idStr = element.$id;
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1136
|
+
const idStr = extractEntityId(element);
|
|
1095
1137
|
if (idStr) {
|
|
1096
1138
|
const loaded = relationData.get(idStr);
|
|
1097
1139
|
if (loaded) {
|
|
@@ -1103,23 +1145,7 @@ function enrichItemWithLoadedRelations(item, loadedRelations) {
|
|
|
1103
1145
|
}
|
|
1104
1146
|
else {
|
|
1105
1147
|
// Handle single relations - get the ID from the thenable proxy or direct value
|
|
1106
|
-
|
|
1107
|
-
if (typeof relationValue === 'string') {
|
|
1108
|
-
relationId = relationValue;
|
|
1109
|
-
}
|
|
1110
|
-
else if (relationValue && typeof relationValue === 'object') {
|
|
1111
|
-
// Try to get ID from proxy's valueOf or toString
|
|
1112
|
-
if ('valueOf' in relationValue && typeof relationValue.valueOf === 'function') {
|
|
1113
|
-
const val = relationValue.valueOf();
|
|
1114
|
-
if (typeof val === 'string') {
|
|
1115
|
-
relationId = val;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
// Also check for $id
|
|
1119
|
-
if (!relationId && '$id' in relationValue) {
|
|
1120
|
-
relationId = relationValue.$id;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1148
|
+
const relationId = extractEntityId(relationValue);
|
|
1123
1149
|
if (relationId) {
|
|
1124
1150
|
const loaded = relationData.get(relationId);
|
|
1125
1151
|
if (loaded) {
|
|
@@ -1130,13 +1156,6 @@ function enrichItemWithLoadedRelations(item, loadedRelations) {
|
|
|
1130
1156
|
}
|
|
1131
1157
|
return enriched;
|
|
1132
1158
|
}
|
|
1133
|
-
/**
|
|
1134
|
-
* Apply batch-loaded results to the mapped results (deprecated, kept for compatibility)
|
|
1135
|
-
*/
|
|
1136
|
-
function applyBatchResults(results, loadedRelations, originalItems) {
|
|
1137
|
-
// No longer used - enrichment happens before callback re-run
|
|
1138
|
-
return results;
|
|
1139
|
-
}
|
|
1140
1159
|
// =============================================================================
|
|
1141
1160
|
// Check Functions
|
|
1142
1161
|
// =============================================================================
|
|
@@ -1154,7 +1173,9 @@ export function isDBPromise(value) {
|
|
|
1154
1173
|
*/
|
|
1155
1174
|
export function getRawDBPromise(value) {
|
|
1156
1175
|
if (RAW_DB_PROMISE_SYMBOL in value) {
|
|
1157
|
-
|
|
1176
|
+
// We know the symbol exists from the check above, so this cast is safe
|
|
1177
|
+
const raw = value[RAW_DB_PROMISE_SYMBOL];
|
|
1178
|
+
return raw;
|
|
1158
1179
|
}
|
|
1159
1180
|
return value;
|
|
1160
1181
|
}
|
|
@@ -1179,9 +1200,6 @@ export function createEntityPromise(type, executor) {
|
|
|
1179
1200
|
export function createSearchPromise(type, executor) {
|
|
1180
1201
|
return new DBPromise({ type, executor });
|
|
1181
1202
|
}
|
|
1182
|
-
// =============================================================================
|
|
1183
|
-
// Entity Operations Wrapper
|
|
1184
|
-
// =============================================================================
|
|
1185
1203
|
/**
|
|
1186
1204
|
* Wrap EntityOperations to return DBPromise
|
|
1187
1205
|
*/
|
|
@@ -1191,28 +1209,28 @@ export function wrapEntityOperations(typeName, operations, actionsAPI) {
|
|
|
1191
1209
|
return new DBPromise({
|
|
1192
1210
|
type: typeName,
|
|
1193
1211
|
executor: () => operations.get(id),
|
|
1194
|
-
actionsAPI,
|
|
1212
|
+
...(actionsAPI !== undefined && { actionsAPI }),
|
|
1195
1213
|
});
|
|
1196
1214
|
},
|
|
1197
1215
|
list(options) {
|
|
1198
1216
|
return new DBPromise({
|
|
1199
1217
|
type: typeName,
|
|
1200
1218
|
executor: () => operations.list(options),
|
|
1201
|
-
actionsAPI,
|
|
1219
|
+
...(actionsAPI !== undefined && { actionsAPI }),
|
|
1202
1220
|
});
|
|
1203
1221
|
},
|
|
1204
1222
|
find(where) {
|
|
1205
1223
|
return new DBPromise({
|
|
1206
1224
|
type: typeName,
|
|
1207
1225
|
executor: () => operations.find(where),
|
|
1208
|
-
actionsAPI,
|
|
1226
|
+
...(actionsAPI !== undefined && { actionsAPI }),
|
|
1209
1227
|
});
|
|
1210
1228
|
},
|
|
1211
1229
|
search(query, options) {
|
|
1212
1230
|
return new DBPromise({
|
|
1213
1231
|
type: typeName,
|
|
1214
1232
|
executor: () => operations.search(query, options),
|
|
1215
|
-
actionsAPI,
|
|
1233
|
+
...(actionsAPI !== undefined && { actionsAPI }),
|
|
1216
1234
|
});
|
|
1217
1235
|
},
|
|
1218
1236
|
first() {
|
|
@@ -1222,7 +1240,7 @@ export function wrapEntityOperations(typeName, operations, actionsAPI) {
|
|
|
1222
1240
|
const items = await operations.list({ limit: 1 });
|
|
1223
1241
|
return items[0] ?? null;
|
|
1224
1242
|
},
|
|
1225
|
-
actionsAPI,
|
|
1243
|
+
...(actionsAPI !== undefined && { actionsAPI }),
|
|
1226
1244
|
});
|
|
1227
1245
|
},
|
|
1228
1246
|
/**
|
|
@@ -1243,7 +1261,9 @@ export function wrapEntityOperations(typeName, operations, actionsAPI) {
|
|
|
1243
1261
|
*/
|
|
1244
1262
|
async forEach(callbackOrOptions, callbackOrOpts) {
|
|
1245
1263
|
// Detect which calling style is being used
|
|
1246
|
-
const isOptionsFirst = typeof callbackOrOptions === 'object' &&
|
|
1264
|
+
const isOptionsFirst = typeof callbackOrOptions === 'object' &&
|
|
1265
|
+
callbackOrOptions !== null &&
|
|
1266
|
+
!('call' in callbackOrOptions);
|
|
1247
1267
|
const callback = isOptionsFirst
|
|
1248
1268
|
? callbackOrOpts
|
|
1249
1269
|
: callbackOrOptions;
|
|
@@ -1255,26 +1275,27 @@ export function wrapEntityOperations(typeName, operations, actionsAPI) {
|
|
|
1255
1275
|
const listPromise = new DBPromise({
|
|
1256
1276
|
type: typeName,
|
|
1257
1277
|
executor: () => operations.list(listOptions),
|
|
1258
|
-
actionsAPI,
|
|
1278
|
+
...(actionsAPI !== undefined && { actionsAPI }),
|
|
1259
1279
|
});
|
|
1260
|
-
return listPromise.forEach(callback, options);
|
|
1280
|
+
return listPromise.forEach(asCallback(callback), options);
|
|
1261
1281
|
},
|
|
1262
|
-
// Semantic search methods
|
|
1282
|
+
// Semantic search methods - delegate to underlying operations
|
|
1283
|
+
// Return empty array if not available for graceful degradation
|
|
1263
1284
|
semanticSearch(query, options) {
|
|
1264
|
-
if (operations.semanticSearch) {
|
|
1265
|
-
|
|
1285
|
+
if (!operations.semanticSearch) {
|
|
1286
|
+
// Return empty array for graceful degradation when semantic search not available
|
|
1287
|
+
return Promise.resolve([]);
|
|
1266
1288
|
}
|
|
1267
|
-
|
|
1268
|
-
return Promise.resolve([]);
|
|
1289
|
+
return operations.semanticSearch(query, options);
|
|
1269
1290
|
},
|
|
1270
1291
|
hybridSearch(query, options) {
|
|
1271
|
-
if (operations.hybridSearch) {
|
|
1272
|
-
|
|
1292
|
+
if (!operations.hybridSearch) {
|
|
1293
|
+
// Return empty array for graceful degradation when hybrid search not available
|
|
1294
|
+
return Promise.resolve([]);
|
|
1273
1295
|
}
|
|
1274
|
-
|
|
1275
|
-
return Promise.resolve([]);
|
|
1296
|
+
return operations.hybridSearch(query, options);
|
|
1276
1297
|
},
|
|
1277
|
-
// Mutations
|
|
1298
|
+
// Mutations - pass through create which supports both (data, options?) and (id, data, options?)
|
|
1278
1299
|
create: operations.create,
|
|
1279
1300
|
update: operations.update,
|
|
1280
1301
|
upsert: operations.upsert,
|