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/schema/index.js
CHANGED
|
@@ -30,23 +30,55 @@
|
|
|
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';
|
|
58
|
+
// Re-export dependency graph functions
|
|
59
|
+
export { buildDependencyGraph, topologicalSort, detectCycles, getParallelGroups, getAllDependencies, hasCycles, visualizeGraph, CircularDependencyError, PRIMITIVE_TYPES, } from './dependency-graph.js';
|
|
60
|
+
// Re-export union fallback functions
|
|
61
|
+
export { parseUnionTypes, parseUnionThresholds, searchUnionTypes, createProviderSearcher, } from './union-fallback.js';
|
|
62
|
+
// Re-export generation context
|
|
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';
|
|
70
|
+
// Re-export verb derivation functions
|
|
71
|
+
export { FORWARD_TO_REVERSE, BIDIRECTIONAL_PAIRS, deriveReverseVerb, fieldNameToVerb, isPassiveVerb, registerVerbPair, registerBidirectionalPair, registerFieldVerb, } from './verb-derivation.js';
|
|
43
72
|
import { Verbs, parseUrl } from '../types.js';
|
|
44
73
|
import { inferNoun, getTypeMeta, conjugate } from '../linguistic.js';
|
|
45
74
|
import { parseSchema } from './parse.js';
|
|
46
75
|
import { resolveProvider, hasSemanticSearch, hasHybridSearch, hasEventsAPI, hasActionsAPI, hasArtifactsAPI, hasEmbeddingsConfig, } from './provider.js';
|
|
47
76
|
import { hydrateEntity, resolveReferenceSpec } from './resolve.js';
|
|
48
|
-
import { resolveForwardExact, generateAIFields, generateContextAwareValue, generateNaturalLanguageContent } from './cascade.js';
|
|
49
|
-
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';
|
|
50
82
|
// =============================================================================
|
|
51
83
|
// Noun/Verb Helpers
|
|
52
84
|
// =============================================================================
|
|
@@ -224,439 +256,8 @@ function schemaToProperties(schema) {
|
|
|
224
256
|
}
|
|
225
257
|
return properties;
|
|
226
258
|
}
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
// =============================================================================
|
|
230
|
-
let nlQueryGenerator = null;
|
|
231
|
-
/**
|
|
232
|
-
* Set the AI generator for natural language queries
|
|
233
|
-
*/
|
|
234
|
-
export function setNLQueryGenerator(generator) {
|
|
235
|
-
nlQueryGenerator = generator;
|
|
236
|
-
}
|
|
237
|
-
function buildNLQueryContext(schema, targetType) {
|
|
238
|
-
const types = [];
|
|
239
|
-
for (const [name, entity] of schema.entities) {
|
|
240
|
-
const fields = [];
|
|
241
|
-
const relationships = [];
|
|
242
|
-
for (const [fieldName, field] of entity.fields) {
|
|
243
|
-
if (field.isRelation && field.relatedType) {
|
|
244
|
-
relationships.push({
|
|
245
|
-
name: fieldName,
|
|
246
|
-
to: field.relatedType,
|
|
247
|
-
cardinality: field.isArray ? 'many' : 'one',
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
-
fields.push(fieldName);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const meta = getTypeMeta(name);
|
|
255
|
-
types.push({
|
|
256
|
-
name,
|
|
257
|
-
singular: meta.singular,
|
|
258
|
-
plural: meta.plural,
|
|
259
|
-
fields,
|
|
260
|
-
relationships,
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
return { types, targetType };
|
|
264
|
-
}
|
|
265
|
-
async function executeNLQuery(question, schema, targetType) {
|
|
266
|
-
if (!nlQueryGenerator) {
|
|
267
|
-
const provider = await resolveProvider();
|
|
268
|
-
const results = [];
|
|
269
|
-
// Simple heuristic for common "list all" patterns in fallback mode
|
|
270
|
-
const lowerQuestion = question.toLowerCase().trim();
|
|
271
|
-
const isListAllQuery = /^(show|list|get|find|display)\s+(all|every|the)?\s*/i.test(lowerQuestion) ||
|
|
272
|
-
lowerQuestion === '' ||
|
|
273
|
-
/\ball\b/i.test(lowerQuestion);
|
|
274
|
-
if (targetType) {
|
|
275
|
-
if (isListAllQuery) {
|
|
276
|
-
// For "show all X" queries, just list everything
|
|
277
|
-
const listResults = await provider.list(targetType);
|
|
278
|
-
results.push(...listResults);
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
const searchResults = await provider.search(targetType, question);
|
|
282
|
-
results.push(...searchResults);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
for (const [typeName] of schema.entities) {
|
|
287
|
-
if (isListAllQuery) {
|
|
288
|
-
const listResults = await provider.list(typeName);
|
|
289
|
-
results.push(...listResults);
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
const searchResults = await provider.search(typeName, question);
|
|
293
|
-
results.push(...searchResults);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return {
|
|
298
|
-
interpretation: `Search for "${question}"`,
|
|
299
|
-
confidence: 0.5,
|
|
300
|
-
results,
|
|
301
|
-
explanation: 'Fallback to keyword search (no AI generator configured)',
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
const context = buildNLQueryContext(schema, targetType);
|
|
305
|
-
const plan = await nlQueryGenerator(question, context);
|
|
306
|
-
const provider = await resolveProvider();
|
|
307
|
-
const results = [];
|
|
308
|
-
for (const typeName of plan.types) {
|
|
309
|
-
let typeResults;
|
|
310
|
-
if (plan.search) {
|
|
311
|
-
typeResults = await provider.search(typeName, plan.search, {
|
|
312
|
-
where: plan.filters,
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
typeResults = await provider.list(typeName, {
|
|
317
|
-
where: plan.filters,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
results.push(...typeResults);
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
interpretation: plan.interpretation,
|
|
324
|
-
confidence: plan.confidence,
|
|
325
|
-
results,
|
|
326
|
-
query: JSON.stringify({ types: plan.types, filters: plan.filters, search: plan.search }),
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
function createNLQueryFn(schema, typeName) {
|
|
330
|
-
return async (strings, ...values) => {
|
|
331
|
-
const question = strings.reduce((acc, str, i) => {
|
|
332
|
-
return acc + str + (values[i] !== undefined ? String(values[i]) : '');
|
|
333
|
-
}, '');
|
|
334
|
-
return executeNLQuery(question, schema, typeName);
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
// =============================================================================
|
|
338
|
-
// Edge Entity Operations
|
|
339
|
-
// =============================================================================
|
|
340
|
-
function createEdgeEntityOperations(schemaEdgeRecords, getProvider) {
|
|
341
|
-
async function getRuntimeEdges() {
|
|
342
|
-
try {
|
|
343
|
-
const provider = await getProvider();
|
|
344
|
-
const runtimeEdges = await provider.list('Edge');
|
|
345
|
-
return runtimeEdges;
|
|
346
|
-
}
|
|
347
|
-
catch {
|
|
348
|
-
return [];
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
async function getAllEdges() {
|
|
352
|
-
const runtimeEdges = await getRuntimeEdges();
|
|
353
|
-
const runtimeEdgeKeys = new Set(runtimeEdges.map(e => `${e.from}:${e.name}`));
|
|
354
|
-
const filteredSchemaEdges = schemaEdgeRecords.filter(e => {
|
|
355
|
-
const key = `${e.from}:${e.name}`;
|
|
356
|
-
const hasRuntimeVersion = runtimeEdgeKeys.has(key);
|
|
357
|
-
if (hasRuntimeVersion && e.matchMode === 'fuzzy') {
|
|
358
|
-
return false;
|
|
359
|
-
}
|
|
360
|
-
return !hasRuntimeVersion;
|
|
361
|
-
});
|
|
362
|
-
return [...filteredSchemaEdges, ...runtimeEdges];
|
|
363
|
-
}
|
|
364
|
-
return {
|
|
365
|
-
async get(id) {
|
|
366
|
-
const runtimeEdges = await getRuntimeEdges();
|
|
367
|
-
const runtimeMatch = runtimeEdges.find(e => e.$id === id || `${e.from}:${e.name}` === id);
|
|
368
|
-
if (runtimeMatch)
|
|
369
|
-
return { ...runtimeMatch, $type: 'Edge' };
|
|
370
|
-
return schemaEdgeRecords.find(e => `${e.from}:${e.name}` === id) ?? null;
|
|
371
|
-
},
|
|
372
|
-
async list(options) {
|
|
373
|
-
let results = await getAllEdges();
|
|
374
|
-
if (options?.where) {
|
|
375
|
-
for (const [key, value] of Object.entries(options.where)) {
|
|
376
|
-
results = results.filter(e => e[key] === value);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
return results.map(e => ({
|
|
380
|
-
...e,
|
|
381
|
-
$id: e.$id || `${e.from}:${e.name}`,
|
|
382
|
-
$type: 'Edge',
|
|
383
|
-
}));
|
|
384
|
-
},
|
|
385
|
-
async find(where) {
|
|
386
|
-
let results = await getAllEdges();
|
|
387
|
-
for (const [key, value] of Object.entries(where)) {
|
|
388
|
-
results = results.filter(e => e[key] === value);
|
|
389
|
-
}
|
|
390
|
-
return results.map(e => ({
|
|
391
|
-
...e,
|
|
392
|
-
$id: e.$id || `${e.from}:${e.name}`,
|
|
393
|
-
$type: 'Edge',
|
|
394
|
-
}));
|
|
395
|
-
},
|
|
396
|
-
async search(query) {
|
|
397
|
-
const allEdges = await getAllEdges();
|
|
398
|
-
const queryLower = query.toLowerCase();
|
|
399
|
-
return allEdges
|
|
400
|
-
.filter(e => String(e.from).toLowerCase().includes(queryLower) ||
|
|
401
|
-
String(e.name).toLowerCase().includes(queryLower) ||
|
|
402
|
-
String(e.to).toLowerCase().includes(queryLower))
|
|
403
|
-
.map(e => ({
|
|
404
|
-
...e,
|
|
405
|
-
$id: e.$id || `${e.from}:${e.name}`,
|
|
406
|
-
$type: 'Edge',
|
|
407
|
-
}));
|
|
408
|
-
},
|
|
409
|
-
async create() {
|
|
410
|
-
throw new Error('Cannot manually create Edge records - they are auto-generated');
|
|
411
|
-
},
|
|
412
|
-
async update() {
|
|
413
|
-
throw new Error('Cannot manually update Edge records - they are auto-generated');
|
|
414
|
-
},
|
|
415
|
-
async upsert() {
|
|
416
|
-
throw new Error('Cannot manually upsert Edge records - they are auto-generated');
|
|
417
|
-
},
|
|
418
|
-
async delete() {
|
|
419
|
-
throw new Error('Cannot manually delete Edge records - they are auto-generated');
|
|
420
|
-
},
|
|
421
|
-
async forEach(optionsOrCallback, maybeCallback) {
|
|
422
|
-
const options = typeof optionsOrCallback === 'function' ? undefined : optionsOrCallback;
|
|
423
|
-
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback;
|
|
424
|
-
const items = await this.list(options);
|
|
425
|
-
for (const item of items) {
|
|
426
|
-
await callback(item);
|
|
427
|
-
}
|
|
428
|
-
},
|
|
429
|
-
async semanticSearch() {
|
|
430
|
-
return [];
|
|
431
|
-
},
|
|
432
|
-
async hybridSearch() {
|
|
433
|
-
return [];
|
|
434
|
-
},
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
// =============================================================================
|
|
438
|
-
// Entity Operations Factory
|
|
439
|
-
// =============================================================================
|
|
440
|
-
function createEntityOperations(typeName, entity, schema) {
|
|
441
|
-
return {
|
|
442
|
-
async get(id) {
|
|
443
|
-
const provider = await resolveProvider();
|
|
444
|
-
const result = await provider.get(typeName, id);
|
|
445
|
-
if (!result)
|
|
446
|
-
return null;
|
|
447
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
448
|
-
},
|
|
449
|
-
async list(options) {
|
|
450
|
-
const provider = await resolveProvider();
|
|
451
|
-
const results = await provider.list(typeName, options);
|
|
452
|
-
return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
|
|
453
|
-
},
|
|
454
|
-
async find(where) {
|
|
455
|
-
const provider = await resolveProvider();
|
|
456
|
-
const results = await provider.list(typeName, {
|
|
457
|
-
where: where,
|
|
458
|
-
});
|
|
459
|
-
return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
|
|
460
|
-
},
|
|
461
|
-
async search(query, options) {
|
|
462
|
-
const provider = await resolveProvider();
|
|
463
|
-
const results = await provider.search(typeName, query, options);
|
|
464
|
-
return Promise.all(results.map((r) => hydrateEntity(r, entity, schema, resolveProvider)));
|
|
465
|
-
},
|
|
466
|
-
async create(idOrData, maybeData) {
|
|
467
|
-
const provider = await resolveProvider();
|
|
468
|
-
const providedId = typeof idOrData === 'string' ? idOrData : undefined;
|
|
469
|
-
const data = typeof idOrData === 'string'
|
|
470
|
-
? maybeData
|
|
471
|
-
: idOrData;
|
|
472
|
-
const entityId = providedId || crypto.randomUUID();
|
|
473
|
-
const { data: resolvedData, pendingRelations } = await resolveForwardExact(typeName, data, entity, schema, provider, entityId);
|
|
474
|
-
const { data: fuzzyResolvedData, pendingRelations: fuzzyPendingRelations } = await resolveForwardFuzzy(typeName, resolvedData, entity, schema, provider, entityId);
|
|
475
|
-
const backwardResolvedData = await resolveBackwardFuzzy(typeName, fuzzyResolvedData, entity, schema, provider);
|
|
476
|
-
const finalData = await generateAIFields(backwardResolvedData, typeName, entity, schema, provider);
|
|
477
|
-
const result = await provider.create(typeName, entityId, finalData);
|
|
478
|
-
for (const rel of pendingRelations) {
|
|
479
|
-
await provider.relate(typeName, entityId, rel.fieldName, rel.targetType, rel.targetId);
|
|
480
|
-
}
|
|
481
|
-
const createdEdgeIds = new Set();
|
|
482
|
-
for (const rel of fuzzyPendingRelations) {
|
|
483
|
-
await provider.relate(typeName, entityId, rel.fieldName, rel.targetType, rel.targetId, {
|
|
484
|
-
matchMode: 'fuzzy',
|
|
485
|
-
similarity: rel.similarity
|
|
486
|
-
});
|
|
487
|
-
const edgeId = `${typeName}:${rel.fieldName}:${entityId}:${rel.targetId}`;
|
|
488
|
-
if (!createdEdgeIds.has(edgeId)) {
|
|
489
|
-
createdEdgeIds.add(edgeId);
|
|
490
|
-
try {
|
|
491
|
-
await provider.create('Edge', edgeId, {
|
|
492
|
-
from: typeName,
|
|
493
|
-
name: rel.fieldName,
|
|
494
|
-
to: rel.targetType,
|
|
495
|
-
direction: 'forward',
|
|
496
|
-
matchMode: 'fuzzy',
|
|
497
|
-
similarity: rel.similarity,
|
|
498
|
-
fromId: entityId,
|
|
499
|
-
toId: rel.targetId,
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
catch {
|
|
503
|
-
// Edge already exists
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
508
|
-
},
|
|
509
|
-
async update(id, data) {
|
|
510
|
-
const provider = await resolveProvider();
|
|
511
|
-
const result = await provider.update(typeName, id, data);
|
|
512
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
513
|
-
},
|
|
514
|
-
async upsert(id, data) {
|
|
515
|
-
const provider = await resolveProvider();
|
|
516
|
-
const existing = await provider.get(typeName, id);
|
|
517
|
-
if (existing) {
|
|
518
|
-
const result = await provider.update(typeName, id, data);
|
|
519
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
520
|
-
}
|
|
521
|
-
const result = await provider.create(typeName, id, data);
|
|
522
|
-
return hydrateEntity(result, entity, schema, resolveProvider);
|
|
523
|
-
},
|
|
524
|
-
async delete(id) {
|
|
525
|
-
const provider = await resolveProvider();
|
|
526
|
-
return provider.delete(typeName, id);
|
|
527
|
-
},
|
|
528
|
-
async forEach(optionsOrCallback, maybeCallback) {
|
|
529
|
-
const options = typeof optionsOrCallback === 'function' ? undefined : optionsOrCallback;
|
|
530
|
-
const callback = typeof optionsOrCallback === 'function'
|
|
531
|
-
? optionsOrCallback
|
|
532
|
-
: maybeCallback;
|
|
533
|
-
const items = await this.list(options);
|
|
534
|
-
for (const item of items) {
|
|
535
|
-
await callback(item);
|
|
536
|
-
}
|
|
537
|
-
},
|
|
538
|
-
async semanticSearch(query, options) {
|
|
539
|
-
const provider = await resolveProvider();
|
|
540
|
-
if (hasSemanticSearch(provider)) {
|
|
541
|
-
const results = await provider.semanticSearch(typeName, query, options);
|
|
542
|
-
return Promise.all(results.map((r) => ({
|
|
543
|
-
...hydrateEntity(r, entity, schema, resolveProvider),
|
|
544
|
-
$score: r.$score,
|
|
545
|
-
})));
|
|
546
|
-
}
|
|
547
|
-
return [];
|
|
548
|
-
},
|
|
549
|
-
async hybridSearch(query, options) {
|
|
550
|
-
const provider = await resolveProvider();
|
|
551
|
-
if (hasHybridSearch(provider)) {
|
|
552
|
-
const results = await provider.hybridSearch(typeName, query, options);
|
|
553
|
-
return Promise.all(results.map((r) => ({
|
|
554
|
-
...hydrateEntity(r, entity, schema, resolveProvider),
|
|
555
|
-
$rrfScore: r.$rrfScore,
|
|
556
|
-
$ftsRank: r.$ftsRank,
|
|
557
|
-
$semanticRank: r.$semanticRank,
|
|
558
|
-
$score: r.$score,
|
|
559
|
-
})));
|
|
560
|
-
}
|
|
561
|
-
return [];
|
|
562
|
-
},
|
|
563
|
-
async draft(data, options) {
|
|
564
|
-
const draftData = { ...data, $phase: 'draft' };
|
|
565
|
-
const refs = {};
|
|
566
|
-
for (const [fieldName, field] of entity.fields) {
|
|
567
|
-
if (draftData[fieldName] !== undefined && draftData[fieldName] !== null) {
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
if (field.operator && field.relatedType) {
|
|
571
|
-
const matchMode = field.matchMode ?? (field.operator.includes('~') ? 'fuzzy' : 'exact');
|
|
572
|
-
if (field.isArray) {
|
|
573
|
-
const generatedText = generateNaturalLanguageContent(fieldName, field.prompt, field.relatedType, data);
|
|
574
|
-
draftData[fieldName] = generatedText;
|
|
575
|
-
const refSpec = {
|
|
576
|
-
field: fieldName,
|
|
577
|
-
operator: field.operator,
|
|
578
|
-
type: field.relatedType,
|
|
579
|
-
matchMode,
|
|
580
|
-
resolved: false,
|
|
581
|
-
prompt: field.prompt,
|
|
582
|
-
generatedText,
|
|
583
|
-
};
|
|
584
|
-
refs[fieldName] = [refSpec];
|
|
585
|
-
if (options?.stream && options.onChunk) {
|
|
586
|
-
options.onChunk(generatedText);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
const generatedText = generateNaturalLanguageContent(fieldName, field.prompt, field.relatedType, data);
|
|
591
|
-
draftData[fieldName] = generatedText;
|
|
592
|
-
refs[fieldName] = {
|
|
593
|
-
field: fieldName,
|
|
594
|
-
operator: field.operator,
|
|
595
|
-
type: field.relatedType,
|
|
596
|
-
matchMode,
|
|
597
|
-
resolved: false,
|
|
598
|
-
prompt: field.prompt,
|
|
599
|
-
generatedText,
|
|
600
|
-
};
|
|
601
|
-
if (options?.stream && options.onChunk) {
|
|
602
|
-
options.onChunk(generatedText);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
draftData.$refs = refs;
|
|
608
|
-
return draftData;
|
|
609
|
-
},
|
|
610
|
-
async resolve(draft, options) {
|
|
611
|
-
// Draft<T> interface requires $phase: 'draft', so we can access it directly
|
|
612
|
-
if (draft.$phase !== 'draft') {
|
|
613
|
-
throw new Error('Cannot resolve entity: not a draft (missing $phase: "draft")');
|
|
614
|
-
}
|
|
615
|
-
const provider = await resolveProvider();
|
|
616
|
-
const resolved = { ...draft };
|
|
617
|
-
const errors = [];
|
|
618
|
-
delete resolved.$refs;
|
|
619
|
-
resolved.$phase = 'resolved';
|
|
620
|
-
const refs = draft.$refs;
|
|
621
|
-
for (const [fieldName, refSpec] of Object.entries(refs)) {
|
|
622
|
-
try {
|
|
623
|
-
if (Array.isArray(refSpec)) {
|
|
624
|
-
const resolvedIds = [];
|
|
625
|
-
for (const spec of refSpec) {
|
|
626
|
-
const resolvedId = await resolveReferenceSpec(spec, resolved, schema, provider, generateContextAwareValue);
|
|
627
|
-
if (resolvedId) {
|
|
628
|
-
resolvedIds.push(resolvedId);
|
|
629
|
-
options?.onResolved?.(fieldName, resolvedId);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
resolved[fieldName] = resolvedIds;
|
|
633
|
-
}
|
|
634
|
-
else {
|
|
635
|
-
const resolvedId = await resolveReferenceSpec(refSpec, resolved, schema, provider, generateContextAwareValue);
|
|
636
|
-
if (resolvedId) {
|
|
637
|
-
resolved[fieldName] = resolvedId;
|
|
638
|
-
options?.onResolved?.(fieldName, resolvedId);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
catch (err) {
|
|
643
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
644
|
-
if (options?.onError === 'skip') {
|
|
645
|
-
errors.push({ field: fieldName, error: errorMsg });
|
|
646
|
-
}
|
|
647
|
-
else {
|
|
648
|
-
throw err;
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
if (errors.length > 0 || options?.onError === 'skip') {
|
|
653
|
-
// resolved is typed as Record<string, unknown>, so we can assign $errors directly
|
|
654
|
-
resolved.$errors = errors;
|
|
655
|
-
}
|
|
656
|
-
return resolved;
|
|
657
|
-
},
|
|
658
|
-
};
|
|
659
|
-
}
|
|
259
|
+
// Note: NL Query functions extracted to nl-query.ts
|
|
260
|
+
// Note: Edge Entity Operations extracted to entity-operations.ts
|
|
660
261
|
// =============================================================================
|
|
661
262
|
// DB Factory
|
|
662
263
|
// =============================================================================
|
|
@@ -665,23 +266,199 @@ function createEntityOperations(typeName, entity, schema) {
|
|
|
665
266
|
*/
|
|
666
267
|
export function DB(schema, options) {
|
|
667
268
|
const parsedSchema = parseSchema(schema);
|
|
668
|
-
// 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
|
|
669
382
|
const edgeEntity = {
|
|
670
383
|
name: 'Edge',
|
|
671
384
|
fields: new Map([
|
|
672
|
-
[
|
|
673
|
-
|
|
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
|
+
],
|
|
674
393
|
['to', { name: 'to', type: 'string', isArray: false, isOptional: false, isRelation: false }],
|
|
675
|
-
[
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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
|
+
],
|
|
679
416
|
]),
|
|
680
417
|
};
|
|
681
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
|
+
}
|
|
682
459
|
// Configure provider with embeddings settings if provided
|
|
683
460
|
if (options?.embeddings) {
|
|
684
|
-
|
|
461
|
+
getProvider().then((provider) => {
|
|
685
462
|
if (hasEmbeddingsConfig(provider)) {
|
|
686
463
|
provider.setEmbeddingsConfig(options.embeddings);
|
|
687
464
|
}
|
|
@@ -690,11 +467,27 @@ export function DB(schema, options) {
|
|
|
690
467
|
// Collect all edge records from the schema
|
|
691
468
|
const allEdgeRecords = [];
|
|
692
469
|
for (const [entityName, entity] of parsedSchema.entities) {
|
|
693
|
-
|
|
470
|
+
// Only create edge records for user-defined entities (not system entities)
|
|
471
|
+
if (entityName !== 'Edge' && entityName !== 'Noun' && entityName !== 'Verb') {
|
|
694
472
|
const edgeRecords = createEdgeRecords(entityName, schema[entityName] ?? {}, entity);
|
|
695
473
|
allEdgeRecords.push(...edgeRecords);
|
|
696
474
|
}
|
|
697
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
|
+
}));
|
|
698
491
|
// Build and set schema relation info for batch loading
|
|
699
492
|
// Maps entityType -> fieldName -> relatedType
|
|
700
493
|
const relationInfo = new Map();
|
|
@@ -714,7 +507,7 @@ export function DB(schema, options) {
|
|
|
714
507
|
// This API adapts DBAction to ForEachActionsAPI interface
|
|
715
508
|
const actionsAPI = {
|
|
716
509
|
async create(data) {
|
|
717
|
-
const provider = await
|
|
510
|
+
const provider = await getProvider();
|
|
718
511
|
if (hasActionsAPI(provider)) {
|
|
719
512
|
const action = await provider.createAction(data);
|
|
720
513
|
return { id: action.id };
|
|
@@ -722,35 +515,45 @@ export function DB(schema, options) {
|
|
|
722
515
|
throw new Error('Provider does not support actions');
|
|
723
516
|
},
|
|
724
517
|
async get(id) {
|
|
725
|
-
const provider = await
|
|
518
|
+
const provider = await getProvider();
|
|
726
519
|
if (hasActionsAPI(provider)) {
|
|
727
520
|
const action = await provider.getAction(id);
|
|
728
521
|
if (!action)
|
|
729
522
|
return null;
|
|
730
523
|
// Adapt DBAction to ForEachActionState
|
|
731
|
-
|
|
524
|
+
const state = {
|
|
732
525
|
id: action.id,
|
|
733
526
|
type: action.action ?? action.type ?? 'unknown',
|
|
734
527
|
status: action.status,
|
|
735
|
-
progress: action.progress,
|
|
736
|
-
total: action.total,
|
|
737
528
|
data: action.objectData ?? {},
|
|
738
|
-
result: action.result,
|
|
739
|
-
error: action.error,
|
|
740
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;
|
|
741
539
|
}
|
|
742
540
|
return null;
|
|
743
541
|
},
|
|
744
542
|
async update(id, updates) {
|
|
745
|
-
const provider = await
|
|
543
|
+
const provider = await getProvider();
|
|
746
544
|
if (hasActionsAPI(provider)) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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);
|
|
754
557
|
return;
|
|
755
558
|
}
|
|
756
559
|
throw new Error('Provider does not support actions');
|
|
@@ -771,12 +574,13 @@ export function DB(schema, options) {
|
|
|
771
574
|
function emitInternalEventForOps(eventType, data) {
|
|
772
575
|
const handlers = eventHandlersForOps.get(eventType);
|
|
773
576
|
if (handlers) {
|
|
774
|
-
|
|
577
|
+
const snapshot = [...handlers];
|
|
578
|
+
for (const handler of snapshot) {
|
|
775
579
|
try {
|
|
776
580
|
handler(data);
|
|
777
581
|
}
|
|
778
582
|
catch (e) {
|
|
779
|
-
|
|
583
|
+
logError(`Error in event handler for ${eventType}:`, e);
|
|
780
584
|
}
|
|
781
585
|
}
|
|
782
586
|
}
|
|
@@ -798,10 +602,23 @@ export function DB(schema, options) {
|
|
|
798
602
|
}
|
|
799
603
|
for (const [entityName, entity] of parsedSchema.entities) {
|
|
800
604
|
if (entityName === 'Edge') {
|
|
801
|
-
|
|
605
|
+
// Edge entity - auto-generated from schema relationships
|
|
606
|
+
const edgeOps = createEdgeEntityOperations(allEdgeRecords, getProvider);
|
|
802
607
|
const wrappedEdgeOps = wrapEntityOperations(entityName, edgeOps, actionsAPI);
|
|
803
608
|
entityOperations[entityName] = makeCallableEntityOps(wrappedEdgeOps, entityName);
|
|
804
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
|
+
}
|
|
805
622
|
else {
|
|
806
623
|
const baseOps = createEntityOperations(entityName, entity, parsedSchema);
|
|
807
624
|
const wrappedOps = wrapEntityOperations(entityName, baseOps, actionsAPI);
|
|
@@ -813,7 +630,7 @@ export function DB(schema, options) {
|
|
|
813
630
|
throw new Error(`Draft method not available for ${entityName}`);
|
|
814
631
|
}
|
|
815
632
|
const draft = await draftMethod(data, options);
|
|
816
|
-
draft
|
|
633
|
+
draft['$type'] = entityName;
|
|
817
634
|
emitInternalEventForOps('draft', draft);
|
|
818
635
|
return draft;
|
|
819
636
|
};
|
|
@@ -824,7 +641,8 @@ export function DB(schema, options) {
|
|
|
824
641
|
}
|
|
825
642
|
const resolved = await resolveMethod(draft, options);
|
|
826
643
|
if (resolved && typeof resolved === 'object') {
|
|
827
|
-
|
|
644
|
+
;
|
|
645
|
+
resolved['$type'] = entityName;
|
|
828
646
|
}
|
|
829
647
|
emitInternalEventForOps('resolve', resolved);
|
|
830
648
|
return resolved;
|
|
@@ -848,27 +666,57 @@ export function DB(schema, options) {
|
|
|
848
666
|
const draft = await draftFn(data);
|
|
849
667
|
return draft;
|
|
850
668
|
}
|
|
669
|
+
// Check if entity has reference fields that need two-phase processing
|
|
670
|
+
const entityDef = parsedSchema.entities.get(entityName);
|
|
851
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
|
|
852
692
|
if (options?.cascade && effectiveMaxDepth > 0) {
|
|
853
|
-
const provider = await
|
|
693
|
+
const provider = await getProvider();
|
|
854
694
|
const entityDef = parsedSchema.entities.get(entityName);
|
|
855
695
|
if (entityDef) {
|
|
856
696
|
// CreateEntityOptions now includes _cascadeState as an optional property
|
|
857
697
|
const cascadeState = options._cascadeState ?? {
|
|
858
698
|
totalEntitiesCreated: 0,
|
|
859
699
|
initialMaxDepth: effectiveMaxDepth,
|
|
860
|
-
rootOnProgress: options.onProgress,
|
|
861
|
-
rootOnError: options.onError,
|
|
862
|
-
stopOnError: options.stopOnError,
|
|
863
|
-
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 }),
|
|
864
704
|
};
|
|
865
705
|
const currentDepth = cascadeState.initialMaxDepth - effectiveMaxDepth;
|
|
866
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
|
+
});
|
|
867
714
|
for (const [fieldName, field] of entityDef.fields) {
|
|
868
715
|
if (cascadeData[fieldName] !== undefined)
|
|
869
716
|
continue;
|
|
870
717
|
if (field.operator === '->' && field.relatedType) {
|
|
871
|
-
if (cascadeState.cascadeTypes &&
|
|
718
|
+
if (cascadeState.cascadeTypes &&
|
|
719
|
+
!cascadeState.cascadeTypes.includes(field.relatedType)) {
|
|
872
720
|
continue;
|
|
873
721
|
}
|
|
874
722
|
const relatedEntity = parsedSchema.entities.get(field.relatedType);
|
|
@@ -882,39 +730,48 @@ export function DB(schema, options) {
|
|
|
882
730
|
totalEntitiesCreated: cascadeState.totalEntitiesCreated,
|
|
883
731
|
});
|
|
884
732
|
const childEntityData = {};
|
|
885
|
-
const parentInstructions = entityDef.schema
|
|
886
|
-
const childInstructions = relatedEntity.schema
|
|
733
|
+
const parentInstructions = entityDef.schema?.['$instructions'];
|
|
734
|
+
const childInstructions = relatedEntity.schema?.['$instructions'];
|
|
887
735
|
const contextParts = [];
|
|
888
736
|
if (parentInstructions)
|
|
889
737
|
contextParts.push(parentInstructions);
|
|
890
738
|
if (childInstructions)
|
|
891
739
|
contextParts.push(childInstructions);
|
|
892
740
|
for (const [key, value] of Object.entries(cascadeData)) {
|
|
893
|
-
if (!key.startsWith('$') &&
|
|
741
|
+
if (!key.startsWith('$') &&
|
|
742
|
+
!key.startsWith('_') &&
|
|
743
|
+
typeof value === 'string' &&
|
|
744
|
+
value) {
|
|
894
745
|
contextParts.push(`${key}: ${value}`);
|
|
895
746
|
}
|
|
896
747
|
}
|
|
897
748
|
const fullContext = contextParts.join(' | ');
|
|
898
749
|
for (const [childFieldName, childField] of relatedEntity.fields) {
|
|
899
|
-
|
|
900
|
-
|
|
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);
|
|
901
755
|
}
|
|
902
756
|
}
|
|
903
757
|
const childOptions = {
|
|
904
758
|
...options,
|
|
759
|
+
cascade: true, // Ensure cascade continues for child entities
|
|
905
760
|
maxDepth: effectiveMaxDepth - 1,
|
|
906
761
|
_cascadeState: cascadeState,
|
|
907
762
|
};
|
|
908
763
|
const relatedOps = entityOperations[field.relatedType];
|
|
909
|
-
const createFn = relatedOps?.create;
|
|
910
|
-
const childEntity = createFn
|
|
911
|
-
|
|
764
|
+
const createFn = relatedOps?.['create'];
|
|
765
|
+
const childEntity = createFn
|
|
766
|
+
? await createFn(childEntityData, childOptions)
|
|
767
|
+
: undefined;
|
|
768
|
+
if (childEntity?.['$id']) {
|
|
912
769
|
cascadeState.totalEntitiesCreated++;
|
|
913
770
|
if (field.isArray) {
|
|
914
|
-
cascadeData[fieldName] = [childEntity
|
|
771
|
+
cascadeData[fieldName] = [childEntity['$id']];
|
|
915
772
|
}
|
|
916
773
|
else {
|
|
917
|
-
cascadeData[fieldName] = childEntity
|
|
774
|
+
cascadeData[fieldName] = childEntity['$id'];
|
|
918
775
|
}
|
|
919
776
|
}
|
|
920
777
|
}
|
|
@@ -926,12 +783,13 @@ export function DB(schema, options) {
|
|
|
926
783
|
}
|
|
927
784
|
}
|
|
928
785
|
}
|
|
786
|
+
const createFn = originalCreate;
|
|
929
787
|
let result;
|
|
930
788
|
if (id) {
|
|
931
|
-
result = await
|
|
789
|
+
result = await createFn.call(wrappedOps, id, cascadeData);
|
|
932
790
|
}
|
|
933
791
|
else {
|
|
934
|
-
result = await
|
|
792
|
+
result = await createFn.call(wrappedOps, cascadeData);
|
|
935
793
|
}
|
|
936
794
|
cascadeState.totalEntitiesCreated++;
|
|
937
795
|
if (currentDepth === 0) {
|
|
@@ -944,8 +802,78 @@ export function DB(schema, options) {
|
|
|
944
802
|
return result;
|
|
945
803
|
}
|
|
946
804
|
}
|
|
947
|
-
|
|
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);
|
|
948
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
|
+
}
|
|
949
877
|
// Make the entity operations callable as a tagged template literal
|
|
950
878
|
entityOperations[entityName] = makeCallableEntityOps(wrappedOps, entityName);
|
|
951
879
|
}
|
|
@@ -970,12 +898,12 @@ export function DB(schema, options) {
|
|
|
970
898
|
const db = {
|
|
971
899
|
$schema: parsedSchema,
|
|
972
900
|
async get(url) {
|
|
973
|
-
const provider = await
|
|
901
|
+
const provider = await getProvider();
|
|
974
902
|
const parsed = parseUrl(url);
|
|
975
903
|
return provider.get(parsed.type, parsed.id);
|
|
976
904
|
},
|
|
977
905
|
async search(query, options) {
|
|
978
|
-
const provider = await
|
|
906
|
+
const provider = await getProvider();
|
|
979
907
|
const results = [];
|
|
980
908
|
for (const [typeName] of parsedSchema.entities) {
|
|
981
909
|
const typeResults = await provider.search(typeName, query, options);
|
|
@@ -984,7 +912,7 @@ export function DB(schema, options) {
|
|
|
984
912
|
return results;
|
|
985
913
|
},
|
|
986
914
|
async semanticSearch(query, options) {
|
|
987
|
-
const provider = await
|
|
915
|
+
const provider = await getProvider();
|
|
988
916
|
const results = [];
|
|
989
917
|
if (hasSemanticSearch(provider)) {
|
|
990
918
|
for (const [typeName] of parsedSchema.entities) {
|
|
@@ -997,13 +925,19 @@ export function DB(schema, options) {
|
|
|
997
925
|
return results.slice(0, limit);
|
|
998
926
|
},
|
|
999
927
|
async count(type, where) {
|
|
1000
|
-
const provider = await
|
|
1001
|
-
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);
|
|
1002
933
|
return results.length;
|
|
1003
934
|
},
|
|
1004
935
|
async forEach(options, callback) {
|
|
1005
|
-
const provider = await
|
|
1006
|
-
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);
|
|
1007
941
|
const concurrency = options.concurrency ?? 1;
|
|
1008
942
|
if (concurrency === 1) {
|
|
1009
943
|
for (const entity of results) {
|
|
@@ -1017,7 +951,7 @@ export function DB(schema, options) {
|
|
|
1017
951
|
}
|
|
1018
952
|
},
|
|
1019
953
|
async set(type, id, data) {
|
|
1020
|
-
const provider = await
|
|
954
|
+
const provider = await getProvider();
|
|
1021
955
|
const existing = await provider.get(type, id);
|
|
1022
956
|
if (existing) {
|
|
1023
957
|
return provider.update(type, id, data);
|
|
@@ -1025,7 +959,7 @@ export function DB(schema, options) {
|
|
|
1025
959
|
return provider.create(type, id, data);
|
|
1026
960
|
},
|
|
1027
961
|
async generate(options) {
|
|
1028
|
-
const provider = await
|
|
962
|
+
const provider = await getProvider();
|
|
1029
963
|
if (options.mode === 'background') {
|
|
1030
964
|
const { createMemoryProvider } = await import('../memory-provider.js');
|
|
1031
965
|
const memProvider = provider;
|
|
@@ -1047,7 +981,7 @@ export function DB(schema, options) {
|
|
|
1047
981
|
const events = {
|
|
1048
982
|
on(pattern, handler) {
|
|
1049
983
|
let unsubscribe = () => { };
|
|
1050
|
-
|
|
984
|
+
getProvider().then((provider) => {
|
|
1051
985
|
if (hasEventsAPI(provider)) {
|
|
1052
986
|
unsubscribe = provider.on(pattern, handler);
|
|
1053
987
|
}
|
|
@@ -1055,7 +989,7 @@ export function DB(schema, options) {
|
|
|
1055
989
|
return () => unsubscribe();
|
|
1056
990
|
},
|
|
1057
991
|
async emit(optionsOrType, data) {
|
|
1058
|
-
const provider = await
|
|
992
|
+
const provider = await getProvider();
|
|
1059
993
|
if (hasEventsAPI(provider)) {
|
|
1060
994
|
// The provider.emit has overloads: (options: CreateEventOptions) or (type: string, data: unknown)
|
|
1061
995
|
if (typeof optionsOrType === 'string') {
|
|
@@ -1065,36 +999,45 @@ export function DB(schema, options) {
|
|
|
1065
999
|
}
|
|
1066
1000
|
const now = new Date();
|
|
1067
1001
|
if (typeof optionsOrType === 'string') {
|
|
1068
|
-
|
|
1002
|
+
const baseEvent = {
|
|
1069
1003
|
id: crypto.randomUUID(),
|
|
1070
1004
|
actor: 'system',
|
|
1071
1005
|
event: optionsOrType,
|
|
1072
|
-
objectData: data,
|
|
1073
1006
|
timestamp: now,
|
|
1074
1007
|
};
|
|
1008
|
+
if (data !== undefined)
|
|
1009
|
+
baseEvent.objectData = data;
|
|
1010
|
+
return baseEvent;
|
|
1075
1011
|
}
|
|
1076
|
-
|
|
1012
|
+
const baseEvent = {
|
|
1077
1013
|
id: crypto.randomUUID(),
|
|
1078
1014
|
actor: optionsOrType.actor,
|
|
1079
|
-
actorData: optionsOrType.actorData,
|
|
1080
1015
|
event: optionsOrType.event,
|
|
1081
|
-
object: optionsOrType.object,
|
|
1082
|
-
objectData: optionsOrType.objectData,
|
|
1083
|
-
result: optionsOrType.result,
|
|
1084
|
-
resultData: optionsOrType.resultData,
|
|
1085
|
-
meta: optionsOrType.meta,
|
|
1086
1016
|
timestamp: now,
|
|
1087
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;
|
|
1088
1031
|
},
|
|
1089
1032
|
async list(options) {
|
|
1090
|
-
const provider = await
|
|
1033
|
+
const provider = await getProvider();
|
|
1091
1034
|
if (hasEventsAPI(provider)) {
|
|
1092
1035
|
return provider.listEvents(options);
|
|
1093
1036
|
}
|
|
1094
1037
|
return [];
|
|
1095
1038
|
},
|
|
1096
1039
|
async replay(options) {
|
|
1097
|
-
const provider = await
|
|
1040
|
+
const provider = await getProvider();
|
|
1098
1041
|
if (hasEventsAPI(provider)) {
|
|
1099
1042
|
await provider.replayEvents(options);
|
|
1100
1043
|
}
|
|
@@ -1103,42 +1046,42 @@ export function DB(schema, options) {
|
|
|
1103
1046
|
// Create Actions API (public version with full DBAction types)
|
|
1104
1047
|
const actions = {
|
|
1105
1048
|
async create(options) {
|
|
1106
|
-
const provider = await
|
|
1049
|
+
const provider = await getProvider();
|
|
1107
1050
|
if (hasActionsAPI(provider)) {
|
|
1108
1051
|
return provider.createAction(options);
|
|
1109
1052
|
}
|
|
1110
1053
|
throw new Error('Provider does not support actions');
|
|
1111
1054
|
},
|
|
1112
1055
|
async get(id) {
|
|
1113
|
-
const provider = await
|
|
1056
|
+
const provider = await getProvider();
|
|
1114
1057
|
if (hasActionsAPI(provider)) {
|
|
1115
1058
|
return provider.getAction(id);
|
|
1116
1059
|
}
|
|
1117
1060
|
return null;
|
|
1118
1061
|
},
|
|
1119
1062
|
async update(id, updates) {
|
|
1120
|
-
const provider = await
|
|
1063
|
+
const provider = await getProvider();
|
|
1121
1064
|
if (hasActionsAPI(provider)) {
|
|
1122
1065
|
return provider.updateAction(id, updates);
|
|
1123
1066
|
}
|
|
1124
1067
|
throw new Error('Provider does not support actions');
|
|
1125
1068
|
},
|
|
1126
1069
|
async list(options) {
|
|
1127
|
-
const provider = await
|
|
1070
|
+
const provider = await getProvider();
|
|
1128
1071
|
if (hasActionsAPI(provider)) {
|
|
1129
1072
|
return provider.listActions(options);
|
|
1130
1073
|
}
|
|
1131
1074
|
return [];
|
|
1132
1075
|
},
|
|
1133
1076
|
async retry(id) {
|
|
1134
|
-
const provider = await
|
|
1077
|
+
const provider = await getProvider();
|
|
1135
1078
|
if (hasActionsAPI(provider)) {
|
|
1136
1079
|
return provider.retryAction(id);
|
|
1137
1080
|
}
|
|
1138
1081
|
throw new Error('Provider does not support actions');
|
|
1139
1082
|
},
|
|
1140
1083
|
async cancel(id) {
|
|
1141
|
-
const provider = await
|
|
1084
|
+
const provider = await getProvider();
|
|
1142
1085
|
if (hasActionsAPI(provider)) {
|
|
1143
1086
|
await provider.cancelAction(id);
|
|
1144
1087
|
}
|
|
@@ -1148,26 +1091,26 @@ export function DB(schema, options) {
|
|
|
1148
1091
|
// Create Artifacts API
|
|
1149
1092
|
const artifacts = {
|
|
1150
1093
|
async get(url, type) {
|
|
1151
|
-
const provider = await
|
|
1094
|
+
const provider = await getProvider();
|
|
1152
1095
|
if (hasArtifactsAPI(provider)) {
|
|
1153
1096
|
return provider.getArtifact(url, type);
|
|
1154
1097
|
}
|
|
1155
1098
|
return null;
|
|
1156
1099
|
},
|
|
1157
1100
|
async set(url, type, data) {
|
|
1158
|
-
const provider = await
|
|
1101
|
+
const provider = await getProvider();
|
|
1159
1102
|
if (hasArtifactsAPI(provider)) {
|
|
1160
1103
|
await provider.setArtifact(url, type, data);
|
|
1161
1104
|
}
|
|
1162
1105
|
},
|
|
1163
1106
|
async delete(url, type) {
|
|
1164
|
-
const provider = await
|
|
1107
|
+
const provider = await getProvider();
|
|
1165
1108
|
if (hasArtifactsAPI(provider)) {
|
|
1166
1109
|
await provider.deleteArtifact(url, type);
|
|
1167
1110
|
}
|
|
1168
1111
|
},
|
|
1169
1112
|
async list(url) {
|
|
1170
|
-
const provider = await
|
|
1113
|
+
const provider = await getProvider();
|
|
1171
1114
|
if (hasArtifactsAPI(provider)) {
|
|
1172
1115
|
return provider.listArtifacts(url);
|
|
1173
1116
|
}
|