ai-database 2.1.3 → 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 +35 -1
- package/README.md +880 -669
- 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 +49 -23
- package/dist/ai-promise-db.d.ts.map +1 -1
- package/dist/ai-promise-db.js +91 -63
- 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 +35 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +106 -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 +128 -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 +48 -17
- package/dist/schema/cascade.d.ts.map +1 -1
- package/dist/schema/cascade.js +477 -278
- 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 +21 -109
- package/dist/schema/dependency-graph.d.ts.map +1 -1
- package/dist/schema/dependency-graph.js +25 -333
- package/dist/schema/dependency-graph.js.map +1 -1
- 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/index.d.ts +28 -34
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +454 -521
- 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 +144 -89
- package/dist/schema/parse.js.map +1 -1
- package/dist/schema/provider.d.ts +37 -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 +237 -95
- 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 +10 -0
- package/dist/schema/semantic.d.ts.map +1 -1
- package/dist/schema/semantic.js +192 -86
- 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.map +1 -1
- package/dist/schema/union-fallback.js +21 -15
- package/dist/schema/union-fallback.js.map +1 -1
- 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/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 -24
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2852 -40
- 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 +50 -5
- package/dist/type-guards.d.ts.map +1 -1
- package/dist/type-guards.js +87 -16
- package/dist/type-guards.js.map +1 -1
- 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 +2 -5
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +65 -93
- package/dist/validation.js.map +1 -1
- 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 +46 -16
- package/src/docs-rels/migrations/0001-init.sql +125 -0
- package/LICENSE +0 -21
package/dist/schema/index.js
CHANGED
|
@@ -30,22 +30,43 @@
|
|
|
30
30
|
*
|
|
31
31
|
* @packageDocumentation
|
|
32
32
|
*/
|
|
33
|
-
import { DBPromise, wrapEntityOperations, setSchemaRelationInfo } from '../ai-promise-db.js';
|
|
33
|
+
import { DBPromise, wrapEntityOperations, setSchemaRelationInfo, } from '../ai-promise-db.js';
|
|
34
|
+
import { logError } from '../logger.js';
|
|
34
35
|
// Re-export parse functions
|
|
35
36
|
export { parseOperator, parseField, parseSchema, isPrimitiveType } from './parse.js';
|
|
36
|
-
export
|
|
37
|
+
// Re-export seed functions
|
|
38
|
+
export { loadSeedData, fetchSeedData, parseDelimitedData, mapSeedDataToRecords } from './seed.js';
|
|
39
|
+
export { setProvider, resolveProvider, hasSemanticSearch, hasHybridSearch, hasEventsAPI, hasActionsAPI, hasArtifactsAPI, hasEmbeddingsConfig, hasTransactionSupport, } from './provider.js';
|
|
40
|
+
// Import resolve functions used internally
|
|
41
|
+
import { isPromptField } from './resolve.js';
|
|
37
42
|
// Re-export resolve functions
|
|
38
|
-
export { isEntityId, inferTypeFromField, resolveContextPath, resolveInstructions, prefetchContext, isPromptField, resolveNestedPending, resolveReferenceSpec, hydrateEntity, } from './resolve.js';
|
|
43
|
+
export { isEntityId, inferTypeFromField, resolveContextPath, resolveInstructions, prefetchContext, prefetchContextPaths, isPromptField, resolveNestedPending, resolveReferenceSpec, hydrateEntity, } from './resolve.js';
|
|
39
44
|
// Re-export cascade functions
|
|
40
|
-
export { generateContextAwareValue, generateAIFields, generateEntity, resolveForwardExact, generateNaturalLanguageContent,
|
|
45
|
+
export { generateContextAwareValue, generateAIFields, generateEntity, resolveForwardExact, generateNaturalLanguageContent,
|
|
46
|
+
// AI generation configuration
|
|
47
|
+
configureAIGeneration, getAIGenerationConfig,
|
|
48
|
+
// Value generator configuration
|
|
49
|
+
setValueGenerator, getValueGenerator, } from './cascade.js';
|
|
41
50
|
// Re-export semantic functions
|
|
42
51
|
export { resolveBackwardFuzzy, resolveForwardFuzzy } from './semantic.js';
|
|
52
|
+
// Re-export NL query generator functions
|
|
53
|
+
export { createDefaultNLQueryGenerator, matchesFilter, applyFilters } from './nl-query-generator.js';
|
|
54
|
+
// Re-export entity operations
|
|
55
|
+
export { createEntityOperations, createEdgeEntityOperations, createNounEntityOperations, createVerbEntityOperations, } from './entity-operations.js';
|
|
56
|
+
// Re-export NL query functions
|
|
57
|
+
export { buildNLQueryContext, executeNLQuery, createNLQueryFn, setNLQueryGenerator, getNLQueryGenerator, } from './nl-query.js';
|
|
43
58
|
// Re-export dependency graph functions
|
|
44
59
|
export { buildDependencyGraph, topologicalSort, detectCycles, getParallelGroups, getAllDependencies, hasCycles, visualizeGraph, CircularDependencyError, PRIMITIVE_TYPES, } from './dependency-graph.js';
|
|
45
60
|
// Re-export union fallback functions
|
|
46
61
|
export { parseUnionTypes, parseUnionThresholds, searchUnionTypes, createProviderSearcher, } from './union-fallback.js';
|
|
47
62
|
// Re-export generation context
|
|
48
63
|
export { GenerationContext, createGenerationContext, ContextOverflowError, } from './generation-context.js';
|
|
64
|
+
// Re-export schema versioning functions
|
|
65
|
+
export { computeSchemaHash, getSchemaVersion, setSchemaVersion, hasSchemaChanged, } from './version.js';
|
|
66
|
+
// Re-export schema diff functions
|
|
67
|
+
export { diffSchemas, describeDiff, } from './diff.js';
|
|
68
|
+
// Re-export migration functions
|
|
69
|
+
export { defineMigration, runMigrations, getPendingMigrations, rollbackLastMigration, } from './migration.js';
|
|
49
70
|
// Re-export verb derivation functions
|
|
50
71
|
export { FORWARD_TO_REVERSE, BIDIRECTIONAL_PAIRS, deriveReverseVerb, fieldNameToVerb, isPassiveVerb, registerVerbPair, registerBidirectionalPair, registerFieldVerb, } from './verb-derivation.js';
|
|
51
72
|
import { Verbs, parseUrl } from '../types.js';
|
|
@@ -53,8 +74,11 @@ import { inferNoun, getTypeMeta, conjugate } from '../linguistic.js';
|
|
|
53
74
|
import { parseSchema } from './parse.js';
|
|
54
75
|
import { resolveProvider, hasSemanticSearch, hasHybridSearch, hasEventsAPI, hasActionsAPI, hasArtifactsAPI, hasEmbeddingsConfig, } from './provider.js';
|
|
55
76
|
import { hydrateEntity, resolveReferenceSpec } from './resolve.js';
|
|
56
|
-
import { resolveForwardExact, generateAIFields, generateContextAwareValue, generateNaturalLanguageContent } from './cascade.js';
|
|
57
|
-
import { resolveBackwardFuzzy, resolveForwardFuzzy } from './semantic.js';
|
|
77
|
+
import { resolveForwardExact, generateAIFields, generateContextAwareValue, generateNaturalLanguageContent, generateEntity, setValueGenerator, } from './cascade.js';
|
|
78
|
+
import { resolveBackwardFuzzy, resolveForwardFuzzy, getFuzzyThreshold } from './semantic.js';
|
|
79
|
+
// Import from extracted modules for use in DB() factory
|
|
80
|
+
import { createEntityOperations, createEdgeEntityOperations, createNounEntityOperations, createVerbEntityOperations, } from './entity-operations.js';
|
|
81
|
+
import { createNLQueryFn } from './nl-query.js';
|
|
58
82
|
// =============================================================================
|
|
59
83
|
// Noun/Verb Helpers
|
|
60
84
|
// =============================================================================
|
|
@@ -232,441 +256,8 @@ function schemaToProperties(schema) {
|
|
|
232
256
|
}
|
|
233
257
|
return properties;
|
|
234
258
|
}
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
// =============================================================================
|
|
238
|
-
let nlQueryGenerator = null;
|
|
239
|
-
/**
|
|
240
|
-
* Set the AI generator for natural language queries
|
|
241
|
-
*/
|
|
242
|
-
export function setNLQueryGenerator(generator) {
|
|
243
|
-
nlQueryGenerator = generator;
|
|
244
|
-
}
|
|
245
|
-
function buildNLQueryContext(schema, targetType) {
|
|
246
|
-
const types = [];
|
|
247
|
-
for (const [name, entity] of schema.entities) {
|
|
248
|
-
const fields = [];
|
|
249
|
-
const relationships = [];
|
|
250
|
-
for (const [fieldName, field] of entity.fields) {
|
|
251
|
-
if (field.isRelation && field.relatedType) {
|
|
252
|
-
relationships.push({
|
|
253
|
-
name: fieldName,
|
|
254
|
-
to: field.relatedType,
|
|
255
|
-
cardinality: field.isArray ? 'many' : 'one',
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
fields.push(fieldName);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
const meta = getTypeMeta(name);
|
|
263
|
-
types.push({
|
|
264
|
-
name,
|
|
265
|
-
singular: meta.singular,
|
|
266
|
-
plural: meta.plural,
|
|
267
|
-
fields,
|
|
268
|
-
relationships,
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
return { types, targetType };
|
|
272
|
-
}
|
|
273
|
-
async function executeNLQuery(question, schema, targetType) {
|
|
274
|
-
if (!nlQueryGenerator) {
|
|
275
|
-
const provider = await resolveProvider();
|
|
276
|
-
const results = [];
|
|
277
|
-
// Simple heuristic for common "list all" patterns in fallback mode
|
|
278
|
-
const lowerQuestion = question.toLowerCase().trim();
|
|
279
|
-
const isListAllQuery = /^(show|list|get|find|display)\s+(all|every|the)?\s*/i.test(lowerQuestion) ||
|
|
280
|
-
lowerQuestion === '' ||
|
|
281
|
-
/\ball\b/i.test(lowerQuestion);
|
|
282
|
-
if (targetType) {
|
|
283
|
-
if (isListAllQuery) {
|
|
284
|
-
// For "show all X" queries, just list everything
|
|
285
|
-
const listResults = await provider.list(targetType);
|
|
286
|
-
results.push(...listResults);
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
const searchResults = await provider.search(targetType, question);
|
|
290
|
-
results.push(...searchResults);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
for (const [typeName] of schema.entities) {
|
|
295
|
-
if (isListAllQuery) {
|
|
296
|
-
const listResults = await provider.list(typeName);
|
|
297
|
-
results.push(...listResults);
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
const searchResults = await provider.search(typeName, question);
|
|
301
|
-
results.push(...searchResults);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return {
|
|
306
|
-
interpretation: `Search for "${question}"`,
|
|
307
|
-
confidence: 0.5,
|
|
308
|
-
results,
|
|
309
|
-
explanation: 'Fallback to keyword search (no AI generator configured)',
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
const context = buildNLQueryContext(schema, targetType);
|
|
313
|
-
const plan = await nlQueryGenerator(question, context);
|
|
314
|
-
const provider = await resolveProvider();
|
|
315
|
-
const results = [];
|
|
316
|
-
for (const typeName of plan.types) {
|
|
317
|
-
let typeResults;
|
|
318
|
-
if (plan.search) {
|
|
319
|
-
typeResults = await provider.search(typeName, plan.search, {
|
|
320
|
-
where: plan.filters,
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
typeResults = await provider.list(typeName, {
|
|
325
|
-
where: plan.filters,
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
results.push(...typeResults);
|
|
329
|
-
}
|
|
330
|
-
return {
|
|
331
|
-
interpretation: plan.interpretation,
|
|
332
|
-
confidence: plan.confidence,
|
|
333
|
-
results,
|
|
334
|
-
query: JSON.stringify({ types: plan.types, filters: plan.filters, search: plan.search }),
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
function createNLQueryFn(schema, typeName) {
|
|
338
|
-
return async (strings, ...values) => {
|
|
339
|
-
const question = strings.reduce((acc, str, i) => {
|
|
340
|
-
return acc + str + (values[i] !== undefined ? String(values[i]) : '');
|
|
341
|
-
}, '');
|
|
342
|
-
return executeNLQuery(question, schema, typeName);
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
// =============================================================================
|
|
346
|
-
// Edge Entity Operations
|
|
347
|
-
// =============================================================================
|
|
348
|
-
function createEdgeEntityOperations(schemaEdgeRecords, getProvider) {
|
|
349
|
-
async function getRuntimeEdges() {
|
|
350
|
-
try {
|
|
351
|
-
const provider = await getProvider();
|
|
352
|
-
const runtimeEdges = await provider.list('Edge');
|
|
353
|
-
return runtimeEdges;
|
|
354
|
-
}
|
|
355
|
-
catch {
|
|
356
|
-
return [];
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
async function getAllEdges() {
|
|
360
|
-
const runtimeEdges = await getRuntimeEdges();
|
|
361
|
-
const runtimeEdgeKeys = new Set(runtimeEdges.map(e => `${e.from}:${e.name}`));
|
|
362
|
-
const filteredSchemaEdges = schemaEdgeRecords.filter(e => {
|
|
363
|
-
const key = `${e.from}:${e.name}`;
|
|
364
|
-
const hasRuntimeVersion = runtimeEdgeKeys.has(key);
|
|
365
|
-
if (hasRuntimeVersion && e.matchMode === 'fuzzy') {
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
return !hasRuntimeVersion;
|
|
369
|
-
});
|
|
370
|
-
return [...filteredSchemaEdges, ...runtimeEdges];
|
|
371
|
-
}
|
|
372
|
-
return {
|
|
373
|
-
async get(id) {
|
|
374
|
-
const runtimeEdges = await getRuntimeEdges();
|
|
375
|
-
const runtimeMatch = runtimeEdges.find(e => e.$id === id || `${e.from}:${e.name}` === id);
|
|
376
|
-
if (runtimeMatch)
|
|
377
|
-
return { ...runtimeMatch, $type: 'Edge' };
|
|
378
|
-
return schemaEdgeRecords.find(e => `${e.from}:${e.name}` === id) ?? null;
|
|
379
|
-
},
|
|
380
|
-
async list(options) {
|
|
381
|
-
let results = await getAllEdges();
|
|
382
|
-
if (options?.where) {
|
|
383
|
-
for (const [key, value] of Object.entries(options.where)) {
|
|
384
|
-
results = results.filter(e => e[key] === value);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
return results.map(e => ({
|
|
388
|
-
...e,
|
|
389
|
-
$id: e.$id || `${e.from}:${e.name}`,
|
|
390
|
-
$type: 'Edge',
|
|
391
|
-
}));
|
|
392
|
-
},
|
|
393
|
-
async find(where) {
|
|
394
|
-
let results = await getAllEdges();
|
|
395
|
-
for (const [key, value] of Object.entries(where)) {
|
|
396
|
-
results = results.filter(e => e[key] === value);
|
|
397
|
-
}
|
|
398
|
-
return results.map(e => ({
|
|
399
|
-
...e,
|
|
400
|
-
$id: e.$id || `${e.from}:${e.name}`,
|
|
401
|
-
$type: 'Edge',
|
|
402
|
-
}));
|
|
403
|
-
},
|
|
404
|
-
async search(query) {
|
|
405
|
-
const allEdges = await getAllEdges();
|
|
406
|
-
const queryLower = query.toLowerCase();
|
|
407
|
-
return allEdges
|
|
408
|
-
.filter(e => String(e.from).toLowerCase().includes(queryLower) ||
|
|
409
|
-
String(e.name).toLowerCase().includes(queryLower) ||
|
|
410
|
-
String(e.to).toLowerCase().includes(queryLower))
|
|
411
|
-
.map(e => ({
|
|
412
|
-
...e,
|
|
413
|
-
$id: e.$id || `${e.from}:${e.name}`,
|
|
414
|
-
$type: 'Edge',
|
|
415
|
-
}));
|
|
416
|
-
},
|
|
417
|
-
async create() {
|
|
418
|
-
throw new Error('Cannot manually create Edge records - they are auto-generated');
|
|
419
|
-
},
|
|
420
|
-
async update() {
|
|
421
|
-
throw new Error('Cannot manually update Edge records - they are auto-generated');
|
|
422
|
-
},
|
|
423
|
-
async upsert() {
|
|
424
|
-
throw new Error('Cannot manually upsert Edge records - they are auto-generated');
|
|
425
|
-
},
|
|
426
|
-
async delete() {
|
|
427
|
-
throw new Error('Cannot manually delete Edge records - they are auto-generated');
|
|
428
|
-
},
|
|
429
|
-
async forEach(optionsOrCallback, maybeCallback) {
|
|
430
|
-
const options = typeof optionsOrCallback === 'function' ? undefined : optionsOrCallback;
|
|
431
|
-
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback;
|
|
432
|
-
const items = await this.list(options);
|
|
433
|
-
for (const item of items) {
|
|
434
|
-
await callback(item);
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
async semanticSearch() {
|
|
438
|
-
return [];
|
|
439
|
-
},
|
|
440
|
-
async hybridSearch() {
|
|
441
|
-
return [];
|
|
442
|
-
},
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
// =============================================================================
|
|
446
|
-
// Entity Operations Factory
|
|
447
|
-
// =============================================================================
|
|
448
|
-
function createEntityOperations(typeName, entity, schema) {
|
|
449
|
-
return {
|
|
450
|
-
async get(id) {
|
|
451
|
-
const provider = await resolveProvider();
|
|
452
|
-
const result = await provider.get(typeName, id);
|
|
453
|
-
if (!result)
|
|
454
|
-
return null;
|
|
455
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
456
|
-
},
|
|
457
|
-
async list(options) {
|
|
458
|
-
const provider = await resolveProvider();
|
|
459
|
-
const results = await provider.list(typeName, options);
|
|
460
|
-
return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
|
|
461
|
-
},
|
|
462
|
-
async find(where) {
|
|
463
|
-
const provider = await resolveProvider();
|
|
464
|
-
const results = await provider.list(typeName, {
|
|
465
|
-
where: where,
|
|
466
|
-
});
|
|
467
|
-
return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
|
|
468
|
-
},
|
|
469
|
-
async search(query, options) {
|
|
470
|
-
const provider = await resolveProvider();
|
|
471
|
-
const results = await provider.search(typeName, query, options);
|
|
472
|
-
return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
|
|
473
|
-
},
|
|
474
|
-
async create(idOrData, maybeData) {
|
|
475
|
-
const provider = await resolveProvider();
|
|
476
|
-
const providedId = typeof idOrData === 'string' ? idOrData : undefined;
|
|
477
|
-
const data = typeof idOrData === 'string'
|
|
478
|
-
? maybeData
|
|
479
|
-
: idOrData;
|
|
480
|
-
const entityId = providedId || crypto.randomUUID();
|
|
481
|
-
const { data: resolvedData, pendingRelations } = await resolveForwardExact(typeName, data, entity, schema, provider, entityId);
|
|
482
|
-
const { data: fuzzyResolvedData, pendingRelations: fuzzyPendingRelations } = await resolveForwardFuzzy(typeName, resolvedData, entity, schema, provider, entityId);
|
|
483
|
-
const backwardResolvedData = await resolveBackwardFuzzy(typeName, fuzzyResolvedData, entity, schema, provider);
|
|
484
|
-
const finalData = await generateAIFields(backwardResolvedData, typeName, entity, schema, provider);
|
|
485
|
-
const result = await provider.create(typeName, entityId, finalData);
|
|
486
|
-
for (const rel of pendingRelations) {
|
|
487
|
-
await provider.relate(typeName, entityId, rel.fieldName, rel.targetType, rel.targetId);
|
|
488
|
-
}
|
|
489
|
-
const createdEdgeIds = new Set();
|
|
490
|
-
for (const rel of fuzzyPendingRelations) {
|
|
491
|
-
await provider.relate(typeName, entityId, rel.fieldName, rel.targetType, rel.targetId, {
|
|
492
|
-
matchMode: 'fuzzy',
|
|
493
|
-
similarity: rel.similarity,
|
|
494
|
-
matchedType: rel.matchedType
|
|
495
|
-
});
|
|
496
|
-
const edgeId = `${typeName}:${rel.fieldName}:${entityId}:${rel.targetId}`;
|
|
497
|
-
if (!createdEdgeIds.has(edgeId)) {
|
|
498
|
-
createdEdgeIds.add(edgeId);
|
|
499
|
-
try {
|
|
500
|
-
await provider.create('Edge', edgeId, {
|
|
501
|
-
from: typeName,
|
|
502
|
-
name: rel.fieldName,
|
|
503
|
-
to: rel.targetType,
|
|
504
|
-
direction: 'forward',
|
|
505
|
-
matchMode: 'fuzzy',
|
|
506
|
-
similarity: rel.similarity,
|
|
507
|
-
matchedType: rel.matchedType,
|
|
508
|
-
fromId: entityId,
|
|
509
|
-
toId: rel.targetId,
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
catch {
|
|
513
|
-
// Edge already exists
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
518
|
-
},
|
|
519
|
-
async update(id, data) {
|
|
520
|
-
const provider = await resolveProvider();
|
|
521
|
-
const result = await provider.update(typeName, id, data);
|
|
522
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
523
|
-
},
|
|
524
|
-
async upsert(id, data) {
|
|
525
|
-
const provider = await resolveProvider();
|
|
526
|
-
const existing = await provider.get(typeName, id);
|
|
527
|
-
if (existing) {
|
|
528
|
-
const result = await provider.update(typeName, id, data);
|
|
529
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
530
|
-
}
|
|
531
|
-
const result = await provider.create(typeName, id, data);
|
|
532
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
533
|
-
},
|
|
534
|
-
async delete(id) {
|
|
535
|
-
const provider = await resolveProvider();
|
|
536
|
-
return provider.delete(typeName, id);
|
|
537
|
-
},
|
|
538
|
-
async forEach(optionsOrCallback, maybeCallback) {
|
|
539
|
-
const options = typeof optionsOrCallback === 'function' ? undefined : optionsOrCallback;
|
|
540
|
-
const callback = typeof optionsOrCallback === 'function'
|
|
541
|
-
? optionsOrCallback
|
|
542
|
-
: maybeCallback;
|
|
543
|
-
const items = await this.list(options);
|
|
544
|
-
for (const item of items) {
|
|
545
|
-
await callback(item);
|
|
546
|
-
}
|
|
547
|
-
},
|
|
548
|
-
async semanticSearch(query, options) {
|
|
549
|
-
const provider = await resolveProvider();
|
|
550
|
-
if (hasSemanticSearch(provider)) {
|
|
551
|
-
const results = await provider.semanticSearch(typeName, query, options);
|
|
552
|
-
return Promise.all(results.map((r) => ({
|
|
553
|
-
...hydrateEntity(r, entity, schema, resolveProvider),
|
|
554
|
-
$score: r.$score,
|
|
555
|
-
})));
|
|
556
|
-
}
|
|
557
|
-
return [];
|
|
558
|
-
},
|
|
559
|
-
async hybridSearch(query, options) {
|
|
560
|
-
const provider = await resolveProvider();
|
|
561
|
-
if (hasHybridSearch(provider)) {
|
|
562
|
-
const results = await provider.hybridSearch(typeName, query, options);
|
|
563
|
-
return Promise.all(results.map((r) => ({
|
|
564
|
-
...hydrateEntity(r, entity, schema, resolveProvider),
|
|
565
|
-
$rrfScore: r.$rrfScore,
|
|
566
|
-
$ftsRank: r.$ftsRank,
|
|
567
|
-
$semanticRank: r.$semanticRank,
|
|
568
|
-
$score: r.$score,
|
|
569
|
-
})));
|
|
570
|
-
}
|
|
571
|
-
return [];
|
|
572
|
-
},
|
|
573
|
-
async draft(data, options) {
|
|
574
|
-
const draftData = { ...data, $phase: 'draft' };
|
|
575
|
-
const refs = {};
|
|
576
|
-
for (const [fieldName, field] of entity.fields) {
|
|
577
|
-
if (draftData[fieldName] !== undefined && draftData[fieldName] !== null) {
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
if (field.operator && field.relatedType) {
|
|
581
|
-
const matchMode = field.matchMode ?? (field.operator.includes('~') ? 'fuzzy' : 'exact');
|
|
582
|
-
if (field.isArray) {
|
|
583
|
-
const generatedText = generateNaturalLanguageContent(fieldName, field.prompt, field.relatedType, data);
|
|
584
|
-
draftData[fieldName] = generatedText;
|
|
585
|
-
const refSpec = {
|
|
586
|
-
field: fieldName,
|
|
587
|
-
operator: field.operator,
|
|
588
|
-
type: field.relatedType,
|
|
589
|
-
matchMode,
|
|
590
|
-
resolved: false,
|
|
591
|
-
prompt: field.prompt,
|
|
592
|
-
generatedText,
|
|
593
|
-
};
|
|
594
|
-
refs[fieldName] = [refSpec];
|
|
595
|
-
if (options?.stream && options.onChunk) {
|
|
596
|
-
options.onChunk(generatedText);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
else {
|
|
600
|
-
const generatedText = generateNaturalLanguageContent(fieldName, field.prompt, field.relatedType, data);
|
|
601
|
-
draftData[fieldName] = generatedText;
|
|
602
|
-
refs[fieldName] = {
|
|
603
|
-
field: fieldName,
|
|
604
|
-
operator: field.operator,
|
|
605
|
-
type: field.relatedType,
|
|
606
|
-
matchMode,
|
|
607
|
-
resolved: false,
|
|
608
|
-
prompt: field.prompt,
|
|
609
|
-
generatedText,
|
|
610
|
-
};
|
|
611
|
-
if (options?.stream && options.onChunk) {
|
|
612
|
-
options.onChunk(generatedText);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
draftData.$refs = refs;
|
|
618
|
-
return draftData;
|
|
619
|
-
},
|
|
620
|
-
async resolve(draft, options) {
|
|
621
|
-
// Draft<T> interface requires $phase: 'draft', so we can access it directly
|
|
622
|
-
if (draft.$phase !== 'draft') {
|
|
623
|
-
throw new Error('Cannot resolve entity: not a draft (missing $phase: "draft")');
|
|
624
|
-
}
|
|
625
|
-
const provider = await resolveProvider();
|
|
626
|
-
const resolved = { ...draft };
|
|
627
|
-
const errors = [];
|
|
628
|
-
delete resolved.$refs;
|
|
629
|
-
resolved.$phase = 'resolved';
|
|
630
|
-
const refs = draft.$refs;
|
|
631
|
-
for (const [fieldName, refSpec] of Object.entries(refs)) {
|
|
632
|
-
try {
|
|
633
|
-
if (Array.isArray(refSpec)) {
|
|
634
|
-
const resolvedIds = [];
|
|
635
|
-
for (const spec of refSpec) {
|
|
636
|
-
const resolvedId = await resolveReferenceSpec(spec, resolved, schema, provider, generateContextAwareValue);
|
|
637
|
-
if (resolvedId) {
|
|
638
|
-
resolvedIds.push(resolvedId);
|
|
639
|
-
options?.onResolved?.(fieldName, resolvedId);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
resolved[fieldName] = resolvedIds;
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
const resolvedId = await resolveReferenceSpec(refSpec, resolved, schema, provider, generateContextAwareValue);
|
|
646
|
-
if (resolvedId) {
|
|
647
|
-
resolved[fieldName] = resolvedId;
|
|
648
|
-
options?.onResolved?.(fieldName, resolvedId);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
catch (err) {
|
|
653
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
654
|
-
if (options?.onError === 'skip') {
|
|
655
|
-
errors.push({ field: fieldName, error: errorMsg });
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
throw err;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
if (errors.length > 0 || options?.onError === 'skip') {
|
|
663
|
-
// resolved is typed as Record<string, unknown>, so we can assign $errors directly
|
|
664
|
-
resolved.$errors = errors;
|
|
665
|
-
}
|
|
666
|
-
return resolved;
|
|
667
|
-
},
|
|
668
|
-
};
|
|
669
|
-
}
|
|
259
|
+
// Note: NL Query functions extracted to nl-query.ts
|
|
260
|
+
// Note: Edge Entity Operations extracted to entity-operations.ts
|
|
670
261
|
// =============================================================================
|
|
671
262
|
// DB Factory
|
|
672
263
|
// =============================================================================
|
|
@@ -675,23 +266,199 @@ function createEntityOperations(typeName, entity, schema) {
|
|
|
675
266
|
*/
|
|
676
267
|
export function DB(schema, options) {
|
|
677
268
|
const parsedSchema = parseSchema(schema);
|
|
678
|
-
// Add
|
|
269
|
+
// Add system entities to the parsed schema (Noun, Verb, Edge)
|
|
270
|
+
// Noun entity - represents type definitions
|
|
271
|
+
const nounEntity = {
|
|
272
|
+
name: 'Noun',
|
|
273
|
+
fields: new Map([
|
|
274
|
+
[
|
|
275
|
+
'name',
|
|
276
|
+
{ name: 'name', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
277
|
+
],
|
|
278
|
+
[
|
|
279
|
+
'singular',
|
|
280
|
+
{ name: 'singular', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
281
|
+
],
|
|
282
|
+
[
|
|
283
|
+
'plural',
|
|
284
|
+
{ name: 'plural', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
285
|
+
],
|
|
286
|
+
[
|
|
287
|
+
'slug',
|
|
288
|
+
{ name: 'slug', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
289
|
+
],
|
|
290
|
+
[
|
|
291
|
+
'slugPlural',
|
|
292
|
+
{
|
|
293
|
+
name: 'slugPlural',
|
|
294
|
+
type: 'string',
|
|
295
|
+
isArray: false,
|
|
296
|
+
isOptional: false,
|
|
297
|
+
isRelation: false,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
[
|
|
301
|
+
'description',
|
|
302
|
+
{
|
|
303
|
+
name: 'description',
|
|
304
|
+
type: 'string',
|
|
305
|
+
isArray: false,
|
|
306
|
+
isOptional: true,
|
|
307
|
+
isRelation: false,
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
[
|
|
311
|
+
'properties',
|
|
312
|
+
{ name: 'properties', type: 'json', isArray: false, isOptional: true, isRelation: false },
|
|
313
|
+
],
|
|
314
|
+
[
|
|
315
|
+
'relationships',
|
|
316
|
+
{
|
|
317
|
+
name: 'relationships',
|
|
318
|
+
type: 'json',
|
|
319
|
+
isArray: false,
|
|
320
|
+
isOptional: true,
|
|
321
|
+
isRelation: false,
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
[
|
|
325
|
+
'actions',
|
|
326
|
+
{ name: 'actions', type: 'json', isArray: false, isOptional: true, isRelation: false },
|
|
327
|
+
],
|
|
328
|
+
[
|
|
329
|
+
'events',
|
|
330
|
+
{ name: 'events', type: 'json', isArray: false, isOptional: true, isRelation: false },
|
|
331
|
+
],
|
|
332
|
+
[
|
|
333
|
+
'metadata',
|
|
334
|
+
{ name: 'metadata', type: 'json', isArray: false, isOptional: true, isRelation: false },
|
|
335
|
+
],
|
|
336
|
+
]),
|
|
337
|
+
};
|
|
338
|
+
parsedSchema.entities.set('Noun', nounEntity);
|
|
339
|
+
// Verb entity - represents action definitions
|
|
340
|
+
const verbEntity = {
|
|
341
|
+
name: 'Verb',
|
|
342
|
+
fields: new Map([
|
|
343
|
+
[
|
|
344
|
+
'action',
|
|
345
|
+
{ name: 'action', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
346
|
+
],
|
|
347
|
+
[
|
|
348
|
+
'actor',
|
|
349
|
+
{ name: 'actor', type: 'string', isArray: false, isOptional: true, isRelation: false },
|
|
350
|
+
],
|
|
351
|
+
['act', { name: 'act', type: 'string', isArray: false, isOptional: true, isRelation: false }],
|
|
352
|
+
[
|
|
353
|
+
'activity',
|
|
354
|
+
{ name: 'activity', type: 'string', isArray: false, isOptional: true, isRelation: false },
|
|
355
|
+
],
|
|
356
|
+
[
|
|
357
|
+
'result',
|
|
358
|
+
{ name: 'result', type: 'string', isArray: false, isOptional: true, isRelation: false },
|
|
359
|
+
],
|
|
360
|
+
[
|
|
361
|
+
'reverse',
|
|
362
|
+
{ name: 'reverse', type: 'json', isArray: false, isOptional: true, isRelation: false },
|
|
363
|
+
],
|
|
364
|
+
[
|
|
365
|
+
'inverse',
|
|
366
|
+
{ name: 'inverse', type: 'string', isArray: false, isOptional: true, isRelation: false },
|
|
367
|
+
],
|
|
368
|
+
[
|
|
369
|
+
'description',
|
|
370
|
+
{
|
|
371
|
+
name: 'description',
|
|
372
|
+
type: 'string',
|
|
373
|
+
isArray: false,
|
|
374
|
+
isOptional: true,
|
|
375
|
+
isRelation: false,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
]),
|
|
379
|
+
};
|
|
380
|
+
parsedSchema.entities.set('Verb', verbEntity);
|
|
381
|
+
// Edge entity - represents relationships
|
|
679
382
|
const edgeEntity = {
|
|
680
383
|
name: 'Edge',
|
|
681
384
|
fields: new Map([
|
|
682
|
-
[
|
|
683
|
-
|
|
385
|
+
[
|
|
386
|
+
'from',
|
|
387
|
+
{ name: 'from', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
388
|
+
],
|
|
389
|
+
[
|
|
390
|
+
'name',
|
|
391
|
+
{ name: 'name', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
392
|
+
],
|
|
684
393
|
['to', { name: 'to', type: 'string', isArray: false, isOptional: false, isRelation: false }],
|
|
685
|
-
[
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
394
|
+
[
|
|
395
|
+
'backref',
|
|
396
|
+
{ name: 'backref', type: 'string', isArray: false, isOptional: true, isRelation: false },
|
|
397
|
+
],
|
|
398
|
+
[
|
|
399
|
+
'cardinality',
|
|
400
|
+
{
|
|
401
|
+
name: 'cardinality',
|
|
402
|
+
type: 'string',
|
|
403
|
+
isArray: false,
|
|
404
|
+
isOptional: false,
|
|
405
|
+
isRelation: false,
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
[
|
|
409
|
+
'direction',
|
|
410
|
+
{ name: 'direction', type: 'string', isArray: false, isOptional: false, isRelation: false },
|
|
411
|
+
],
|
|
412
|
+
[
|
|
413
|
+
'matchMode',
|
|
414
|
+
{ name: 'matchMode', type: 'string', isArray: false, isOptional: true, isRelation: false },
|
|
415
|
+
],
|
|
689
416
|
]),
|
|
690
417
|
};
|
|
691
418
|
parsedSchema.entities.set('Edge', edgeEntity);
|
|
419
|
+
// Create local getProvider function for dependency injection
|
|
420
|
+
// If options.provider is provided, use it; otherwise fall back to global resolveProvider()
|
|
421
|
+
let cachedProvider = null;
|
|
422
|
+
let providerPromise = null;
|
|
423
|
+
async function getProvider() {
|
|
424
|
+
// Return cached provider if available
|
|
425
|
+
if (cachedProvider)
|
|
426
|
+
return cachedProvider;
|
|
427
|
+
// Return pending promise if resolution is in progress
|
|
428
|
+
if (providerPromise)
|
|
429
|
+
return providerPromise;
|
|
430
|
+
// Check if options.provider is provided (dependency injection)
|
|
431
|
+
if (options?.provider) {
|
|
432
|
+
providerPromise = (async () => {
|
|
433
|
+
const providerOption = options.provider;
|
|
434
|
+
if (typeof providerOption === 'function') {
|
|
435
|
+
// It's a factory function - call it
|
|
436
|
+
const result = providerOption();
|
|
437
|
+
// Handle both sync and async factory functions
|
|
438
|
+
cachedProvider = result instanceof Promise ? await result : result;
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
// It's a direct provider instance
|
|
442
|
+
cachedProvider = providerOption;
|
|
443
|
+
}
|
|
444
|
+
return cachedProvider;
|
|
445
|
+
})();
|
|
446
|
+
return providerPromise;
|
|
447
|
+
}
|
|
448
|
+
// Fall back to global resolveProvider()
|
|
449
|
+
providerPromise = resolveProvider().then((p) => {
|
|
450
|
+
cachedProvider = p;
|
|
451
|
+
return p;
|
|
452
|
+
});
|
|
453
|
+
return providerPromise;
|
|
454
|
+
}
|
|
455
|
+
// Configure value generator if provided
|
|
456
|
+
if (options?.valueGenerator) {
|
|
457
|
+
setValueGenerator(options.valueGenerator);
|
|
458
|
+
}
|
|
692
459
|
// Configure provider with embeddings settings if provided
|
|
693
460
|
if (options?.embeddings) {
|
|
694
|
-
|
|
461
|
+
getProvider().then((provider) => {
|
|
695
462
|
if (hasEmbeddingsConfig(provider)) {
|
|
696
463
|
provider.setEmbeddingsConfig(options.embeddings);
|
|
697
464
|
}
|
|
@@ -700,11 +467,27 @@ export function DB(schema, options) {
|
|
|
700
467
|
// Collect all edge records from the schema
|
|
701
468
|
const allEdgeRecords = [];
|
|
702
469
|
for (const [entityName, entity] of parsedSchema.entities) {
|
|
703
|
-
|
|
470
|
+
// Only create edge records for user-defined entities (not system entities)
|
|
471
|
+
if (entityName !== 'Edge' && entityName !== 'Noun' && entityName !== 'Verb') {
|
|
704
472
|
const edgeRecords = createEdgeRecords(entityName, schema[entityName] ?? {}, entity);
|
|
705
473
|
allEdgeRecords.push(...edgeRecords);
|
|
706
474
|
}
|
|
707
475
|
}
|
|
476
|
+
// Collect all noun records from the schema (user-defined entities only)
|
|
477
|
+
const allNounRecords = [];
|
|
478
|
+
for (const [entityName, entity] of parsedSchema.entities) {
|
|
479
|
+
// Only create noun records for user-defined entities (not system entities)
|
|
480
|
+
if (entityName !== 'Edge' && entityName !== 'Noun' && entityName !== 'Verb') {
|
|
481
|
+
const nounRecord = createNounRecord(entityName, schema[entityName]);
|
|
482
|
+
allNounRecords.push(nounRecord);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// Collect all verb records from the standard verbs
|
|
486
|
+
const allVerbRecords = Object.values(Verbs).map((verb) => ({
|
|
487
|
+
...verb,
|
|
488
|
+
$id: verb.action,
|
|
489
|
+
$type: 'Verb',
|
|
490
|
+
}));
|
|
708
491
|
// Build and set schema relation info for batch loading
|
|
709
492
|
// Maps entityType -> fieldName -> relatedType
|
|
710
493
|
const relationInfo = new Map();
|
|
@@ -724,7 +507,7 @@ export function DB(schema, options) {
|
|
|
724
507
|
// This API adapts DBAction to ForEachActionsAPI interface
|
|
725
508
|
const actionsAPI = {
|
|
726
509
|
async create(data) {
|
|
727
|
-
const provider = await
|
|
510
|
+
const provider = await getProvider();
|
|
728
511
|
if (hasActionsAPI(provider)) {
|
|
729
512
|
const action = await provider.createAction(data);
|
|
730
513
|
return { id: action.id };
|
|
@@ -732,35 +515,45 @@ export function DB(schema, options) {
|
|
|
732
515
|
throw new Error('Provider does not support actions');
|
|
733
516
|
},
|
|
734
517
|
async get(id) {
|
|
735
|
-
const provider = await
|
|
518
|
+
const provider = await getProvider();
|
|
736
519
|
if (hasActionsAPI(provider)) {
|
|
737
520
|
const action = await provider.getAction(id);
|
|
738
521
|
if (!action)
|
|
739
522
|
return null;
|
|
740
523
|
// Adapt DBAction to ForEachActionState
|
|
741
|
-
|
|
524
|
+
const state = {
|
|
742
525
|
id: action.id,
|
|
743
526
|
type: action.action ?? action.type ?? 'unknown',
|
|
744
527
|
status: action.status,
|
|
745
|
-
progress: action.progress,
|
|
746
|
-
total: action.total,
|
|
747
528
|
data: action.objectData ?? {},
|
|
748
|
-
result: action.result,
|
|
749
|
-
error: action.error,
|
|
750
529
|
};
|
|
530
|
+
if (action.progress !== undefined)
|
|
531
|
+
state.progress = action.progress;
|
|
532
|
+
if (action.total !== undefined)
|
|
533
|
+
state.total = action.total;
|
|
534
|
+
if (action.result !== undefined)
|
|
535
|
+
state.result = action.result;
|
|
536
|
+
if (action.error !== undefined)
|
|
537
|
+
state.error = action.error;
|
|
538
|
+
return state;
|
|
751
539
|
}
|
|
752
540
|
return null;
|
|
753
541
|
},
|
|
754
542
|
async update(id, updates) {
|
|
755
|
-
const provider = await
|
|
543
|
+
const provider = await getProvider();
|
|
756
544
|
if (hasActionsAPI(provider)) {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
545
|
+
const updatePayload = {};
|
|
546
|
+
if (updates.status !== undefined)
|
|
547
|
+
updatePayload.status = updates.status;
|
|
548
|
+
if (updates.progress !== undefined)
|
|
549
|
+
updatePayload.progress = updates.progress;
|
|
550
|
+
if (updates.error !== undefined)
|
|
551
|
+
updatePayload.error = updates.error;
|
|
552
|
+
// ForEachResult needs to be converted to Record<string, unknown> for DBAction.result
|
|
553
|
+
if (updates.result !== undefined) {
|
|
554
|
+
updatePayload.result = updates.result;
|
|
555
|
+
}
|
|
556
|
+
await provider.updateAction(id, updatePayload);
|
|
764
557
|
return;
|
|
765
558
|
}
|
|
766
559
|
throw new Error('Provider does not support actions');
|
|
@@ -781,12 +574,13 @@ export function DB(schema, options) {
|
|
|
781
574
|
function emitInternalEventForOps(eventType, data) {
|
|
782
575
|
const handlers = eventHandlersForOps.get(eventType);
|
|
783
576
|
if (handlers) {
|
|
784
|
-
|
|
577
|
+
const snapshot = [...handlers];
|
|
578
|
+
for (const handler of snapshot) {
|
|
785
579
|
try {
|
|
786
580
|
handler(data);
|
|
787
581
|
}
|
|
788
582
|
catch (e) {
|
|
789
|
-
|
|
583
|
+
logError(`Error in event handler for ${eventType}:`, e);
|
|
790
584
|
}
|
|
791
585
|
}
|
|
792
586
|
}
|
|
@@ -808,10 +602,23 @@ export function DB(schema, options) {
|
|
|
808
602
|
}
|
|
809
603
|
for (const [entityName, entity] of parsedSchema.entities) {
|
|
810
604
|
if (entityName === 'Edge') {
|
|
811
|
-
|
|
605
|
+
// Edge entity - auto-generated from schema relationships
|
|
606
|
+
const edgeOps = createEdgeEntityOperations(allEdgeRecords, getProvider);
|
|
812
607
|
const wrappedEdgeOps = wrapEntityOperations(entityName, edgeOps, actionsAPI);
|
|
813
608
|
entityOperations[entityName] = makeCallableEntityOps(wrappedEdgeOps, entityName);
|
|
814
609
|
}
|
|
610
|
+
else if (entityName === 'Noun') {
|
|
611
|
+
// Noun entity - auto-generated from schema entity types
|
|
612
|
+
const nounOps = createNounEntityOperations(allNounRecords);
|
|
613
|
+
const wrappedNounOps = wrapEntityOperations(entityName, nounOps, actionsAPI);
|
|
614
|
+
entityOperations[entityName] = makeCallableEntityOps(wrappedNounOps, entityName);
|
|
615
|
+
}
|
|
616
|
+
else if (entityName === 'Verb') {
|
|
617
|
+
// Verb entity - standard verbs with conjugation forms
|
|
618
|
+
const verbOps = createVerbEntityOperations(allVerbRecords);
|
|
619
|
+
const wrappedVerbOps = wrapEntityOperations(entityName, verbOps, actionsAPI);
|
|
620
|
+
entityOperations[entityName] = makeCallableEntityOps(wrappedVerbOps, entityName);
|
|
621
|
+
}
|
|
815
622
|
else {
|
|
816
623
|
const baseOps = createEntityOperations(entityName, entity, parsedSchema);
|
|
817
624
|
const wrappedOps = wrapEntityOperations(entityName, baseOps, actionsAPI);
|
|
@@ -823,7 +630,7 @@ export function DB(schema, options) {
|
|
|
823
630
|
throw new Error(`Draft method not available for ${entityName}`);
|
|
824
631
|
}
|
|
825
632
|
const draft = await draftMethod(data, options);
|
|
826
|
-
draft
|
|
633
|
+
draft['$type'] = entityName;
|
|
827
634
|
emitInternalEventForOps('draft', draft);
|
|
828
635
|
return draft;
|
|
829
636
|
};
|
|
@@ -834,7 +641,8 @@ export function DB(schema, options) {
|
|
|
834
641
|
}
|
|
835
642
|
const resolved = await resolveMethod(draft, options);
|
|
836
643
|
if (resolved && typeof resolved === 'object') {
|
|
837
|
-
|
|
644
|
+
;
|
|
645
|
+
resolved['$type'] = entityName;
|
|
838
646
|
}
|
|
839
647
|
emitInternalEventForOps('resolve', resolved);
|
|
840
648
|
return resolved;
|
|
@@ -858,27 +666,57 @@ export function DB(schema, options) {
|
|
|
858
666
|
const draft = await draftFn(data);
|
|
859
667
|
return draft;
|
|
860
668
|
}
|
|
669
|
+
// Check if entity has reference fields that need two-phase processing
|
|
670
|
+
const entityDef = parsedSchema.entities.get(entityName);
|
|
861
671
|
const effectiveMaxDepth = options?.maxDepth ?? (options?.cascade ? 3 : 0);
|
|
672
|
+
// Disable auto-generation when:
|
|
673
|
+
// 1. cascade is explicitly set to false
|
|
674
|
+
// 2. cascade is true but maxDepth is 0 (depth exhausted)
|
|
675
|
+
// When cascade is undefined, single-level array generation is allowed
|
|
676
|
+
const cascadeExplicitlyDisabled = options?.cascade === false || (options?.cascade === true && effectiveMaxDepth === 0);
|
|
677
|
+
const hasReferenceFields = entityDef &&
|
|
678
|
+
Array.from(entityDef.fields.values()).some((field) => {
|
|
679
|
+
if (!field.operator || !field.relatedType)
|
|
680
|
+
return false;
|
|
681
|
+
// Exclude forward fuzzy (~>) - handled by resolveForwardFuzzy in the direct create path
|
|
682
|
+
if (field.operator === '~>')
|
|
683
|
+
return false;
|
|
684
|
+
// For forward exact (->) array fields when cascade is explicitly disabled
|
|
685
|
+
if (field.operator === '->' && field.isArray && cascadeExplicitlyDisabled) {
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
688
|
+
return true;
|
|
689
|
+
});
|
|
690
|
+
// Cascade takes priority over two-phase processing when enabled
|
|
691
|
+
// Cascade handles generating related entities through the graph
|
|
862
692
|
if (options?.cascade && effectiveMaxDepth > 0) {
|
|
863
|
-
const provider = await
|
|
693
|
+
const provider = await getProvider();
|
|
864
694
|
const entityDef = parsedSchema.entities.get(entityName);
|
|
865
695
|
if (entityDef) {
|
|
866
696
|
// CreateEntityOptions now includes _cascadeState as an optional property
|
|
867
697
|
const cascadeState = options._cascadeState ?? {
|
|
868
698
|
totalEntitiesCreated: 0,
|
|
869
699
|
initialMaxDepth: effectiveMaxDepth,
|
|
870
|
-
rootOnProgress: options.onProgress,
|
|
871
|
-
rootOnError: options.onError,
|
|
872
|
-
stopOnError: options.stopOnError,
|
|
873
|
-
cascadeTypes: options.cascadeTypes,
|
|
700
|
+
...(options.onProgress !== undefined && { rootOnProgress: options.onProgress }),
|
|
701
|
+
...(options.onError !== undefined && { rootOnError: options.onError }),
|
|
702
|
+
...(options.stopOnError !== undefined && { stopOnError: options.stopOnError }),
|
|
703
|
+
...(options.cascadeTypes !== undefined && { cascadeTypes: options.cascadeTypes }),
|
|
874
704
|
};
|
|
875
705
|
const currentDepth = cascadeState.initialMaxDepth - effectiveMaxDepth;
|
|
876
706
|
const cascadeData = { ...data };
|
|
707
|
+
// Emit progress for current entity being generated
|
|
708
|
+
cascadeState.rootOnProgress?.({
|
|
709
|
+
phase: 'generating',
|
|
710
|
+
depth: currentDepth,
|
|
711
|
+
currentType: entityName,
|
|
712
|
+
totalEntitiesCreated: cascadeState.totalEntitiesCreated,
|
|
713
|
+
});
|
|
877
714
|
for (const [fieldName, field] of entityDef.fields) {
|
|
878
715
|
if (cascadeData[fieldName] !== undefined)
|
|
879
716
|
continue;
|
|
880
717
|
if (field.operator === '->' && field.relatedType) {
|
|
881
|
-
if (cascadeState.cascadeTypes &&
|
|
718
|
+
if (cascadeState.cascadeTypes &&
|
|
719
|
+
!cascadeState.cascadeTypes.includes(field.relatedType)) {
|
|
882
720
|
continue;
|
|
883
721
|
}
|
|
884
722
|
const relatedEntity = parsedSchema.entities.get(field.relatedType);
|
|
@@ -892,39 +730,48 @@ export function DB(schema, options) {
|
|
|
892
730
|
totalEntitiesCreated: cascadeState.totalEntitiesCreated,
|
|
893
731
|
});
|
|
894
732
|
const childEntityData = {};
|
|
895
|
-
const parentInstructions = entityDef.schema
|
|
896
|
-
const childInstructions = relatedEntity.schema
|
|
733
|
+
const parentInstructions = entityDef.schema?.['$instructions'];
|
|
734
|
+
const childInstructions = relatedEntity.schema?.['$instructions'];
|
|
897
735
|
const contextParts = [];
|
|
898
736
|
if (parentInstructions)
|
|
899
737
|
contextParts.push(parentInstructions);
|
|
900
738
|
if (childInstructions)
|
|
901
739
|
contextParts.push(childInstructions);
|
|
902
740
|
for (const [key, value] of Object.entries(cascadeData)) {
|
|
903
|
-
if (!key.startsWith('$') &&
|
|
741
|
+
if (!key.startsWith('$') &&
|
|
742
|
+
!key.startsWith('_') &&
|
|
743
|
+
typeof value === 'string' &&
|
|
744
|
+
value) {
|
|
904
745
|
contextParts.push(`${key}: ${value}`);
|
|
905
746
|
}
|
|
906
747
|
}
|
|
907
748
|
const fullContext = contextParts.join(' | ');
|
|
908
749
|
for (const [childFieldName, childField] of relatedEntity.fields) {
|
|
909
|
-
|
|
910
|
-
|
|
750
|
+
const isPrompt = isPromptField(childField);
|
|
751
|
+
if (!childField.isRelation && (childField.type === 'string' || isPrompt)) {
|
|
752
|
+
// Use field type as hint for prompt fields
|
|
753
|
+
const fieldHint = isPrompt ? childField.type : undefined;
|
|
754
|
+
childEntityData[childFieldName] = generateContextAwareValue(childFieldName, field.relatedType, fullContext, fieldHint, cascadeData);
|
|
911
755
|
}
|
|
912
756
|
}
|
|
913
757
|
const childOptions = {
|
|
914
758
|
...options,
|
|
759
|
+
cascade: true, // Ensure cascade continues for child entities
|
|
915
760
|
maxDepth: effectiveMaxDepth - 1,
|
|
916
761
|
_cascadeState: cascadeState,
|
|
917
762
|
};
|
|
918
763
|
const relatedOps = entityOperations[field.relatedType];
|
|
919
|
-
const createFn = relatedOps?.create;
|
|
920
|
-
const childEntity = createFn
|
|
921
|
-
|
|
764
|
+
const createFn = relatedOps?.['create'];
|
|
765
|
+
const childEntity = createFn
|
|
766
|
+
? await createFn(childEntityData, childOptions)
|
|
767
|
+
: undefined;
|
|
768
|
+
if (childEntity?.['$id']) {
|
|
922
769
|
cascadeState.totalEntitiesCreated++;
|
|
923
770
|
if (field.isArray) {
|
|
924
|
-
cascadeData[fieldName] = [childEntity
|
|
771
|
+
cascadeData[fieldName] = [childEntity['$id']];
|
|
925
772
|
}
|
|
926
773
|
else {
|
|
927
|
-
cascadeData[fieldName] = childEntity
|
|
774
|
+
cascadeData[fieldName] = childEntity['$id'];
|
|
928
775
|
}
|
|
929
776
|
}
|
|
930
777
|
}
|
|
@@ -936,12 +783,13 @@ export function DB(schema, options) {
|
|
|
936
783
|
}
|
|
937
784
|
}
|
|
938
785
|
}
|
|
786
|
+
const createFn = originalCreate;
|
|
939
787
|
let result;
|
|
940
788
|
if (id) {
|
|
941
|
-
result = await
|
|
789
|
+
result = await createFn.call(wrappedOps, id, cascadeData);
|
|
942
790
|
}
|
|
943
791
|
else {
|
|
944
|
-
result = await
|
|
792
|
+
result = await createFn.call(wrappedOps, cascadeData);
|
|
945
793
|
}
|
|
946
794
|
cascadeState.totalEntitiesCreated++;
|
|
947
795
|
if (currentDepth === 0) {
|
|
@@ -954,8 +802,78 @@ export function DB(schema, options) {
|
|
|
954
802
|
return result;
|
|
955
803
|
}
|
|
956
804
|
}
|
|
957
|
-
|
|
805
|
+
// Use two-phase draft/resolve pipeline when entity has reference fields (but cascade not enabled)
|
|
806
|
+
if (hasReferenceFields) {
|
|
807
|
+
// Phase 1: Draft - create placeholder with natural language refs
|
|
808
|
+
// Skip promptless refs when cascade is not explicitly enabled (default behavior = no auto-generation)
|
|
809
|
+
const skipPromptless = options?.cascade !== true;
|
|
810
|
+
const draft = await draftFn(data, { _skipPromptlessRefs: skipPromptless });
|
|
811
|
+
// Phase 2: Resolve - convert refs to actual entity IDs
|
|
812
|
+
const resolved = await resolveFn(draft);
|
|
813
|
+
// Extract clean data for persistence (remove $phase, $refs, $errors)
|
|
814
|
+
const { $phase, $refs, $errors, $type, ...cleanData } = resolved;
|
|
815
|
+
// Phase 3: Generate AI fields for entities with $context dependencies
|
|
816
|
+
// The draft phase skips prompt fields for entities with $context because
|
|
817
|
+
// those fields need pre-fetched context data to generate properly.
|
|
818
|
+
// generateAIFields handles this context pre-fetching and field generation.
|
|
819
|
+
const provider = await getProvider();
|
|
820
|
+
const entityDefForAI = parsedSchema.entities.get(entityName);
|
|
821
|
+
let finalCleanData = cleanData;
|
|
822
|
+
if (entityDefForAI) {
|
|
823
|
+
finalCleanData = await generateAIFields(cleanData, entityName, entityDefForAI, parsedSchema, provider);
|
|
824
|
+
}
|
|
825
|
+
const createFn = originalCreate;
|
|
826
|
+
let result;
|
|
827
|
+
if (id) {
|
|
828
|
+
result = await createFn.call(wrappedOps, id, finalCleanData);
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
result = await createFn.call(wrappedOps, finalCleanData);
|
|
832
|
+
}
|
|
833
|
+
return result;
|
|
834
|
+
}
|
|
835
|
+
// Pre-initialize empty arrays for ->Type[] fields when cascade is explicitly disabled
|
|
836
|
+
// This prevents resolveForwardExact from auto-generating entities for array fields
|
|
837
|
+
let processedData = data;
|
|
838
|
+
if (cascadeExplicitlyDisabled && entityDef) {
|
|
839
|
+
processedData = { ...data };
|
|
840
|
+
for (const [fieldName, field] of entityDef.fields) {
|
|
841
|
+
if (processedData[fieldName] !== undefined)
|
|
842
|
+
continue;
|
|
843
|
+
if (field.isArray && field.operator === '->' && field.relatedType) {
|
|
844
|
+
processedData[fieldName] = [];
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
// Call with properly typed arguments (already extracted above)
|
|
849
|
+
// Use type assertion for internal overload dispatch via .call()
|
|
850
|
+
const createFnFinal = originalCreate;
|
|
851
|
+
if (id) {
|
|
852
|
+
return createFnFinal.call(wrappedOps, id, processedData, options);
|
|
853
|
+
}
|
|
854
|
+
return createFnFinal.call(wrappedOps, processedData, options);
|
|
958
855
|
};
|
|
856
|
+
// Add seed method if entity has seed configuration
|
|
857
|
+
if (entity.seedConfig) {
|
|
858
|
+
const seedConfig = entity.seedConfig;
|
|
859
|
+
wrappedOps['seed'] = async () => {
|
|
860
|
+
const { loadSeedData } = await import('./seed.js');
|
|
861
|
+
const records = await loadSeedData(seedConfig);
|
|
862
|
+
const provider = await getProvider();
|
|
863
|
+
for (const record of records) {
|
|
864
|
+
const { $id, ...data } = record;
|
|
865
|
+
// Upsert: check if exists, then update or create
|
|
866
|
+
const existing = await provider.get(entityName, $id);
|
|
867
|
+
if (existing) {
|
|
868
|
+
await provider.update(entityName, $id, data);
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
await provider.create(entityName, $id, data);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return { count: records.length };
|
|
875
|
+
};
|
|
876
|
+
}
|
|
959
877
|
// Make the entity operations callable as a tagged template literal
|
|
960
878
|
entityOperations[entityName] = makeCallableEntityOps(wrappedOps, entityName);
|
|
961
879
|
}
|
|
@@ -980,12 +898,12 @@ export function DB(schema, options) {
|
|
|
980
898
|
const db = {
|
|
981
899
|
$schema: parsedSchema,
|
|
982
900
|
async get(url) {
|
|
983
|
-
const provider = await
|
|
901
|
+
const provider = await getProvider();
|
|
984
902
|
const parsed = parseUrl(url);
|
|
985
903
|
return provider.get(parsed.type, parsed.id);
|
|
986
904
|
},
|
|
987
905
|
async search(query, options) {
|
|
988
|
-
const provider = await
|
|
906
|
+
const provider = await getProvider();
|
|
989
907
|
const results = [];
|
|
990
908
|
for (const [typeName] of parsedSchema.entities) {
|
|
991
909
|
const typeResults = await provider.search(typeName, query, options);
|
|
@@ -994,7 +912,7 @@ export function DB(schema, options) {
|
|
|
994
912
|
return results;
|
|
995
913
|
},
|
|
996
914
|
async semanticSearch(query, options) {
|
|
997
|
-
const provider = await
|
|
915
|
+
const provider = await getProvider();
|
|
998
916
|
const results = [];
|
|
999
917
|
if (hasSemanticSearch(provider)) {
|
|
1000
918
|
for (const [typeName] of parsedSchema.entities) {
|
|
@@ -1007,13 +925,19 @@ export function DB(schema, options) {
|
|
|
1007
925
|
return results.slice(0, limit);
|
|
1008
926
|
},
|
|
1009
927
|
async count(type, where) {
|
|
1010
|
-
const provider = await
|
|
1011
|
-
const
|
|
928
|
+
const provider = await getProvider();
|
|
929
|
+
const listOpts = {};
|
|
930
|
+
if (where !== undefined)
|
|
931
|
+
listOpts.where = where;
|
|
932
|
+
const results = await provider.list(type, listOpts);
|
|
1012
933
|
return results.length;
|
|
1013
934
|
},
|
|
1014
935
|
async forEach(options, callback) {
|
|
1015
|
-
const provider = await
|
|
1016
|
-
const
|
|
936
|
+
const provider = await getProvider();
|
|
937
|
+
const listOpts = {};
|
|
938
|
+
if (options.where !== undefined)
|
|
939
|
+
listOpts.where = options.where;
|
|
940
|
+
const results = await provider.list(options.type, listOpts);
|
|
1017
941
|
const concurrency = options.concurrency ?? 1;
|
|
1018
942
|
if (concurrency === 1) {
|
|
1019
943
|
for (const entity of results) {
|
|
@@ -1027,7 +951,7 @@ export function DB(schema, options) {
|
|
|
1027
951
|
}
|
|
1028
952
|
},
|
|
1029
953
|
async set(type, id, data) {
|
|
1030
|
-
const provider = await
|
|
954
|
+
const provider = await getProvider();
|
|
1031
955
|
const existing = await provider.get(type, id);
|
|
1032
956
|
if (existing) {
|
|
1033
957
|
return provider.update(type, id, data);
|
|
@@ -1035,7 +959,7 @@ export function DB(schema, options) {
|
|
|
1035
959
|
return provider.create(type, id, data);
|
|
1036
960
|
},
|
|
1037
961
|
async generate(options) {
|
|
1038
|
-
const provider = await
|
|
962
|
+
const provider = await getProvider();
|
|
1039
963
|
if (options.mode === 'background') {
|
|
1040
964
|
const { createMemoryProvider } = await import('../memory-provider.js');
|
|
1041
965
|
const memProvider = provider;
|
|
@@ -1057,7 +981,7 @@ export function DB(schema, options) {
|
|
|
1057
981
|
const events = {
|
|
1058
982
|
on(pattern, handler) {
|
|
1059
983
|
let unsubscribe = () => { };
|
|
1060
|
-
|
|
984
|
+
getProvider().then((provider) => {
|
|
1061
985
|
if (hasEventsAPI(provider)) {
|
|
1062
986
|
unsubscribe = provider.on(pattern, handler);
|
|
1063
987
|
}
|
|
@@ -1065,7 +989,7 @@ export function DB(schema, options) {
|
|
|
1065
989
|
return () => unsubscribe();
|
|
1066
990
|
},
|
|
1067
991
|
async emit(optionsOrType, data) {
|
|
1068
|
-
const provider = await
|
|
992
|
+
const provider = await getProvider();
|
|
1069
993
|
if (hasEventsAPI(provider)) {
|
|
1070
994
|
// The provider.emit has overloads: (options: CreateEventOptions) or (type: string, data: unknown)
|
|
1071
995
|
if (typeof optionsOrType === 'string') {
|
|
@@ -1075,36 +999,45 @@ export function DB(schema, options) {
|
|
|
1075
999
|
}
|
|
1076
1000
|
const now = new Date();
|
|
1077
1001
|
if (typeof optionsOrType === 'string') {
|
|
1078
|
-
|
|
1002
|
+
const baseEvent = {
|
|
1079
1003
|
id: crypto.randomUUID(),
|
|
1080
1004
|
actor: 'system',
|
|
1081
1005
|
event: optionsOrType,
|
|
1082
|
-
objectData: data,
|
|
1083
1006
|
timestamp: now,
|
|
1084
1007
|
};
|
|
1008
|
+
if (data !== undefined)
|
|
1009
|
+
baseEvent.objectData = data;
|
|
1010
|
+
return baseEvent;
|
|
1085
1011
|
}
|
|
1086
|
-
|
|
1012
|
+
const baseEvent = {
|
|
1087
1013
|
id: crypto.randomUUID(),
|
|
1088
1014
|
actor: optionsOrType.actor,
|
|
1089
|
-
actorData: optionsOrType.actorData,
|
|
1090
1015
|
event: optionsOrType.event,
|
|
1091
|
-
object: optionsOrType.object,
|
|
1092
|
-
objectData: optionsOrType.objectData,
|
|
1093
|
-
result: optionsOrType.result,
|
|
1094
|
-
resultData: optionsOrType.resultData,
|
|
1095
|
-
meta: optionsOrType.meta,
|
|
1096
1016
|
timestamp: now,
|
|
1097
1017
|
};
|
|
1018
|
+
if (optionsOrType.actorData !== undefined)
|
|
1019
|
+
baseEvent.actorData = optionsOrType.actorData;
|
|
1020
|
+
if (optionsOrType.object !== undefined)
|
|
1021
|
+
baseEvent.object = optionsOrType.object;
|
|
1022
|
+
if (optionsOrType.objectData !== undefined)
|
|
1023
|
+
baseEvent.objectData = optionsOrType.objectData;
|
|
1024
|
+
if (optionsOrType.result !== undefined)
|
|
1025
|
+
baseEvent.result = optionsOrType.result;
|
|
1026
|
+
if (optionsOrType.resultData !== undefined)
|
|
1027
|
+
baseEvent.resultData = optionsOrType.resultData;
|
|
1028
|
+
if (optionsOrType.meta !== undefined)
|
|
1029
|
+
baseEvent.meta = optionsOrType.meta;
|
|
1030
|
+
return baseEvent;
|
|
1098
1031
|
},
|
|
1099
1032
|
async list(options) {
|
|
1100
|
-
const provider = await
|
|
1033
|
+
const provider = await getProvider();
|
|
1101
1034
|
if (hasEventsAPI(provider)) {
|
|
1102
1035
|
return provider.listEvents(options);
|
|
1103
1036
|
}
|
|
1104
1037
|
return [];
|
|
1105
1038
|
},
|
|
1106
1039
|
async replay(options) {
|
|
1107
|
-
const provider = await
|
|
1040
|
+
const provider = await getProvider();
|
|
1108
1041
|
if (hasEventsAPI(provider)) {
|
|
1109
1042
|
await provider.replayEvents(options);
|
|
1110
1043
|
}
|
|
@@ -1113,42 +1046,42 @@ export function DB(schema, options) {
|
|
|
1113
1046
|
// Create Actions API (public version with full DBAction types)
|
|
1114
1047
|
const actions = {
|
|
1115
1048
|
async create(options) {
|
|
1116
|
-
const provider = await
|
|
1049
|
+
const provider = await getProvider();
|
|
1117
1050
|
if (hasActionsAPI(provider)) {
|
|
1118
1051
|
return provider.createAction(options);
|
|
1119
1052
|
}
|
|
1120
1053
|
throw new Error('Provider does not support actions');
|
|
1121
1054
|
},
|
|
1122
1055
|
async get(id) {
|
|
1123
|
-
const provider = await
|
|
1056
|
+
const provider = await getProvider();
|
|
1124
1057
|
if (hasActionsAPI(provider)) {
|
|
1125
1058
|
return provider.getAction(id);
|
|
1126
1059
|
}
|
|
1127
1060
|
return null;
|
|
1128
1061
|
},
|
|
1129
1062
|
async update(id, updates) {
|
|
1130
|
-
const provider = await
|
|
1063
|
+
const provider = await getProvider();
|
|
1131
1064
|
if (hasActionsAPI(provider)) {
|
|
1132
1065
|
return provider.updateAction(id, updates);
|
|
1133
1066
|
}
|
|
1134
1067
|
throw new Error('Provider does not support actions');
|
|
1135
1068
|
},
|
|
1136
1069
|
async list(options) {
|
|
1137
|
-
const provider = await
|
|
1070
|
+
const provider = await getProvider();
|
|
1138
1071
|
if (hasActionsAPI(provider)) {
|
|
1139
1072
|
return provider.listActions(options);
|
|
1140
1073
|
}
|
|
1141
1074
|
return [];
|
|
1142
1075
|
},
|
|
1143
1076
|
async retry(id) {
|
|
1144
|
-
const provider = await
|
|
1077
|
+
const provider = await getProvider();
|
|
1145
1078
|
if (hasActionsAPI(provider)) {
|
|
1146
1079
|
return provider.retryAction(id);
|
|
1147
1080
|
}
|
|
1148
1081
|
throw new Error('Provider does not support actions');
|
|
1149
1082
|
},
|
|
1150
1083
|
async cancel(id) {
|
|
1151
|
-
const provider = await
|
|
1084
|
+
const provider = await getProvider();
|
|
1152
1085
|
if (hasActionsAPI(provider)) {
|
|
1153
1086
|
await provider.cancelAction(id);
|
|
1154
1087
|
}
|
|
@@ -1158,26 +1091,26 @@ export function DB(schema, options) {
|
|
|
1158
1091
|
// Create Artifacts API
|
|
1159
1092
|
const artifacts = {
|
|
1160
1093
|
async get(url, type) {
|
|
1161
|
-
const provider = await
|
|
1094
|
+
const provider = await getProvider();
|
|
1162
1095
|
if (hasArtifactsAPI(provider)) {
|
|
1163
1096
|
return provider.getArtifact(url, type);
|
|
1164
1097
|
}
|
|
1165
1098
|
return null;
|
|
1166
1099
|
},
|
|
1167
1100
|
async set(url, type, data) {
|
|
1168
|
-
const provider = await
|
|
1101
|
+
const provider = await getProvider();
|
|
1169
1102
|
if (hasArtifactsAPI(provider)) {
|
|
1170
1103
|
await provider.setArtifact(url, type, data);
|
|
1171
1104
|
}
|
|
1172
1105
|
},
|
|
1173
1106
|
async delete(url, type) {
|
|
1174
|
-
const provider = await
|
|
1107
|
+
const provider = await getProvider();
|
|
1175
1108
|
if (hasArtifactsAPI(provider)) {
|
|
1176
1109
|
await provider.deleteArtifact(url, type);
|
|
1177
1110
|
}
|
|
1178
1111
|
},
|
|
1179
1112
|
async list(url) {
|
|
1180
|
-
const provider = await
|
|
1113
|
+
const provider = await getProvider();
|
|
1181
1114
|
if (hasArtifactsAPI(provider)) {
|
|
1182
1115
|
return provider.listArtifacts(url);
|
|
1183
1116
|
}
|