@utaba/deep-memory-storage-sqlserver 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- import sql from 'mssql';
2
- import { StorageProvider, SearchProvider, SearchableEntity } from '@utaba/deep-memory/providers';
1
+ import * as _utaba_deep_memory_types from '@utaba/deep-memory/types';
3
2
  import { StorageRepositoryConfig, StoredRepository, RepositoryFilter, PaginatedResult, StoredRepositorySummary, RepositoryUpdate, RepositoryStats, MemoryVocabulary, PaginationOptions, VocabularyChangeRecord, StoredEntity, StoredEntityUpdate, StorageFindQuery, StoredRelationship, RelationshipQueryOptions, StorageExploreOptions, StorageNeighbourhood, StoragePathOptions, StoragePathResult, StorageTimelineOptions, StorageTimelineResult, ExportChunk, ImportChunk, BulkImportResult, SearchOptions, SearchHit } from '@utaba/deep-memory/types';
3
+ import sql from 'mssql';
4
+ import { StorageProvider, EnsureSchemaResult, SearchProvider, SearchableEntity } from '@utaba/deep-memory/providers';
4
5
 
5
6
  /** Configuration for SqlServerStorageProvider */
6
7
  interface SqlServerStorageProviderConfig {
@@ -19,12 +20,24 @@ declare class SqlServerStorageProvider implements StorageProvider {
19
20
  private getPool;
20
21
  initialise(): Promise<void>;
21
22
  dispose(): Promise<void>;
22
- ensureSchema(): Promise<void>;
23
+ /**
24
+ * Ensure the target database exists. If constructed with a sql.config and the
25
+ * database does not yet exist, creates it via a temporary connection to master,
26
+ * then (re)connects the main pool to the newly created database.
27
+ *
28
+ * @returns true if the database was created, false if it already existed.
29
+ */
30
+ private ensureDatabase;
31
+ ensureSchema(): Promise<EnsureSchemaResult>;
23
32
  createRepository(config: StorageRepositoryConfig): Promise<StoredRepository>;
24
33
  getRepository(repositoryId: string): Promise<StoredRepository | null>;
25
34
  listRepositories(filter?: RepositoryFilter): Promise<PaginatedResult<StoredRepositorySummary>>;
26
35
  updateRepository(repositoryId: string, updates: RepositoryUpdate): Promise<StoredRepository>;
27
- deleteRepository(repositoryId: string): Promise<void>;
36
+ deleteRepository(repositoryId: string, _onProgress?: _utaba_deep_memory_types.DeleteProgressCallback): Promise<void>;
37
+ deleteAllContents(repositoryId: string, _onProgress?: _utaba_deep_memory_types.DeleteProgressCallback): Promise<{
38
+ deletedEntities: number;
39
+ deletedRelationships: number;
40
+ }>;
28
41
  getRepositoryStats(repositoryId: string): Promise<RepositoryStats>;
29
42
  getVocabulary(repositoryId: string): Promise<MemoryVocabulary>;
30
43
  saveVocabulary(repositoryId: string, vocabulary: MemoryVocabulary): Promise<void>;
@@ -56,7 +69,7 @@ declare class SqlServerStorageProvider implements StorageProvider {
56
69
  findPaths(repositoryId: string, sourceId: string, targetId: string, options: StoragePathOptions): Promise<StoragePathResult>;
57
70
  getTimeline(repositoryId: string, entityId: string, options: StorageTimelineOptions): Promise<StorageTimelineResult>;
58
71
  exportAll(repositoryId: string): AsyncIterable<ExportChunk>;
59
- importBulk(repositoryId: string, data: ImportChunk[]): Promise<BulkImportResult>;
72
+ importBulk(repositoryId: string, data: ImportChunk[], _options?: _utaba_deep_memory_types.BulkImportOptions): Promise<BulkImportResult>;
60
73
  /** Creates a TVP table from an array of string IDs (eliminates plan cache bloat from IN clauses). */
61
74
  private createIdListTvp;
62
75
  /** Returns a StoredEntity without the embedding column (lighter I/O). */
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import sql from 'mssql';
2
- import { StorageProvider, SearchProvider, SearchableEntity } from '@utaba/deep-memory/providers';
1
+ import * as _utaba_deep_memory_types from '@utaba/deep-memory/types';
3
2
  import { StorageRepositoryConfig, StoredRepository, RepositoryFilter, PaginatedResult, StoredRepositorySummary, RepositoryUpdate, RepositoryStats, MemoryVocabulary, PaginationOptions, VocabularyChangeRecord, StoredEntity, StoredEntityUpdate, StorageFindQuery, StoredRelationship, RelationshipQueryOptions, StorageExploreOptions, StorageNeighbourhood, StoragePathOptions, StoragePathResult, StorageTimelineOptions, StorageTimelineResult, ExportChunk, ImportChunk, BulkImportResult, SearchOptions, SearchHit } from '@utaba/deep-memory/types';
3
+ import sql from 'mssql';
4
+ import { StorageProvider, EnsureSchemaResult, SearchProvider, SearchableEntity } from '@utaba/deep-memory/providers';
4
5
 
5
6
  /** Configuration for SqlServerStorageProvider */
6
7
  interface SqlServerStorageProviderConfig {
@@ -19,12 +20,24 @@ declare class SqlServerStorageProvider implements StorageProvider {
19
20
  private getPool;
20
21
  initialise(): Promise<void>;
21
22
  dispose(): Promise<void>;
22
- ensureSchema(): Promise<void>;
23
+ /**
24
+ * Ensure the target database exists. If constructed with a sql.config and the
25
+ * database does not yet exist, creates it via a temporary connection to master,
26
+ * then (re)connects the main pool to the newly created database.
27
+ *
28
+ * @returns true if the database was created, false if it already existed.
29
+ */
30
+ private ensureDatabase;
31
+ ensureSchema(): Promise<EnsureSchemaResult>;
23
32
  createRepository(config: StorageRepositoryConfig): Promise<StoredRepository>;
24
33
  getRepository(repositoryId: string): Promise<StoredRepository | null>;
25
34
  listRepositories(filter?: RepositoryFilter): Promise<PaginatedResult<StoredRepositorySummary>>;
26
35
  updateRepository(repositoryId: string, updates: RepositoryUpdate): Promise<StoredRepository>;
27
- deleteRepository(repositoryId: string): Promise<void>;
36
+ deleteRepository(repositoryId: string, _onProgress?: _utaba_deep_memory_types.DeleteProgressCallback): Promise<void>;
37
+ deleteAllContents(repositoryId: string, _onProgress?: _utaba_deep_memory_types.DeleteProgressCallback): Promise<{
38
+ deletedEntities: number;
39
+ deletedRelationships: number;
40
+ }>;
28
41
  getRepositoryStats(repositoryId: string): Promise<RepositoryStats>;
29
42
  getVocabulary(repositoryId: string): Promise<MemoryVocabulary>;
30
43
  saveVocabulary(repositoryId: string, vocabulary: MemoryVocabulary): Promise<void>;
@@ -56,7 +69,7 @@ declare class SqlServerStorageProvider implements StorageProvider {
56
69
  findPaths(repositoryId: string, sourceId: string, targetId: string, options: StoragePathOptions): Promise<StoragePathResult>;
57
70
  getTimeline(repositoryId: string, entityId: string, options: StorageTimelineOptions): Promise<StorageTimelineResult>;
58
71
  exportAll(repositoryId: string): AsyncIterable<ExportChunk>;
59
- importBulk(repositoryId: string, data: ImportChunk[]): Promise<BulkImportResult>;
72
+ importBulk(repositoryId: string, data: ImportChunk[], _options?: _utaba_deep_memory_types.BulkImportOptions): Promise<BulkImportResult>;
60
73
  /** Creates a TVP table from an array of string IDs (eliminates plan cache bloat from IN clauses). */
61
74
  private createIdListTvp;
62
75
  /** Returns a StoredEntity without the embedding column (lighter I/O). */
package/dist/index.js CHANGED
@@ -431,7 +431,51 @@ var SqlServerStorageProvider = class {
431
431
  }
432
432
  this.pool = null;
433
433
  }
434
+ /**
435
+ * Ensure the target database exists. If constructed with a sql.config and the
436
+ * database does not yet exist, creates it via a temporary connection to master,
437
+ * then (re)connects the main pool to the newly created database.
438
+ *
439
+ * @returns true if the database was created, false if it already existed.
440
+ */
441
+ async ensureDatabase() {
442
+ if (this.config.connection instanceof sql.ConnectionPool) {
443
+ return false;
444
+ }
445
+ const cfg = this.config.connection;
446
+ const dbName = cfg.database;
447
+ if (!dbName) {
448
+ return false;
449
+ }
450
+ let created = false;
451
+ const masterPool = new sql.ConnectionPool({ ...cfg, database: "master" });
452
+ try {
453
+ await masterPool.connect();
454
+ const result = await masterPool.request().input("dbName", sql.NVarChar, dbName).query(
455
+ `SELECT COUNT(*) AS cnt FROM sys.databases WHERE name = @dbName`
456
+ );
457
+ const exists = (result.recordset[0]?.cnt ?? 0) > 0;
458
+ if (!exists) {
459
+ if (!/^[A-Za-z0-9_-]+$/.test(dbName)) {
460
+ throw new ProviderError(
461
+ `Invalid database name '${dbName}'. Only alphanumeric characters, hyphens, and underscores are allowed.`
462
+ );
463
+ }
464
+ await masterPool.request().query(`CREATE DATABASE [${dbName}]`);
465
+ created = true;
466
+ }
467
+ } finally {
468
+ await masterPool.close();
469
+ }
470
+ if (!this.pool || !this.pool.connected) {
471
+ this.pool = new sql.ConnectionPool(cfg);
472
+ this.ownsPool = true;
473
+ await this.pool.connect();
474
+ }
475
+ return created;
476
+ }
434
477
  async ensureSchema() {
478
+ const databaseCreated = await this.ensureDatabase();
435
479
  const pool = this.getPool();
436
480
  const metaCheck = await pool.request().query(
437
481
  `SELECT COUNT(*) AS cnt FROM sys.tables WHERE name = 'dm_meta' AND schema_id = SCHEMA_ID('${this.schema}')`
@@ -448,7 +492,12 @@ var SqlServerStorageProvider = class {
448
492
  );
449
493
  }
450
494
  if (currentVersion === SCHEMA_VERSION) {
451
- return;
495
+ return {
496
+ databaseCreated,
497
+ schemaCreated: false,
498
+ alreadyUpToDate: !databaseCreated,
499
+ schemaVersion: SCHEMA_VERSION
500
+ };
452
501
  }
453
502
  }
454
503
  const ddl = getSchemaSQL(this.schema);
@@ -463,6 +512,12 @@ var SqlServerStorageProvider = class {
463
512
  }
464
513
  }
465
514
  }
515
+ return {
516
+ databaseCreated,
517
+ schemaCreated: true,
518
+ alreadyUpToDate: false,
519
+ schemaVersion: SCHEMA_VERSION
520
+ };
466
521
  }
467
522
  // ─── Repository ──────────────────────────────────────────────────
468
523
  async createRepository(config) {
@@ -612,13 +667,23 @@ var SqlServerStorageProvider = class {
612
667
  if (!updated) throw new RepositoryNotFoundError(repositoryId);
613
668
  return updated;
614
669
  }
615
- async deleteRepository(repositoryId) {
670
+ async deleteRepository(repositoryId, _onProgress) {
616
671
  const pool = this.getPool();
617
672
  const result = await pool.request().input("id", sql.UniqueIdentifier, repositoryId).query(`DELETE FROM ${this.t("dm_repositories")} WHERE [repository_id] = @id`);
618
673
  if (result.rowsAffected[0] === 0) {
619
674
  throw new RepositoryNotFoundError(repositoryId);
620
675
  }
621
676
  }
677
+ async deleteAllContents(repositoryId, _onProgress) {
678
+ await this.assertRepository(repositoryId);
679
+ const pool = this.getPool();
680
+ const relResult = await pool.request().input("id", sql.UniqueIdentifier, repositoryId).query(`DELETE FROM ${this.t("dm_relationships")} WHERE [repository_id] = @id`);
681
+ const entityResult = await pool.request().input("id", sql.UniqueIdentifier, repositoryId).query(`DELETE FROM ${this.t("dm_entities")} WHERE [repository_id] = @id`);
682
+ return {
683
+ deletedEntities: entityResult.rowsAffected[0] ?? 0,
684
+ deletedRelationships: relResult.rowsAffected[0] ?? 0
685
+ };
686
+ }
622
687
  async getRepositoryStats(repositoryId) {
623
688
  await this.assertRepository(repositoryId);
624
689
  const pool = this.getPool();
@@ -1308,7 +1373,7 @@ var SqlServerStorageProvider = class {
1308
1373
  }
1309
1374
  }
1310
1375
  }
1311
- async importBulk(repositoryId, data) {
1376
+ async importBulk(repositoryId, data, _options) {
1312
1377
  await this.assertRepository(repositoryId);
1313
1378
  const pool = this.getPool();
1314
1379
  let entitiesImported = 0;