@utaba/deep-memory-storage-sqlserver 0.6.0 → 0.7.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SqlServerStorageProvider.ts","../src/schema.ts","../src/SqlServerSearchProvider.ts"],"sourcesContent":["// SqlServerStorageProvider — SQL Server implementation of StorageProvider\n\nimport sql from 'mssql';\nimport type { StorageProvider, EnsureSchemaResult } from '@utaba/deep-memory/providers';\nimport type {\n StoredEntity,\n StoredEntityUpdate,\n StoredRelationship,\n RelationshipQueryOptions,\n MemoryVocabulary,\n VocabularyChangeRecord,\n StorageRepositoryConfig,\n StoredRepository,\n StoredRepositorySummary,\n RepositoryFilter,\n RepositoryStats,\n RepositoryUpdate,\n StorageFindQuery,\n StorageExploreOptions,\n StoragePathOptions,\n StorageTimelineOptions,\n PaginationOptions,\n PaginatedResult,\n StorageNeighborhood,\n StoragePathResult,\n StorageTimelineResult,\n StorageTimelineEvent,\n BulkImportResult,\n} from '@utaba/deep-memory/types';\nimport type { ExportChunk, ImportChunk } from '@utaba/deep-memory/types';\nimport type { Provenance } from '@utaba/deep-memory/types';\nimport {\n RepositoryNotFoundError,\n DuplicateRepositoryError,\n EntityNotFoundError,\n DuplicateEntityError,\n RelationshipNotFoundError,\n DuplicateRelationshipError,\n ProviderError,\n matchesPropertyFilters,\n} from '@utaba/deep-memory';\nimport { getSchemaSQL, SCHEMA_VERSION } from './schema.js';\n\n/** Configuration for SqlServerStorageProvider */\nexport interface SqlServerStorageProviderConfig {\n /** mssql connection config or an existing connection pool */\n connection: sql.config | sql.ConnectionPool;\n /** SQL Server schema name (default: 'dbo') */\n schema?: string;\n}\n\n// ─── Column projection constants ───────────────────────────────────\n\n/** All entity columns except embedding — used by graph traversal, timeline, etc. */\nconst ENTITY_COLS_LIGHT = [\n 'entity_id', 'slug', 'repository_id', 'entity_type', 'label', 'summary',\n 'properties', 'data', 'data_format',\n 'created_by', 'created_by_type', 'created_at',\n 'created_in_conversation', 'created_from_message',\n 'modified_by', 'modified_by_type', 'modified_at',\n 'modified_in_conversation', 'modified_from_message',\n].map(c => `[${c}]`).join(', ');\n\n/** All entity columns including embedding — used by getEntity, getEntities, exportAll */\nconst ENTITY_COLS_FULL = `${ENTITY_COLS_LIGHT}, [embedding]`;\n\n// ─── Row-mapping helpers ────────────────────────────────────────────\n\nfunction provenanceFromRow(row: sql.IRecordSet<unknown>[number]): Provenance {\n const r = row as Record<string, unknown>;\n return {\n createdBy: r['created_by'] as string,\n createdByType: r['created_by_type'] as 'user' | 'agent',\n createdAt: r['created_at'] as string,\n createdInConversation: (r['created_in_conversation'] as string) || undefined,\n createdFromMessage: (r['created_from_message'] as string) || undefined,\n modifiedBy: r['modified_by'] as string,\n modifiedByType: r['modified_by_type'] as 'user' | 'agent',\n modifiedAt: r['modified_at'] as string,\n modifiedInConversation: (r['modified_in_conversation'] as string) || undefined,\n modifiedFromMessage: (r['modified_from_message'] as string) || undefined,\n };\n}\n\n/**\n * Add provenance filter conditions to a SQL query.\n * Uses a prefix to avoid parameter name collisions across data/count requests.\n */\nfunction addProvenanceConditions(\n req: sql.Request,\n prov: import('@utaba/deep-memory').ProvenanceFilter,\n conditions: string[],\n prefix: string,\n): void {\n if (prov.conversationIds && prov.conversationIds.length > 0) {\n const placeholders = prov.conversationIds.map((id, i) => {\n req.input(`${prefix}ConvId${i}`, sql.NVarChar, id);\n return `@${prefix}ConvId${i}`;\n });\n const inClause = placeholders.join(',');\n conditions.push(`([created_in_conversation] IN (${inClause}) OR [modified_in_conversation] IN (${inClause}))`);\n }\n if (prov.actors && prov.actors.length > 0) {\n const placeholders = prov.actors.map((a, i) => {\n req.input(`${prefix}Actor${i}`, sql.NVarChar, a);\n return `@${prefix}Actor${i}`;\n });\n const inClause = placeholders.join(',');\n conditions.push(`([created_by] IN (${inClause}) OR [modified_by] IN (${inClause}))`);\n }\n if (prov.dateRange) {\n req.input(`${prefix}DateFrom`, sql.NVarChar, prov.dateRange.from);\n req.input(`${prefix}DateTo`, sql.NVarChar, prov.dateRange.to);\n conditions.push(`([created_at] >= @${prefix}DateFrom AND [created_at] <= @${prefix}DateTo) OR ([modified_at] >= @${prefix}DateFrom AND [modified_at] <= @${prefix}DateTo)`);\n }\n}\n\nfunction entityFromRow(row: sql.IRecordSet<unknown>[number]): StoredEntity {\n const r = row as Record<string, unknown>;\n return {\n id: r['entity_id'] as string,\n slug: r['slug'] as string,\n entityType: r['entity_type'] as string,\n label: r['label'] as string,\n summary: (r['summary'] as string) || undefined,\n properties: JSON.parse((r['properties'] as string) || '{}') as Record<string, unknown>,\n data: (r['data'] as string) || undefined,\n dataFormat: (r['data_format'] as string) || undefined,\n provenance: provenanceFromRow(row),\n embedding: ('embedding' in r && r['embedding']) ? (JSON.parse(r['embedding'] as string) as number[]) : undefined,\n };\n}\n\nfunction relationshipFromRow(row: sql.IRecordSet<unknown>[number]): StoredRelationship {\n const r = row as Record<string, unknown>;\n return {\n id: r['relationship_id'] as string,\n relationshipType: r['relationship_type'] as string,\n sourceEntityId: r['source_entity_id'] as string,\n targetEntityId: r['target_entity_id'] as string,\n properties: JSON.parse((r['properties'] as string) || '{}') as Record<string, unknown>,\n bidirectional: r['bidirectional'] === true || r['bidirectional'] === 1,\n provenance: provenanceFromRow(row),\n };\n}\n\nfunction changeRecordFromRow(row: sql.IRecordSet<unknown>[number]): VocabularyChangeRecord {\n const r = row as Record<string, unknown>;\n return {\n changeId: r['change_id'] as string,\n changeType: r['change_type'] as VocabularyChangeRecord['changeType'],\n typeName: r['type_name'] as string,\n previousVersion: (r['previous_version'] as string) || undefined,\n newVersion: r['new_version'] as string,\n proposedBy: r['proposed_by'] as string,\n proposedAt: r['proposed_at'] as string,\n approvedBy: (r['approved_by'] as string) || undefined,\n approvedAt: (r['approved_at'] as string) || undefined,\n reason: r['reason'] as string,\n };\n}\n\n// ─── Provider ───────────────────────────────────────────────────────\n\nexport class SqlServerStorageProvider implements StorageProvider {\n private pool: sql.ConnectionPool | null = null;\n private ownsPool: boolean;\n private readonly config: SqlServerStorageProviderConfig;\n private readonly schema: string;\n\n constructor(config: SqlServerStorageProviderConfig) {\n this.config = config;\n this.schema = config.schema ?? 'dbo';\n this.ownsPool = !(config.connection instanceof sql.ConnectionPool);\n }\n\n private t(table: string): string {\n return `[${this.schema}].[${table}]`;\n }\n\n private getPool(): sql.ConnectionPool {\n if (!this.pool) {\n throw new ProviderError(\n 'SqlServerStorageProvider not initialized. Call initialize() first.',\n );\n }\n return this.pool;\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────\n\n async initialize(): Promise<void> {\n if (this.config.connection instanceof sql.ConnectionPool) {\n this.pool = this.config.connection;\n this.ownsPool = false;\n if (!this.pool.connected) {\n await this.pool.connect();\n }\n } else {\n this.pool = new sql.ConnectionPool(this.config.connection);\n this.ownsPool = true;\n await this.pool.connect();\n }\n\n }\n\n async dispose(): Promise<void> {\n if (this.ownsPool && this.pool) {\n await this.pool.close();\n }\n this.pool = null;\n }\n\n /**\n * Ensure the target database exists. If constructed with a sql.config and the\n * database does not yet exist, creates it via a temporary connection to master,\n * then (re)connects the main pool to the newly created database.\n *\n * @returns true if the database was created, false if it already existed.\n */\n private async ensureDatabase(): Promise<boolean> {\n // Only possible when we own the pool and have the raw config\n if (this.config.connection instanceof sql.ConnectionPool) {\n return false; // Pre-existing pool — caller is responsible for DB existence\n }\n\n const cfg = this.config.connection;\n const dbName = cfg.database;\n if (!dbName) {\n return false; // No database specified — nothing to create\n }\n\n let created = false;\n\n // Connect to master to check / create the database\n const masterPool = new sql.ConnectionPool({ ...cfg, database: 'master' });\n try {\n await masterPool.connect();\n const result = await masterPool.request()\n .input('dbName', sql.NVarChar, dbName)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM sys.databases WHERE name = @dbName`,\n );\n const exists = (result.recordset[0]?.cnt ?? 0) > 0;\n\n if (!exists) {\n // Database names cannot be parameterized — validate to prevent injection\n if (!/^[A-Za-z0-9_-]+$/.test(dbName)) {\n throw new ProviderError(\n `Invalid database name '${dbName}'. Only alphanumeric characters, hyphens, and underscores are allowed.`,\n );\n }\n await masterPool.request().query(`CREATE DATABASE [${dbName}]`);\n created = true;\n }\n } finally {\n await masterPool.close();\n }\n\n // If the main pool isn't connected yet (initialize failed because the DB\n // didn't exist), connect it now that the database exists.\n if (!this.pool || !this.pool.connected) {\n this.pool = new sql.ConnectionPool(cfg);\n this.ownsPool = true;\n await this.pool.connect();\n }\n\n return created;\n }\n\n async ensureSchema(): Promise<EnsureSchemaResult> {\n // If constructed with a sql.config (not a pre-existing pool), ensure the\n // target database exists before attempting any schema operations.\n const databaseCreated = await this.ensureDatabase();\n\n const pool = this.getPool();\n\n // Check if meta table exists to detect existing schema\n const metaCheck = await pool.request().query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM sys.tables WHERE name = 'dm_meta' AND schema_id = SCHEMA_ID('${this.schema}')`,\n );\n const metaExists = (metaCheck.recordset[0]?.cnt ?? 0) > 0;\n\n if (metaExists) {\n // Check version\n const versionResult = await pool.request().query<{ value: string }>(\n `SELECT [value] FROM ${this.t('dm_meta')} WHERE [key] = 'schema_version'`,\n );\n const currentVersion = parseInt(versionResult.recordset[0]?.value ?? '0', 10);\n if (currentVersion > SCHEMA_VERSION) {\n throw new ProviderError(\n `Database schema version ${currentVersion} is newer than provider version ${SCHEMA_VERSION}. Update the provider package.`,\n );\n }\n if (currentVersion === SCHEMA_VERSION) {\n return {\n databaseCreated,\n schemaCreated: false,\n alreadyUpToDate: !databaseCreated,\n schemaVersion: SCHEMA_VERSION,\n };\n }\n // Future: run migrations from currentVersion to SCHEMA_VERSION\n }\n\n // Create all tables (IF NOT EXISTS guards in the SQL handle idempotency)\n const ddl = getSchemaSQL(this.schema);\n // Split on blank-line boundaries (double newline) to keep BEGIN...END blocks intact\n const statements = ddl\n .split(/\\n\\n+/)\n .map((s) => s.split('\\n').filter((line) => !line.trimStart().startsWith('--')).join('\\n').trim())\n .filter((s) => s.length > 0);\n for (const stmt of statements) {\n try {\n await pool.request().query(stmt);\n } catch (err) {\n // Ignore \"already exists\" errors for indexes (they lack IF NOT EXISTS)\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes('already exists')) {\n throw new ProviderError(`Schema creation failed: ${msg}`);\n }\n }\n }\n\n return {\n databaseCreated,\n schemaCreated: true,\n alreadyUpToDate: false,\n schemaVersion: SCHEMA_VERSION,\n };\n }\n\n // ─── Repository ──────────────────────────────────────────────────\n\n async createRepository(config: StorageRepositoryConfig): Promise<StoredRepository> {\n const pool = this.getPool();\n\n // Check for duplicate\n const existing = await pool.request()\n .input('id', sql.UniqueIdentifier, config.repositoryId)\n .query<{ repository_id: string }>(\n `SELECT [repository_id] FROM ${this.t('dm_repositories')} WHERE [repository_id] = @id`,\n );\n\n if (existing.recordset.length > 0) {\n throw new DuplicateRepositoryError(config.repositoryId);\n }\n\n await pool.request()\n .input('id', sql.UniqueIdentifier, config.repositoryId)\n .input('type', sql.NVarChar, config.type ?? null)\n .input('label', sql.NVarChar, config.label)\n .input('description', sql.NVarChar, config.description ?? null)\n .input('legal', sql.NVarChar, config.legal ?? null)\n .input('owner', sql.NVarChar, config.owner ?? null)\n .input('governanceConfig', sql.NVarChar, JSON.stringify(config.governanceConfig))\n .input('metadata', sql.NVarChar, config.metadata ? JSON.stringify(config.metadata) : null)\n .input('createdAt', sql.NVarChar, config.createdAt)\n .input('createdBy', sql.NVarChar, config.createdBy)\n .query(`\n INSERT INTO ${this.t('dm_repositories')}\n ([repository_id], [type], [label], [description], [legal], [owner], [governance_config], [metadata], [created_at], [created_by])\n VALUES (@id, @type, @label, @description, @legal, @owner, @governanceConfig, @metadata, @createdAt, @createdBy)\n `);\n\n // Create empty vocabulary\n const emptyVocabulary: MemoryVocabulary = {\n version: '0.0.0',\n lastModified: config.createdAt,\n modifiedBy: config.createdBy,\n entityTypes: [],\n relationshipTypes: [],\n };\n\n await pool.request()\n .input('id', sql.UniqueIdentifier, config.repositoryId)\n .input('vocabulary', sql.NVarChar, JSON.stringify(emptyVocabulary))\n .query(`\n INSERT INTO ${this.t('dm_vocabularies')} ([repository_id], [vocabulary])\n VALUES (@id, @vocabulary)\n `);\n\n return {\n repositoryId: config.repositoryId,\n type: config.type,\n label: config.label,\n description: config.description,\n legal: config.legal,\n owner: config.owner,\n governanceConfig: config.governanceConfig,\n metadata: config.metadata,\n createdAt: config.createdAt,\n createdBy: config.createdBy,\n };\n }\n\n async getRepository(repositoryId: string): Promise<StoredRepository | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_repositories')} WHERE [repository_id] = @id`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n\n const metadataRaw = row['metadata'] as string | null;\n return {\n repositoryId: row['repository_id'] as string,\n type: (row['type'] as string) || undefined,\n label: row['label'] as string,\n description: (row['description'] as string) || undefined,\n legal: (row['legal'] as string) || undefined,\n owner: (row['owner'] as string) || undefined,\n governanceConfig: JSON.parse(row['governance_config'] as string) as StoredRepository['governanceConfig'],\n metadata: metadataRaw ? JSON.parse(metadataRaw) as StoredRepository['metadata'] : undefined,\n createdAt: row['created_at'] as string,\n createdBy: row['created_by'] as string,\n };\n }\n\n async listRepositories(\n filter?: RepositoryFilter,\n ): Promise<PaginatedResult<StoredRepositorySummary>> {\n const pool = this.getPool();\n const offset = filter?.offset ?? 0;\n const limit = filter?.limit ?? 20;\n\n const countReq = pool.request();\n const dataReq = pool.request();\n\n let where = '';\n if (filter?.type) {\n countReq.input('type', sql.NVarChar, filter.type);\n dataReq.input('type', sql.NVarChar, filter.type);\n where = 'WHERE [type] = @type';\n }\n\n // Get total count\n const countResult = await countReq.query<Record<string, unknown>>(\n `SELECT COUNT(*) AS [cnt] FROM ${this.t('dm_repositories')} ${where}`,\n );\n const total = (countResult.recordset[0]?.['cnt'] as number) ?? 0;\n\n // Fetch paginated results\n dataReq.input('offset', sql.Int, offset);\n dataReq.input('limit', sql.Int, limit);\n\n const result = await dataReq.query<Record<string, unknown>>(\n `SELECT [repository_id], [type], [label], [description], [governance_config]\n FROM ${this.t('dm_repositories')} ${where}\n ORDER BY [label]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n const items: StoredRepositorySummary[] = result.recordset.map((row) => ({\n repositoryId: row['repository_id'] as string,\n type: (row['type'] as string) || undefined,\n label: row['label'] as string,\n description: (row['description'] as string) || undefined,\n governanceConfig: JSON.parse(row['governance_config'] as string) as StoredRepository['governanceConfig'],\n }));\n\n return {\n items,\n total,\n hasMore: offset + items.length < total,\n limit,\n offset,\n };\n }\n\n async updateRepository(repositoryId: string, updates: RepositoryUpdate): Promise<StoredRepository> {\n const pool = this.getPool();\n\n // Build dynamic SET clause from provided fields\n const setClauses: string[] = [];\n const request = pool.request().input('id', sql.UniqueIdentifier, repositoryId);\n\n if (updates.label !== undefined) {\n setClauses.push('[label] = @label');\n request.input('label', sql.NVarChar, updates.label);\n }\n if (updates.description !== undefined) {\n setClauses.push('[description] = @description');\n request.input('description', sql.NVarChar, updates.description);\n }\n if (updates.type !== undefined) {\n setClauses.push('[type] = @type');\n request.input('type', sql.NVarChar, updates.type);\n }\n if (updates.legal !== undefined) {\n setClauses.push('[legal] = @legal');\n request.input('legal', sql.NVarChar, updates.legal);\n }\n if (updates.owner !== undefined) {\n setClauses.push('[owner] = @owner');\n request.input('owner', sql.NVarChar, updates.owner);\n }\n if (updates.governanceConfig !== undefined) {\n setClauses.push('[governance_config] = @governanceConfig');\n request.input('governanceConfig', sql.NVarChar, JSON.stringify(updates.governanceConfig));\n }\n if (updates.metadata !== undefined) {\n // Shallow merge with existing metadata\n const existing = await this.getRepository(repositoryId);\n if (!existing) throw new RepositoryNotFoundError(repositoryId);\n const merged = { ...existing.metadata, ...updates.metadata };\n setClauses.push('[metadata] = @metadata');\n request.input('metadata', sql.NVarChar, JSON.stringify(merged));\n }\n\n if (setClauses.length === 0) {\n const existing = await this.getRepository(repositoryId);\n if (!existing) throw new RepositoryNotFoundError(repositoryId);\n return existing;\n }\n\n const result = await request.query(\n `UPDATE ${this.t('dm_repositories')} SET ${setClauses.join(', ')} WHERE [repository_id] = @id`,\n );\n\n if (result.rowsAffected[0] === 0) {\n throw new RepositoryNotFoundError(repositoryId);\n }\n\n const updated = await this.getRepository(repositoryId);\n if (!updated) throw new RepositoryNotFoundError(repositoryId);\n return updated;\n }\n\n async deleteRepository(repositoryId: string, _onProgress?: import('@utaba/deep-memory/types').DeleteProgressCallback): Promise<void> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query(`DELETE FROM ${this.t('dm_repositories')} WHERE [repository_id] = @id`);\n\n if (result.rowsAffected[0] === 0) {\n throw new RepositoryNotFoundError(repositoryId);\n }\n }\n\n async deleteAllContents(repositoryId: string, _onProgress?: import('@utaba/deep-memory/types').DeleteProgressCallback): Promise<{ deletedEntities: number; deletedRelationships: number }> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Delete relationships first (FK constraint), then entities\n const relResult = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query(`DELETE FROM ${this.t('dm_relationships')} WHERE [repository_id] = @id`);\n\n const entityResult = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query(`DELETE FROM ${this.t('dm_entities')} WHERE [repository_id] = @id`);\n\n return {\n deletedEntities: entityResult.rowsAffected[0] ?? 0,\n deletedRelationships: relResult.rowsAffected[0] ?? 0,\n };\n }\n\n async getRepositoryStats(repositoryId: string): Promise<RepositoryStats> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n const [entityStats, relStats, vocab] = await Promise.all([\n pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ entity_type: string; cnt: number }>(\n `SELECT [entity_type], COUNT(*) AS cnt\n FROM ${this.t('dm_entities')} WHERE [repository_id] = @id\n GROUP BY [entity_type]`,\n ),\n pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ relationship_type: string; cnt: number }>(\n `SELECT [relationship_type], COUNT(*) AS cnt\n FROM ${this.t('dm_relationships')} WHERE [repository_id] = @id\n GROUP BY [relationship_type]`,\n ),\n this.getVocabulary(repositoryId),\n ]);\n\n const entityTypeBreakdown: Record<string, number> = {};\n let entityCount = 0;\n for (const row of entityStats.recordset) {\n entityTypeBreakdown[row.entity_type] = row.cnt;\n entityCount += row.cnt;\n }\n\n const relationshipTypeBreakdown: Record<string, number> = {};\n let relationshipCount = 0;\n for (const row of relStats.recordset) {\n relationshipTypeBreakdown[row.relationship_type] = row.cnt;\n relationshipCount += row.cnt;\n }\n\n return {\n entityCount,\n relationshipCount,\n vocabularyVersion: vocab.version,\n entityTypeBreakdown,\n relationshipTypeBreakdown,\n };\n }\n\n // ─── Vocabulary ──────────────────────────────────────────────────\n\n async getVocabulary(repositoryId: string): Promise<MemoryVocabulary> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ vocabulary: string }>(\n `SELECT [vocabulary] FROM ${this.t('dm_vocabularies')} WHERE [repository_id] = @id`,\n );\n\n const row = result.recordset[0];\n if (!row) {\n // Should not happen if repository exists, but handle gracefully\n return {\n version: '0.0.0',\n lastModified: new Date().toISOString(),\n modifiedBy: 'system',\n entityTypes: [],\n relationshipTypes: [],\n };\n }\n\n return JSON.parse(row.vocabulary) as MemoryVocabulary;\n }\n\n async saveVocabulary(repositoryId: string, vocabulary: MemoryVocabulary): Promise<void> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .input('vocabulary', sql.NVarChar, JSON.stringify(vocabulary))\n .query(`\n UPDATE ${this.t('dm_vocabularies')}\n SET [vocabulary] = @vocabulary\n WHERE [repository_id] = @id\n `);\n }\n\n async getVocabularyChangeLog(\n repositoryId: string,\n options?: PaginationOptions,\n ): Promise<PaginatedResult<VocabularyChangeRecord>> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n const limit = options?.limit ?? 10;\n const offset = options?.offset ?? 0;\n\n const countResult = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_vocabulary_change_log')} WHERE [repository_id] = @id`,\n );\n const total = countResult.recordset[0]?.cnt ?? 0;\n\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .input('limit', sql.Int, limit)\n .input('offset', sql.Int, offset)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_vocabulary_change_log')}\n WHERE [repository_id] = @id\n ORDER BY [proposed_at] DESC\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n return {\n items: result.recordset.map(changeRecordFromRow),\n total,\n hasMore: offset + limit < total,\n limit,\n offset,\n };\n }\n\n // ─── Entities ────────────────────────────────────────────────────\n\n async createEntity(repositoryId: string, entity: StoredEntity): Promise<StoredEntity> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Check for duplicate\n const existing = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entity.id)\n .query<{ entity_id: string }>(\n `SELECT [entity_id] FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n if (existing.recordset.length > 0) {\n throw new DuplicateEntityError(entity.id);\n }\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entity.id)\n .input('slug', sql.NVarChar, entity.slug)\n .input('entityType', sql.NVarChar, entity.entityType)\n .input('label', sql.NVarChar, entity.label)\n .input('summary', sql.NVarChar, entity.summary ?? null)\n .input('properties', sql.NVarChar, JSON.stringify(entity.properties))\n .input('data', sql.NVarChar, entity.data ?? null)\n .input('dataFormat', sql.NVarChar, entity.dataFormat ?? null)\n .input('embedding', sql.NVarChar, entity.embedding ? JSON.stringify(entity.embedding) : null);\n\n this.addProvenanceInputs(req, entity.provenance);\n\n await req.query(`\n INSERT INTO ${this.t('dm_entities')} (\n [repository_id], [entity_id], [slug], [entity_type], [label], [summary],\n [properties], [data], [data_format], [embedding],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @entityId, @slug, @entityType, @label, @summary,\n @properties, @data, @dataFormat, @embedding,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n )\n `);\n\n return entity;\n }\n\n async getEntity(repositoryId: string, entityId: string): Promise<StoredEntity | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return entityFromRow(row);\n }\n\n async getEntityBySlug(repositoryId: string, slug: string): Promise<StoredEntity | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('slug', sql.NVarChar, slug)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [slug] = @slug`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return entityFromRow(row);\n }\n\n async getEntities(\n repositoryId: string,\n entityIds: string[],\n ): Promise<Map<string, StoredEntity>> {\n const pool = this.getPool();\n const result = new Map<string, StoredEntity>();\n if (entityIds.length === 0) return result;\n\n const tvp = this.createIdListTvp(entityIds);\n const rows = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId\n AND [entity_id] IN (SELECT [id] FROM @entityIds)`,\n );\n\n for (const row of rows.recordset) {\n const entity = entityFromRow(row);\n result.set(entity.id, entity);\n }\n\n return result;\n }\n\n async updateEntity(\n repositoryId: string,\n entityId: string,\n updates: StoredEntityUpdate,\n ): Promise<StoredEntity> {\n const pool = this.getPool();\n\n // Get existing entity\n const existing = await this.getEntity(repositoryId, entityId);\n if (!existing) {\n throw new EntityNotFoundError(entityId);\n }\n\n const updated: StoredEntity = {\n ...existing,\n label: updates.label ?? existing.label,\n slug: updates.slug ?? existing.slug,\n summary: updates.summary !== undefined ? updates.summary : existing.summary,\n properties: updates.properties ?? existing.properties,\n data: updates.data !== undefined ? updates.data : existing.data,\n dataFormat: updates.dataFormat !== undefined ? updates.dataFormat : existing.dataFormat,\n provenance: updates.provenance,\n embedding: updates.embedding ?? existing.embedding,\n };\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .input('slug', sql.NVarChar, updated.slug)\n .input('label', sql.NVarChar, updated.label)\n .input('summary', sql.NVarChar, updated.summary ?? null)\n .input('properties', sql.NVarChar, JSON.stringify(updated.properties))\n .input('data', sql.NVarChar, updated.data ?? null)\n .input('dataFormat', sql.NVarChar, updated.dataFormat ?? null)\n .input('embedding', sql.NVarChar, updated.embedding ? JSON.stringify(updated.embedding) : null)\n .input('modifiedBy', sql.NVarChar, updates.provenance.modifiedBy)\n .input('modifiedByType', sql.NVarChar, updates.provenance.modifiedByType)\n .input('modifiedAt', sql.NVarChar, updates.provenance.modifiedAt)\n .input('modifiedInConversation', sql.NVarChar, updates.provenance.modifiedInConversation ?? null)\n .input('modifiedFromMessage', sql.NVarChar, updates.provenance.modifiedFromMessage ?? null);\n\n await req.query(`\n UPDATE ${this.t('dm_entities')} SET\n [slug] = @slug,\n [label] = @label,\n [summary] = @summary,\n [properties] = @properties,\n [data] = @data,\n [data_format] = @dataFormat,\n [embedding] = @embedding,\n [modified_by] = @modifiedBy,\n [modified_by_type] = @modifiedByType,\n [modified_at] = @modifiedAt,\n [modified_in_conversation] = @modifiedInConversation,\n [modified_from_message] = @modifiedFromMessage\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId\n `);\n\n return updated;\n }\n\n async deleteEntity(repositoryId: string, entityId: string): Promise<void> {\n const pool = this.getPool();\n\n // Delete relationships first (FK constraints would block otherwise)\n // Two targeted DELETEs hit source/target indexes instead of one OR scan\n const delReq = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId);\n await delReq.query(`\n DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId;\n DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId;\n `);\n\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .query(\n `DELETE FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n if (result.rowsAffected[0] === 0) {\n throw new EntityNotFoundError(entityId);\n }\n }\n\n async deleteEntitiesByType(\n repositoryId: string,\n entityType: string,\n ): Promise<{ deletedEntities: number; deletedRelationships: number }> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Delete relationships where entities of this type are the SOURCE\n const srcResult = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityType', sql.NVarChar, entityType)\n .query(`\n DELETE r FROM ${this.t('dm_relationships')} r\n INNER JOIN ${this.t('dm_entities')} e\n ON r.[repository_id] = e.[repository_id]\n AND r.[source_entity_id] = e.[entity_id]\n WHERE e.[repository_id] = @repoId AND e.[entity_type] = @entityType\n `);\n\n // Delete relationships where entities of this type are the TARGET\n const tgtResult = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityType', sql.NVarChar, entityType)\n .query(`\n DELETE r FROM ${this.t('dm_relationships')} r\n INNER JOIN ${this.t('dm_entities')} e\n ON r.[repository_id] = e.[repository_id]\n AND r.[target_entity_id] = e.[entity_id]\n WHERE e.[repository_id] = @repoId AND e.[entity_type] = @entityType\n `);\n\n const deletedRelationships = (srcResult.rowsAffected[0] ?? 0) + (tgtResult.rowsAffected[0] ?? 0);\n\n // Delete the entities\n const entResult = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityType', sql.NVarChar, entityType)\n .query(\n `DELETE FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_type] = @entityType`,\n );\n const deletedEntities = entResult.rowsAffected[0] ?? 0;\n\n return { deletedEntities, deletedRelationships };\n }\n\n async findEntities(\n repositoryId: string,\n query: StorageFindQuery,\n ): Promise<PaginatedResult<StoredEntity>> {\n const pool = this.getPool();\n const req = pool.request().input('repoId', sql.UniqueIdentifier, repositoryId);\n\n const conditions = ['[repository_id] = @repoId'];\n\n // Type filter\n if (query.entityTypes && query.entityTypes.length > 0) {\n const typePlaceholders = query.entityTypes.map((t, i) => {\n req.input(`et${i}`, sql.NVarChar, t);\n return `@et${i}`;\n });\n conditions.push(`[entity_type] IN (${typePlaceholders.join(',')})`);\n }\n\n // Search term (case-insensitive LIKE on label and summary)\n if (query.searchTerm) {\n req.input('searchTerm', sql.NVarChar, `%${query.searchTerm}%`);\n conditions.push(`([label] LIKE @searchTerm OR [summary] LIKE @searchTerm)`);\n }\n\n // Property filter (exact match via JSON_VALUE)\n if (query.properties) {\n const entries = Object.entries(query.properties);\n for (let i = 0; i < entries.length; i++) {\n const [key, value] = entries[i]!;\n req.input(`propKey${i}`, sql.NVarChar, `$.${key}`);\n req.input(`propVal${i}`, sql.NVarChar, String(value));\n conditions.push(`JSON_VALUE([properties], @propKey${i}) = @propVal${i}`);\n }\n }\n\n // Provenance filter\n if (query.provenance) {\n addProvenanceConditions(req, query.provenance, conditions, 'data');\n }\n\n const where = conditions.join(' AND ');\n\n // Build a separate request for the count (mssql doesn't allow reusing requests)\n\n const countReq = pool.request().input('repoId', sql.UniqueIdentifier, repositoryId);\n const countConditions = ['[repository_id] = @repoId'];\n\n if (query.entityTypes && query.entityTypes.length > 0) {\n const typePlaceholders = query.entityTypes.map((t, i) => {\n countReq.input(`et${i}`, sql.NVarChar, t);\n return `@et${i}`;\n });\n countConditions.push(`[entity_type] IN (${typePlaceholders.join(',')})`);\n }\n if (query.searchTerm) {\n countReq.input('searchTerm', sql.NVarChar, `%${query.searchTerm}%`);\n countConditions.push(`([label] LIKE @searchTerm OR [summary] LIKE @searchTerm)`);\n }\n if (query.properties) {\n const entries = Object.entries(query.properties);\n for (let i = 0; i < entries.length; i++) {\n const [key, value] = entries[i]!;\n countReq.input(`propKey${i}`, sql.NVarChar, `$.${key}`);\n countReq.input(`propVal${i}`, sql.NVarChar, String(value));\n countConditions.push(`JSON_VALUE([properties], @propKey${i}) = @propVal${i}`);\n }\n }\n\n // Provenance filter (count query)\n if (query.provenance) {\n addProvenanceConditions(countReq, query.provenance, countConditions, 'count');\n }\n\n const countWhere = countConditions.join(' AND ');\n const totalResult = await countReq.query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_entities')} WHERE ${countWhere}`,\n );\n const total = totalResult.recordset[0]?.cnt ?? 0;\n\n // Fetch page\n req.input('limit', sql.Int, query.limit);\n req.input('offset', sql.Int, query.offset);\n\n const result = await req.query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE ${where}\n ORDER BY [entity_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n return {\n items: result.recordset.map(entityFromRow),\n total,\n hasMore: query.offset + query.limit < total,\n limit: query.limit,\n offset: query.offset,\n };\n }\n\n // ─── Relationships ──────────────────────────────────────────────\n\n async createRelationship(\n repositoryId: string,\n relationship: StoredRelationship,\n ): Promise<StoredRelationship> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Check for duplicate\n const existing = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationship.id)\n .query<{ relationship_id: string }>(\n `SELECT [relationship_id] FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_id] = @relId`,\n );\n\n if (existing.recordset.length > 0) {\n throw new DuplicateRelationshipError(relationship.id);\n }\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationship.id)\n .input('relType', sql.NVarChar, relationship.relationshipType)\n .input('sourceId', sql.NVarChar, relationship.sourceEntityId)\n .input('targetId', sql.NVarChar, relationship.targetEntityId)\n .input('properties', sql.NVarChar, JSON.stringify(relationship.properties))\n .input('bidirectional', sql.Bit, relationship.bidirectional ? 1 : 0);\n\n this.addProvenanceInputs(req, relationship.provenance);\n\n await req.query(`\n INSERT INTO ${this.t('dm_relationships')} (\n [repository_id], [relationship_id], [relationship_type],\n [source_entity_id], [target_entity_id], [properties], [bidirectional],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @relId, @relType,\n @sourceId, @targetId, @properties, @bidirectional,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n )\n `);\n\n return relationship;\n }\n\n async getRelationship(\n repositoryId: string,\n relationshipId: string,\n ): Promise<StoredRelationship | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationshipId)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_id] = @relId`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return relationshipFromRow(row);\n }\n\n async getEntityRelationships(\n repositoryId: string,\n entityId: string,\n options?: RelationshipQueryOptions,\n ): Promise<PaginatedResult<StoredRelationship>> {\n const pool = this.getPool();\n const direction = options?.direction ?? 'both';\n const limit = options?.limit ?? 10;\n const offset = options?.offset ?? 0;\n const tbl = this.t('dm_relationships');\n\n // Build relationship type filter clause (shared across branches)\n let rtFilter = '';\n const rtInputs: Array<{ name: string; value: string }> = [];\n if (options?.relationshipTypes && options.relationshipTypes.length > 0) {\n const placeholders = options.relationshipTypes.map((t, i) => {\n rtInputs.push({ name: `rt${i}`, value: t });\n return `@rt${i}`;\n });\n rtFilter = ` AND [relationship_type] IN (${placeholders.join(',')})`;\n }\n\n // Build UNION ALL query — each branch targets a specific nonclustered index\n // instead of forcing an OR-based scan across source/target columns.\n const unionBranches = this.buildRelationshipUnion(tbl, direction, rtFilter);\n\n const addParams = (req: sql.Request): sql.Request => {\n req.input('repoId', sql.UniqueIdentifier, repositoryId);\n req.input('entityId', sql.NVarChar, entityId);\n for (const p of rtInputs) req.input(p.name, sql.NVarChar, p.value);\n return req;\n };\n\n // Count\n const countReq = addParams(pool.request());\n const totalResult = await countReq.query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM (${unionBranches}) AS _u`,\n );\n const total = totalResult.recordset[0]?.cnt ?? 0;\n\n // Fetch page\n const fetchReq = addParams(pool.request());\n fetchReq.input('limit', sql.Int, limit);\n fetchReq.input('offset', sql.Int, offset);\n\n const result = await fetchReq.query<Record<string, unknown>>(\n `SELECT * FROM (${unionBranches}) AS _u\n ORDER BY [relationship_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n let items = result.recordset.map(relationshipFromRow);\n\n // Apply property filters in-memory\n if (options?.propertyFilters && options.propertyFilters.length > 0) {\n items = items.filter((r) => matchesPropertyFilters(r.properties, options.propertyFilters!));\n const filteredTotal = total; // approximate — exact count would require re-querying\n return {\n items,\n total: filteredTotal,\n hasMore: offset + limit < filteredTotal,\n limit,\n offset,\n };\n }\n\n return {\n items,\n total,\n hasMore: offset + limit < total,\n limit,\n offset,\n };\n }\n\n /**\n * Build a UNION ALL query that seeks on source and target indexes separately,\n * avoiding OR-based index scans. Each branch produces an index seek at scale.\n */\n private buildRelationshipUnion(tbl: string, direction: string, rtFilter: string): string {\n // Source branch: seeks ix_dm_relationships_source (repo, source_entity_id, relationship_type)\n const srcBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId${rtFilter}`;\n // Target branch: seeks ix_dm_relationships_target (repo, target_entity_id, bidirectional, relationship_type)\n const tgtBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId${rtFilter}`;\n // Bidirectional target: seeks ix_dm_relationships_target with bidirectional = 1\n const tgtBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId AND [bidirectional] = 1${rtFilter}`;\n // Bidirectional source: seeks ix_dm_relationships_source with bidirectional = 1\n const srcBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId AND [bidirectional] = 1${rtFilter}`;\n\n switch (direction) {\n case 'outbound':\n // Outbound = where entity is source, OR where entity is target of a bidirectional rel\n return `${srcBase} UNION ALL ${tgtBidi} AND [source_entity_id] <> @entityId`;\n case 'inbound':\n // Inbound = where entity is target, OR where entity is source of a bidirectional rel\n return `${tgtBase} UNION ALL ${srcBidi} AND [target_entity_id] <> @entityId`;\n case 'both':\n default:\n // Both = where entity is source UNION where entity is target (excluding duplicates from source branch)\n return `${srcBase} UNION ALL ${tgtBase} AND [source_entity_id] <> @entityId`;\n }\n }\n\n async deleteRelationship(repositoryId: string, relationshipId: string): Promise<void> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationshipId)\n .query(\n `DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_id] = @relId`,\n );\n\n if (result.rowsAffected[0] === 0) {\n throw new RelationshipNotFoundError(relationshipId);\n }\n }\n\n async deleteRelationshipsByType(\n repositoryId: string,\n relationshipType: string,\n ): Promise<{ deletedRelationships: number }> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relType', sql.NVarChar, relationshipType)\n .query(\n `DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_type] = @relType`,\n );\n\n return { deletedRelationships: result.rowsAffected[0] ?? 0 };\n }\n\n // ─── Graph Traversal ────────────────────────────────────────────\n\n async exploreNeighborhood(\n repositoryId: string,\n entityId: string,\n options: StorageExploreOptions,\n ): Promise<StorageNeighborhood> {\n // Verify the center entity exists (light — no embedding needed)\n const center = await this.getEntityLight(repositoryId, entityId);\n if (!center) {\n throw new EntityNotFoundError(entityId);\n }\n\n const layers: StorageNeighborhood['layers'] = [];\n const visited = new Set<string>([entityId]);\n let currentFrontier = new Set<string>([entityId]);\n\n for (let depth = 0; depth < options.depth; depth++) {\n const layer: StorageNeighborhood['layers'][number] = {};\n const nextFrontier = new Set<string>();\n\n // Batch: fetch all relationships for the entire frontier in one query\n const frontierIds = [...currentFrontier];\n const relsByEntity = await this.getRelationshipsForEntities(\n repositoryId,\n frontierIds,\n options.direction,\n options.relationshipTypes,\n );\n\n // Collect all connected entity IDs we need to fetch\n const connectedIdsToFetch = new Set<string>();\n const pendingRels: Array<{ frontierEntityId: string; rel: StoredRelationship; connectedEntityId: string }> = [];\n\n for (const frontierEntityId of frontierIds) {\n const rels = relsByEntity.get(frontierEntityId) ?? [];\n for (const rel of rels) {\n let connectedEntityId: string | undefined;\n if (rel.sourceEntityId === frontierEntityId) {\n connectedEntityId = rel.targetEntityId;\n } else if (rel.targetEntityId === frontierEntityId) {\n connectedEntityId = rel.sourceEntityId;\n }\n if (!connectedEntityId || visited.has(connectedEntityId)) continue;\n\n // Filter by relationship property values\n if (options.relationshipPropertyFilters && options.relationshipPropertyFilters.length > 0) {\n if (!matchesPropertyFilters(rel.properties, options.relationshipPropertyFilters)) {\n continue;\n }\n }\n\n connectedIdsToFetch.add(connectedEntityId);\n pendingRels.push({ frontierEntityId, rel, connectedEntityId });\n }\n }\n\n // Batch: fetch all connected entities in one query\n const connectedEntities = await this.getEntitiesLight(repositoryId, [...connectedIdsToFetch]);\n\n // Process results in memory\n for (const { rel, connectedEntityId } of pendingRels) {\n if (visited.has(connectedEntityId)) continue;\n\n const connectedEntity = connectedEntities.get(connectedEntityId);\n if (!connectedEntity) continue;\n\n if (options.entityTypes && !options.entityTypes.includes(connectedEntity.entityType)) {\n continue;\n }\n\n const relType = rel.relationshipType;\n if (!layer[relType]) {\n layer[relType] = { total: 0, entities: [], relationships: [] };\n }\n\n const group = layer[relType]!;\n group.total++;\n\n if (group.entities.length < options.limitPerType) {\n group.entities.push(connectedEntity);\n group.relationships.push(rel);\n }\n\n nextFrontier.add(connectedEntityId);\n visited.add(connectedEntityId);\n }\n\n layers.push(layer);\n currentFrontier = nextFrontier;\n if (nextFrontier.size === 0) break;\n }\n\n return { centerId: entityId, layers };\n }\n\n async findPaths(\n repositoryId: string,\n sourceId: string,\n targetId: string,\n options: StoragePathOptions,\n ): Promise<StoragePathResult> {\n // Verify both entities exist (light — no embedding needed)\n const [source, target] = await Promise.all([\n this.getEntityLight(repositoryId, sourceId),\n this.getEntityLight(repositoryId, targetId),\n ]);\n if (!source) throw new EntityNotFoundError(sourceId);\n if (!target) throw new EntityNotFoundError(targetId);\n\n if (sourceId === targetId) {\n return { paths: [{ entityIds: [sourceId], relationshipIds: [] }], totalPaths: 1 };\n }\n\n // BFS path finding — processes in depth levels for batch relationship fetching\n const paths: Array<{ entityIds: string[]; relationshipIds: string[] }> = [];\n let currentLevel: Array<{ entityId: string; path: string[]; relPath: string[] }> = [\n { entityId: sourceId, path: [sourceId], relPath: [] },\n ];\n const visitedAtDepth = new Map<string, number>();\n visitedAtDepth.set(sourceId, 0);\n\n for (let depth = 0; depth <= options.maxDepth && currentLevel.length > 0 && paths.length < options.limit + options.offset; depth++) {\n // Batch: fetch relationships for all frontier entities at this depth\n const frontierIds = [...new Set(currentLevel.map(e => e.entityId))];\n const relsByEntity = await this.getRelationshipsForEntities(\n repositoryId,\n frontierIds,\n 'both',\n options.relationshipTypes,\n );\n\n const nextLevel: Array<{ entityId: string; path: string[]; relPath: string[] }> = [];\n\n for (const current of currentLevel) {\n if (paths.length >= options.limit + options.offset) break;\n\n const rels = relsByEntity.get(current.entityId) ?? [];\n for (const rel of rels) {\n // Filter by relationship property values\n if (options.relationshipPropertyFilters && options.relationshipPropertyFilters.length > 0) {\n if (!matchesPropertyFilters(rel.properties, options.relationshipPropertyFilters)) {\n continue;\n }\n }\n\n let nextEntityId: string | undefined;\n if (rel.sourceEntityId === current.entityId) {\n nextEntityId = rel.targetEntityId;\n } else if (rel.targetEntityId === current.entityId) {\n nextEntityId = rel.sourceEntityId;\n }\n\n if (!nextEntityId) continue;\n if (current.path.includes(nextEntityId) && nextEntityId !== targetId) continue;\n\n const newPath = [...current.path, nextEntityId];\n const newRelPath = [...current.relPath, rel.id];\n\n if (nextEntityId === targetId) {\n paths.push({ entityIds: newPath, relationshipIds: newRelPath });\n } else if (newPath.length <= options.maxDepth) {\n const prevDepth = visitedAtDepth.get(nextEntityId);\n if (prevDepth === undefined || prevDepth >= newPath.length - 1) {\n visitedAtDepth.set(nextEntityId, newPath.length - 1);\n nextLevel.push({ entityId: nextEntityId, path: newPath, relPath: newRelPath });\n }\n }\n }\n }\n\n // Filter next level by entity types if specified (batch-fetch entity types)\n if (options.entityTypes && nextLevel.length > 0) {\n const nextIds = [...new Set(nextLevel.map(e => e.entityId))];\n const entityMap = await this.getEntitiesLight(repositoryId, nextIds);\n const allowedIds = new Set<string>();\n for (const [id, e] of entityMap) {\n if (options.entityTypes.includes(e.entityType)) {\n allowedIds.add(id);\n }\n }\n currentLevel = nextLevel.filter(e => allowedIds.has(e.entityId));\n } else {\n currentLevel = nextLevel;\n }\n }\n\n const paginatedPaths = paths.slice(options.offset, options.offset + options.limit);\n return { paths: paginatedPaths, totalPaths: paths.length };\n }\n\n // ─── Timeline ───────────────────────────────────────────────────\n\n async getTimeline(\n repositoryId: string,\n entityId: string,\n options: StorageTimelineOptions,\n ): Promise<StorageTimelineResult> {\n const entity = await this.getEntityLight(repositoryId, entityId);\n if (!entity) {\n throw new EntityNotFoundError(entityId);\n }\n\n const events: StorageTimelineEvent[] = [];\n\n // Entity creation event\n events.push({\n timestamp: entity.provenance.createdAt,\n eventType: 'entity:created',\n entityId,\n });\n\n // Entity modification event\n if (entity.provenance.modifiedAt !== entity.provenance.createdAt) {\n events.push({\n timestamp: entity.provenance.modifiedAt,\n eventType: 'entity:updated',\n entityId,\n });\n }\n\n // Relationship events involving this entity — push time-range filter into SQL\n const pool = this.getPool();\n const relReq = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .input('from', sql.NVarChar, options.timeRange?.from ?? null)\n .input('to', sql.NVarChar, options.timeRange?.to ?? null);\n\n const relResult = await relReq.query<Record<string, unknown>>(\n `SELECT [relationship_id], [created_at] FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId\n AND (@from IS NULL OR [created_at] >= @from)\n AND (@to IS NULL OR [created_at] <= @to)\n UNION ALL\n SELECT [relationship_id], [created_at] FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId\n AND [source_entity_id] <> @entityId\n AND (@from IS NULL OR [created_at] >= @from)\n AND (@to IS NULL OR [created_at] <= @to)`,\n );\n\n for (const row of relResult.recordset) {\n events.push({\n timestamp: row['created_at'] as string,\n eventType: 'relationship:created',\n entityId,\n relationshipId: row['relationship_id'] as string,\n });\n }\n\n // Filter by time range (still needed for entity events which come from provenance)\n let filtered = events;\n if (options.timeRange) {\n const from = new Date(options.timeRange.from).getTime();\n const to = new Date(options.timeRange.to).getTime();\n filtered = filtered.filter((e) => {\n const t = new Date(e.timestamp).getTime();\n return t >= from && t <= to;\n });\n }\n\n // Filter by event types\n if (options.eventTypes && options.eventTypes.length > 0) {\n filtered = filtered.filter((e) => options.eventTypes!.includes(e.eventType));\n }\n\n // Sort descending\n filtered.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n const total = filtered.length;\n const items = filtered.slice(options.offset, options.offset + options.limit);\n\n return { events: items, total };\n }\n\n // ─── Bulk Operations ────────────────────────────────────────────\n\n async *exportAll(repositoryId: string): AsyncIterable<ExportChunk> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n const batchSize = 100;\n\n // Export entities\n const entityCount = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_entities')} WHERE [repository_id] = @repoId`,\n );\n const totalEntities = entityCount.recordset[0]?.cnt ?? 0;\n\n if (totalEntities === 0) {\n yield { type: 'entities', data: [], sequence: 0, isLast: true };\n } else {\n for (let offset = 0; offset < totalEntities; offset += batchSize) {\n const batch = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('offset', sql.Int, offset)\n .input('limit', sql.Int, batchSize)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_FULL} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId\n ORDER BY [entity_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n yield {\n type: 'entities',\n data: batch.recordset.map(entityFromRow),\n sequence: Math.floor(offset / batchSize),\n isLast: offset + batchSize >= totalEntities,\n };\n }\n }\n\n // Export relationships\n const relCount = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_relationships')} WHERE [repository_id] = @repoId`,\n );\n const totalRels = relCount.recordset[0]?.cnt ?? 0;\n\n if (totalRels === 0) {\n yield { type: 'relationships', data: [], sequence: 0, isLast: true };\n } else {\n for (let offset = 0; offset < totalRels; offset += batchSize) {\n const batch = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('offset', sql.Int, offset)\n .input('limit', sql.Int, batchSize)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId\n ORDER BY [relationship_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n yield {\n type: 'relationships',\n data: batch.recordset.map(relationshipFromRow),\n sequence: Math.floor(offset / batchSize),\n isLast: offset + batchSize >= totalRels,\n };\n }\n }\n }\n\n async importBulk(\n repositoryId: string,\n data: ImportChunk[],\n _options?: import('@utaba/deep-memory/types').BulkImportOptions,\n ): Promise<BulkImportResult> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n let entitiesImported = 0;\n let relationshipsImported = 0;\n\n const transaction = pool.transaction();\n await transaction.begin();\n try {\n for (const chunk of data) {\n if (chunk.entities) {\n for (const entity of chunk.entities) {\n const req = transaction.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entity.id)\n .input('slug', sql.NVarChar, entity.slug)\n .input('entityType', sql.NVarChar, entity.entityType)\n .input('label', sql.NVarChar, entity.label)\n .input('summary', sql.NVarChar, entity.summary ?? null)\n .input('properties', sql.NVarChar, JSON.stringify(entity.properties))\n .input('data', sql.NVarChar, entity.data ?? null)\n .input('dataFormat', sql.NVarChar, entity.dataFormat ?? null)\n .input('embedding', sql.NVarChar, entity.embedding ? JSON.stringify(entity.embedding) : null);\n\n this.addProvenanceInputs(req, entity.provenance);\n\n await req.query(`\n MERGE ${this.t('dm_entities')} AS target\n USING (SELECT @repoId AS repository_id, @entityId AS entity_id) AS source\n ON target.[repository_id] = source.repository_id AND target.[entity_id] = source.entity_id\n WHEN MATCHED THEN UPDATE SET\n [entity_type] = @entityType, [slug] = @slug, [label] = @label, [summary] = @summary,\n [properties] = @properties, [data] = @data, [data_format] = @dataFormat,\n [embedding] = @embedding,\n [modified_by] = @modifiedBy, [modified_by_type] = @modifiedByType,\n [modified_at] = @modifiedAt, [modified_in_conversation] = @modifiedInConversation,\n [modified_from_message] = @modifiedFromMessage\n WHEN NOT MATCHED THEN INSERT (\n [repository_id], [entity_id], [slug], [entity_type], [label], [summary],\n [properties], [data], [data_format], [embedding],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @entityId, @slug, @entityType, @label, @summary,\n @properties, @data, @dataFormat, @embedding,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n );\n `);\n entitiesImported++;\n }\n }\n\n if (chunk.relationships) {\n for (const rel of chunk.relationships) {\n const req = transaction.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, rel.id)\n .input('relType', sql.NVarChar, rel.relationshipType)\n .input('sourceId', sql.NVarChar, rel.sourceEntityId)\n .input('targetId', sql.NVarChar, rel.targetEntityId)\n .input('properties', sql.NVarChar, JSON.stringify(rel.properties))\n .input('bidirectional', sql.Bit, rel.bidirectional ? 1 : 0);\n\n this.addProvenanceInputs(req, rel.provenance);\n\n await req.query(`\n MERGE ${this.t('dm_relationships')} AS target\n USING (SELECT @repoId AS repository_id, @relId AS relationship_id) AS source\n ON target.[repository_id] = source.repository_id AND target.[relationship_id] = source.relationship_id\n WHEN MATCHED THEN UPDATE SET\n [relationship_type] = @relType, [source_entity_id] = @sourceId,\n [target_entity_id] = @targetId, [properties] = @properties,\n [bidirectional] = @bidirectional,\n [modified_by] = @modifiedBy, [modified_by_type] = @modifiedByType,\n [modified_at] = @modifiedAt, [modified_in_conversation] = @modifiedInConversation,\n [modified_from_message] = @modifiedFromMessage\n WHEN NOT MATCHED THEN INSERT (\n [repository_id], [relationship_id], [relationship_type],\n [source_entity_id], [target_entity_id], [properties], [bidirectional],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @relId, @relType,\n @sourceId, @targetId, @properties, @bidirectional,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n );\n `);\n relationshipsImported++;\n }\n }\n }\n await transaction.commit();\n } catch (err) {\n await transaction.rollback();\n throw err;\n }\n\n return { entitiesImported, relationshipsImported, errors: [] };\n }\n\n // ─── Private helpers ────────────────────────────────────────────\n\n /** Creates a TVP table from an array of string IDs (eliminates plan cache bloat from IN clauses). */\n private createIdListTvp(ids: string[]): sql.Table {\n const tvp = new sql.Table(`${this.schema}.dm_id_list`);\n tvp.columns.add('id', sql.NVarChar(300));\n for (const id of ids) tvp.rows.add(id);\n return tvp;\n }\n\n /** Returns a StoredEntity without the embedding column (lighter I/O). */\n private async getEntityLight(repositoryId: string, entityId: string): Promise<StoredEntity | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return entityFromRow(row);\n }\n\n /** Returns multiple entities without embedding columns, using TVP for batch lookup. */\n private async getEntitiesLight(\n repositoryId: string,\n entityIds: string[],\n ): Promise<Map<string, StoredEntity>> {\n const pool = this.getPool();\n const result = new Map<string, StoredEntity>();\n if (entityIds.length === 0) return result;\n\n const tvp = this.createIdListTvp(entityIds);\n const rows = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId\n AND [entity_id] IN (SELECT [id] FROM @entityIds)`,\n );\n\n for (const row of rows.recordset) {\n const entity = entityFromRow(row);\n result.set(entity.id, entity);\n }\n\n return result;\n }\n\n /**\n * Fetches relationships for multiple entity IDs in a single query using TVP.\n * Returns results grouped by the frontier entity ID.\n */\n private async getRelationshipsForEntities(\n repositoryId: string,\n entityIds: string[],\n direction: string,\n relationshipTypes?: string[],\n ): Promise<Map<string, StoredRelationship[]>> {\n const pool = this.getPool();\n const result = new Map<string, StoredRelationship[]>();\n if (entityIds.length === 0) return result;\n\n const tbl = this.t('dm_relationships');\n const tvp = this.createIdListTvp(entityIds);\n\n let rtFilter = '';\n const rtInputs: Array<{ name: string; value: string }> = [];\n if (relationshipTypes && relationshipTypes.length > 0) {\n const placeholders = relationshipTypes.map((t, i) => {\n rtInputs.push({ name: `rt${i}`, value: t });\n return `@rt${i}`;\n });\n rtFilter = ` AND [relationship_type] IN (${placeholders.join(',')})`;\n }\n\n // Build UNION ALL branches using TVP instead of single @entityId\n const srcBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] IN (SELECT [id] FROM @entityIds)${rtFilter}`;\n const tgtBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] IN (SELECT [id] FROM @entityIds)${rtFilter}`;\n const tgtBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] IN (SELECT [id] FROM @entityIds) AND [bidirectional] = 1${rtFilter}`;\n const srcBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] IN (SELECT [id] FROM @entityIds) AND [bidirectional] = 1${rtFilter}`;\n\n let unionQuery: string;\n switch (direction) {\n case 'outbound':\n unionQuery = `${srcBase} UNION ALL ${tgtBidi}`;\n break;\n case 'inbound':\n unionQuery = `${tgtBase} UNION ALL ${srcBidi}`;\n break;\n case 'both':\n default:\n unionQuery = `${srcBase} UNION ALL ${tgtBase}`;\n break;\n }\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp);\n for (const p of rtInputs) req.input(p.name, sql.NVarChar, p.value);\n\n const rows = await req.query<Record<string, unknown>>(unionQuery);\n\n const entityIdSet = new Set(entityIds);\n for (const row of rows.recordset) {\n const rel = relationshipFromRow(row);\n // Determine which frontier entity this relationship belongs to\n const frontierIds: string[] = [];\n if (entityIdSet.has(rel.sourceEntityId)) frontierIds.push(rel.sourceEntityId);\n if (entityIdSet.has(rel.targetEntityId)) frontierIds.push(rel.targetEntityId);\n for (const fid of frontierIds) {\n let list = result.get(fid);\n if (!list) {\n list = [];\n result.set(fid, list);\n }\n list.push(rel);\n }\n }\n\n return result;\n }\n\n private async assertRepository(repositoryId: string): Promise<void> {\n const repo = await this.getRepository(repositoryId);\n if (!repo) {\n throw new RepositoryNotFoundError(repositoryId);\n }\n }\n\n private addProvenanceInputs(req: sql.Request, provenance: Provenance): void {\n req.input('createdBy', sql.NVarChar, provenance.createdBy);\n req.input('createdByType', sql.NVarChar, provenance.createdByType);\n req.input('createdAt', sql.NVarChar, provenance.createdAt);\n req.input('createdInConversation', sql.NVarChar, provenance.createdInConversation ?? null);\n req.input('createdFromMessage', sql.NVarChar, provenance.createdFromMessage ?? null);\n req.input('modifiedBy', sql.NVarChar, provenance.modifiedBy);\n req.input('modifiedByType', sql.NVarChar, provenance.modifiedByType);\n req.input('modifiedAt', sql.NVarChar, provenance.modifiedAt);\n req.input('modifiedInConversation', sql.NVarChar, provenance.modifiedInConversation ?? null);\n req.input('modifiedFromMessage', sql.NVarChar, provenance.modifiedFromMessage ?? null);\n }\n}\n","// SQL Server schema for @utaba/deep-memory StorageProvider\n//\n// Naming conventions:\n// Tables: plural snake_case (entities, relationships)\n// Columns: snake_case (entity_id, created_at)\n// Indexes: ix_{table}_{columns}\n// Primary keys: pk_{table}\n// Foreign keys: fk_{table}_{referenced_table}\n//\n// All tables are prefixed with dm_ (deep memory) to avoid collisions\n// when co-located with other schemas in a shared database.\n\nexport const SCHEMA_VERSION = 1;\n\n/**\n * Returns the full DDL for creating the deep-memory schema.\n *\n * @param schema - Optional SQL Server schema name (default: 'dbo').\n * The schema must already exist in the database.\n */\nexport function getSchemaSQL(schema = 'dbo'): string {\n const s = schema;\n\n return `\n-- ============================================================\n-- @utaba/deep-memory SQL Server schema v${SCHEMA_VERSION}\n-- ============================================================\n\n-- Schema version tracking\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_meta' AND schema_id = SCHEMA_ID('${s}'))\nBEGIN\n CREATE TABLE [${s}].[dm_meta] (\n [key] NVARCHAR(100) NOT NULL,\n [value] NVARCHAR(MAX) NOT NULL,\n CONSTRAINT [pk_dm_meta] PRIMARY KEY ([key])\n );\n INSERT INTO [${s}].[dm_meta] ([key], [value])\n VALUES ('schema_version', '${SCHEMA_VERSION}');\nEND;\n\n-- Repositories\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_repositories' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_repositories] (\n [repository_id] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),\n [type] NVARCHAR(128) NULL,\n [label] NVARCHAR(500) NOT NULL,\n [description] NVARCHAR(MAX) NULL,\n [legal] NVARCHAR(MAX) NULL,\n [owner] NVARCHAR(500) NULL,\n [governance_config] NVARCHAR(MAX) NOT NULL, -- JSON\n [metadata] NVARCHAR(MAX) NULL, -- JSON\n [created_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [created_by] NVARCHAR(255) NOT NULL,\n CONSTRAINT [pk_dm_repositories] PRIMARY KEY ([repository_id])\n);\n\n-- Vocabularies (one JSON document per repository)\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_vocabularies' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_vocabularies] (\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [vocabulary] NVARCHAR(MAX) NOT NULL, -- JSON (MemoryVocabulary)\n CONSTRAINT [pk_dm_vocabularies] PRIMARY KEY ([repository_id]),\n CONSTRAINT [fk_dm_vocabularies_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE\n);\n\n-- Vocabulary change log\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_vocabulary_change_log' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_vocabulary_change_log] (\n [change_id] NVARCHAR(128) NOT NULL,\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [change_type] NVARCHAR(50) NOT NULL,\n [type_name] NVARCHAR(255) NOT NULL,\n [previous_version] NVARCHAR(50) NULL,\n [new_version] NVARCHAR(50) NOT NULL,\n [proposed_by] NVARCHAR(255) NOT NULL,\n [proposed_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [approved_by] NVARCHAR(255) NULL,\n [approved_at] NVARCHAR(50) NULL, -- ISO 8601\n [reason] NVARCHAR(MAX) NOT NULL,\n CONSTRAINT [pk_dm_vocabulary_change_log] PRIMARY KEY ([repository_id], [change_id]),\n CONSTRAINT [fk_dm_vocabulary_change_log_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE\n);\n\nCREATE NONCLUSTERED INDEX [ix_dm_vocabulary_change_log_proposed_at]\n ON [${s}].[dm_vocabulary_change_log] ([repository_id], [proposed_at] DESC);\n\n-- Entities\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_entities' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_entities] (\n [ft_key] INT NOT NULL IDENTITY(1,1), -- surrogate for FT index\n [entity_id] NVARCHAR(300) NOT NULL,\n [slug] NVARCHAR(300) NOT NULL,\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [entity_type] NVARCHAR(255) NOT NULL,\n [label] NVARCHAR(500) NOT NULL,\n [summary] NVARCHAR(MAX) NULL,\n [properties] NVARCHAR(MAX) NOT NULL, -- JSON\n [data] NVARCHAR(MAX) NULL,\n [data_format] NVARCHAR(100) NULL,\n [embedding] NVARCHAR(MAX) NULL, -- JSON array of numbers\n -- Provenance\n [created_by] NVARCHAR(255) NOT NULL,\n [created_by_type] NVARCHAR(10) NOT NULL, -- 'user' | 'agent'\n [created_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [created_in_conversation] NVARCHAR(255) NULL,\n [created_from_message] NVARCHAR(255) NULL,\n [modified_by] NVARCHAR(255) NOT NULL,\n [modified_by_type] NVARCHAR(10) NOT NULL,\n [modified_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [modified_in_conversation] NVARCHAR(255) NULL,\n [modified_from_message] NVARCHAR(255) NULL,\n CONSTRAINT [pk_dm_entities] PRIMARY KEY ([repository_id], [entity_id]),\n CONSTRAINT [uq_dm_entities_ft_key] UNIQUE ([ft_key]),\n CONSTRAINT [fk_dm_entities_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE\n);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_type]\n ON [${s}].[dm_entities] ([repository_id], [entity_type]);\nCREATE NONCLUSTERED INDEX [ix_dm_entities_label]\n ON [${s}].[dm_entities] ([repository_id], [label]);\n\nCREATE UNIQUE NONCLUSTERED INDEX [ix_dm_entities_slug]\n ON [${s}].[dm_entities] ([repository_id], [slug]);\n\n-- Provenance indexes for conversation/actor/temporal queries\nCREATE NONCLUSTERED INDEX [ix_dm_entities_created_conversation]\n ON [${s}].[dm_entities] ([repository_id], [created_in_conversation])\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_modified_conversation]\n ON [${s}].[dm_entities] ([repository_id], [modified_in_conversation])\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_created_by]\n ON [${s}].[dm_entities] ([repository_id], [created_by])\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_modified_at]\n ON [${s}].[dm_entities] ([repository_id], [modified_at] DESC)\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\n-- Full-text catalog and index on entities\nIF NOT EXISTS (SELECT 1 FROM sys.fulltext_catalogs WHERE name = 'dm_fulltext_catalog')\n CREATE FULLTEXT CATALOG [dm_fulltext_catalog] AS DEFAULT;\n\nIF NOT EXISTS (\n SELECT 1 FROM sys.fulltext_indexes fi\n JOIN sys.tables t ON fi.object_id = t.object_id\n WHERE t.name = 'dm_entities' AND t.schema_id = SCHEMA_ID('${s}')\n)\nCREATE FULLTEXT INDEX ON [${s}].[dm_entities] (\n [label] LANGUAGE 1033,\n [summary] LANGUAGE 1033,\n [data] LANGUAGE 1033,\n [properties] LANGUAGE 1033\n)\nKEY INDEX [uq_dm_entities_ft_key]\nON [dm_fulltext_catalog]\nWITH CHANGE_TRACKING AUTO;\n\n-- Relationships\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_relationships' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_relationships] (\n [relationship_id] NVARCHAR(300) NOT NULL,\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [relationship_type] NVARCHAR(255) NOT NULL,\n [source_entity_id] NVARCHAR(300) NOT NULL,\n [target_entity_id] NVARCHAR(300) NOT NULL,\n [properties] NVARCHAR(MAX) NOT NULL, -- JSON\n [bidirectional] BIT NOT NULL DEFAULT 0,\n -- Provenance\n [created_by] NVARCHAR(255) NOT NULL,\n [created_by_type] NVARCHAR(10) NOT NULL,\n [created_at] NVARCHAR(50) NOT NULL,\n [created_in_conversation] NVARCHAR(255) NULL,\n [created_from_message] NVARCHAR(255) NULL,\n [modified_by] NVARCHAR(255) NOT NULL,\n [modified_by_type] NVARCHAR(10) NOT NULL,\n [modified_at] NVARCHAR(50) NOT NULL,\n [modified_in_conversation] NVARCHAR(255) NULL,\n [modified_from_message] NVARCHAR(255) NULL,\n CONSTRAINT [pk_dm_relationships] PRIMARY KEY ([repository_id], [relationship_id]),\n CONSTRAINT [fk_dm_relationships_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE,\n CONSTRAINT [fk_dm_relationships_source]\n FOREIGN KEY ([repository_id], [source_entity_id]) REFERENCES [${s}].[dm_entities]([repository_id], [entity_id]),\n CONSTRAINT [fk_dm_relationships_target]\n FOREIGN KEY ([repository_id], [target_entity_id]) REFERENCES [${s}].[dm_entities]([repository_id], [entity_id])\n);\n\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_source]\n ON [${s}].[dm_relationships] ([repository_id], [source_entity_id], [relationship_type])\n INCLUDE ([target_entity_id], [bidirectional]);\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_target]\n ON [${s}].[dm_relationships] ([repository_id], [target_entity_id], [relationship_type])\n INCLUDE ([source_entity_id], [bidirectional]);\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_type]\n ON [${s}].[dm_relationships] ([repository_id], [relationship_type]);\n\n-- Relationship provenance indexes\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_created_conversation]\n ON [${s}].[dm_relationships] ([repository_id], [created_in_conversation]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_modified_at]\n ON [${s}].[dm_relationships] ([repository_id], [modified_at] DESC);\n\n-- Table-valued parameter type for batch ID lookups (eliminates plan cache bloat)\nIF NOT EXISTS (SELECT 1 FROM sys.types WHERE name = 'dm_id_list' AND is_table_type = 1)\n CREATE TYPE [${s}].[dm_id_list] AS TABLE ([id] NVARCHAR(300) NOT NULL);\n`.trim();\n}\n\n/**\n * Returns DDL for the dm_search_entities stored procedure.\n *\n * The procedure uses FREETEXTTABLE for natural-language queries and falls back\n * to CONTAINSTABLE when the caller passes @UseContains = 1 (exact phrase / prefix).\n * It returns ranked results with highlight snippets for label, summary, and data.\n *\n * Must be executed as a separate batch (not inside the main schema DDL) because\n * CREATE OR ALTER PROCEDURE must be the first statement in a batch.\n */\nexport function getSearchProcSQL(schema = 'dbo'): string {\n const s = schema;\n\n return `\nCREATE OR ALTER PROCEDURE [${s}].[dm_search_entities]\n @RepositoryId UNIQUEIDENTIFIER,\n @Query NVARCHAR(4000),\n @EntityTypes NVARCHAR(MAX) = NULL, -- JSON array of strings, e.g. '[\"person\",\"project\"]'\n @Limit INT = 20,\n @Offset INT = 0,\n @UseContains BIT = 0 -- 0 = FREETEXTTABLE (natural language), 1 = CONTAINSTABLE (exact/prefix)\nAS\nBEGIN\n SET NOCOUNT ON;\n\n -- Parse entity type filter from JSON array into a temp table\n CREATE TABLE #entity_types ([type_name] NVARCHAR(255));\n IF @EntityTypes IS NOT NULL AND @EntityTypes <> '[]'\n BEGIN\n INSERT INTO #entity_types ([type_name])\n SELECT TRIM(value) FROM OPENJSON(@EntityTypes);\n END;\n\n DECLARE @HasTypeFilter BIT = CASE WHEN EXISTS (SELECT 1 FROM #entity_types) THEN 1 ELSE 0 END;\n\n -- CTE: ranked full-text matches\n ;WITH ft_results AS (\n SELECT\n e.[entity_id],\n e.[slug],\n e.[entity_type],\n e.[label],\n e.[summary],\n e.[data],\n e.[properties],\n ft.[RANK] AS ft_rank\n FROM (\n SELECT [KEY], [RANK]\n FROM FREETEXTTABLE([${s}].[dm_entities], ([label], [summary], [data], [properties]), @Query)\n WHERE @UseContains = 0\n UNION ALL\n SELECT [KEY], [RANK]\n FROM CONTAINSTABLE([${s}].[dm_entities], ([label], [summary], [data], [properties]), @Query)\n WHERE @UseContains = 1\n ) AS ft\n INNER JOIN [${s}].[dm_entities] e ON e.[ft_key] = ft.[KEY]\n WHERE e.[repository_id] = @RepositoryId\n AND (@HasTypeFilter = 0 OR e.[entity_type] IN (SELECT [type_name] FROM #entity_types))\n ),\n -- Count total matching rows before pagination\n ft_counted AS (\n SELECT *, COUNT(*) OVER () AS total_count FROM ft_results\n )\n SELECT\n [entity_id],\n [slug],\n [entity_type],\n [label],\n [summary],\n [data],\n [properties],\n [ft_rank],\n [total_count],\n -- Highlight snippets: return the first 200 chars of each matched field\n -- (the application layer will do finer-grained highlighting using the query terms)\n CASE WHEN FREETEXT([label], @Query) THEN LEFT([label], 200) ELSE NULL END AS [hl_label],\n CASE WHEN FREETEXT([summary], @Query) THEN LEFT(CAST([summary] AS NVARCHAR(200)), 200) ELSE NULL END AS [hl_summary],\n CASE WHEN FREETEXT([data], @Query) THEN LEFT(CAST([data] AS NVARCHAR(200)), 200) ELSE NULL END AS [hl_data],\n CASE WHEN FREETEXT([properties], @Query) THEN LEFT(CAST([properties] AS NVARCHAR(200)), 200) ELSE NULL END AS [hl_properties]\n FROM ft_counted\n ORDER BY [ft_rank] DESC\n OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY;\n\n DROP TABLE #entity_types;\nEND;\n `.trim();\n}\n","// SqlServerSearchProvider — SQL Server full-text search implementation of SearchProvider\n\nimport sql from 'mssql';\nimport type { SearchProvider, SearchableEntity } from '@utaba/deep-memory/providers';\nimport type { SearchOptions } from '@utaba/deep-memory/types';\nimport type { PaginatedResult, SearchHit } from '@utaba/deep-memory/types';\nimport { ProviderError } from '@utaba/deep-memory';\nimport { getSearchProcSQL } from './schema.js';\n\n/** Configuration for SqlServerSearchProvider */\nexport interface SqlServerSearchProviderConfig {\n /** mssql connection pool (should be the same pool used by the StorageProvider) */\n pool: sql.ConnectionPool;\n /** SQL Server schema name (default: 'dbo') */\n schema?: string;\n}\n\n/**\n * Normalize a raw FT rank (typically 0–1000 from FREETEXTTABLE) into a 0–1 score.\n * Clamps to [0, 1] to handle edge cases.\n */\nfunction normalizeRank(rank: number): number {\n return Math.min(1, Math.max(0, rank / 1000));\n}\n\n/**\n * Build highlight snippets from the stored-procedure output.\n * For each field that matched, extract a window around the first occurrence\n * of any query term and return it.\n */\nfunction buildHighlights(\n query: string,\n row: Record<string, unknown>,\n): Record<string, string[]> | undefined {\n const highlights: Record<string, string[]> = {};\n const terms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 0);\n\n const fields: Array<{ key: string; hlCol: string }> = [\n { key: 'label', hlCol: 'hl_label' },\n { key: 'summary', hlCol: 'hl_summary' },\n { key: 'data', hlCol: 'hl_data' },\n { key: 'properties', hlCol: 'hl_properties' },\n ];\n\n for (const { key, hlCol } of fields) {\n const snippet = row[hlCol] as string | null;\n if (!snippet) continue;\n\n // Find the best window around a matched term\n const lowerSnippet = snippet.toLowerCase();\n for (const term of terms) {\n const idx = lowerSnippet.indexOf(term);\n if (idx !== -1) {\n const windowStart = Math.max(0, idx - 40);\n const windowEnd = Math.min(snippet.length, idx + term.length + 40);\n const prefix = windowStart > 0 ? '...' : '';\n const suffix = windowEnd < snippet.length ? '...' : '';\n const window = prefix + snippet.slice(windowStart, windowEnd) + suffix;\n if (!highlights[key]) highlights[key] = [];\n highlights[key].push(window);\n break; // one snippet per field\n }\n }\n }\n\n return Object.keys(highlights).length > 0 ? highlights : undefined;\n}\n\nexport class SqlServerSearchProvider implements SearchProvider {\n private readonly pool: sql.ConnectionPool;\n private readonly schema: string;\n private procedureCreated = false;\n\n constructor(config: SqlServerSearchProviderConfig) {\n this.pool = config.pool;\n this.schema = config.schema ?? 'dbo';\n }\n\n /**\n * Ensure the stored procedure exists. Called lazily on first search.\n * Idempotent — uses CREATE OR ALTER.\n */\n async ensureProcedure(): Promise<void> {\n if (this.procedureCreated) return;\n try {\n const ddl = getSearchProcSQL(this.schema);\n await this.pool.request().query(ddl);\n this.procedureCreated = true;\n } catch (err) {\n throw new ProviderError(\n `Failed to create search stored procedure: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n /**\n * Index an entity for full-text search.\n *\n * No-op: the FT index on dm_entities uses CHANGE_TRACKING AUTO,\n * so SQL Server automatically indexes rows on insert/update.\n */\n async indexEntity(\n _repositoryId: string,\n _entity: SearchableEntity,\n ): Promise<void> {\n // Auto-maintained by SQL Server FT change tracking\n }\n\n /**\n * Remove an entity from the search index.\n *\n * No-op: the FT index auto-removes when the row is deleted from dm_entities.\n */\n async removeEntity(\n _repositoryId: string,\n _entityId: string,\n ): Promise<void> {\n // Auto-maintained by SQL Server FT change tracking\n }\n\n /**\n * Full-text search across entity labels, summaries, properties, and data.\n * Calls the dm_search_entities stored procedure using FREETEXTTABLE\n * for natural-language queries.\n */\n async search(\n repositoryId: string,\n query: string,\n options?: SearchOptions,\n ): Promise<PaginatedResult<SearchHit>> {\n await this.ensureProcedure();\n\n const limit = options?.limit ?? 20;\n const offset = options?.offset ?? 0;\n const entityTypes = options?.entityTypes;\n\n try {\n const request = this.pool.request();\n request.input('RepositoryId', sql.UniqueIdentifier, repositoryId);\n request.input('Query', sql.NVarChar(4000), query);\n request.input(\n 'EntityTypes',\n sql.NVarChar(sql.MAX),\n entityTypes && entityTypes.length > 0\n ? JSON.stringify(entityTypes)\n : null,\n );\n request.input('Limit', sql.Int, limit);\n request.input('Offset', sql.Int, offset);\n request.input('UseContains', sql.Bit, 0); // FREETEXTTABLE for natural language\n\n const result = await request.execute(\n `[${this.schema}].[dm_search_entities]`,\n );\n\n const rows = result.recordset as Array<Record<string, unknown>>;\n\n const total =\n rows.length > 0 ? (rows[0]!['total_count'] as number) : 0;\n\n const items: SearchHit[] = rows.map((row) => ({\n id: row['entity_id'] as string,\n score: normalizeRank(row['ft_rank'] as number),\n highlights: buildHighlights(query, row),\n }));\n\n return {\n items,\n total,\n hasMore: offset + items.length < total,\n limit,\n offset,\n };\n } catch (err) {\n throw new ProviderError(\n `Full-text search failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n /**\n * Re-index an entire repository.\n *\n * Since the FT index is auto-maintained, this triggers a manual\n * population of the full-text catalog to pick up any pending changes.\n */\n async reindexRepository(\n _repositoryId: string,\n _entities: AsyncIterable<SearchableEntity>,\n ): Promise<void> {\n try {\n await this.pool\n .request()\n .query(\n `ALTER FULLTEXT CATALOG [dm_fulltext_catalog] REORGANIZE`,\n );\n } catch (err) {\n throw new ProviderError(\n `Full-text reindex failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":["sql","ProviderError","ProviderError","sql"]}
1
+ {"version":3,"sources":["../src/SqlServerStorageProvider.ts","../src/schema.ts","../src/SqlServerSearchProvider.ts"],"sourcesContent":["// SqlServerStorageProvider — SQL Server implementation of StorageProvider\n\nimport sql from 'mssql';\nimport type { StorageProvider, EnsureSchemaResult } from '@utaba/deep-memory/providers';\nimport type {\n StoredEntity,\n StoredEntityUpdate,\n StoredRelationship,\n RelationshipQueryOptions,\n MemoryVocabulary,\n VocabularyChangeRecord,\n StorageRepositoryConfig,\n StoredRepository,\n StoredRepositorySummary,\n RepositoryFilter,\n RepositoryStats,\n RepositoryUpdate,\n StorageFindQuery,\n StorageExploreOptions,\n StoragePathOptions,\n StorageTimelineOptions,\n PaginationOptions,\n PaginatedResult,\n StorageNeighborhood,\n StoragePathResult,\n StorageTimelineResult,\n StorageTimelineEvent,\n BulkImportResult,\n} from '@utaba/deep-memory/types';\nimport type { ExportChunk, ImportChunk } from '@utaba/deep-memory/types';\nimport type { Provenance } from '@utaba/deep-memory/types';\nimport {\n RepositoryNotFoundError,\n DuplicateRepositoryError,\n EntityNotFoundError,\n DuplicateEntityError,\n RelationshipNotFoundError,\n DuplicateRelationshipError,\n ProviderError,\n matchesPropertyFilters,\n} from '@utaba/deep-memory';\nimport { getSchemaSQL, SCHEMA_VERSION } from './schema.js';\n\n/** Configuration for SqlServerStorageProvider */\nexport interface SqlServerStorageProviderConfig {\n /** mssql connection config or an existing connection pool */\n connection: sql.config | sql.ConnectionPool;\n /** SQL Server schema name (default: 'dbo') */\n schema?: string;\n}\n\n// ─── Column projection constants ───────────────────────────────────\n\n/** All entity columns except embedding — used by graph traversal, timeline, etc. */\nconst ENTITY_COLS_LIGHT = [\n 'entity_id', 'slug', 'repository_id', 'entity_type', 'label', 'summary',\n 'properties', 'data', 'data_format',\n 'created_by', 'created_by_type', 'created_at',\n 'created_in_conversation', 'created_from_message',\n 'modified_by', 'modified_by_type', 'modified_at',\n 'modified_in_conversation', 'modified_from_message',\n].map(c => `[${c}]`).join(', ');\n\n/** All entity columns including embedding — used by getEntity, getEntities, exportAll */\nconst ENTITY_COLS_FULL = `${ENTITY_COLS_LIGHT}, [embedding]`;\n\n// ─── Row-mapping helpers ────────────────────────────────────────────\n\nfunction provenanceFromRow(row: sql.IRecordSet<unknown>[number]): Provenance {\n const r = row as Record<string, unknown>;\n return {\n createdBy: r['created_by'] as string,\n createdByType: r['created_by_type'] as 'user' | 'agent',\n createdAt: r['created_at'] as string,\n createdInConversation: (r['created_in_conversation'] as string) || undefined,\n createdFromMessage: (r['created_from_message'] as string) || undefined,\n modifiedBy: r['modified_by'] as string,\n modifiedByType: r['modified_by_type'] as 'user' | 'agent',\n modifiedAt: r['modified_at'] as string,\n modifiedInConversation: (r['modified_in_conversation'] as string) || undefined,\n modifiedFromMessage: (r['modified_from_message'] as string) || undefined,\n };\n}\n\n/**\n * Add provenance filter conditions to a SQL query.\n * Uses a prefix to avoid parameter name collisions across data/count requests.\n */\nfunction addProvenanceConditions(\n req: sql.Request,\n prov: import('@utaba/deep-memory').ProvenanceFilter,\n conditions: string[],\n prefix: string,\n): void {\n if (prov.conversationIds && prov.conversationIds.length > 0) {\n const placeholders = prov.conversationIds.map((id, i) => {\n req.input(`${prefix}ConvId${i}`, sql.NVarChar, id);\n return `@${prefix}ConvId${i}`;\n });\n const inClause = placeholders.join(',');\n conditions.push(`([created_in_conversation] IN (${inClause}) OR [modified_in_conversation] IN (${inClause}))`);\n }\n if (prov.actors && prov.actors.length > 0) {\n const placeholders = prov.actors.map((a, i) => {\n req.input(`${prefix}Actor${i}`, sql.NVarChar, a);\n return `@${prefix}Actor${i}`;\n });\n const inClause = placeholders.join(',');\n conditions.push(`([created_by] IN (${inClause}) OR [modified_by] IN (${inClause}))`);\n }\n if (prov.dateRange) {\n req.input(`${prefix}DateFrom`, sql.NVarChar, prov.dateRange.from);\n req.input(`${prefix}DateTo`, sql.NVarChar, prov.dateRange.to);\n conditions.push(`([created_at] >= @${prefix}DateFrom AND [created_at] <= @${prefix}DateTo) OR ([modified_at] >= @${prefix}DateFrom AND [modified_at] <= @${prefix}DateTo)`);\n }\n}\n\nfunction entityFromRow(row: sql.IRecordSet<unknown>[number]): StoredEntity {\n const r = row as Record<string, unknown>;\n return {\n id: r['entity_id'] as string,\n slug: r['slug'] as string,\n entityType: r['entity_type'] as string,\n label: r['label'] as string,\n summary: (r['summary'] as string) || undefined,\n properties: JSON.parse((r['properties'] as string) || '{}') as Record<string, unknown>,\n data: (r['data'] as string) || undefined,\n dataFormat: (r['data_format'] as string) || undefined,\n provenance: provenanceFromRow(row),\n embedding: ('embedding' in r && r['embedding']) ? (JSON.parse(r['embedding'] as string) as number[]) : undefined,\n };\n}\n\nfunction relationshipFromRow(row: sql.IRecordSet<unknown>[number]): StoredRelationship {\n const r = row as Record<string, unknown>;\n return {\n id: r['relationship_id'] as string,\n relationshipType: r['relationship_type'] as string,\n sourceEntityId: r['source_entity_id'] as string,\n targetEntityId: r['target_entity_id'] as string,\n properties: JSON.parse((r['properties'] as string) || '{}') as Record<string, unknown>,\n bidirectional: r['bidirectional'] === true || r['bidirectional'] === 1,\n provenance: provenanceFromRow(row),\n };\n}\n\nfunction changeRecordFromRow(row: sql.IRecordSet<unknown>[number]): VocabularyChangeRecord {\n const r = row as Record<string, unknown>;\n return {\n changeId: r['change_id'] as string,\n changeType: r['change_type'] as VocabularyChangeRecord['changeType'],\n typeName: r['type_name'] as string,\n previousVersion: (r['previous_version'] as string) || undefined,\n newVersion: r['new_version'] as string,\n proposedBy: r['proposed_by'] as string,\n proposedAt: r['proposed_at'] as string,\n approvedBy: (r['approved_by'] as string) || undefined,\n approvedAt: (r['approved_at'] as string) || undefined,\n reason: r['reason'] as string,\n };\n}\n\n// ─── Provider ───────────────────────────────────────────────────────\n\nexport class SqlServerStorageProvider implements StorageProvider {\n private pool: sql.ConnectionPool | null = null;\n private ownsPool: boolean;\n private readonly config: SqlServerStorageProviderConfig;\n private readonly schema: string;\n\n constructor(config: SqlServerStorageProviderConfig) {\n this.config = config;\n this.schema = config.schema ?? 'dbo';\n this.ownsPool = !(config.connection instanceof sql.ConnectionPool);\n }\n\n private t(table: string): string {\n return `[${this.schema}].[${table}]`;\n }\n\n private getPool(): sql.ConnectionPool {\n if (!this.pool) {\n throw new ProviderError(\n 'SqlServerStorageProvider not initialized. Call initialize() first.',\n );\n }\n return this.pool;\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────\n\n async initialize(): Promise<void> {\n if (this.config.connection instanceof sql.ConnectionPool) {\n this.pool = this.config.connection;\n this.ownsPool = false;\n if (!this.pool.connected) {\n await this.pool.connect();\n }\n } else {\n this.pool = new sql.ConnectionPool(this.config.connection);\n this.ownsPool = true;\n await this.pool.connect();\n }\n\n }\n\n async dispose(): Promise<void> {\n if (this.ownsPool && this.pool) {\n await this.pool.close();\n }\n this.pool = null;\n }\n\n /**\n * Ensure the target database exists. If constructed with a sql.config and the\n * database does not yet exist, creates it via a temporary connection to master,\n * then (re)connects the main pool to the newly created database.\n *\n * @returns true if the database was created, false if it already existed.\n */\n private async ensureDatabase(): Promise<boolean> {\n // Only possible when we own the pool and have the raw config\n if (this.config.connection instanceof sql.ConnectionPool) {\n return false; // Pre-existing pool — caller is responsible for DB existence\n }\n\n const cfg = this.config.connection;\n const dbName = cfg.database;\n if (!dbName) {\n return false; // No database specified — nothing to create\n }\n\n let created = false;\n\n // Connect to master to check / create the database\n const masterPool = new sql.ConnectionPool({ ...cfg, database: 'master' });\n try {\n await masterPool.connect();\n const result = await masterPool.request()\n .input('dbName', sql.NVarChar, dbName)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM sys.databases WHERE name = @dbName`,\n );\n const exists = (result.recordset[0]?.cnt ?? 0) > 0;\n\n if (!exists) {\n // Database names cannot be parameterized — validate to prevent injection\n if (!/^[A-Za-z0-9_-]+$/.test(dbName)) {\n throw new ProviderError(\n `Invalid database name '${dbName}'. Only alphanumeric characters, hyphens, and underscores are allowed.`,\n );\n }\n await masterPool.request().query(`CREATE DATABASE [${dbName}]`);\n created = true;\n }\n } finally {\n await masterPool.close();\n }\n\n // If the main pool isn't connected yet (initialize failed because the DB\n // didn't exist), connect it now that the database exists.\n if (!this.pool || !this.pool.connected) {\n this.pool = new sql.ConnectionPool(cfg);\n this.ownsPool = true;\n await this.pool.connect();\n }\n\n return created;\n }\n\n async ensureSchema(): Promise<EnsureSchemaResult> {\n // If constructed with a sql.config (not a pre-existing pool), ensure the\n // target database exists before attempting any schema operations.\n const databaseCreated = await this.ensureDatabase();\n\n const pool = this.getPool();\n\n // Check if meta table exists to detect existing schema\n const metaCheck = await pool.request().query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM sys.tables WHERE name = 'dm_meta' AND schema_id = SCHEMA_ID('${this.schema}')`,\n );\n const metaExists = (metaCheck.recordset[0]?.cnt ?? 0) > 0;\n\n if (metaExists) {\n // Check version\n const versionResult = await pool.request().query<{ value: string }>(\n `SELECT [value] FROM ${this.t('dm_meta')} WHERE [key] = 'schema_version'`,\n );\n const currentVersion = parseInt(versionResult.recordset[0]?.value ?? '0', 10);\n if (currentVersion > SCHEMA_VERSION) {\n throw new ProviderError(\n `Database schema version ${currentVersion} is newer than provider version ${SCHEMA_VERSION}. Update the provider package.`,\n );\n }\n if (currentVersion === SCHEMA_VERSION) {\n return {\n databaseCreated,\n schemaCreated: false,\n alreadyUpToDate: !databaseCreated,\n schemaVersion: SCHEMA_VERSION,\n };\n }\n // Future: run migrations from currentVersion to SCHEMA_VERSION\n }\n\n // Create all tables (IF NOT EXISTS guards in the SQL handle idempotency)\n const ddl = getSchemaSQL(this.schema);\n // Split on blank-line boundaries (double newline) to keep BEGIN...END blocks intact\n const statements = ddl\n .split(/\\n\\n+/)\n .map((s) => s.split('\\n').filter((line) => !line.trimStart().startsWith('--')).join('\\n').trim())\n .filter((s) => s.length > 0);\n for (const stmt of statements) {\n try {\n await pool.request().query(stmt);\n } catch (err) {\n // Ignore \"already exists\" errors for indexes (they lack IF NOT EXISTS)\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes('already exists')) {\n throw new ProviderError(`Schema creation failed: ${msg}`);\n }\n }\n }\n\n return {\n databaseCreated,\n schemaCreated: true,\n alreadyUpToDate: false,\n schemaVersion: SCHEMA_VERSION,\n };\n }\n\n // ─── Repository ──────────────────────────────────────────────────\n\n async createRepository(config: StorageRepositoryConfig): Promise<StoredRepository> {\n const pool = this.getPool();\n\n // Check for duplicate\n const existing = await pool.request()\n .input('id', sql.UniqueIdentifier, config.repositoryId)\n .query<{ repository_id: string }>(\n `SELECT [repository_id] FROM ${this.t('dm_repositories')} WHERE [repository_id] = @id`,\n );\n\n if (existing.recordset.length > 0) {\n throw new DuplicateRepositoryError(config.repositoryId);\n }\n\n await pool.request()\n .input('id', sql.UniqueIdentifier, config.repositoryId)\n .input('type', sql.NVarChar, config.type ?? null)\n .input('label', sql.NVarChar, config.label)\n .input('description', sql.NVarChar, config.description ?? null)\n .input('legal', sql.NVarChar, config.legal ?? null)\n .input('owner', sql.NVarChar, config.owner ?? null)\n .input('governanceConfig', sql.NVarChar, JSON.stringify(config.governanceConfig))\n .input('metadata', sql.NVarChar, config.metadata ? JSON.stringify(config.metadata) : null)\n .input('createdAt', sql.NVarChar, config.createdAt)\n .input('createdBy', sql.NVarChar, config.createdBy)\n .query(`\n INSERT INTO ${this.t('dm_repositories')}\n ([repository_id], [type], [label], [description], [legal], [owner], [governance_config], [metadata], [created_at], [created_by])\n VALUES (@id, @type, @label, @description, @legal, @owner, @governanceConfig, @metadata, @createdAt, @createdBy)\n `);\n\n // Create empty vocabulary\n const emptyVocabulary: MemoryVocabulary = {\n version: '0.0.0',\n lastModified: config.createdAt,\n modifiedBy: config.createdBy,\n entityTypes: [],\n relationshipTypes: [],\n };\n\n await pool.request()\n .input('id', sql.UniqueIdentifier, config.repositoryId)\n .input('vocabulary', sql.NVarChar, JSON.stringify(emptyVocabulary))\n .query(`\n INSERT INTO ${this.t('dm_vocabularies')} ([repository_id], [vocabulary])\n VALUES (@id, @vocabulary)\n `);\n\n return {\n repositoryId: config.repositoryId,\n type: config.type,\n label: config.label,\n description: config.description,\n legal: config.legal,\n owner: config.owner,\n governanceConfig: config.governanceConfig,\n metadata: config.metadata,\n createdAt: config.createdAt,\n createdBy: config.createdBy,\n };\n }\n\n async getRepository(repositoryId: string): Promise<StoredRepository | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_repositories')} WHERE [repository_id] = @id`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n\n const metadataRaw = row['metadata'] as string | null;\n return {\n repositoryId: row['repository_id'] as string,\n type: (row['type'] as string) || undefined,\n label: row['label'] as string,\n description: (row['description'] as string) || undefined,\n legal: (row['legal'] as string) || undefined,\n owner: (row['owner'] as string) || undefined,\n governanceConfig: JSON.parse(row['governance_config'] as string) as StoredRepository['governanceConfig'],\n metadata: metadataRaw ? JSON.parse(metadataRaw) as StoredRepository['metadata'] : undefined,\n createdAt: row['created_at'] as string,\n createdBy: row['created_by'] as string,\n };\n }\n\n async listRepositories(\n filter?: RepositoryFilter,\n ): Promise<PaginatedResult<StoredRepositorySummary>> {\n const pool = this.getPool();\n const offset = filter?.offset ?? 0;\n const limit = filter?.limit ?? 20;\n\n const countReq = pool.request();\n const dataReq = pool.request();\n\n let where = '';\n if (filter?.type) {\n countReq.input('type', sql.NVarChar, filter.type);\n dataReq.input('type', sql.NVarChar, filter.type);\n where = 'WHERE [type] = @type';\n }\n\n // Get total count\n const countResult = await countReq.query<Record<string, unknown>>(\n `SELECT COUNT(*) AS [cnt] FROM ${this.t('dm_repositories')} ${where}`,\n );\n const total = (countResult.recordset[0]?.['cnt'] as number) ?? 0;\n\n // Fetch paginated results\n dataReq.input('offset', sql.Int, offset);\n dataReq.input('limit', sql.Int, limit);\n\n const result = await dataReq.query<Record<string, unknown>>(\n `SELECT [repository_id], [type], [label], [description], [governance_config]\n FROM ${this.t('dm_repositories')} ${where}\n ORDER BY [label]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n const items: StoredRepositorySummary[] = result.recordset.map((row) => ({\n repositoryId: row['repository_id'] as string,\n type: (row['type'] as string) || undefined,\n label: row['label'] as string,\n description: (row['description'] as string) || undefined,\n governanceConfig: JSON.parse(row['governance_config'] as string) as StoredRepository['governanceConfig'],\n }));\n\n return {\n items,\n total,\n hasMore: offset + items.length < total,\n limit,\n offset,\n };\n }\n\n async updateRepository(repositoryId: string, updates: RepositoryUpdate): Promise<StoredRepository> {\n const pool = this.getPool();\n\n // Build dynamic SET clause from provided fields\n const setClauses: string[] = [];\n const request = pool.request().input('id', sql.UniqueIdentifier, repositoryId);\n\n if (updates.label !== undefined) {\n setClauses.push('[label] = @label');\n request.input('label', sql.NVarChar, updates.label);\n }\n if (updates.description !== undefined) {\n setClauses.push('[description] = @description');\n request.input('description', sql.NVarChar, updates.description);\n }\n if (updates.type !== undefined) {\n setClauses.push('[type] = @type');\n request.input('type', sql.NVarChar, updates.type);\n }\n if (updates.legal !== undefined) {\n setClauses.push('[legal] = @legal');\n request.input('legal', sql.NVarChar, updates.legal);\n }\n if (updates.owner !== undefined) {\n setClauses.push('[owner] = @owner');\n request.input('owner', sql.NVarChar, updates.owner);\n }\n if (updates.governanceConfig !== undefined) {\n setClauses.push('[governance_config] = @governanceConfig');\n request.input('governanceConfig', sql.NVarChar, JSON.stringify(updates.governanceConfig));\n }\n if (updates.metadata !== undefined) {\n // Shallow merge with existing metadata\n const existing = await this.getRepository(repositoryId);\n if (!existing) throw new RepositoryNotFoundError(repositoryId);\n const merged = { ...existing.metadata, ...updates.metadata };\n setClauses.push('[metadata] = @metadata');\n request.input('metadata', sql.NVarChar, JSON.stringify(merged));\n }\n\n if (setClauses.length === 0) {\n const existing = await this.getRepository(repositoryId);\n if (!existing) throw new RepositoryNotFoundError(repositoryId);\n return existing;\n }\n\n const result = await request.query(\n `UPDATE ${this.t('dm_repositories')} SET ${setClauses.join(', ')} WHERE [repository_id] = @id`,\n );\n\n if (result.rowsAffected[0] === 0) {\n throw new RepositoryNotFoundError(repositoryId);\n }\n\n const updated = await this.getRepository(repositoryId);\n if (!updated) throw new RepositoryNotFoundError(repositoryId);\n return updated;\n }\n\n async deleteRepository(repositoryId: string, _onProgress?: import('@utaba/deep-memory/types').DeleteProgressCallback): Promise<void> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query(`DELETE FROM ${this.t('dm_repositories')} WHERE [repository_id] = @id`);\n\n if (result.rowsAffected[0] === 0) {\n throw new RepositoryNotFoundError(repositoryId);\n }\n }\n\n async deleteAllContents(repositoryId: string, _onProgress?: import('@utaba/deep-memory/types').DeleteProgressCallback): Promise<{ deletedEntities: number; deletedRelationships: number }> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Delete relationships first (FK constraint), then entities\n const relResult = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query(`DELETE FROM ${this.t('dm_relationships')} WHERE [repository_id] = @id`);\n\n const entityResult = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query(`DELETE FROM ${this.t('dm_entities')} WHERE [repository_id] = @id`);\n\n return {\n deletedEntities: entityResult.rowsAffected[0] ?? 0,\n deletedRelationships: relResult.rowsAffected[0] ?? 0,\n };\n }\n\n async getRepositoryStats(repositoryId: string): Promise<RepositoryStats> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n const [entityStats, relStats, vocab] = await Promise.all([\n pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ entity_type: string; cnt: number }>(\n `SELECT [entity_type], COUNT(*) AS cnt\n FROM ${this.t('dm_entities')} WHERE [repository_id] = @id\n GROUP BY [entity_type]`,\n ),\n pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ relationship_type: string; cnt: number }>(\n `SELECT [relationship_type], COUNT(*) AS cnt\n FROM ${this.t('dm_relationships')} WHERE [repository_id] = @id\n GROUP BY [relationship_type]`,\n ),\n this.getVocabulary(repositoryId),\n ]);\n\n const entityTypeBreakdown: Record<string, number> = {};\n let entityCount = 0;\n for (const row of entityStats.recordset) {\n entityTypeBreakdown[row.entity_type] = row.cnt;\n entityCount += row.cnt;\n }\n\n const relationshipTypeBreakdown: Record<string, number> = {};\n let relationshipCount = 0;\n for (const row of relStats.recordset) {\n relationshipTypeBreakdown[row.relationship_type] = row.cnt;\n relationshipCount += row.cnt;\n }\n\n return {\n entityCount,\n relationshipCount,\n vocabularyVersion: vocab.version,\n entityTypeBreakdown,\n relationshipTypeBreakdown,\n };\n }\n\n // ─── Vocabulary ──────────────────────────────────────────────────\n\n async getVocabulary(repositoryId: string): Promise<MemoryVocabulary> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ vocabulary: string }>(\n `SELECT [vocabulary] FROM ${this.t('dm_vocabularies')} WHERE [repository_id] = @id`,\n );\n\n const row = result.recordset[0];\n if (!row) {\n // Should not happen if repository exists, but handle gracefully\n return {\n version: '0.0.0',\n lastModified: new Date().toISOString(),\n modifiedBy: 'system',\n entityTypes: [],\n relationshipTypes: [],\n };\n }\n\n return JSON.parse(row.vocabulary) as MemoryVocabulary;\n }\n\n async saveVocabulary(repositoryId: string, vocabulary: MemoryVocabulary): Promise<void> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .input('vocabulary', sql.NVarChar, JSON.stringify(vocabulary))\n .query(`\n UPDATE ${this.t('dm_vocabularies')}\n SET [vocabulary] = @vocabulary\n WHERE [repository_id] = @id\n `);\n }\n\n async getVocabularyChangeLog(\n repositoryId: string,\n options?: PaginationOptions,\n ): Promise<PaginatedResult<VocabularyChangeRecord>> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n const limit = options?.limit ?? 10;\n const offset = options?.offset ?? 0;\n\n const countResult = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_vocabulary_change_log')} WHERE [repository_id] = @id`,\n );\n const total = countResult.recordset[0]?.cnt ?? 0;\n\n const result = await pool.request()\n .input('id', sql.UniqueIdentifier, repositoryId)\n .input('limit', sql.Int, limit)\n .input('offset', sql.Int, offset)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_vocabulary_change_log')}\n WHERE [repository_id] = @id\n ORDER BY [proposed_at] DESC\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n return {\n items: result.recordset.map(changeRecordFromRow),\n total,\n hasMore: offset + limit < total,\n limit,\n offset,\n };\n }\n\n // ─── Entities ────────────────────────────────────────────────────\n\n async createEntity(repositoryId: string, entity: StoredEntity): Promise<StoredEntity> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Check for duplicate\n const existing = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entity.id)\n .query<{ entity_id: string }>(\n `SELECT [entity_id] FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n if (existing.recordset.length > 0) {\n throw new DuplicateEntityError(entity.id);\n }\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entity.id)\n .input('slug', sql.NVarChar, entity.slug)\n .input('entityType', sql.NVarChar, entity.entityType)\n .input('label', sql.NVarChar, entity.label)\n .input('summary', sql.NVarChar, entity.summary ?? null)\n .input('properties', sql.NVarChar, JSON.stringify(entity.properties))\n .input('data', sql.NVarChar, entity.data ?? null)\n .input('dataFormat', sql.NVarChar, entity.dataFormat ?? null)\n .input('embedding', sql.NVarChar, entity.embedding ? JSON.stringify(entity.embedding) : null);\n\n this.addProvenanceInputs(req, entity.provenance);\n\n await req.query(`\n INSERT INTO ${this.t('dm_entities')} (\n [repository_id], [entity_id], [slug], [entity_type], [label], [summary],\n [properties], [data], [data_format], [embedding],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @entityId, @slug, @entityType, @label, @summary,\n @properties, @data, @dataFormat, @embedding,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n )\n `);\n\n return entity;\n }\n\n async getEntity(repositoryId: string, entityId: string): Promise<StoredEntity | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return entityFromRow(row);\n }\n\n async getEntityBySlug(repositoryId: string, slug: string): Promise<StoredEntity | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('slug', sql.NVarChar, slug)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [slug] = @slug`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return entityFromRow(row);\n }\n\n async getEntities(\n repositoryId: string,\n entityIds: string[],\n ): Promise<Map<string, StoredEntity>> {\n const pool = this.getPool();\n const result = new Map<string, StoredEntity>();\n if (entityIds.length === 0) return result;\n\n const tvp = this.createIdListTvp(entityIds);\n const rows = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId\n AND [entity_id] IN (SELECT [id] FROM @entityIds)`,\n );\n\n for (const row of rows.recordset) {\n const entity = entityFromRow(row);\n result.set(entity.id, entity);\n }\n\n return result;\n }\n\n async updateEntity(\n repositoryId: string,\n entityId: string,\n updates: StoredEntityUpdate,\n ): Promise<StoredEntity> {\n const pool = this.getPool();\n\n // Get existing entity\n const existing = await this.getEntity(repositoryId, entityId);\n if (!existing) {\n throw new EntityNotFoundError(entityId);\n }\n\n // For optional string fields, null clears, undefined preserves, string sets.\n const updated: StoredEntity = {\n ...existing,\n entityType: updates.entityType ?? existing.entityType,\n label: updates.label ?? existing.label,\n slug: updates.slug ?? existing.slug,\n summary: updates.summary === undefined ? existing.summary : (updates.summary ?? undefined),\n properties: updates.properties ?? existing.properties,\n data: updates.data === undefined ? existing.data : (updates.data ?? undefined),\n dataFormat: updates.dataFormat === undefined ? existing.dataFormat : (updates.dataFormat ?? undefined),\n provenance: updates.provenance,\n embedding: updates.embedding ?? existing.embedding,\n };\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .input('entityType', sql.NVarChar, updated.entityType)\n .input('slug', sql.NVarChar, updated.slug)\n .input('label', sql.NVarChar, updated.label)\n .input('summary', sql.NVarChar, updated.summary ?? null)\n .input('properties', sql.NVarChar, JSON.stringify(updated.properties))\n .input('data', sql.NVarChar, updated.data ?? null)\n .input('dataFormat', sql.NVarChar, updated.dataFormat ?? null)\n .input('embedding', sql.NVarChar, updated.embedding ? JSON.stringify(updated.embedding) : null)\n .input('modifiedBy', sql.NVarChar, updates.provenance.modifiedBy)\n .input('modifiedByType', sql.NVarChar, updates.provenance.modifiedByType)\n .input('modifiedAt', sql.NVarChar, updates.provenance.modifiedAt)\n .input('modifiedInConversation', sql.NVarChar, updates.provenance.modifiedInConversation ?? null)\n .input('modifiedFromMessage', sql.NVarChar, updates.provenance.modifiedFromMessage ?? null);\n\n await req.query(`\n UPDATE ${this.t('dm_entities')} SET\n [entity_type] = @entityType,\n [slug] = @slug,\n [label] = @label,\n [summary] = @summary,\n [properties] = @properties,\n [data] = @data,\n [data_format] = @dataFormat,\n [embedding] = @embedding,\n [modified_by] = @modifiedBy,\n [modified_by_type] = @modifiedByType,\n [modified_at] = @modifiedAt,\n [modified_in_conversation] = @modifiedInConversation,\n [modified_from_message] = @modifiedFromMessage\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId\n `);\n\n return updated;\n }\n\n async deleteEntity(repositoryId: string, entityId: string): Promise<void> {\n const pool = this.getPool();\n\n // Delete relationships first (FK constraints would block otherwise)\n // Two targeted DELETEs hit source/target indexes instead of one OR scan\n const delReq = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId);\n await delReq.query(`\n DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId;\n DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId;\n `);\n\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .query(\n `DELETE FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n if (result.rowsAffected[0] === 0) {\n throw new EntityNotFoundError(entityId);\n }\n }\n\n async deleteEntities(\n repositoryId: string,\n ids: string[],\n ): Promise<{ deleted: string[]; notFound: string[] }> {\n if (ids.length === 0) return { deleted: [], notFound: [] };\n\n const pool = this.getPool();\n\n // Cascade: delete relationships where any of these entities is source or target\n const tvp1 = this.createIdListTvp(ids);\n const cascadeReq = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp1);\n await cascadeReq.query(`\n DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [source_entity_id] IN (SELECT [id] FROM @entityIds);\n DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [target_entity_id] IN (SELECT [id] FROM @entityIds);\n `);\n\n // Delete entities — OUTPUT DELETED tells us which rows actually existed\n const tvp2 = this.createIdListTvp(ids);\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp2)\n .query<{ entity_id: string }>(\n `DELETE FROM ${this.t('dm_entities')}\n OUTPUT DELETED.[entity_id]\n WHERE [repository_id] = @repoId\n AND [entity_id] IN (SELECT [id] FROM @entityIds)`,\n );\n\n const deleted = result.recordset.map((row) => row.entity_id);\n const deletedSet = new Set(deleted);\n return { deleted, notFound: ids.filter((id) => !deletedSet.has(id)) };\n }\n\n async deleteEntitiesByType(\n repositoryId: string,\n entityType: string,\n ): Promise<{ deletedEntities: number; deletedRelationships: number }> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Delete relationships where entities of this type are the SOURCE\n const srcResult = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityType', sql.NVarChar, entityType)\n .query(`\n DELETE r FROM ${this.t('dm_relationships')} r\n INNER JOIN ${this.t('dm_entities')} e\n ON r.[repository_id] = e.[repository_id]\n AND r.[source_entity_id] = e.[entity_id]\n WHERE e.[repository_id] = @repoId AND e.[entity_type] = @entityType\n `);\n\n // Delete relationships where entities of this type are the TARGET\n const tgtResult = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityType', sql.NVarChar, entityType)\n .query(`\n DELETE r FROM ${this.t('dm_relationships')} r\n INNER JOIN ${this.t('dm_entities')} e\n ON r.[repository_id] = e.[repository_id]\n AND r.[target_entity_id] = e.[entity_id]\n WHERE e.[repository_id] = @repoId AND e.[entity_type] = @entityType\n `);\n\n const deletedRelationships = (srcResult.rowsAffected[0] ?? 0) + (tgtResult.rowsAffected[0] ?? 0);\n\n // Delete the entities\n const entResult = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityType', sql.NVarChar, entityType)\n .query(\n `DELETE FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_type] = @entityType`,\n );\n const deletedEntities = entResult.rowsAffected[0] ?? 0;\n\n return { deletedEntities, deletedRelationships };\n }\n\n async findEntities(\n repositoryId: string,\n query: StorageFindQuery,\n ): Promise<PaginatedResult<StoredEntity>> {\n const pool = this.getPool();\n const req = pool.request().input('repoId', sql.UniqueIdentifier, repositoryId);\n\n const conditions = ['[repository_id] = @repoId'];\n\n // Type filter\n if (query.entityTypes && query.entityTypes.length > 0) {\n const typePlaceholders = query.entityTypes.map((t, i) => {\n req.input(`et${i}`, sql.NVarChar, t);\n return `@et${i}`;\n });\n conditions.push(`[entity_type] IN (${typePlaceholders.join(',')})`);\n }\n\n // Search term (case-insensitive LIKE on label and summary)\n if (query.searchTerm) {\n req.input('searchTerm', sql.NVarChar, `%${query.searchTerm}%`);\n conditions.push(`([label] LIKE @searchTerm OR [summary] LIKE @searchTerm)`);\n }\n\n // Property filter (exact match via JSON_VALUE)\n if (query.properties) {\n const entries = Object.entries(query.properties);\n for (let i = 0; i < entries.length; i++) {\n const [key, value] = entries[i]!;\n req.input(`propKey${i}`, sql.NVarChar, `$.${key}`);\n req.input(`propVal${i}`, sql.NVarChar, String(value));\n conditions.push(`JSON_VALUE([properties], @propKey${i}) = @propVal${i}`);\n }\n }\n\n // Provenance filter\n if (query.provenance) {\n addProvenanceConditions(req, query.provenance, conditions, 'data');\n }\n\n const where = conditions.join(' AND ');\n\n // Build a separate request for the count (mssql doesn't allow reusing requests)\n\n const countReq = pool.request().input('repoId', sql.UniqueIdentifier, repositoryId);\n const countConditions = ['[repository_id] = @repoId'];\n\n if (query.entityTypes && query.entityTypes.length > 0) {\n const typePlaceholders = query.entityTypes.map((t, i) => {\n countReq.input(`et${i}`, sql.NVarChar, t);\n return `@et${i}`;\n });\n countConditions.push(`[entity_type] IN (${typePlaceholders.join(',')})`);\n }\n if (query.searchTerm) {\n countReq.input('searchTerm', sql.NVarChar, `%${query.searchTerm}%`);\n countConditions.push(`([label] LIKE @searchTerm OR [summary] LIKE @searchTerm)`);\n }\n if (query.properties) {\n const entries = Object.entries(query.properties);\n for (let i = 0; i < entries.length; i++) {\n const [key, value] = entries[i]!;\n countReq.input(`propKey${i}`, sql.NVarChar, `$.${key}`);\n countReq.input(`propVal${i}`, sql.NVarChar, String(value));\n countConditions.push(`JSON_VALUE([properties], @propKey${i}) = @propVal${i}`);\n }\n }\n\n // Provenance filter (count query)\n if (query.provenance) {\n addProvenanceConditions(countReq, query.provenance, countConditions, 'count');\n }\n\n const countWhere = countConditions.join(' AND ');\n const totalResult = await countReq.query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_entities')} WHERE ${countWhere}`,\n );\n const total = totalResult.recordset[0]?.cnt ?? 0;\n\n // Fetch page\n req.input('limit', sql.Int, query.limit);\n req.input('offset', sql.Int, query.offset);\n\n const result = await req.query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE ${where}\n ORDER BY [entity_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n return {\n items: result.recordset.map(entityFromRow),\n total,\n hasMore: query.offset + query.limit < total,\n limit: query.limit,\n offset: query.offset,\n };\n }\n\n // ─── Relationships ──────────────────────────────────────────────\n\n async createRelationship(\n repositoryId: string,\n relationship: StoredRelationship,\n ): Promise<StoredRelationship> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n // Check for duplicate\n const existing = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationship.id)\n .query<{ relationship_id: string }>(\n `SELECT [relationship_id] FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_id] = @relId`,\n );\n\n if (existing.recordset.length > 0) {\n throw new DuplicateRelationshipError(relationship.id);\n }\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationship.id)\n .input('relType', sql.NVarChar, relationship.relationshipType)\n .input('sourceId', sql.NVarChar, relationship.sourceEntityId)\n .input('targetId', sql.NVarChar, relationship.targetEntityId)\n .input('properties', sql.NVarChar, JSON.stringify(relationship.properties))\n .input('bidirectional', sql.Bit, relationship.bidirectional ? 1 : 0);\n\n this.addProvenanceInputs(req, relationship.provenance);\n\n await req.query(`\n INSERT INTO ${this.t('dm_relationships')} (\n [repository_id], [relationship_id], [relationship_type],\n [source_entity_id], [target_entity_id], [properties], [bidirectional],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @relId, @relType,\n @sourceId, @targetId, @properties, @bidirectional,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n )\n `);\n\n return relationship;\n }\n\n async getRelationship(\n repositoryId: string,\n relationshipId: string,\n ): Promise<StoredRelationship | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationshipId)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_id] = @relId`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return relationshipFromRow(row);\n }\n\n async getEntityRelationships(\n repositoryId: string,\n entityId: string,\n options?: RelationshipQueryOptions,\n ): Promise<PaginatedResult<StoredRelationship>> {\n const pool = this.getPool();\n const direction = options?.direction ?? 'both';\n const limit = options?.limit ?? 10;\n const offset = options?.offset ?? 0;\n const tbl = this.t('dm_relationships');\n\n // Build relationship type filter clause (shared across branches)\n let rtFilter = '';\n const rtInputs: Array<{ name: string; value: string }> = [];\n if (options?.relationshipTypes && options.relationshipTypes.length > 0) {\n const placeholders = options.relationshipTypes.map((t, i) => {\n rtInputs.push({ name: `rt${i}`, value: t });\n return `@rt${i}`;\n });\n rtFilter = ` AND [relationship_type] IN (${placeholders.join(',')})`;\n }\n\n // Build UNION ALL query — each branch targets a specific nonclustered index\n // instead of forcing an OR-based scan across source/target columns.\n const unionBranches = this.buildRelationshipUnion(tbl, direction, rtFilter);\n\n const addParams = (req: sql.Request): sql.Request => {\n req.input('repoId', sql.UniqueIdentifier, repositoryId);\n req.input('entityId', sql.NVarChar, entityId);\n for (const p of rtInputs) req.input(p.name, sql.NVarChar, p.value);\n return req;\n };\n\n // Count\n const countReq = addParams(pool.request());\n const totalResult = await countReq.query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM (${unionBranches}) AS _u`,\n );\n const total = totalResult.recordset[0]?.cnt ?? 0;\n\n // Fetch page\n const fetchReq = addParams(pool.request());\n fetchReq.input('limit', sql.Int, limit);\n fetchReq.input('offset', sql.Int, offset);\n\n const result = await fetchReq.query<Record<string, unknown>>(\n `SELECT * FROM (${unionBranches}) AS _u\n ORDER BY [relationship_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n let items = result.recordset.map(relationshipFromRow);\n\n // Apply property filters in-memory\n if (options?.propertyFilters && options.propertyFilters.length > 0) {\n items = items.filter((r) => matchesPropertyFilters(r.properties, options.propertyFilters!));\n const filteredTotal = total; // approximate — exact count would require re-querying\n return {\n items,\n total: filteredTotal,\n hasMore: offset + limit < filteredTotal,\n limit,\n offset,\n };\n }\n\n return {\n items,\n total,\n hasMore: offset + limit < total,\n limit,\n offset,\n };\n }\n\n /**\n * Build a UNION ALL query that seeks on source and target indexes separately,\n * avoiding OR-based index scans. Each branch produces an index seek at scale.\n */\n private buildRelationshipUnion(tbl: string, direction: string, rtFilter: string): string {\n // Source branch: seeks ix_dm_relationships_source (repo, source_entity_id, relationship_type)\n const srcBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId${rtFilter}`;\n // Target branch: seeks ix_dm_relationships_target (repo, target_entity_id, bidirectional, relationship_type)\n const tgtBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId${rtFilter}`;\n // Bidirectional target: seeks ix_dm_relationships_target with bidirectional = 1\n const tgtBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId AND [bidirectional] = 1${rtFilter}`;\n // Bidirectional source: seeks ix_dm_relationships_source with bidirectional = 1\n const srcBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId AND [bidirectional] = 1${rtFilter}`;\n\n switch (direction) {\n case 'outbound':\n // Outbound = where entity is source, OR where entity is target of a bidirectional rel\n return `${srcBase} UNION ALL ${tgtBidi} AND [source_entity_id] <> @entityId`;\n case 'inbound':\n // Inbound = where entity is target, OR where entity is source of a bidirectional rel\n return `${tgtBase} UNION ALL ${srcBidi} AND [target_entity_id] <> @entityId`;\n case 'both':\n default:\n // Both = where entity is source UNION where entity is target (excluding duplicates from source branch)\n return `${srcBase} UNION ALL ${tgtBase} AND [source_entity_id] <> @entityId`;\n }\n }\n\n async deleteRelationship(repositoryId: string, relationshipId: string): Promise<void> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, relationshipId)\n .query(\n `DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_id] = @relId`,\n );\n\n if (result.rowsAffected[0] === 0) {\n throw new RelationshipNotFoundError(relationshipId);\n }\n }\n\n async deleteRelationships(\n repositoryId: string,\n ids: string[],\n ): Promise<{ deleted: string[]; notFound: string[] }> {\n if (ids.length === 0) return { deleted: [], notFound: [] };\n\n const pool = this.getPool();\n const tvp = this.createIdListTvp(ids);\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relIds', tvp)\n .query<{ relationship_id: string }>(\n `DELETE FROM ${this.t('dm_relationships')}\n OUTPUT DELETED.[relationship_id]\n WHERE [repository_id] = @repoId\n AND [relationship_id] IN (SELECT [id] FROM @relIds)`,\n );\n\n const deleted = result.recordset.map((row) => row.relationship_id);\n const deletedSet = new Set(deleted);\n return { deleted, notFound: ids.filter((id) => !deletedSet.has(id)) };\n }\n\n async deleteRelationshipsByType(\n repositoryId: string,\n relationshipType: string,\n ): Promise<{ deletedRelationships: number }> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relType', sql.NVarChar, relationshipType)\n .query(\n `DELETE FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [relationship_type] = @relType`,\n );\n\n return { deletedRelationships: result.rowsAffected[0] ?? 0 };\n }\n\n // ─── Graph Traversal ────────────────────────────────────────────\n\n async exploreNeighborhood(\n repositoryId: string,\n entityId: string,\n options: StorageExploreOptions,\n ): Promise<StorageNeighborhood> {\n // Verify the center entity exists (light — no embedding needed)\n const center = await this.getEntityLight(repositoryId, entityId);\n if (!center) {\n throw new EntityNotFoundError(entityId);\n }\n\n const layers: StorageNeighborhood['layers'] = [];\n const visited = new Set<string>([entityId]);\n let currentFrontier = new Set<string>([entityId]);\n\n for (let depth = 0; depth < options.depth; depth++) {\n const layer: StorageNeighborhood['layers'][number] = {};\n const nextFrontier = new Set<string>();\n\n // Batch: fetch all relationships for the entire frontier in one query\n const frontierIds = [...currentFrontier];\n const relsByEntity = await this.getRelationshipsForEntities(\n repositoryId,\n frontierIds,\n options.direction,\n options.relationshipTypes,\n );\n\n // Collect all connected entity IDs we need to fetch\n const connectedIdsToFetch = new Set<string>();\n const pendingRels: Array<{ frontierEntityId: string; rel: StoredRelationship; connectedEntityId: string }> = [];\n\n for (const frontierEntityId of frontierIds) {\n const rels = relsByEntity.get(frontierEntityId) ?? [];\n for (const rel of rels) {\n let connectedEntityId: string | undefined;\n if (rel.sourceEntityId === frontierEntityId) {\n connectedEntityId = rel.targetEntityId;\n } else if (rel.targetEntityId === frontierEntityId) {\n connectedEntityId = rel.sourceEntityId;\n }\n if (!connectedEntityId || visited.has(connectedEntityId)) continue;\n\n // Filter by relationship property values\n if (options.relationshipPropertyFilters && options.relationshipPropertyFilters.length > 0) {\n if (!matchesPropertyFilters(rel.properties, options.relationshipPropertyFilters)) {\n continue;\n }\n }\n\n connectedIdsToFetch.add(connectedEntityId);\n pendingRels.push({ frontierEntityId, rel, connectedEntityId });\n }\n }\n\n // Batch: fetch all connected entities in one query\n const connectedEntities = await this.getEntitiesLight(repositoryId, [...connectedIdsToFetch]);\n\n // Process results in memory\n for (const { rel, connectedEntityId } of pendingRels) {\n if (visited.has(connectedEntityId)) continue;\n\n const connectedEntity = connectedEntities.get(connectedEntityId);\n if (!connectedEntity) continue;\n\n if (options.entityTypes && !options.entityTypes.includes(connectedEntity.entityType)) {\n continue;\n }\n\n const relType = rel.relationshipType;\n if (!layer[relType]) {\n layer[relType] = { total: 0, entities: [], relationships: [] };\n }\n\n const group = layer[relType]!;\n group.total++;\n\n if (group.entities.length < options.limitPerType) {\n group.entities.push(connectedEntity);\n group.relationships.push(rel);\n }\n\n nextFrontier.add(connectedEntityId);\n visited.add(connectedEntityId);\n }\n\n layers.push(layer);\n currentFrontier = nextFrontier;\n if (nextFrontier.size === 0) break;\n }\n\n return { centerId: entityId, layers };\n }\n\n async findPaths(\n repositoryId: string,\n sourceId: string,\n targetId: string,\n options: StoragePathOptions,\n ): Promise<StoragePathResult> {\n // Verify both entities exist (light — no embedding needed)\n const [source, target] = await Promise.all([\n this.getEntityLight(repositoryId, sourceId),\n this.getEntityLight(repositoryId, targetId),\n ]);\n if (!source) throw new EntityNotFoundError(sourceId);\n if (!target) throw new EntityNotFoundError(targetId);\n\n if (sourceId === targetId) {\n return { paths: [{ entityIds: [sourceId], relationshipIds: [] }], totalPaths: 1 };\n }\n\n // BFS path finding — processes in depth levels for batch relationship fetching\n const paths: Array<{ entityIds: string[]; relationshipIds: string[] }> = [];\n let currentLevel: Array<{ entityId: string; path: string[]; relPath: string[] }> = [\n { entityId: sourceId, path: [sourceId], relPath: [] },\n ];\n const visitedAtDepth = new Map<string, number>();\n visitedAtDepth.set(sourceId, 0);\n\n for (let depth = 0; depth <= options.maxDepth && currentLevel.length > 0 && paths.length < options.limit + options.offset; depth++) {\n // Batch: fetch relationships for all frontier entities at this depth\n const frontierIds = [...new Set(currentLevel.map(e => e.entityId))];\n const relsByEntity = await this.getRelationshipsForEntities(\n repositoryId,\n frontierIds,\n 'both',\n options.relationshipTypes,\n );\n\n const nextLevel: Array<{ entityId: string; path: string[]; relPath: string[] }> = [];\n\n for (const current of currentLevel) {\n if (paths.length >= options.limit + options.offset) break;\n\n const rels = relsByEntity.get(current.entityId) ?? [];\n for (const rel of rels) {\n // Filter by relationship property values\n if (options.relationshipPropertyFilters && options.relationshipPropertyFilters.length > 0) {\n if (!matchesPropertyFilters(rel.properties, options.relationshipPropertyFilters)) {\n continue;\n }\n }\n\n let nextEntityId: string | undefined;\n if (rel.sourceEntityId === current.entityId) {\n nextEntityId = rel.targetEntityId;\n } else if (rel.targetEntityId === current.entityId) {\n nextEntityId = rel.sourceEntityId;\n }\n\n if (!nextEntityId) continue;\n if (current.path.includes(nextEntityId) && nextEntityId !== targetId) continue;\n\n const newPath = [...current.path, nextEntityId];\n const newRelPath = [...current.relPath, rel.id];\n\n if (nextEntityId === targetId) {\n paths.push({ entityIds: newPath, relationshipIds: newRelPath });\n } else if (newPath.length <= options.maxDepth) {\n const prevDepth = visitedAtDepth.get(nextEntityId);\n if (prevDepth === undefined || prevDepth >= newPath.length - 1) {\n visitedAtDepth.set(nextEntityId, newPath.length - 1);\n nextLevel.push({ entityId: nextEntityId, path: newPath, relPath: newRelPath });\n }\n }\n }\n }\n\n // Filter next level by entity types if specified (batch-fetch entity types)\n if (options.entityTypes && nextLevel.length > 0) {\n const nextIds = [...new Set(nextLevel.map(e => e.entityId))];\n const entityMap = await this.getEntitiesLight(repositoryId, nextIds);\n const allowedIds = new Set<string>();\n for (const [id, e] of entityMap) {\n if (options.entityTypes.includes(e.entityType)) {\n allowedIds.add(id);\n }\n }\n currentLevel = nextLevel.filter(e => allowedIds.has(e.entityId));\n } else {\n currentLevel = nextLevel;\n }\n }\n\n const paginatedPaths = paths.slice(options.offset, options.offset + options.limit);\n return { paths: paginatedPaths, totalPaths: paths.length };\n }\n\n // ─── Timeline ───────────────────────────────────────────────────\n\n async getTimeline(\n repositoryId: string,\n entityId: string,\n options: StorageTimelineOptions,\n ): Promise<StorageTimelineResult> {\n const entity = await this.getEntityLight(repositoryId, entityId);\n if (!entity) {\n throw new EntityNotFoundError(entityId);\n }\n\n const events: StorageTimelineEvent[] = [];\n\n // Entity creation event\n events.push({\n timestamp: entity.provenance.createdAt,\n eventType: 'entity:created',\n entityId,\n });\n\n // Entity modification event\n if (entity.provenance.modifiedAt !== entity.provenance.createdAt) {\n events.push({\n timestamp: entity.provenance.modifiedAt,\n eventType: 'entity:updated',\n entityId,\n });\n }\n\n // Relationship events involving this entity — push time-range filter into SQL\n const pool = this.getPool();\n const relReq = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .input('from', sql.NVarChar, options.timeRange?.from ?? null)\n .input('to', sql.NVarChar, options.timeRange?.to ?? null);\n\n const relResult = await relReq.query<Record<string, unknown>>(\n `SELECT [relationship_id], [created_at] FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [source_entity_id] = @entityId\n AND (@from IS NULL OR [created_at] >= @from)\n AND (@to IS NULL OR [created_at] <= @to)\n UNION ALL\n SELECT [relationship_id], [created_at] FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId AND [target_entity_id] = @entityId\n AND [source_entity_id] <> @entityId\n AND (@from IS NULL OR [created_at] >= @from)\n AND (@to IS NULL OR [created_at] <= @to)`,\n );\n\n for (const row of relResult.recordset) {\n events.push({\n timestamp: row['created_at'] as string,\n eventType: 'relationship:created',\n entityId,\n relationshipId: row['relationship_id'] as string,\n });\n }\n\n // Filter by time range (still needed for entity events which come from provenance)\n let filtered = events;\n if (options.timeRange) {\n const from = new Date(options.timeRange.from).getTime();\n const to = new Date(options.timeRange.to).getTime();\n filtered = filtered.filter((e) => {\n const t = new Date(e.timestamp).getTime();\n return t >= from && t <= to;\n });\n }\n\n // Filter by event types\n if (options.eventTypes && options.eventTypes.length > 0) {\n filtered = filtered.filter((e) => options.eventTypes!.includes(e.eventType));\n }\n\n // Sort descending\n filtered.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n const total = filtered.length;\n const items = filtered.slice(options.offset, options.offset + options.limit);\n\n return { events: items, total };\n }\n\n // ─── Bulk Operations ────────────────────────────────────────────\n\n async *exportAll(repositoryId: string): AsyncIterable<ExportChunk> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n const batchSize = 100;\n\n // Export entities\n const entityCount = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_entities')} WHERE [repository_id] = @repoId`,\n );\n const totalEntities = entityCount.recordset[0]?.cnt ?? 0;\n\n if (totalEntities === 0) {\n yield { type: 'entities', data: [], sequence: 0, isLast: true };\n } else {\n for (let offset = 0; offset < totalEntities; offset += batchSize) {\n const batch = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('offset', sql.Int, offset)\n .input('limit', sql.Int, batchSize)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_FULL} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId\n ORDER BY [entity_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n yield {\n type: 'entities',\n data: batch.recordset.map(entityFromRow),\n sequence: Math.floor(offset / batchSize),\n isLast: offset + batchSize >= totalEntities,\n };\n }\n }\n\n // Export relationships\n const relCount = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .query<{ cnt: number }>(\n `SELECT COUNT(*) AS cnt FROM ${this.t('dm_relationships')} WHERE [repository_id] = @repoId`,\n );\n const totalRels = relCount.recordset[0]?.cnt ?? 0;\n\n if (totalRels === 0) {\n yield { type: 'relationships', data: [], sequence: 0, isLast: true };\n } else {\n for (let offset = 0; offset < totalRels; offset += batchSize) {\n const batch = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('offset', sql.Int, offset)\n .input('limit', sql.Int, batchSize)\n .query<Record<string, unknown>>(\n `SELECT * FROM ${this.t('dm_relationships')}\n WHERE [repository_id] = @repoId\n ORDER BY [relationship_id]\n OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`,\n );\n\n yield {\n type: 'relationships',\n data: batch.recordset.map(relationshipFromRow),\n sequence: Math.floor(offset / batchSize),\n isLast: offset + batchSize >= totalRels,\n };\n }\n }\n }\n\n async importBulk(\n repositoryId: string,\n data: ImportChunk[],\n _options?: import('@utaba/deep-memory/types').BulkImportOptions,\n ): Promise<BulkImportResult> {\n await this.assertRepository(repositoryId);\n const pool = this.getPool();\n let entitiesImported = 0;\n let relationshipsImported = 0;\n\n const transaction = pool.transaction();\n await transaction.begin();\n try {\n for (const chunk of data) {\n if (chunk.entities) {\n for (const entity of chunk.entities) {\n const req = transaction.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entity.id)\n .input('slug', sql.NVarChar, entity.slug)\n .input('entityType', sql.NVarChar, entity.entityType)\n .input('label', sql.NVarChar, entity.label)\n .input('summary', sql.NVarChar, entity.summary ?? null)\n .input('properties', sql.NVarChar, JSON.stringify(entity.properties))\n .input('data', sql.NVarChar, entity.data ?? null)\n .input('dataFormat', sql.NVarChar, entity.dataFormat ?? null)\n .input('embedding', sql.NVarChar, entity.embedding ? JSON.stringify(entity.embedding) : null);\n\n this.addProvenanceInputs(req, entity.provenance);\n\n await req.query(`\n MERGE ${this.t('dm_entities')} AS target\n USING (SELECT @repoId AS repository_id, @entityId AS entity_id) AS source\n ON target.[repository_id] = source.repository_id AND target.[entity_id] = source.entity_id\n WHEN MATCHED THEN UPDATE SET\n [entity_type] = @entityType, [slug] = @slug, [label] = @label, [summary] = @summary,\n [properties] = @properties, [data] = @data, [data_format] = @dataFormat,\n [embedding] = @embedding,\n [modified_by] = @modifiedBy, [modified_by_type] = @modifiedByType,\n [modified_at] = @modifiedAt, [modified_in_conversation] = @modifiedInConversation,\n [modified_from_message] = @modifiedFromMessage\n WHEN NOT MATCHED THEN INSERT (\n [repository_id], [entity_id], [slug], [entity_type], [label], [summary],\n [properties], [data], [data_format], [embedding],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @entityId, @slug, @entityType, @label, @summary,\n @properties, @data, @dataFormat, @embedding,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n );\n `);\n entitiesImported++;\n }\n }\n\n if (chunk.relationships) {\n for (const rel of chunk.relationships) {\n const req = transaction.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('relId', sql.NVarChar, rel.id)\n .input('relType', sql.NVarChar, rel.relationshipType)\n .input('sourceId', sql.NVarChar, rel.sourceEntityId)\n .input('targetId', sql.NVarChar, rel.targetEntityId)\n .input('properties', sql.NVarChar, JSON.stringify(rel.properties))\n .input('bidirectional', sql.Bit, rel.bidirectional ? 1 : 0);\n\n this.addProvenanceInputs(req, rel.provenance);\n\n await req.query(`\n MERGE ${this.t('dm_relationships')} AS target\n USING (SELECT @repoId AS repository_id, @relId AS relationship_id) AS source\n ON target.[repository_id] = source.repository_id AND target.[relationship_id] = source.relationship_id\n WHEN MATCHED THEN UPDATE SET\n [relationship_type] = @relType, [source_entity_id] = @sourceId,\n [target_entity_id] = @targetId, [properties] = @properties,\n [bidirectional] = @bidirectional,\n [modified_by] = @modifiedBy, [modified_by_type] = @modifiedByType,\n [modified_at] = @modifiedAt, [modified_in_conversation] = @modifiedInConversation,\n [modified_from_message] = @modifiedFromMessage\n WHEN NOT MATCHED THEN INSERT (\n [repository_id], [relationship_id], [relationship_type],\n [source_entity_id], [target_entity_id], [properties], [bidirectional],\n [created_by], [created_by_type], [created_at],\n [created_in_conversation], [created_from_message],\n [modified_by], [modified_by_type], [modified_at],\n [modified_in_conversation], [modified_from_message]\n ) VALUES (\n @repoId, @relId, @relType,\n @sourceId, @targetId, @properties, @bidirectional,\n @createdBy, @createdByType, @createdAt,\n @createdInConversation, @createdFromMessage,\n @modifiedBy, @modifiedByType, @modifiedAt,\n @modifiedInConversation, @modifiedFromMessage\n );\n `);\n relationshipsImported++;\n }\n }\n }\n await transaction.commit();\n } catch (err) {\n await transaction.rollback();\n throw err;\n }\n\n return { entitiesImported, relationshipsImported, errors: [] };\n }\n\n // ─── Private helpers ────────────────────────────────────────────\n\n /** Creates a TVP table from an array of string IDs (eliminates plan cache bloat from IN clauses). */\n private createIdListTvp(ids: string[]): sql.Table {\n const tvp = new sql.Table(`${this.schema}.dm_id_list`);\n tvp.columns.add('id', sql.NVarChar(300));\n for (const id of ids) tvp.rows.add(id);\n return tvp;\n }\n\n /** Returns a StoredEntity without the embedding column (lighter I/O). */\n private async getEntityLight(repositoryId: string, entityId: string): Promise<StoredEntity | null> {\n const pool = this.getPool();\n const result = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityId', sql.NVarChar, entityId)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId AND [entity_id] = @entityId`,\n );\n\n const row = result.recordset[0];\n if (!row) return null;\n return entityFromRow(row);\n }\n\n /** Returns multiple entities without embedding columns, using TVP for batch lookup. */\n private async getEntitiesLight(\n repositoryId: string,\n entityIds: string[],\n ): Promise<Map<string, StoredEntity>> {\n const pool = this.getPool();\n const result = new Map<string, StoredEntity>();\n if (entityIds.length === 0) return result;\n\n const tvp = this.createIdListTvp(entityIds);\n const rows = await pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp)\n .query<Record<string, unknown>>(\n `SELECT ${ENTITY_COLS_LIGHT} FROM ${this.t('dm_entities')}\n WHERE [repository_id] = @repoId\n AND [entity_id] IN (SELECT [id] FROM @entityIds)`,\n );\n\n for (const row of rows.recordset) {\n const entity = entityFromRow(row);\n result.set(entity.id, entity);\n }\n\n return result;\n }\n\n /**\n * Fetches relationships for multiple entity IDs in a single query using TVP.\n * Returns results grouped by the frontier entity ID.\n */\n private async getRelationshipsForEntities(\n repositoryId: string,\n entityIds: string[],\n direction: string,\n relationshipTypes?: string[],\n ): Promise<Map<string, StoredRelationship[]>> {\n const pool = this.getPool();\n const result = new Map<string, StoredRelationship[]>();\n if (entityIds.length === 0) return result;\n\n const tbl = this.t('dm_relationships');\n const tvp = this.createIdListTvp(entityIds);\n\n let rtFilter = '';\n const rtInputs: Array<{ name: string; value: string }> = [];\n if (relationshipTypes && relationshipTypes.length > 0) {\n const placeholders = relationshipTypes.map((t, i) => {\n rtInputs.push({ name: `rt${i}`, value: t });\n return `@rt${i}`;\n });\n rtFilter = ` AND [relationship_type] IN (${placeholders.join(',')})`;\n }\n\n // Build UNION ALL branches using TVP instead of single @entityId\n const srcBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] IN (SELECT [id] FROM @entityIds)${rtFilter}`;\n const tgtBase = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] IN (SELECT [id] FROM @entityIds)${rtFilter}`;\n const tgtBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [target_entity_id] IN (SELECT [id] FROM @entityIds) AND [bidirectional] = 1${rtFilter}`;\n const srcBidi = `SELECT * FROM ${tbl} WHERE [repository_id] = @repoId AND [source_entity_id] IN (SELECT [id] FROM @entityIds) AND [bidirectional] = 1${rtFilter}`;\n\n let unionQuery: string;\n switch (direction) {\n case 'outbound':\n unionQuery = `${srcBase} UNION ALL ${tgtBidi}`;\n break;\n case 'inbound':\n unionQuery = `${tgtBase} UNION ALL ${srcBidi}`;\n break;\n case 'both':\n default:\n unionQuery = `${srcBase} UNION ALL ${tgtBase}`;\n break;\n }\n\n const req = pool.request()\n .input('repoId', sql.UniqueIdentifier, repositoryId)\n .input('entityIds', tvp);\n for (const p of rtInputs) req.input(p.name, sql.NVarChar, p.value);\n\n const rows = await req.query<Record<string, unknown>>(unionQuery);\n\n const entityIdSet = new Set(entityIds);\n for (const row of rows.recordset) {\n const rel = relationshipFromRow(row);\n // Determine which frontier entity this relationship belongs to\n const frontierIds: string[] = [];\n if (entityIdSet.has(rel.sourceEntityId)) frontierIds.push(rel.sourceEntityId);\n if (entityIdSet.has(rel.targetEntityId)) frontierIds.push(rel.targetEntityId);\n for (const fid of frontierIds) {\n let list = result.get(fid);\n if (!list) {\n list = [];\n result.set(fid, list);\n }\n list.push(rel);\n }\n }\n\n return result;\n }\n\n private async assertRepository(repositoryId: string): Promise<void> {\n const repo = await this.getRepository(repositoryId);\n if (!repo) {\n throw new RepositoryNotFoundError(repositoryId);\n }\n }\n\n private addProvenanceInputs(req: sql.Request, provenance: Provenance): void {\n req.input('createdBy', sql.NVarChar, provenance.createdBy);\n req.input('createdByType', sql.NVarChar, provenance.createdByType);\n req.input('createdAt', sql.NVarChar, provenance.createdAt);\n req.input('createdInConversation', sql.NVarChar, provenance.createdInConversation ?? null);\n req.input('createdFromMessage', sql.NVarChar, provenance.createdFromMessage ?? null);\n req.input('modifiedBy', sql.NVarChar, provenance.modifiedBy);\n req.input('modifiedByType', sql.NVarChar, provenance.modifiedByType);\n req.input('modifiedAt', sql.NVarChar, provenance.modifiedAt);\n req.input('modifiedInConversation', sql.NVarChar, provenance.modifiedInConversation ?? null);\n req.input('modifiedFromMessage', sql.NVarChar, provenance.modifiedFromMessage ?? null);\n }\n}\n","// SQL Server schema for @utaba/deep-memory StorageProvider\n//\n// Naming conventions:\n// Tables: plural snake_case (entities, relationships)\n// Columns: snake_case (entity_id, created_at)\n// Indexes: ix_{table}_{columns}\n// Primary keys: pk_{table}\n// Foreign keys: fk_{table}_{referenced_table}\n//\n// All tables are prefixed with dm_ (deep memory) to avoid collisions\n// when co-located with other schemas in a shared database.\n\nexport const SCHEMA_VERSION = 1;\n\n/**\n * Returns the full DDL for creating the deep-memory schema.\n *\n * @param schema - Optional SQL Server schema name (default: 'dbo').\n * The schema must already exist in the database.\n */\nexport function getSchemaSQL(schema = 'dbo'): string {\n const s = schema;\n\n return `\n-- ============================================================\n-- @utaba/deep-memory SQL Server schema v${SCHEMA_VERSION}\n-- ============================================================\n\n-- Schema version tracking\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_meta' AND schema_id = SCHEMA_ID('${s}'))\nBEGIN\n CREATE TABLE [${s}].[dm_meta] (\n [key] NVARCHAR(100) NOT NULL,\n [value] NVARCHAR(MAX) NOT NULL,\n CONSTRAINT [pk_dm_meta] PRIMARY KEY ([key])\n );\n INSERT INTO [${s}].[dm_meta] ([key], [value])\n VALUES ('schema_version', '${SCHEMA_VERSION}');\nEND;\n\n-- Repositories\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_repositories' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_repositories] (\n [repository_id] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),\n [type] NVARCHAR(128) NULL,\n [label] NVARCHAR(500) NOT NULL,\n [description] NVARCHAR(MAX) NULL,\n [legal] NVARCHAR(MAX) NULL,\n [owner] NVARCHAR(500) NULL,\n [governance_config] NVARCHAR(MAX) NOT NULL, -- JSON\n [metadata] NVARCHAR(MAX) NULL, -- JSON\n [created_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [created_by] NVARCHAR(255) NOT NULL,\n CONSTRAINT [pk_dm_repositories] PRIMARY KEY ([repository_id])\n);\n\n-- Vocabularies (one JSON document per repository)\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_vocabularies' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_vocabularies] (\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [vocabulary] NVARCHAR(MAX) NOT NULL, -- JSON (MemoryVocabulary)\n CONSTRAINT [pk_dm_vocabularies] PRIMARY KEY ([repository_id]),\n CONSTRAINT [fk_dm_vocabularies_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE\n);\n\n-- Vocabulary change log\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_vocabulary_change_log' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_vocabulary_change_log] (\n [change_id] NVARCHAR(128) NOT NULL,\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [change_type] NVARCHAR(50) NOT NULL,\n [type_name] NVARCHAR(255) NOT NULL,\n [previous_version] NVARCHAR(50) NULL,\n [new_version] NVARCHAR(50) NOT NULL,\n [proposed_by] NVARCHAR(255) NOT NULL,\n [proposed_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [approved_by] NVARCHAR(255) NULL,\n [approved_at] NVARCHAR(50) NULL, -- ISO 8601\n [reason] NVARCHAR(MAX) NOT NULL,\n CONSTRAINT [pk_dm_vocabulary_change_log] PRIMARY KEY ([repository_id], [change_id]),\n CONSTRAINT [fk_dm_vocabulary_change_log_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE\n);\n\nCREATE NONCLUSTERED INDEX [ix_dm_vocabulary_change_log_proposed_at]\n ON [${s}].[dm_vocabulary_change_log] ([repository_id], [proposed_at] DESC);\n\n-- Entities\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_entities' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_entities] (\n [ft_key] INT NOT NULL IDENTITY(1,1), -- surrogate for FT index\n [entity_id] NVARCHAR(300) NOT NULL,\n [slug] NVARCHAR(300) NOT NULL,\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [entity_type] NVARCHAR(255) NOT NULL,\n [label] NVARCHAR(500) NOT NULL,\n [summary] NVARCHAR(MAX) NULL,\n [properties] NVARCHAR(MAX) NOT NULL, -- JSON\n [data] NVARCHAR(MAX) NULL,\n [data_format] NVARCHAR(100) NULL,\n [embedding] NVARCHAR(MAX) NULL, -- JSON array of numbers\n -- Provenance\n [created_by] NVARCHAR(255) NOT NULL,\n [created_by_type] NVARCHAR(10) NOT NULL, -- 'user' | 'agent'\n [created_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [created_in_conversation] NVARCHAR(255) NULL,\n [created_from_message] NVARCHAR(255) NULL,\n [modified_by] NVARCHAR(255) NOT NULL,\n [modified_by_type] NVARCHAR(10) NOT NULL,\n [modified_at] NVARCHAR(50) NOT NULL, -- ISO 8601\n [modified_in_conversation] NVARCHAR(255) NULL,\n [modified_from_message] NVARCHAR(255) NULL,\n CONSTRAINT [pk_dm_entities] PRIMARY KEY ([repository_id], [entity_id]),\n CONSTRAINT [uq_dm_entities_ft_key] UNIQUE ([ft_key]),\n CONSTRAINT [fk_dm_entities_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE\n);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_type]\n ON [${s}].[dm_entities] ([repository_id], [entity_type]);\nCREATE NONCLUSTERED INDEX [ix_dm_entities_label]\n ON [${s}].[dm_entities] ([repository_id], [label]);\n\nCREATE UNIQUE NONCLUSTERED INDEX [ix_dm_entities_slug]\n ON [${s}].[dm_entities] ([repository_id], [slug]);\n\n-- Provenance indexes for conversation/actor/temporal queries\nCREATE NONCLUSTERED INDEX [ix_dm_entities_created_conversation]\n ON [${s}].[dm_entities] ([repository_id], [created_in_conversation])\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_modified_conversation]\n ON [${s}].[dm_entities] ([repository_id], [modified_in_conversation])\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_created_by]\n ON [${s}].[dm_entities] ([repository_id], [created_by])\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_entities_modified_at]\n ON [${s}].[dm_entities] ([repository_id], [modified_at] DESC)\n INCLUDE ([entity_id], [entity_type], [label], [summary]);\n\n-- Full-text catalog and index on entities\nIF NOT EXISTS (SELECT 1 FROM sys.fulltext_catalogs WHERE name = 'dm_fulltext_catalog')\n CREATE FULLTEXT CATALOG [dm_fulltext_catalog] AS DEFAULT;\n\nIF NOT EXISTS (\n SELECT 1 FROM sys.fulltext_indexes fi\n JOIN sys.tables t ON fi.object_id = t.object_id\n WHERE t.name = 'dm_entities' AND t.schema_id = SCHEMA_ID('${s}')\n)\nCREATE FULLTEXT INDEX ON [${s}].[dm_entities] (\n [label] LANGUAGE 1033,\n [summary] LANGUAGE 1033,\n [data] LANGUAGE 1033,\n [properties] LANGUAGE 1033\n)\nKEY INDEX [uq_dm_entities_ft_key]\nON [dm_fulltext_catalog]\nWITH CHANGE_TRACKING AUTO;\n\n-- Relationships\nIF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'dm_relationships' AND schema_id = SCHEMA_ID('${s}'))\nCREATE TABLE [${s}].[dm_relationships] (\n [relationship_id] NVARCHAR(300) NOT NULL,\n [repository_id] UNIQUEIDENTIFIER NOT NULL,\n [relationship_type] NVARCHAR(255) NOT NULL,\n [source_entity_id] NVARCHAR(300) NOT NULL,\n [target_entity_id] NVARCHAR(300) NOT NULL,\n [properties] NVARCHAR(MAX) NOT NULL, -- JSON\n [bidirectional] BIT NOT NULL DEFAULT 0,\n -- Provenance\n [created_by] NVARCHAR(255) NOT NULL,\n [created_by_type] NVARCHAR(10) NOT NULL,\n [created_at] NVARCHAR(50) NOT NULL,\n [created_in_conversation] NVARCHAR(255) NULL,\n [created_from_message] NVARCHAR(255) NULL,\n [modified_by] NVARCHAR(255) NOT NULL,\n [modified_by_type] NVARCHAR(10) NOT NULL,\n [modified_at] NVARCHAR(50) NOT NULL,\n [modified_in_conversation] NVARCHAR(255) NULL,\n [modified_from_message] NVARCHAR(255) NULL,\n CONSTRAINT [pk_dm_relationships] PRIMARY KEY ([repository_id], [relationship_id]),\n CONSTRAINT [fk_dm_relationships_repositories]\n FOREIGN KEY ([repository_id]) REFERENCES [${s}].[dm_repositories]([repository_id])\n ON DELETE CASCADE,\n CONSTRAINT [fk_dm_relationships_source]\n FOREIGN KEY ([repository_id], [source_entity_id]) REFERENCES [${s}].[dm_entities]([repository_id], [entity_id]),\n CONSTRAINT [fk_dm_relationships_target]\n FOREIGN KEY ([repository_id], [target_entity_id]) REFERENCES [${s}].[dm_entities]([repository_id], [entity_id])\n);\n\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_source]\n ON [${s}].[dm_relationships] ([repository_id], [source_entity_id], [relationship_type])\n INCLUDE ([target_entity_id], [bidirectional]);\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_target]\n ON [${s}].[dm_relationships] ([repository_id], [target_entity_id], [relationship_type])\n INCLUDE ([source_entity_id], [bidirectional]);\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_type]\n ON [${s}].[dm_relationships] ([repository_id], [relationship_type]);\n\n-- Relationship provenance indexes\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_created_conversation]\n ON [${s}].[dm_relationships] ([repository_id], [created_in_conversation]);\n\nCREATE NONCLUSTERED INDEX [ix_dm_relationships_modified_at]\n ON [${s}].[dm_relationships] ([repository_id], [modified_at] DESC);\n\n-- Table-valued parameter type for batch ID lookups (eliminates plan cache bloat)\nIF NOT EXISTS (SELECT 1 FROM sys.types WHERE name = 'dm_id_list' AND is_table_type = 1)\n CREATE TYPE [${s}].[dm_id_list] AS TABLE ([id] NVARCHAR(300) NOT NULL);\n`.trim();\n}\n\n/**\n * Returns DDL for the dm_search_entities stored procedure.\n *\n * The procedure uses FREETEXTTABLE for natural-language queries and falls back\n * to CONTAINSTABLE when the caller passes @UseContains = 1 (exact phrase / prefix).\n * It returns ranked results with highlight snippets for label, summary, and data.\n *\n * Must be executed as a separate batch (not inside the main schema DDL) because\n * CREATE OR ALTER PROCEDURE must be the first statement in a batch.\n */\nexport function getSearchProcSQL(schema = 'dbo'): string {\n const s = schema;\n\n return `\nCREATE OR ALTER PROCEDURE [${s}].[dm_search_entities]\n @RepositoryId UNIQUEIDENTIFIER,\n @Query NVARCHAR(4000),\n @EntityTypes NVARCHAR(MAX) = NULL, -- JSON array of strings, e.g. '[\"person\",\"project\"]'\n @Limit INT = 20,\n @Offset INT = 0,\n @UseContains BIT = 0 -- 0 = FREETEXTTABLE (natural language), 1 = CONTAINSTABLE (exact/prefix)\nAS\nBEGIN\n SET NOCOUNT ON;\n\n -- Parse entity type filter from JSON array into a temp table\n CREATE TABLE #entity_types ([type_name] NVARCHAR(255));\n IF @EntityTypes IS NOT NULL AND @EntityTypes <> '[]'\n BEGIN\n INSERT INTO #entity_types ([type_name])\n SELECT TRIM(value) FROM OPENJSON(@EntityTypes);\n END;\n\n DECLARE @HasTypeFilter BIT = CASE WHEN EXISTS (SELECT 1 FROM #entity_types) THEN 1 ELSE 0 END;\n\n -- CTE: ranked full-text matches\n ;WITH ft_results AS (\n SELECT\n e.[entity_id],\n e.[slug],\n e.[entity_type],\n e.[label],\n e.[summary],\n e.[data],\n e.[properties],\n ft.[RANK] AS ft_rank\n FROM (\n SELECT [KEY], [RANK]\n FROM FREETEXTTABLE([${s}].[dm_entities], ([label], [summary], [data], [properties]), @Query)\n WHERE @UseContains = 0\n UNION ALL\n SELECT [KEY], [RANK]\n FROM CONTAINSTABLE([${s}].[dm_entities], ([label], [summary], [data], [properties]), @Query)\n WHERE @UseContains = 1\n ) AS ft\n INNER JOIN [${s}].[dm_entities] e ON e.[ft_key] = ft.[KEY]\n WHERE e.[repository_id] = @RepositoryId\n AND (@HasTypeFilter = 0 OR e.[entity_type] IN (SELECT [type_name] FROM #entity_types))\n ),\n -- Count total matching rows before pagination\n ft_counted AS (\n SELECT *, COUNT(*) OVER () AS total_count FROM ft_results\n )\n SELECT\n [entity_id],\n [slug],\n [entity_type],\n [label],\n [summary],\n [data],\n [properties],\n [ft_rank],\n [total_count],\n -- Highlight snippets: return the first 200 chars of each matched field\n -- (the application layer will do finer-grained highlighting using the query terms)\n CASE WHEN FREETEXT([label], @Query) THEN LEFT([label], 200) ELSE NULL END AS [hl_label],\n CASE WHEN FREETEXT([summary], @Query) THEN LEFT(CAST([summary] AS NVARCHAR(200)), 200) ELSE NULL END AS [hl_summary],\n CASE WHEN FREETEXT([data], @Query) THEN LEFT(CAST([data] AS NVARCHAR(200)), 200) ELSE NULL END AS [hl_data],\n CASE WHEN FREETEXT([properties], @Query) THEN LEFT(CAST([properties] AS NVARCHAR(200)), 200) ELSE NULL END AS [hl_properties]\n FROM ft_counted\n ORDER BY [ft_rank] DESC\n OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY;\n\n DROP TABLE #entity_types;\nEND;\n `.trim();\n}\n","// SqlServerSearchProvider — SQL Server full-text search implementation of SearchProvider\n\nimport sql from 'mssql';\nimport type { SearchProvider, SearchableEntity } from '@utaba/deep-memory/providers';\nimport type { SearchOptions } from '@utaba/deep-memory/types';\nimport type { PaginatedResult, SearchHit } from '@utaba/deep-memory/types';\nimport { ProviderError } from '@utaba/deep-memory';\nimport { getSearchProcSQL } from './schema.js';\n\n/** Configuration for SqlServerSearchProvider */\nexport interface SqlServerSearchProviderConfig {\n /** mssql connection pool (should be the same pool used by the StorageProvider) */\n pool: sql.ConnectionPool;\n /** SQL Server schema name (default: 'dbo') */\n schema?: string;\n}\n\n/**\n * Normalize a raw FT rank (typically 0–1000 from FREETEXTTABLE) into a 0–1 score.\n * Clamps to [0, 1] to handle edge cases.\n */\nfunction normalizeRank(rank: number): number {\n return Math.min(1, Math.max(0, rank / 1000));\n}\n\n/**\n * Build highlight snippets from the stored-procedure output.\n * For each field that matched, extract a window around the first occurrence\n * of any query term and return it.\n */\nfunction buildHighlights(\n query: string,\n row: Record<string, unknown>,\n): Record<string, string[]> | undefined {\n const highlights: Record<string, string[]> = {};\n const terms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 0);\n\n const fields: Array<{ key: string; hlCol: string }> = [\n { key: 'label', hlCol: 'hl_label' },\n { key: 'summary', hlCol: 'hl_summary' },\n { key: 'data', hlCol: 'hl_data' },\n { key: 'properties', hlCol: 'hl_properties' },\n ];\n\n for (const { key, hlCol } of fields) {\n const snippet = row[hlCol] as string | null;\n if (!snippet) continue;\n\n // Find the best window around a matched term\n const lowerSnippet = snippet.toLowerCase();\n for (const term of terms) {\n const idx = lowerSnippet.indexOf(term);\n if (idx !== -1) {\n const windowStart = Math.max(0, idx - 40);\n const windowEnd = Math.min(snippet.length, idx + term.length + 40);\n const prefix = windowStart > 0 ? '...' : '';\n const suffix = windowEnd < snippet.length ? '...' : '';\n const window = prefix + snippet.slice(windowStart, windowEnd) + suffix;\n if (!highlights[key]) highlights[key] = [];\n highlights[key].push(window);\n break; // one snippet per field\n }\n }\n }\n\n return Object.keys(highlights).length > 0 ? highlights : undefined;\n}\n\nexport class SqlServerSearchProvider implements SearchProvider {\n private readonly pool: sql.ConnectionPool;\n private readonly schema: string;\n private procedureCreated = false;\n\n constructor(config: SqlServerSearchProviderConfig) {\n this.pool = config.pool;\n this.schema = config.schema ?? 'dbo';\n }\n\n /**\n * Ensure the stored procedure exists. Called lazily on first search.\n * Idempotent — uses CREATE OR ALTER.\n */\n async ensureProcedure(): Promise<void> {\n if (this.procedureCreated) return;\n try {\n const ddl = getSearchProcSQL(this.schema);\n await this.pool.request().query(ddl);\n this.procedureCreated = true;\n } catch (err) {\n throw new ProviderError(\n `Failed to create search stored procedure: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n /**\n * Index an entity for full-text search.\n *\n * No-op: the FT index on dm_entities uses CHANGE_TRACKING AUTO,\n * so SQL Server automatically indexes rows on insert/update.\n */\n async indexEntity(\n _repositoryId: string,\n _entity: SearchableEntity,\n ): Promise<void> {\n // Auto-maintained by SQL Server FT change tracking\n }\n\n /**\n * Remove an entity from the search index.\n *\n * No-op: the FT index auto-removes when the row is deleted from dm_entities.\n */\n async removeEntity(\n _repositoryId: string,\n _entityId: string,\n ): Promise<void> {\n // Auto-maintained by SQL Server FT change tracking\n }\n\n /**\n * Full-text search across entity labels, summaries, properties, and data.\n * Calls the dm_search_entities stored procedure using FREETEXTTABLE\n * for natural-language queries.\n */\n async search(\n repositoryId: string,\n query: string,\n options?: SearchOptions,\n ): Promise<PaginatedResult<SearchHit>> {\n await this.ensureProcedure();\n\n const limit = options?.limit ?? 20;\n const offset = options?.offset ?? 0;\n const entityTypes = options?.entityTypes;\n\n try {\n const request = this.pool.request();\n request.input('RepositoryId', sql.UniqueIdentifier, repositoryId);\n request.input('Query', sql.NVarChar(4000), query);\n request.input(\n 'EntityTypes',\n sql.NVarChar(sql.MAX),\n entityTypes && entityTypes.length > 0\n ? JSON.stringify(entityTypes)\n : null,\n );\n request.input('Limit', sql.Int, limit);\n request.input('Offset', sql.Int, offset);\n request.input('UseContains', sql.Bit, 0); // FREETEXTTABLE for natural language\n\n const result = await request.execute(\n `[${this.schema}].[dm_search_entities]`,\n );\n\n const rows = result.recordset as Array<Record<string, unknown>>;\n\n const total =\n rows.length > 0 ? (rows[0]!['total_count'] as number) : 0;\n\n const items: SearchHit[] = rows.map((row) => ({\n id: row['entity_id'] as string,\n score: normalizeRank(row['ft_rank'] as number),\n highlights: buildHighlights(query, row),\n }));\n\n return {\n items,\n total,\n hasMore: offset + items.length < total,\n limit,\n offset,\n };\n } catch (err) {\n throw new ProviderError(\n `Full-text search failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n /**\n * Re-index an entire repository.\n *\n * Since the FT index is auto-maintained, this triggers a manual\n * population of the full-text catalog to pick up any pending changes.\n */\n async reindexRepository(\n _repositoryId: string,\n _entities: AsyncIterable<SearchableEntity>,\n ): Promise<void> {\n try {\n await this.pool\n .request()\n .query(\n `ALTER FULLTEXT CATALOG [dm_fulltext_catalog] REORGANIZE`,\n );\n } catch (err) {\n throw new ProviderError(\n `Full-text reindex failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":["sql","ProviderError","ProviderError","sql"]}