@utaba/deep-memory 0.2.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/{StorageProvider-DR9HLYHJ.d.ts → StorageProvider-CSbaIY6X.d.cts} +8 -3
- package/dist/{StorageProvider-C3tKhfuw.d.cts → StorageProvider-DqW-zpd0.d.ts} +8 -3
- package/dist/index.cjs +324 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -8
- package/dist/index.d.ts +27 -8
- package/dist/index.js +324 -50
- package/dist/index.js.map +1 -1
- package/dist/{portability-DdjsCB07.d.cts → portability-1KBMVBGJ.d.cts} +19 -1
- package/dist/{portability-DdjsCB07.d.ts → portability-1KBMVBGJ.d.ts} +19 -1
- package/dist/providers/index.d.cts +9 -3
- package/dist/providers/index.d.ts +9 -3
- package/dist/testing/conformance.cjs +22 -0
- package/dist/testing/conformance.cjs.map +1 -1
- package/dist/testing/conformance.d.cts +2 -2
- package/dist/testing/conformance.d.ts +2 -2
- package/dist/testing/conformance.js +22 -0
- package/dist/testing/conformance.js.map +1 -1
- package/dist/{traversal-9JdiqjZ9.d.ts → traversal-B4SUysM-.d.ts} +98 -11
- package/dist/{traversal-BB_yERbf.d.cts → traversal-DQynd-to.d.cts} +98 -11
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +28 -4
- package/dist/types/index.d.ts +28 -4
- package/package.json +1 -1
|
@@ -911,6 +911,24 @@ interface ImportChunk {
|
|
|
911
911
|
entities?: StoredEntity[];
|
|
912
912
|
relationships?: StoredRelationship[];
|
|
913
913
|
}
|
|
914
|
+
/** Options for bulk import operations at the storage provider level */
|
|
915
|
+
interface BulkImportOptions {
|
|
916
|
+
/**
|
|
917
|
+
* Skip existence checks before inserting.
|
|
918
|
+
* When true, the provider assumes items do not already exist and uses direct
|
|
919
|
+
* inserts instead of upserts. This is safe for freshly created repositories
|
|
920
|
+
* and significantly faster for providers that must otherwise check each item.
|
|
921
|
+
* Default: false (upsert behavior — check existence, then create or update).
|
|
922
|
+
*/
|
|
923
|
+
skipExistenceCheck?: boolean;
|
|
924
|
+
}
|
|
925
|
+
/** Progress callback for delete operations */
|
|
926
|
+
type DeleteProgressCallback = (progress: {
|
|
927
|
+
entitiesDeleted: number;
|
|
928
|
+
relationshipsDeleted: number;
|
|
929
|
+
totalEntities: number;
|
|
930
|
+
totalRelationships: number;
|
|
931
|
+
}) => void | Promise<void>;
|
|
914
932
|
/** Header for streaming import — sent before data chunks */
|
|
915
933
|
interface ImportStreamHeader {
|
|
916
934
|
manifest: ExportManifest;
|
|
@@ -937,4 +955,4 @@ interface ImportResult {
|
|
|
937
955
|
warnings: ImportWarning[];
|
|
938
956
|
}
|
|
939
957
|
|
|
940
|
-
export type {
|
|
958
|
+
export type { TimelineResult as $, VocabularyProposal as A, BulkImportOptions as B, CreateEntityInput as C, DetailLevel as D, Entity as E, VocabularyProposalResult as F, GovernanceConfig as G, ProvenanceContext as H, ImportChunk as I, Provenance as J, FindEntitiesQuery as K, ReembedResult as L, MemoryVocabulary as M, Relationship as N, GraphResult as O, PropertyFilter as P, ExploreOptions as Q, RelationshipSummary as R, StorageRepositoryConfig as S, Neighbourhood as T, UpdateEntityInput as U, VocabularyChangeRecord as V, PathOptions as W, PathResult as X, ConceptSearchOptions as Y, ScoredEntity as Z, TimelineOptions as _, EntitySummary as a, RepositoryConfig as a0, RepositorySummary as a1, ExportOptions as a2, ExportArchive as a3, ImportOptions as a4, ImportResult as a5, ExportStreamItem as a6, ImportStreamHeader as a7, SearchOptions as a8, SearchHit as a9, TimelineEvent as aA, TimelineRelationshipDetail as aB, VocabularyInput as aC, EnrichedRelationship as aa, EntityMap as ab, EntityTypeInput as ac, ExportLegalMetadata as ad, ExportManifest as ae, ExportPipelineMetadata as af, GetEntitiesOptions as ag, GetEntityOptions as ah, GovernanceMode as ai, ImportWarning as aj, NeighbourhoodCentre as ak, NeighbourhoodGroup as al, NeighbourhoodLayer as am, Path as an, PropertySchema as ao, PropertyType as ap, ProvenanceFilter as aq, RelationshipDirection as ar, RelationshipTypeDefinition as as, RelationshipTypeInput as at, RepositoryMetadata as au, StorageNeighbourhoodGroup as av, StorageNeighbourhoodLayer as aw, StoragePath as ax, StorageTimelineEvent as ay, TimelineEntityRef as az, EntityBrief as b, StoredRepository as c, RepositoryFilter as d, PaginatedResult as e, StoredRepositorySummary as f, RepositoryUpdate as g, DeleteProgressCallback as h, RepositoryStats as i, PaginationOptions as j, StoredEntity as k, StoredEntityUpdate as l, StorageFindQuery as m, StoredRelationship as n, RelationshipQueryOptions as o, StorageExploreOptions as p, StorageNeighbourhood as q, StoragePathOptions as r, StoragePathResult as s, StorageTimelineOptions as t, StorageTimelineResult as u, ExportChunk as v, BulkImportResult as w, ResolvedVocabulary as x, CreateRelationshipInput as y, EntityTypeDefinition as z };
|
|
@@ -911,6 +911,24 @@ interface ImportChunk {
|
|
|
911
911
|
entities?: StoredEntity[];
|
|
912
912
|
relationships?: StoredRelationship[];
|
|
913
913
|
}
|
|
914
|
+
/** Options for bulk import operations at the storage provider level */
|
|
915
|
+
interface BulkImportOptions {
|
|
916
|
+
/**
|
|
917
|
+
* Skip existence checks before inserting.
|
|
918
|
+
* When true, the provider assumes items do not already exist and uses direct
|
|
919
|
+
* inserts instead of upserts. This is safe for freshly created repositories
|
|
920
|
+
* and significantly faster for providers that must otherwise check each item.
|
|
921
|
+
* Default: false (upsert behavior — check existence, then create or update).
|
|
922
|
+
*/
|
|
923
|
+
skipExistenceCheck?: boolean;
|
|
924
|
+
}
|
|
925
|
+
/** Progress callback for delete operations */
|
|
926
|
+
type DeleteProgressCallback = (progress: {
|
|
927
|
+
entitiesDeleted: number;
|
|
928
|
+
relationshipsDeleted: number;
|
|
929
|
+
totalEntities: number;
|
|
930
|
+
totalRelationships: number;
|
|
931
|
+
}) => void | Promise<void>;
|
|
914
932
|
/** Header for streaming import — sent before data chunks */
|
|
915
933
|
interface ImportStreamHeader {
|
|
916
934
|
manifest: ExportManifest;
|
|
@@ -937,4 +955,4 @@ interface ImportResult {
|
|
|
937
955
|
warnings: ImportWarning[];
|
|
938
956
|
}
|
|
939
957
|
|
|
940
|
-
export type {
|
|
958
|
+
export type { TimelineResult as $, VocabularyProposal as A, BulkImportOptions as B, CreateEntityInput as C, DetailLevel as D, Entity as E, VocabularyProposalResult as F, GovernanceConfig as G, ProvenanceContext as H, ImportChunk as I, Provenance as J, FindEntitiesQuery as K, ReembedResult as L, MemoryVocabulary as M, Relationship as N, GraphResult as O, PropertyFilter as P, ExploreOptions as Q, RelationshipSummary as R, StorageRepositoryConfig as S, Neighbourhood as T, UpdateEntityInput as U, VocabularyChangeRecord as V, PathOptions as W, PathResult as X, ConceptSearchOptions as Y, ScoredEntity as Z, TimelineOptions as _, EntitySummary as a, RepositoryConfig as a0, RepositorySummary as a1, ExportOptions as a2, ExportArchive as a3, ImportOptions as a4, ImportResult as a5, ExportStreamItem as a6, ImportStreamHeader as a7, SearchOptions as a8, SearchHit as a9, TimelineEvent as aA, TimelineRelationshipDetail as aB, VocabularyInput as aC, EnrichedRelationship as aa, EntityMap as ab, EntityTypeInput as ac, ExportLegalMetadata as ad, ExportManifest as ae, ExportPipelineMetadata as af, GetEntitiesOptions as ag, GetEntityOptions as ah, GovernanceMode as ai, ImportWarning as aj, NeighbourhoodCentre as ak, NeighbourhoodGroup as al, NeighbourhoodLayer as am, Path as an, PropertySchema as ao, PropertyType as ap, ProvenanceFilter as aq, RelationshipDirection as ar, RelationshipTypeDefinition as as, RelationshipTypeInput as at, RepositoryMetadata as au, StorageNeighbourhoodGroup as av, StorageNeighbourhoodLayer as aw, StoragePath as ax, StorageTimelineEvent as ay, TimelineEntityRef as az, EntityBrief as b, StoredRepository as c, RepositoryFilter as d, PaginatedResult as e, StoredRepositorySummary as f, RepositoryUpdate as g, DeleteProgressCallback as h, RepositoryStats as i, PaginationOptions as j, StoredEntity as k, StoredEntityUpdate as l, StorageFindQuery as m, StoredRelationship as n, RelationshipQueryOptions as o, StorageExploreOptions as p, StorageNeighbourhood as q, StoragePathOptions as r, StoragePathResult as s, StorageTimelineOptions as t, StorageTimelineResult as u, ExportChunk as v, BulkImportResult as w, ResolvedVocabulary as x, CreateRelationshipInput as y, EntityTypeDefinition as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { E as EnsureSchemaResult, S as StorageProvider } from '../StorageProvider-
|
|
2
|
-
import {
|
|
3
|
-
import { T as TraversalSpec, a as TraversalResult } from '../traversal-
|
|
1
|
+
export { E as EnsureSchemaResult, S as StorageProvider } from '../StorageProvider-CSbaIY6X.cjs';
|
|
2
|
+
import { a8 as SearchOptions, e as PaginatedResult, a9 as SearchHit } from '../portability-1KBMVBGJ.cjs';
|
|
3
|
+
import { T as TraversalSpec, a as TraversalResult } from '../traversal-DQynd-to.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* EmbeddingProvider — enables semantic search and vocabulary deduplication.
|
|
@@ -123,6 +123,12 @@ interface GraphTraversalCapabilities {
|
|
|
123
123
|
supportsRepeat: boolean;
|
|
124
124
|
/** Whether the provider supports dedup across traversal results. */
|
|
125
125
|
supportsDedup: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Whether the provider can return relationship summaries (outbound/inbound
|
|
128
|
+
* counts by type) natively in a single traversal query.
|
|
129
|
+
* When false, the library falls back to a batch fetch + local computation.
|
|
130
|
+
*/
|
|
131
|
+
supportsRelationshipSummary: boolean;
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
export type { EmbeddingProvider, GraphTraversalCapabilities, GraphTraversalProvider, LockHandle, LockOptions, LockProvider, SearchProvider, SearchableEntity };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { E as EnsureSchemaResult, S as StorageProvider } from '../StorageProvider-
|
|
2
|
-
import {
|
|
3
|
-
import { T as TraversalSpec, a as TraversalResult } from '../traversal-
|
|
1
|
+
export { E as EnsureSchemaResult, S as StorageProvider } from '../StorageProvider-DqW-zpd0.js';
|
|
2
|
+
import { a8 as SearchOptions, e as PaginatedResult, a9 as SearchHit } from '../portability-1KBMVBGJ.js';
|
|
3
|
+
import { T as TraversalSpec, a as TraversalResult } from '../traversal-B4SUysM-.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* EmbeddingProvider — enables semantic search and vocabulary deduplication.
|
|
@@ -123,6 +123,12 @@ interface GraphTraversalCapabilities {
|
|
|
123
123
|
supportsRepeat: boolean;
|
|
124
124
|
/** Whether the provider supports dedup across traversal results. */
|
|
125
125
|
supportsDedup: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Whether the provider can return relationship summaries (outbound/inbound
|
|
128
|
+
* counts by type) natively in a single traversal query.
|
|
129
|
+
* When false, the library falls back to a batch fetch + local computation.
|
|
130
|
+
*/
|
|
131
|
+
supportsRelationshipSummary: boolean;
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
export type { EmbeddingProvider, GraphTraversalCapabilities, GraphTraversalProvider, LockHandle, LockOptions, LockProvider, SearchProvider, SearchableEntity };
|
|
@@ -334,6 +334,28 @@ function runStorageProviderConformanceTests(factory) {
|
|
|
334
334
|
(0, import_vitest.expect)(e).not.toBeNull();
|
|
335
335
|
});
|
|
336
336
|
});
|
|
337
|
+
(0, import_vitest.describe)("deleteAllContents", () => {
|
|
338
|
+
(0, import_vitest.it)("deletes all entities and relationships but preserves the repository", async () => {
|
|
339
|
+
await provider.createEntity(repoId, makeEntity("e1", "alpha"));
|
|
340
|
+
await provider.createEntity(repoId, makeEntity("e2", "beta"));
|
|
341
|
+
await provider.createRelationship(repoId, makeRelationship("r1", "links", "e1", "e2"));
|
|
342
|
+
const result = await provider.deleteAllContents(repoId);
|
|
343
|
+
(0, import_vitest.expect)(result.deletedEntities).toBe(2);
|
|
344
|
+
(0, import_vitest.expect)(result.deletedRelationships).toBe(1);
|
|
345
|
+
const repo = await provider.getRepository(repoId);
|
|
346
|
+
(0, import_vitest.expect)(repo).not.toBeNull();
|
|
347
|
+
const vocab = await provider.getVocabulary(repoId);
|
|
348
|
+
(0, import_vitest.expect)(vocab).toBeDefined();
|
|
349
|
+
const stats = await provider.getRepositoryStats(repoId);
|
|
350
|
+
(0, import_vitest.expect)(stats.entityCount).toBe(0);
|
|
351
|
+
(0, import_vitest.expect)(stats.relationshipCount).toBe(0);
|
|
352
|
+
});
|
|
353
|
+
(0, import_vitest.it)("returns zero counts on an empty repository", async () => {
|
|
354
|
+
const result = await provider.deleteAllContents(repoId);
|
|
355
|
+
(0, import_vitest.expect)(result.deletedEntities).toBe(0);
|
|
356
|
+
(0, import_vitest.expect)(result.deletedRelationships).toBe(0);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
337
359
|
(0, import_vitest.describe)("stats reflect data", () => {
|
|
338
360
|
(0, import_vitest.it)("counts entities and relationships", async () => {
|
|
339
361
|
await provider.createEntity(repoId, makeEntity("e1", "alpha"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers-builtin/conformance.ts"],"sourcesContent":["// Provider Conformance Test Suite\n// Any StorageProvider implementer can import and run these tests to verify conformance.\n//\n// Usage:\n// import { runStorageProviderConformanceTests } from '@utaba/deep-memory';\n// runStorageProviderConformanceTests(() => new MyStorageProvider());\n\nimport { describe, it, expect, beforeEach } from 'vitest';\nimport type { StorageProvider } from '../providers/StorageProvider.js';\nimport type { StoredEntity } from '../types/entities.js';\nimport type { StoredRelationship } from '../types/relationships.js';\nimport type { Provenance } from '../types/provenance.js';\n\nfunction makeProvenance(): Provenance {\n const now = new Date().toISOString();\n return {\n createdBy: 'conformance-test',\n createdByType: 'agent',\n createdAt: now,\n modifiedBy: 'conformance-test',\n modifiedByType: 'agent',\n modifiedAt: now,\n };\n}\n\nfunction makeEntity(id: string, type = 'test-type', label?: string): StoredEntity {\n return {\n id,\n slug: `${type}:${(label ?? id).toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n entityType: type,\n label: label ?? id,\n summary: `Summary for ${id}`,\n properties: { key: 'value' },\n provenance: makeProvenance(),\n };\n}\n\nfunction makeRelationship(\n id: string,\n type: string,\n sourceId: string,\n targetId: string,\n bidirectional = false,\n): StoredRelationship {\n return {\n id,\n relationshipType: type,\n sourceEntityId: sourceId,\n targetEntityId: targetId,\n properties: {},\n bidirectional,\n provenance: makeProvenance(),\n };\n}\n\n/**\n * Run the full StorageProvider conformance test suite.\n *\n * @param factory - A function that creates a fresh, empty StorageProvider instance.\n * Called before each test to ensure isolation.\n */\nexport function runStorageProviderConformanceTests(\n factory: () => StorageProvider | Promise<StorageProvider>,\n): void {\n // Use a stable GUID so external cleanup scripts can target it\n const repoId = '40000000-0000-4000-a000-000000000001';\n\n let provider: StorageProvider;\n\n async function setup(): Promise<void> {\n provider = await factory();\n if (provider.initialise) await provider.initialise();\n\n await provider.createRepository({\n repositoryId: repoId,\n label: 'Conformance Test',\n governanceConfig: { mode: 'open' },\n createdAt: new Date().toISOString(),\n createdBy: 'conformance-test',\n });\n }\n\n describe('StorageProvider Conformance Tests', () => {\n beforeEach(async () => {\n await setup();\n });\n\n // ─── Repository ─────────────────────────────────────────\n\n describe('repository operations', () => {\n it('creates a repository', async () => {\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n expect(repo!.repositoryId).toBe(repoId);\n expect(repo!.label).toBe('Conformance Test');\n });\n\n it('returns null for non-existent repository', async () => {\n const repo = await provider.getRepository('ffffffff-ffff-4fff-afff-ffffffffffff');\n expect(repo).toBeNull();\n });\n\n it('lists repositories', async () => {\n const list = await provider.listRepositories();\n expect(list.items.length).toBeGreaterThanOrEqual(1);\n expect(list.items.some((r) => r.repositoryId === repoId)).toBe(true);\n });\n\n it('updates a repository', async () => {\n const updated = await provider.updateRepository(repoId, {\n label: 'Updated Label',\n description: 'Updated description',\n governanceConfig: { mode: 'open', defaultSimilarityThreshold: 0.4 },\n });\n expect(updated.label).toBe('Updated Label');\n expect(updated.description).toBe('Updated description');\n expect(updated.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n\n // Verify persistence\n const fetched = await provider.getRepository(repoId);\n expect(fetched!.label).toBe('Updated Label');\n expect(fetched!.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n });\n\n it('deletes a repository', async () => {\n await provider.deleteRepository(repoId);\n expect(await provider.getRepository(repoId)).toBeNull();\n });\n\n it('returns repository stats', async () => {\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n expect(typeof stats.vocabularyVersion).toBe('string');\n });\n });\n\n // ─── Vocabulary ─────────────────────────────────────────\n\n describe('vocabulary operations', () => {\n it('gets and saves vocabulary', async () => {\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n expect(typeof vocab.version).toBe('string');\n\n const updated = { ...vocab, version: '1.0.0' };\n await provider.saveVocabulary(repoId, updated);\n\n const fetched = await provider.getVocabulary(repoId);\n expect(fetched.version).toBe('1.0.0');\n });\n\n it('returns vocabulary change log', async () => {\n const log = await provider.getVocabularyChangeLog(repoId);\n expect(Array.isArray(log.items)).toBe(true);\n });\n });\n\n // ─── Entities ───────────────────────────────────────────\n\n describe('entity operations', () => {\n it('creates and retrieves an entity', async () => {\n const entity = makeEntity('e1');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntity(repoId, 'e1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.label).toBe('e1');\n });\n\n it('retrieves an entity by slug', async () => {\n const entity = makeEntity('e1', 'test-type', 'Alpha');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntityBySlug(repoId, entity.slug);\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.slug).toBe(entity.slug);\n });\n\n it('returns null for non-existent entity', async () => {\n const result = await provider.getEntity(repoId, 'nonexistent');\n expect(result).toBeNull();\n });\n\n it('returns null for non-existent slug', async () => {\n const result = await provider.getEntityBySlug(repoId, 'nonexistent:slug');\n expect(result).toBeNull();\n });\n\n it('batch retrieves entities', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n\n const map = await provider.getEntities(repoId, ['e1', 'e2', 'missing']);\n expect(map.size).toBe(2);\n expect(map.has('e1')).toBe(true);\n expect(map.has('e2')).toBe(true);\n expect(map.has('missing')).toBe(false);\n });\n\n it('updates an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const updated = await provider.updateEntity(repoId, 'e1', {\n label: 'Updated Label',\n provenance: makeProvenance(),\n });\n expect(updated.label).toBe('Updated Label');\n\n const fetched = await provider.getEntity(repoId, 'e1');\n expect(fetched!.label).toBe('Updated Label');\n });\n\n it('deletes an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.deleteEntity(repoId, 'e1');\n expect(await provider.getEntity(repoId, 'e1')).toBeNull();\n });\n\n it('finds entities by search term', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'test-type', 'Alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'test-type', 'Beta'));\n\n const result = await provider.findEntities(repoId, {\n searchTerm: 'alpha',\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.label).toBe('Alpha');\n });\n\n it('finds entities by type filter', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'type-a', 'A'));\n await provider.createEntity(repoId, makeEntity('e2', 'type-b', 'B'));\n\n const result = await provider.findEntities(repoId, {\n entityTypes: ['type-a'],\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.entityType).toBe('type-a');\n });\n\n it('paginates find results', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n await provider.createEntity(repoId, makeEntity('e3'));\n\n const page1 = await provider.findEntities(repoId, { limit: 2, offset: 0 });\n expect(page1.items).toHaveLength(2);\n expect(page1.hasMore).toBe(true);\n\n const page2 = await provider.findEntities(repoId, { limit: 2, offset: 2 });\n expect(page2.items).toHaveLength(1);\n expect(page2.hasMore).toBe(false);\n });\n });\n\n // ─── Relationships ──────────────────────────────────────\n\n describe('relationship operations', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a'));\n await provider.createEntity(repoId, makeEntity('b'));\n await provider.createEntity(repoId, makeEntity('c'));\n });\n\n it('creates and retrieves a relationship', async () => {\n const rel = makeRelationship('r1', 'connects', 'a', 'b');\n await provider.createRelationship(repoId, rel);\n\n const retrieved = await provider.getRelationship(repoId, 'r1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.sourceEntityId).toBe('a');\n expect(retrieved!.targetEntityId).toBe('b');\n });\n\n it('returns null for non-existent relationship', async () => {\n expect(await provider.getRelationship(repoId, 'nonexistent')).toBeNull();\n });\n\n it('gets entity relationships', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const result = await provider.getEntityRelationships(repoId, 'a');\n expect(result.items).toHaveLength(2);\n });\n\n it('filters relationships by direction', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const outbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'outbound' });\n expect(outbound.items).toHaveLength(1);\n expect(outbound.items[0]!.targetEntityId).toBe('b');\n\n const inbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'inbound' });\n expect(inbound.items).toHaveLength(1);\n expect(inbound.items[0]!.sourceEntityId).toBe('c');\n });\n\n it('deletes a relationship', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.deleteRelationship(repoId, 'r1');\n expect(await provider.getRelationship(repoId, 'r1')).toBeNull();\n });\n });\n\n // ─── Graph Traversal ────────────────────────────────────\n\n describe('graph traversal', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a', 'node', 'A'));\n await provider.createEntity(repoId, makeEntity('b', 'node', 'B'));\n await provider.createEntity(repoId, makeEntity('c', 'node', 'C'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'links', 'b', 'c'));\n });\n\n it('explores neighbourhood at depth 1', async () => {\n const result = await provider.exploreNeighbourhood(repoId, 'a', {\n depth: 1,\n direction: 'both',\n limitPerType: 10,\n offsetPerType: 0,\n });\n expect(result.centreId).toBe('a');\n expect(result.layers).toHaveLength(1);\n });\n\n it('finds paths between connected entities', async () => {\n const result = await provider.findPaths(repoId, 'a', 'c', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('c');\n });\n\n it('returns empty paths when no connection', async () => {\n await provider.createEntity(repoId, makeEntity('isolated', 'node', 'Isolated'));\n const result = await provider.findPaths(repoId, 'a', 'isolated', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths).toHaveLength(0);\n });\n\n it('finds paths through non-bidirectional inbound edges', async () => {\n // Graph: a → b ← d (both edges are non-bidirectional)\n // Path from a to d should traverse: a →(outbound) b ←(inbound) d\n await provider.createEntity(repoId, makeEntity('d', 'node', 'D'));\n await provider.createRelationship(repoId, makeRelationship('r3', 'links', 'd', 'b'));\n const result = await provider.findPaths(repoId, 'a', 'd', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('d');\n });\n });\n\n // ─── Timeline ───────────────────────────────────────────\n\n describe('timeline', () => {\n it('returns timeline events', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const result = await provider.getTimeline(repoId, 'e1', {\n limit: 10,\n offset: 0,\n });\n expect(result.events.length).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ─── Bulk Operations ────────────────────────────────────\n\n describe('bulk operations', () => {\n it('exports data', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n\n const chunks = [];\n for await (const chunk of provider.exportAll(repoId)) {\n chunks.push(chunk);\n }\n expect(chunks.length).toBeGreaterThanOrEqual(1);\n });\n\n it('imports data', async () => {\n const result = await provider.importBulk(repoId, [\n { entities: [makeEntity('imported-1'), makeEntity('imported-2')] },\n { relationships: [makeRelationship('ir1', 'links', 'imported-1', 'imported-2')] },\n ]);\n expect(result.entitiesImported).toBe(2);\n expect(result.relationshipsImported).toBe(1);\n\n // Verify imported data is accessible\n const e = await provider.getEntity(repoId, 'imported-1');\n expect(e).not.toBeNull();\n });\n });\n\n // ─── Stats after data ───────────────────────────────────\n\n describe('stats reflect data', () => {\n it('counts entities and relationships', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e3', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(3);\n expect(stats.relationshipCount).toBe(1);\n expect(stats.entityTypeBreakdown['alpha']).toBe(2);\n expect(stats.entityTypeBreakdown['beta']).toBe(1);\n expect(stats.relationshipTypeBreakdown['links']).toBe(1);\n });\n });\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/providers-builtin/conformance.ts"],"sourcesContent":["// Provider Conformance Test Suite\n// Any StorageProvider implementer can import and run these tests to verify conformance.\n//\n// Usage:\n// import { runStorageProviderConformanceTests } from '@utaba/deep-memory';\n// runStorageProviderConformanceTests(() => new MyStorageProvider());\n\nimport { describe, it, expect, beforeEach } from 'vitest';\nimport type { StorageProvider } from '../providers/StorageProvider.js';\nimport type { StoredEntity } from '../types/entities.js';\nimport type { StoredRelationship } from '../types/relationships.js';\nimport type { Provenance } from '../types/provenance.js';\n\nfunction makeProvenance(): Provenance {\n const now = new Date().toISOString();\n return {\n createdBy: 'conformance-test',\n createdByType: 'agent',\n createdAt: now,\n modifiedBy: 'conformance-test',\n modifiedByType: 'agent',\n modifiedAt: now,\n };\n}\n\nfunction makeEntity(id: string, type = 'test-type', label?: string): StoredEntity {\n return {\n id,\n slug: `${type}:${(label ?? id).toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n entityType: type,\n label: label ?? id,\n summary: `Summary for ${id}`,\n properties: { key: 'value' },\n provenance: makeProvenance(),\n };\n}\n\nfunction makeRelationship(\n id: string,\n type: string,\n sourceId: string,\n targetId: string,\n bidirectional = false,\n): StoredRelationship {\n return {\n id,\n relationshipType: type,\n sourceEntityId: sourceId,\n targetEntityId: targetId,\n properties: {},\n bidirectional,\n provenance: makeProvenance(),\n };\n}\n\n/**\n * Run the full StorageProvider conformance test suite.\n *\n * @param factory - A function that creates a fresh, empty StorageProvider instance.\n * Called before each test to ensure isolation.\n */\nexport function runStorageProviderConformanceTests(\n factory: () => StorageProvider | Promise<StorageProvider>,\n): void {\n // Use a stable GUID so external cleanup scripts can target it\n const repoId = '40000000-0000-4000-a000-000000000001';\n\n let provider: StorageProvider;\n\n async function setup(): Promise<void> {\n provider = await factory();\n if (provider.initialise) await provider.initialise();\n\n await provider.createRepository({\n repositoryId: repoId,\n label: 'Conformance Test',\n governanceConfig: { mode: 'open' },\n createdAt: new Date().toISOString(),\n createdBy: 'conformance-test',\n });\n }\n\n describe('StorageProvider Conformance Tests', () => {\n beforeEach(async () => {\n await setup();\n });\n\n // ─── Repository ─────────────────────────────────────────\n\n describe('repository operations', () => {\n it('creates a repository', async () => {\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n expect(repo!.repositoryId).toBe(repoId);\n expect(repo!.label).toBe('Conformance Test');\n });\n\n it('returns null for non-existent repository', async () => {\n const repo = await provider.getRepository('ffffffff-ffff-4fff-afff-ffffffffffff');\n expect(repo).toBeNull();\n });\n\n it('lists repositories', async () => {\n const list = await provider.listRepositories();\n expect(list.items.length).toBeGreaterThanOrEqual(1);\n expect(list.items.some((r) => r.repositoryId === repoId)).toBe(true);\n });\n\n it('updates a repository', async () => {\n const updated = await provider.updateRepository(repoId, {\n label: 'Updated Label',\n description: 'Updated description',\n governanceConfig: { mode: 'open', defaultSimilarityThreshold: 0.4 },\n });\n expect(updated.label).toBe('Updated Label');\n expect(updated.description).toBe('Updated description');\n expect(updated.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n\n // Verify persistence\n const fetched = await provider.getRepository(repoId);\n expect(fetched!.label).toBe('Updated Label');\n expect(fetched!.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n });\n\n it('deletes a repository', async () => {\n await provider.deleteRepository(repoId);\n expect(await provider.getRepository(repoId)).toBeNull();\n });\n\n it('returns repository stats', async () => {\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n expect(typeof stats.vocabularyVersion).toBe('string');\n });\n });\n\n // ─── Vocabulary ─────────────────────────────────────────\n\n describe('vocabulary operations', () => {\n it('gets and saves vocabulary', async () => {\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n expect(typeof vocab.version).toBe('string');\n\n const updated = { ...vocab, version: '1.0.0' };\n await provider.saveVocabulary(repoId, updated);\n\n const fetched = await provider.getVocabulary(repoId);\n expect(fetched.version).toBe('1.0.0');\n });\n\n it('returns vocabulary change log', async () => {\n const log = await provider.getVocabularyChangeLog(repoId);\n expect(Array.isArray(log.items)).toBe(true);\n });\n });\n\n // ─── Entities ───────────────────────────────────────────\n\n describe('entity operations', () => {\n it('creates and retrieves an entity', async () => {\n const entity = makeEntity('e1');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntity(repoId, 'e1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.label).toBe('e1');\n });\n\n it('retrieves an entity by slug', async () => {\n const entity = makeEntity('e1', 'test-type', 'Alpha');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntityBySlug(repoId, entity.slug);\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.slug).toBe(entity.slug);\n });\n\n it('returns null for non-existent entity', async () => {\n const result = await provider.getEntity(repoId, 'nonexistent');\n expect(result).toBeNull();\n });\n\n it('returns null for non-existent slug', async () => {\n const result = await provider.getEntityBySlug(repoId, 'nonexistent:slug');\n expect(result).toBeNull();\n });\n\n it('batch retrieves entities', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n\n const map = await provider.getEntities(repoId, ['e1', 'e2', 'missing']);\n expect(map.size).toBe(2);\n expect(map.has('e1')).toBe(true);\n expect(map.has('e2')).toBe(true);\n expect(map.has('missing')).toBe(false);\n });\n\n it('updates an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const updated = await provider.updateEntity(repoId, 'e1', {\n label: 'Updated Label',\n provenance: makeProvenance(),\n });\n expect(updated.label).toBe('Updated Label');\n\n const fetched = await provider.getEntity(repoId, 'e1');\n expect(fetched!.label).toBe('Updated Label');\n });\n\n it('deletes an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.deleteEntity(repoId, 'e1');\n expect(await provider.getEntity(repoId, 'e1')).toBeNull();\n });\n\n it('finds entities by search term', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'test-type', 'Alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'test-type', 'Beta'));\n\n const result = await provider.findEntities(repoId, {\n searchTerm: 'alpha',\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.label).toBe('Alpha');\n });\n\n it('finds entities by type filter', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'type-a', 'A'));\n await provider.createEntity(repoId, makeEntity('e2', 'type-b', 'B'));\n\n const result = await provider.findEntities(repoId, {\n entityTypes: ['type-a'],\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.entityType).toBe('type-a');\n });\n\n it('paginates find results', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n await provider.createEntity(repoId, makeEntity('e3'));\n\n const page1 = await provider.findEntities(repoId, { limit: 2, offset: 0 });\n expect(page1.items).toHaveLength(2);\n expect(page1.hasMore).toBe(true);\n\n const page2 = await provider.findEntities(repoId, { limit: 2, offset: 2 });\n expect(page2.items).toHaveLength(1);\n expect(page2.hasMore).toBe(false);\n });\n });\n\n // ─── Relationships ──────────────────────────────────────\n\n describe('relationship operations', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a'));\n await provider.createEntity(repoId, makeEntity('b'));\n await provider.createEntity(repoId, makeEntity('c'));\n });\n\n it('creates and retrieves a relationship', async () => {\n const rel = makeRelationship('r1', 'connects', 'a', 'b');\n await provider.createRelationship(repoId, rel);\n\n const retrieved = await provider.getRelationship(repoId, 'r1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.sourceEntityId).toBe('a');\n expect(retrieved!.targetEntityId).toBe('b');\n });\n\n it('returns null for non-existent relationship', async () => {\n expect(await provider.getRelationship(repoId, 'nonexistent')).toBeNull();\n });\n\n it('gets entity relationships', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const result = await provider.getEntityRelationships(repoId, 'a');\n expect(result.items).toHaveLength(2);\n });\n\n it('filters relationships by direction', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const outbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'outbound' });\n expect(outbound.items).toHaveLength(1);\n expect(outbound.items[0]!.targetEntityId).toBe('b');\n\n const inbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'inbound' });\n expect(inbound.items).toHaveLength(1);\n expect(inbound.items[0]!.sourceEntityId).toBe('c');\n });\n\n it('deletes a relationship', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.deleteRelationship(repoId, 'r1');\n expect(await provider.getRelationship(repoId, 'r1')).toBeNull();\n });\n });\n\n // ─── Graph Traversal ────────────────────────────────────\n\n describe('graph traversal', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a', 'node', 'A'));\n await provider.createEntity(repoId, makeEntity('b', 'node', 'B'));\n await provider.createEntity(repoId, makeEntity('c', 'node', 'C'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'links', 'b', 'c'));\n });\n\n it('explores neighbourhood at depth 1', async () => {\n const result = await provider.exploreNeighbourhood(repoId, 'a', {\n depth: 1,\n direction: 'both',\n limitPerType: 10,\n offsetPerType: 0,\n });\n expect(result.centreId).toBe('a');\n expect(result.layers).toHaveLength(1);\n });\n\n it('finds paths between connected entities', async () => {\n const result = await provider.findPaths(repoId, 'a', 'c', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('c');\n });\n\n it('returns empty paths when no connection', async () => {\n await provider.createEntity(repoId, makeEntity('isolated', 'node', 'Isolated'));\n const result = await provider.findPaths(repoId, 'a', 'isolated', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths).toHaveLength(0);\n });\n\n it('finds paths through non-bidirectional inbound edges', async () => {\n // Graph: a → b ← d (both edges are non-bidirectional)\n // Path from a to d should traverse: a →(outbound) b ←(inbound) d\n await provider.createEntity(repoId, makeEntity('d', 'node', 'D'));\n await provider.createRelationship(repoId, makeRelationship('r3', 'links', 'd', 'b'));\n const result = await provider.findPaths(repoId, 'a', 'd', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('d');\n });\n });\n\n // ─── Timeline ───────────────────────────────────────────\n\n describe('timeline', () => {\n it('returns timeline events', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const result = await provider.getTimeline(repoId, 'e1', {\n limit: 10,\n offset: 0,\n });\n expect(result.events.length).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ─── Bulk Operations ────────────────────────────────────\n\n describe('bulk operations', () => {\n it('exports data', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n\n const chunks = [];\n for await (const chunk of provider.exportAll(repoId)) {\n chunks.push(chunk);\n }\n expect(chunks.length).toBeGreaterThanOrEqual(1);\n });\n\n it('imports data', async () => {\n const result = await provider.importBulk(repoId, [\n { entities: [makeEntity('imported-1'), makeEntity('imported-2')] },\n { relationships: [makeRelationship('ir1', 'links', 'imported-1', 'imported-2')] },\n ]);\n expect(result.entitiesImported).toBe(2);\n expect(result.relationshipsImported).toBe(1);\n\n // Verify imported data is accessible\n const e = await provider.getEntity(repoId, 'imported-1');\n expect(e).not.toBeNull();\n });\n });\n\n // ─── Delete All Contents ───────────────────────────────\n\n describe('deleteAllContents', () => {\n it('deletes all entities and relationships but preserves the repository', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const result = await provider.deleteAllContents(repoId);\n expect(result.deletedEntities).toBe(2);\n expect(result.deletedRelationships).toBe(1);\n\n // Repository still exists\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n\n // Vocabulary still exists\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n\n // Contents are gone\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n });\n\n it('returns zero counts on an empty repository', async () => {\n const result = await provider.deleteAllContents(repoId);\n expect(result.deletedEntities).toBe(0);\n expect(result.deletedRelationships).toBe(0);\n });\n });\n\n // ─── Stats after data ───────────────────────────────────\n\n describe('stats reflect data', () => {\n it('counts entities and relationships', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e3', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(3);\n expect(stats.relationshipCount).toBe(1);\n expect(stats.entityTypeBreakdown['alpha']).toBe(2);\n expect(stats.entityTypeBreakdown['beta']).toBe(1);\n expect(stats.relationshipTypeBreakdown['links']).toBe(1);\n });\n });\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StorageProvider } from '../StorageProvider-
|
|
2
|
-
import '../portability-
|
|
1
|
+
import { S as StorageProvider } from '../StorageProvider-CSbaIY6X.cjs';
|
|
2
|
+
import '../portability-1KBMVBGJ.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Run the full StorageProvider conformance test suite.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StorageProvider } from '../StorageProvider-
|
|
2
|
-
import '../portability-
|
|
1
|
+
import { S as StorageProvider } from '../StorageProvider-DqW-zpd0.js';
|
|
2
|
+
import '../portability-1KBMVBGJ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Run the full StorageProvider conformance test suite.
|
|
@@ -310,6 +310,28 @@ function runStorageProviderConformanceTests(factory) {
|
|
|
310
310
|
expect(e).not.toBeNull();
|
|
311
311
|
});
|
|
312
312
|
});
|
|
313
|
+
describe("deleteAllContents", () => {
|
|
314
|
+
it("deletes all entities and relationships but preserves the repository", async () => {
|
|
315
|
+
await provider.createEntity(repoId, makeEntity("e1", "alpha"));
|
|
316
|
+
await provider.createEntity(repoId, makeEntity("e2", "beta"));
|
|
317
|
+
await provider.createRelationship(repoId, makeRelationship("r1", "links", "e1", "e2"));
|
|
318
|
+
const result = await provider.deleteAllContents(repoId);
|
|
319
|
+
expect(result.deletedEntities).toBe(2);
|
|
320
|
+
expect(result.deletedRelationships).toBe(1);
|
|
321
|
+
const repo = await provider.getRepository(repoId);
|
|
322
|
+
expect(repo).not.toBeNull();
|
|
323
|
+
const vocab = await provider.getVocabulary(repoId);
|
|
324
|
+
expect(vocab).toBeDefined();
|
|
325
|
+
const stats = await provider.getRepositoryStats(repoId);
|
|
326
|
+
expect(stats.entityCount).toBe(0);
|
|
327
|
+
expect(stats.relationshipCount).toBe(0);
|
|
328
|
+
});
|
|
329
|
+
it("returns zero counts on an empty repository", async () => {
|
|
330
|
+
const result = await provider.deleteAllContents(repoId);
|
|
331
|
+
expect(result.deletedEntities).toBe(0);
|
|
332
|
+
expect(result.deletedRelationships).toBe(0);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
313
335
|
describe("stats reflect data", () => {
|
|
314
336
|
it("counts entities and relationships", async () => {
|
|
315
337
|
await provider.createEntity(repoId, makeEntity("e1", "alpha"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers-builtin/conformance.ts"],"sourcesContent":["// Provider Conformance Test Suite\n// Any StorageProvider implementer can import and run these tests to verify conformance.\n//\n// Usage:\n// import { runStorageProviderConformanceTests } from '@utaba/deep-memory';\n// runStorageProviderConformanceTests(() => new MyStorageProvider());\n\nimport { describe, it, expect, beforeEach } from 'vitest';\nimport type { StorageProvider } from '../providers/StorageProvider.js';\nimport type { StoredEntity } from '../types/entities.js';\nimport type { StoredRelationship } from '../types/relationships.js';\nimport type { Provenance } from '../types/provenance.js';\n\nfunction makeProvenance(): Provenance {\n const now = new Date().toISOString();\n return {\n createdBy: 'conformance-test',\n createdByType: 'agent',\n createdAt: now,\n modifiedBy: 'conformance-test',\n modifiedByType: 'agent',\n modifiedAt: now,\n };\n}\n\nfunction makeEntity(id: string, type = 'test-type', label?: string): StoredEntity {\n return {\n id,\n slug: `${type}:${(label ?? id).toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n entityType: type,\n label: label ?? id,\n summary: `Summary for ${id}`,\n properties: { key: 'value' },\n provenance: makeProvenance(),\n };\n}\n\nfunction makeRelationship(\n id: string,\n type: string,\n sourceId: string,\n targetId: string,\n bidirectional = false,\n): StoredRelationship {\n return {\n id,\n relationshipType: type,\n sourceEntityId: sourceId,\n targetEntityId: targetId,\n properties: {},\n bidirectional,\n provenance: makeProvenance(),\n };\n}\n\n/**\n * Run the full StorageProvider conformance test suite.\n *\n * @param factory - A function that creates a fresh, empty StorageProvider instance.\n * Called before each test to ensure isolation.\n */\nexport function runStorageProviderConformanceTests(\n factory: () => StorageProvider | Promise<StorageProvider>,\n): void {\n // Use a stable GUID so external cleanup scripts can target it\n const repoId = '40000000-0000-4000-a000-000000000001';\n\n let provider: StorageProvider;\n\n async function setup(): Promise<void> {\n provider = await factory();\n if (provider.initialise) await provider.initialise();\n\n await provider.createRepository({\n repositoryId: repoId,\n label: 'Conformance Test',\n governanceConfig: { mode: 'open' },\n createdAt: new Date().toISOString(),\n createdBy: 'conformance-test',\n });\n }\n\n describe('StorageProvider Conformance Tests', () => {\n beforeEach(async () => {\n await setup();\n });\n\n // ─── Repository ─────────────────────────────────────────\n\n describe('repository operations', () => {\n it('creates a repository', async () => {\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n expect(repo!.repositoryId).toBe(repoId);\n expect(repo!.label).toBe('Conformance Test');\n });\n\n it('returns null for non-existent repository', async () => {\n const repo = await provider.getRepository('ffffffff-ffff-4fff-afff-ffffffffffff');\n expect(repo).toBeNull();\n });\n\n it('lists repositories', async () => {\n const list = await provider.listRepositories();\n expect(list.items.length).toBeGreaterThanOrEqual(1);\n expect(list.items.some((r) => r.repositoryId === repoId)).toBe(true);\n });\n\n it('updates a repository', async () => {\n const updated = await provider.updateRepository(repoId, {\n label: 'Updated Label',\n description: 'Updated description',\n governanceConfig: { mode: 'open', defaultSimilarityThreshold: 0.4 },\n });\n expect(updated.label).toBe('Updated Label');\n expect(updated.description).toBe('Updated description');\n expect(updated.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n\n // Verify persistence\n const fetched = await provider.getRepository(repoId);\n expect(fetched!.label).toBe('Updated Label');\n expect(fetched!.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n });\n\n it('deletes a repository', async () => {\n await provider.deleteRepository(repoId);\n expect(await provider.getRepository(repoId)).toBeNull();\n });\n\n it('returns repository stats', async () => {\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n expect(typeof stats.vocabularyVersion).toBe('string');\n });\n });\n\n // ─── Vocabulary ─────────────────────────────────────────\n\n describe('vocabulary operations', () => {\n it('gets and saves vocabulary', async () => {\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n expect(typeof vocab.version).toBe('string');\n\n const updated = { ...vocab, version: '1.0.0' };\n await provider.saveVocabulary(repoId, updated);\n\n const fetched = await provider.getVocabulary(repoId);\n expect(fetched.version).toBe('1.0.0');\n });\n\n it('returns vocabulary change log', async () => {\n const log = await provider.getVocabularyChangeLog(repoId);\n expect(Array.isArray(log.items)).toBe(true);\n });\n });\n\n // ─── Entities ───────────────────────────────────────────\n\n describe('entity operations', () => {\n it('creates and retrieves an entity', async () => {\n const entity = makeEntity('e1');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntity(repoId, 'e1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.label).toBe('e1');\n });\n\n it('retrieves an entity by slug', async () => {\n const entity = makeEntity('e1', 'test-type', 'Alpha');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntityBySlug(repoId, entity.slug);\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.slug).toBe(entity.slug);\n });\n\n it('returns null for non-existent entity', async () => {\n const result = await provider.getEntity(repoId, 'nonexistent');\n expect(result).toBeNull();\n });\n\n it('returns null for non-existent slug', async () => {\n const result = await provider.getEntityBySlug(repoId, 'nonexistent:slug');\n expect(result).toBeNull();\n });\n\n it('batch retrieves entities', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n\n const map = await provider.getEntities(repoId, ['e1', 'e2', 'missing']);\n expect(map.size).toBe(2);\n expect(map.has('e1')).toBe(true);\n expect(map.has('e2')).toBe(true);\n expect(map.has('missing')).toBe(false);\n });\n\n it('updates an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const updated = await provider.updateEntity(repoId, 'e1', {\n label: 'Updated Label',\n provenance: makeProvenance(),\n });\n expect(updated.label).toBe('Updated Label');\n\n const fetched = await provider.getEntity(repoId, 'e1');\n expect(fetched!.label).toBe('Updated Label');\n });\n\n it('deletes an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.deleteEntity(repoId, 'e1');\n expect(await provider.getEntity(repoId, 'e1')).toBeNull();\n });\n\n it('finds entities by search term', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'test-type', 'Alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'test-type', 'Beta'));\n\n const result = await provider.findEntities(repoId, {\n searchTerm: 'alpha',\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.label).toBe('Alpha');\n });\n\n it('finds entities by type filter', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'type-a', 'A'));\n await provider.createEntity(repoId, makeEntity('e2', 'type-b', 'B'));\n\n const result = await provider.findEntities(repoId, {\n entityTypes: ['type-a'],\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.entityType).toBe('type-a');\n });\n\n it('paginates find results', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n await provider.createEntity(repoId, makeEntity('e3'));\n\n const page1 = await provider.findEntities(repoId, { limit: 2, offset: 0 });\n expect(page1.items).toHaveLength(2);\n expect(page1.hasMore).toBe(true);\n\n const page2 = await provider.findEntities(repoId, { limit: 2, offset: 2 });\n expect(page2.items).toHaveLength(1);\n expect(page2.hasMore).toBe(false);\n });\n });\n\n // ─── Relationships ──────────────────────────────────────\n\n describe('relationship operations', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a'));\n await provider.createEntity(repoId, makeEntity('b'));\n await provider.createEntity(repoId, makeEntity('c'));\n });\n\n it('creates and retrieves a relationship', async () => {\n const rel = makeRelationship('r1', 'connects', 'a', 'b');\n await provider.createRelationship(repoId, rel);\n\n const retrieved = await provider.getRelationship(repoId, 'r1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.sourceEntityId).toBe('a');\n expect(retrieved!.targetEntityId).toBe('b');\n });\n\n it('returns null for non-existent relationship', async () => {\n expect(await provider.getRelationship(repoId, 'nonexistent')).toBeNull();\n });\n\n it('gets entity relationships', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const result = await provider.getEntityRelationships(repoId, 'a');\n expect(result.items).toHaveLength(2);\n });\n\n it('filters relationships by direction', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const outbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'outbound' });\n expect(outbound.items).toHaveLength(1);\n expect(outbound.items[0]!.targetEntityId).toBe('b');\n\n const inbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'inbound' });\n expect(inbound.items).toHaveLength(1);\n expect(inbound.items[0]!.sourceEntityId).toBe('c');\n });\n\n it('deletes a relationship', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.deleteRelationship(repoId, 'r1');\n expect(await provider.getRelationship(repoId, 'r1')).toBeNull();\n });\n });\n\n // ─── Graph Traversal ────────────────────────────────────\n\n describe('graph traversal', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a', 'node', 'A'));\n await provider.createEntity(repoId, makeEntity('b', 'node', 'B'));\n await provider.createEntity(repoId, makeEntity('c', 'node', 'C'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'links', 'b', 'c'));\n });\n\n it('explores neighbourhood at depth 1', async () => {\n const result = await provider.exploreNeighbourhood(repoId, 'a', {\n depth: 1,\n direction: 'both',\n limitPerType: 10,\n offsetPerType: 0,\n });\n expect(result.centreId).toBe('a');\n expect(result.layers).toHaveLength(1);\n });\n\n it('finds paths between connected entities', async () => {\n const result = await provider.findPaths(repoId, 'a', 'c', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('c');\n });\n\n it('returns empty paths when no connection', async () => {\n await provider.createEntity(repoId, makeEntity('isolated', 'node', 'Isolated'));\n const result = await provider.findPaths(repoId, 'a', 'isolated', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths).toHaveLength(0);\n });\n\n it('finds paths through non-bidirectional inbound edges', async () => {\n // Graph: a → b ← d (both edges are non-bidirectional)\n // Path from a to d should traverse: a →(outbound) b ←(inbound) d\n await provider.createEntity(repoId, makeEntity('d', 'node', 'D'));\n await provider.createRelationship(repoId, makeRelationship('r3', 'links', 'd', 'b'));\n const result = await provider.findPaths(repoId, 'a', 'd', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('d');\n });\n });\n\n // ─── Timeline ───────────────────────────────────────────\n\n describe('timeline', () => {\n it('returns timeline events', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const result = await provider.getTimeline(repoId, 'e1', {\n limit: 10,\n offset: 0,\n });\n expect(result.events.length).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ─── Bulk Operations ────────────────────────────────────\n\n describe('bulk operations', () => {\n it('exports data', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n\n const chunks = [];\n for await (const chunk of provider.exportAll(repoId)) {\n chunks.push(chunk);\n }\n expect(chunks.length).toBeGreaterThanOrEqual(1);\n });\n\n it('imports data', async () => {\n const result = await provider.importBulk(repoId, [\n { entities: [makeEntity('imported-1'), makeEntity('imported-2')] },\n { relationships: [makeRelationship('ir1', 'links', 'imported-1', 'imported-2')] },\n ]);\n expect(result.entitiesImported).toBe(2);\n expect(result.relationshipsImported).toBe(1);\n\n // Verify imported data is accessible\n const e = await provider.getEntity(repoId, 'imported-1');\n expect(e).not.toBeNull();\n });\n });\n\n // ─── Stats after data ───────────────────────────────────\n\n describe('stats reflect data', () => {\n it('counts entities and relationships', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e3', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(3);\n expect(stats.relationshipCount).toBe(1);\n expect(stats.entityTypeBreakdown['alpha']).toBe(2);\n expect(stats.entityTypeBreakdown['beta']).toBe(1);\n expect(stats.relationshipTypeBreakdown['links']).toBe(1);\n });\n });\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/providers-builtin/conformance.ts"],"sourcesContent":["// Provider Conformance Test Suite\n// Any StorageProvider implementer can import and run these tests to verify conformance.\n//\n// Usage:\n// import { runStorageProviderConformanceTests } from '@utaba/deep-memory';\n// runStorageProviderConformanceTests(() => new MyStorageProvider());\n\nimport { describe, it, expect, beforeEach } from 'vitest';\nimport type { StorageProvider } from '../providers/StorageProvider.js';\nimport type { StoredEntity } from '../types/entities.js';\nimport type { StoredRelationship } from '../types/relationships.js';\nimport type { Provenance } from '../types/provenance.js';\n\nfunction makeProvenance(): Provenance {\n const now = new Date().toISOString();\n return {\n createdBy: 'conformance-test',\n createdByType: 'agent',\n createdAt: now,\n modifiedBy: 'conformance-test',\n modifiedByType: 'agent',\n modifiedAt: now,\n };\n}\n\nfunction makeEntity(id: string, type = 'test-type', label?: string): StoredEntity {\n return {\n id,\n slug: `${type}:${(label ?? id).toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n entityType: type,\n label: label ?? id,\n summary: `Summary for ${id}`,\n properties: { key: 'value' },\n provenance: makeProvenance(),\n };\n}\n\nfunction makeRelationship(\n id: string,\n type: string,\n sourceId: string,\n targetId: string,\n bidirectional = false,\n): StoredRelationship {\n return {\n id,\n relationshipType: type,\n sourceEntityId: sourceId,\n targetEntityId: targetId,\n properties: {},\n bidirectional,\n provenance: makeProvenance(),\n };\n}\n\n/**\n * Run the full StorageProvider conformance test suite.\n *\n * @param factory - A function that creates a fresh, empty StorageProvider instance.\n * Called before each test to ensure isolation.\n */\nexport function runStorageProviderConformanceTests(\n factory: () => StorageProvider | Promise<StorageProvider>,\n): void {\n // Use a stable GUID so external cleanup scripts can target it\n const repoId = '40000000-0000-4000-a000-000000000001';\n\n let provider: StorageProvider;\n\n async function setup(): Promise<void> {\n provider = await factory();\n if (provider.initialise) await provider.initialise();\n\n await provider.createRepository({\n repositoryId: repoId,\n label: 'Conformance Test',\n governanceConfig: { mode: 'open' },\n createdAt: new Date().toISOString(),\n createdBy: 'conformance-test',\n });\n }\n\n describe('StorageProvider Conformance Tests', () => {\n beforeEach(async () => {\n await setup();\n });\n\n // ─── Repository ─────────────────────────────────────────\n\n describe('repository operations', () => {\n it('creates a repository', async () => {\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n expect(repo!.repositoryId).toBe(repoId);\n expect(repo!.label).toBe('Conformance Test');\n });\n\n it('returns null for non-existent repository', async () => {\n const repo = await provider.getRepository('ffffffff-ffff-4fff-afff-ffffffffffff');\n expect(repo).toBeNull();\n });\n\n it('lists repositories', async () => {\n const list = await provider.listRepositories();\n expect(list.items.length).toBeGreaterThanOrEqual(1);\n expect(list.items.some((r) => r.repositoryId === repoId)).toBe(true);\n });\n\n it('updates a repository', async () => {\n const updated = await provider.updateRepository(repoId, {\n label: 'Updated Label',\n description: 'Updated description',\n governanceConfig: { mode: 'open', defaultSimilarityThreshold: 0.4 },\n });\n expect(updated.label).toBe('Updated Label');\n expect(updated.description).toBe('Updated description');\n expect(updated.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n\n // Verify persistence\n const fetched = await provider.getRepository(repoId);\n expect(fetched!.label).toBe('Updated Label');\n expect(fetched!.governanceConfig.defaultSimilarityThreshold).toBe(0.4);\n });\n\n it('deletes a repository', async () => {\n await provider.deleteRepository(repoId);\n expect(await provider.getRepository(repoId)).toBeNull();\n });\n\n it('returns repository stats', async () => {\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n expect(typeof stats.vocabularyVersion).toBe('string');\n });\n });\n\n // ─── Vocabulary ─────────────────────────────────────────\n\n describe('vocabulary operations', () => {\n it('gets and saves vocabulary', async () => {\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n expect(typeof vocab.version).toBe('string');\n\n const updated = { ...vocab, version: '1.0.0' };\n await provider.saveVocabulary(repoId, updated);\n\n const fetched = await provider.getVocabulary(repoId);\n expect(fetched.version).toBe('1.0.0');\n });\n\n it('returns vocabulary change log', async () => {\n const log = await provider.getVocabularyChangeLog(repoId);\n expect(Array.isArray(log.items)).toBe(true);\n });\n });\n\n // ─── Entities ───────────────────────────────────────────\n\n describe('entity operations', () => {\n it('creates and retrieves an entity', async () => {\n const entity = makeEntity('e1');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntity(repoId, 'e1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.label).toBe('e1');\n });\n\n it('retrieves an entity by slug', async () => {\n const entity = makeEntity('e1', 'test-type', 'Alpha');\n await provider.createEntity(repoId, entity);\n\n const retrieved = await provider.getEntityBySlug(repoId, entity.slug);\n expect(retrieved).not.toBeNull();\n expect(retrieved!.id).toBe('e1');\n expect(retrieved!.slug).toBe(entity.slug);\n });\n\n it('returns null for non-existent entity', async () => {\n const result = await provider.getEntity(repoId, 'nonexistent');\n expect(result).toBeNull();\n });\n\n it('returns null for non-existent slug', async () => {\n const result = await provider.getEntityBySlug(repoId, 'nonexistent:slug');\n expect(result).toBeNull();\n });\n\n it('batch retrieves entities', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n\n const map = await provider.getEntities(repoId, ['e1', 'e2', 'missing']);\n expect(map.size).toBe(2);\n expect(map.has('e1')).toBe(true);\n expect(map.has('e2')).toBe(true);\n expect(map.has('missing')).toBe(false);\n });\n\n it('updates an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const updated = await provider.updateEntity(repoId, 'e1', {\n label: 'Updated Label',\n provenance: makeProvenance(),\n });\n expect(updated.label).toBe('Updated Label');\n\n const fetched = await provider.getEntity(repoId, 'e1');\n expect(fetched!.label).toBe('Updated Label');\n });\n\n it('deletes an entity', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.deleteEntity(repoId, 'e1');\n expect(await provider.getEntity(repoId, 'e1')).toBeNull();\n });\n\n it('finds entities by search term', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'test-type', 'Alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'test-type', 'Beta'));\n\n const result = await provider.findEntities(repoId, {\n searchTerm: 'alpha',\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.label).toBe('Alpha');\n });\n\n it('finds entities by type filter', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'type-a', 'A'));\n await provider.createEntity(repoId, makeEntity('e2', 'type-b', 'B'));\n\n const result = await provider.findEntities(repoId, {\n entityTypes: ['type-a'],\n limit: 10,\n offset: 0,\n });\n expect(result.items).toHaveLength(1);\n expect(result.items[0]!.entityType).toBe('type-a');\n });\n\n it('paginates find results', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n await provider.createEntity(repoId, makeEntity('e2'));\n await provider.createEntity(repoId, makeEntity('e3'));\n\n const page1 = await provider.findEntities(repoId, { limit: 2, offset: 0 });\n expect(page1.items).toHaveLength(2);\n expect(page1.hasMore).toBe(true);\n\n const page2 = await provider.findEntities(repoId, { limit: 2, offset: 2 });\n expect(page2.items).toHaveLength(1);\n expect(page2.hasMore).toBe(false);\n });\n });\n\n // ─── Relationships ──────────────────────────────────────\n\n describe('relationship operations', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a'));\n await provider.createEntity(repoId, makeEntity('b'));\n await provider.createEntity(repoId, makeEntity('c'));\n });\n\n it('creates and retrieves a relationship', async () => {\n const rel = makeRelationship('r1', 'connects', 'a', 'b');\n await provider.createRelationship(repoId, rel);\n\n const retrieved = await provider.getRelationship(repoId, 'r1');\n expect(retrieved).not.toBeNull();\n expect(retrieved!.sourceEntityId).toBe('a');\n expect(retrieved!.targetEntityId).toBe('b');\n });\n\n it('returns null for non-existent relationship', async () => {\n expect(await provider.getRelationship(repoId, 'nonexistent')).toBeNull();\n });\n\n it('gets entity relationships', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const result = await provider.getEntityRelationships(repoId, 'a');\n expect(result.items).toHaveLength(2);\n });\n\n it('filters relationships by direction', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'connects', 'c', 'a'));\n\n const outbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'outbound' });\n expect(outbound.items).toHaveLength(1);\n expect(outbound.items[0]!.targetEntityId).toBe('b');\n\n const inbound = await provider.getEntityRelationships(repoId, 'a', { direction: 'inbound' });\n expect(inbound.items).toHaveLength(1);\n expect(inbound.items[0]!.sourceEntityId).toBe('c');\n });\n\n it('deletes a relationship', async () => {\n await provider.createRelationship(repoId, makeRelationship('r1', 'connects', 'a', 'b'));\n await provider.deleteRelationship(repoId, 'r1');\n expect(await provider.getRelationship(repoId, 'r1')).toBeNull();\n });\n });\n\n // ─── Graph Traversal ────────────────────────────────────\n\n describe('graph traversal', () => {\n beforeEach(async () => {\n await provider.createEntity(repoId, makeEntity('a', 'node', 'A'));\n await provider.createEntity(repoId, makeEntity('b', 'node', 'B'));\n await provider.createEntity(repoId, makeEntity('c', 'node', 'C'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'a', 'b'));\n await provider.createRelationship(repoId, makeRelationship('r2', 'links', 'b', 'c'));\n });\n\n it('explores neighbourhood at depth 1', async () => {\n const result = await provider.exploreNeighbourhood(repoId, 'a', {\n depth: 1,\n direction: 'both',\n limitPerType: 10,\n offsetPerType: 0,\n });\n expect(result.centreId).toBe('a');\n expect(result.layers).toHaveLength(1);\n });\n\n it('finds paths between connected entities', async () => {\n const result = await provider.findPaths(repoId, 'a', 'c', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('c');\n });\n\n it('returns empty paths when no connection', async () => {\n await provider.createEntity(repoId, makeEntity('isolated', 'node', 'Isolated'));\n const result = await provider.findPaths(repoId, 'a', 'isolated', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths).toHaveLength(0);\n });\n\n it('finds paths through non-bidirectional inbound edges', async () => {\n // Graph: a → b ← d (both edges are non-bidirectional)\n // Path from a to d should traverse: a →(outbound) b ←(inbound) d\n await provider.createEntity(repoId, makeEntity('d', 'node', 'D'));\n await provider.createRelationship(repoId, makeRelationship('r3', 'links', 'd', 'b'));\n const result = await provider.findPaths(repoId, 'a', 'd', {\n maxDepth: 3,\n limit: 5,\n offset: 0,\n });\n expect(result.paths.length).toBeGreaterThanOrEqual(1);\n const firstPath = result.paths[0]!;\n expect(firstPath.entityIds[0]).toBe('a');\n expect(firstPath.entityIds[firstPath.entityIds.length - 1]).toBe('d');\n });\n });\n\n // ─── Timeline ───────────────────────────────────────────\n\n describe('timeline', () => {\n it('returns timeline events', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n const result = await provider.getTimeline(repoId, 'e1', {\n limit: 10,\n offset: 0,\n });\n expect(result.events.length).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ─── Bulk Operations ────────────────────────────────────\n\n describe('bulk operations', () => {\n it('exports data', async () => {\n await provider.createEntity(repoId, makeEntity('e1'));\n\n const chunks = [];\n for await (const chunk of provider.exportAll(repoId)) {\n chunks.push(chunk);\n }\n expect(chunks.length).toBeGreaterThanOrEqual(1);\n });\n\n it('imports data', async () => {\n const result = await provider.importBulk(repoId, [\n { entities: [makeEntity('imported-1'), makeEntity('imported-2')] },\n { relationships: [makeRelationship('ir1', 'links', 'imported-1', 'imported-2')] },\n ]);\n expect(result.entitiesImported).toBe(2);\n expect(result.relationshipsImported).toBe(1);\n\n // Verify imported data is accessible\n const e = await provider.getEntity(repoId, 'imported-1');\n expect(e).not.toBeNull();\n });\n });\n\n // ─── Delete All Contents ───────────────────────────────\n\n describe('deleteAllContents', () => {\n it('deletes all entities and relationships but preserves the repository', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const result = await provider.deleteAllContents(repoId);\n expect(result.deletedEntities).toBe(2);\n expect(result.deletedRelationships).toBe(1);\n\n // Repository still exists\n const repo = await provider.getRepository(repoId);\n expect(repo).not.toBeNull();\n\n // Vocabulary still exists\n const vocab = await provider.getVocabulary(repoId);\n expect(vocab).toBeDefined();\n\n // Contents are gone\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(0);\n expect(stats.relationshipCount).toBe(0);\n });\n\n it('returns zero counts on an empty repository', async () => {\n const result = await provider.deleteAllContents(repoId);\n expect(result.deletedEntities).toBe(0);\n expect(result.deletedRelationships).toBe(0);\n });\n });\n\n // ─── Stats after data ───────────────────────────────────\n\n describe('stats reflect data', () => {\n it('counts entities and relationships', async () => {\n await provider.createEntity(repoId, makeEntity('e1', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e2', 'alpha'));\n await provider.createEntity(repoId, makeEntity('e3', 'beta'));\n await provider.createRelationship(repoId, makeRelationship('r1', 'links', 'e1', 'e2'));\n\n const stats = await provider.getRepositoryStats(repoId);\n expect(stats.entityCount).toBe(3);\n expect(stats.relationshipCount).toBe(1);\n expect(stats.entityTypeBreakdown['alpha']).toBe(2);\n expect(stats.entityTypeBreakdown['beta']).toBe(1);\n expect(stats.relationshipTypeBreakdown['links']).toBe(1);\n });\n });\n });\n}\n"],"mappings":"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","names":[]}
|