Skip to main content

@idpass/data-collect-core / IndexedDbEntityStorageAdapter

Class: IndexedDbEntityStorageAdapter

Defined in: storage/IndexedDbEntityStorageAdapter.ts:93

IndexedDB implementation of the EntityStorageAdapter for browser-based entity persistence.

This adapter provides offline-first entity storage using the browser's IndexedDB API. It implements the full EntityStorageAdapter interface with optimized indexing for fast queries and efficient duplicate detection.

Key features:

  • Offline Storage: Stores entities locally in the browser using IndexedDB.
  • Multi-Tenant Support: Isolated databases per tenant using tenant ID prefixes.
  • Optimized Indexing: Multiple indexes for fast lookups (GUID, name, externalId, timestamps).
  • Search Capabilities: Flexible search with operators ($gt, $lt, $eq, $regex).
  • Duplicate Detection: Built-in storage for potential duplicate pairs.
  • Change Tracking: Tracks initial and modified entity states for sync.

Architecture:

  • Uses IndexedDB object stores with compound keys for efficient storage.
  • Implements cursor-based iteration for memory-efficient operations.
  • Provides ACID transaction support for data consistency.
  • Supports both simple and complex search criteria.

Examples

Basic usage:

const adapter = new IndexedDbEntityStorageAdapter('tenant-123');
await adapter.initialize();

// Save an entity pair
const entityPair: EntityPair = {
guid: 'person-456',
initial: originalEntity,
modified: updatedEntity
};
await adapter.saveEntity(entityPair);

// Retrieve entity
const retrieved = await adapter.getEntity('person-456');

Search entities:

// Search for adults with age greater than 18
const adults = await adapter.searchEntities([
{ "modified.data.age": { $gt: 18 } },
{ "modified.type": "individual" }
]);

// Search by name pattern
const smiths = await adapter.searchEntities([
{ "modified.data.name": { $regex: "smith" } }
]);

// Simple substring search
const smithFamilies = await adapter.searchEntities([
{ "modified.data.familyName": "smith" }
]);

Multi-tenant setup:

// Tenant-specific adapter
const tenantAdapter = new IndexedDbEntityStorageAdapter('org-xyz');
await tenantAdapter.initialize(); // Creates database: entityStore_org-xyz

// Default adapter
const defaultAdapter = new IndexedDbEntityStorageAdapter();
await defaultAdapter.initialize(); // Creates database: entityStore

Implements

Constructors

Constructor

new IndexedDbEntityStorageAdapter(tenantId): IndexedDbEntityStorageAdapter

Defined in: storage/IndexedDbEntityStorageAdapter.ts:113

Creates a new IndexedDbEntityStorageAdapter instance.

Parameters

tenantId

string = ""

Optional tenant identifier for multi-tenant isolation. When provided, creates a separate database prefixed with tenant ID.

Returns

IndexedDbEntityStorageAdapter

Example

// Default database (entityStore)
const adapter = new IndexedDbEntityStorageAdapter();

// Tenant-specific database (entityStore_org-123)
const tenantAdapter = new IndexedDbEntityStorageAdapter('org-123');

Properties

tenantId

readonly tenantId: string = ""

Defined in: storage/IndexedDbEntityStorageAdapter.ts:113

Optional tenant identifier for multi-tenant isolation. When provided, creates a separate database prefixed with tenant ID.

Methods

closeConnection()

closeConnection(): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:127

Closes the IndexedDB connection and cleans up resources.

For IndexedDB, connections are automatically managed by the browser, so this method is a no-op but maintained for interface compatibility.

Returns

Promise<void>

A Promise that resolves when the connection is closed.

Implementation of

EntityStorageAdapter.closeConnection


initialize()

initialize(): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:144

Initializes the IndexedDB database with required object stores and indexes.

Returns

Promise<void>

A Promise that resolves when the database is initialized.

Throws

When IndexedDB is not supported or database creation fails.

Example

const adapter = new IndexedDbEntityStorageAdapter('tenant-123');
await adapter.initialize();
// Now ready for entity operations

Implementation of

EntityStorageAdapter.initialize


getAllEntities()

getAllEntities(): Promise<EntityPair[]>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:191

Retrieves all entities stored in the database.

Returns

Promise<EntityPair[]>

Array of all entity pairs.

Example

const allEntities = await adapter.getAllEntities();
console.log(`Found ${allEntities.length} entities`);

// Filter by type
const individuals = allEntities.filter(e => e.modified.type === 'individual');
const groups = allEntities.filter(e => e.modified.type === 'group');

Implementation of

EntityStorageAdapter.getAllEntities


searchEntities()

searchEntities(criteria): Promise<EntityPair[]>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:230

Searches entities using flexible criteria with support for operators and string matching.

Supports multiple search operators:

  • $gt: Greater than comparison.
  • $lt: Less than comparison.
  • $eq: Exact equality.
  • $regex: Regular expression pattern matching.
  • String values: Case-insensitive substring search.
  • Numeric values: Exact equality.

Searches both initial and modified entity states, as well as nested data properties.

Parameters

criteria

SearchCriteria

Array of search criteria objects.

Returns

Promise<EntityPair[]>

Array of entity pairs matching all criteria.

Example

// Search for adults with age greater than 18
const adults = await adapter.searchEntities([
{ "modified.data.age": { $gt: 18 } },
{ "modified.type": "individual" }
]);

// Search by name pattern (case-insensitive)
const johns = await adapter.searchEntities([
{ "modified.data.name": { $regex: "john" } }
]);

// Simple substring search
const smithFamilies = await adapter.searchEntities([
{ "modified.data.familyName": "smith" }
]);

Implementation of

EntityStorageAdapter.searchEntities


saveEntity()

saveEntity(entity): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:317

Saves an entity pair (initial and modified states) to IndexedDB.

Stores both the initial state (for conflict resolution) and modified state (current version) with the entity's GUID as the primary key.

Parameters

entity

EntityPair

Entity pair containing initial and modified states.

Returns

Promise<void>

A Promise that resolves when the entity is saved.

Throws

When IndexedDB is not initialized or save operation fails.

Example

const entityPair: EntityPair = {
guid: 'person-123',
initial: originalEntity,
modified: { ...originalEntity, data: { ...originalEntity.data, age: 31 } }
};

await adapter.saveEntity(entityPair);

Implementation of

EntityStorageAdapter.saveEntity


getEntity()

getEntity(guid): Promise<EntityPair | null>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:356

Retrieves an entity pair by its GUID.

Uses the optimized GUID index for fast lookups.

Parameters

guid

string

Global unique identifier of the entity.

Returns

Promise<EntityPair | null>

Entity pair if found, null otherwise.

Example

const entity = await adapter.getEntity('person-123');
if (entity) {
console.log('Current state:', entity.modified);
console.log('Original state:', entity.initial);
} else {
console.log('Entity not found');
}

Implementation of

EntityStorageAdapter.getEntity


getEntityByExternalId()

getEntityByExternalId(externalId): Promise<EntityPair | null>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:401

Retrieves an entity pair by its external system identifier.

Useful for finding entities that have been synced with external systems like OpenSPP or other third-party platforms.

Parameters

externalId

string

External system identifier.

Returns

Promise<EntityPair | null>

Entity pair if found, null otherwise.

Example

// Find entity by OpenSPP ID
const entity = await adapter.getEntityByExternalId('openspp-456');
if (entity) {
console.log('Synced entity:', entity.modified.data);
}

Implementation of

EntityStorageAdapter.getEntityByExternalId


getModifiedEntitiesSince()

getModifiedEntitiesSince(timestamp): Promise<EntityPair[]>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:478

Retrieves entities that have been modified since a specific timestamp.

Uses the lastUpdated index for efficient timestamp-based queries. Essential for incremental synchronization operations.

Parameters

timestamp

string

ISO timestamp to filter from (exclusive).

Returns

Promise<EntityPair[]>

Array of entity pairs modified after the timestamp.

Example

const lastSync = '2024-01-01T00:00:00.000Z';
const modified = await adapter.getModifiedEntitiesSince(lastSync);

console.log(`${modified.length} entities modified since last sync`);
for (const entity of modified) {
console.log(`${entity.modified.data.name} updated at ${entity.modified.lastUpdated}`);
}

markEntityAsSynced()

markEntityAsSynced(id): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:527

Marks an entity as synced by updating its lastUpdated timestamp.

Used by sync managers to track which entities have been successfully synchronized with remote systems.

Parameters

id

string

GUID of the entity to mark as synced.

Returns

Promise<void>

A Promise that resolves when the entity is marked as synced.

Throws

When IndexedDB is not initialized.

Example

// After successful sync
await adapter.markEntityAsSynced('person-123');

deleteEntity()

deleteEntity(id): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:560

Deletes an entity and cleans up any related duplicate entries.

Removes the entity from both the main store and any potential duplicate pairs where this entity appears as either the primary or duplicate entity.

Parameters

id

string

GUID of the entity to delete.

Returns

Promise<void>

A Promise that resolves when the entity is deleted.

Throws

When IndexedDB is not initialized.

Example

await adapter.deleteEntity('person-123');
console.log('Entity and related duplicates removed');

Implementation of

EntityStorageAdapter.deleteEntity


savePotentialDuplicates()

savePotentialDuplicates(duplicates): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:610

Saves potential duplicate entity pairs for manual review.

Stores pairs of entity GUIDs that may represent the same real-world entity. These pairs are typically identified by automated duplicate detection algorithms.

Parameters

duplicates

object[]

Array of entity GUID pairs flagged as potential duplicates.

Returns

Promise<void>

A Promise that resolves when duplicates are saved.

Throws

When IndexedDB is not initialized.

Example

const duplicatePairs = [
{ entityGuid: 'person-123', duplicateGuid: 'person-456' },
{ entityGuid: 'person-789', duplicateGuid: 'person-101' }
];

await adapter.savePotentialDuplicates(duplicatePairs);
console.log('Duplicate pairs saved for review');

Implementation of

EntityStorageAdapter.savePotentialDuplicates


getPotentialDuplicates()

getPotentialDuplicates(): Promise<object[]>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:649

Retrieves all potential duplicate entity pairs awaiting review.

Returns pairs of entity GUIDs that have been flagged by duplicate detection algorithms and need manual review and resolution.

Returns

Promise<object[]>

Throws

When IndexedDB is not initialized.

Example

const duplicates = await adapter.getPotentialDuplicates();

for (const pair of duplicates) {
const entity1 = await adapter.getEntity(pair.entityGuid);
const entity2 = await adapter.getEntity(pair.duplicateGuid);

console.log('Potential duplicate detected:');
console.log('Entity 1:', entity1?.modified.data);
console.log('Entity 2:', entity2?.modified.data);
}

Implementation of

EntityStorageAdapter.getPotentialDuplicates


resolvePotentialDuplicates()

resolvePotentialDuplicates(duplicates): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:690

Resolves potential duplicate pairs by removing them from the review queue.

Typically called after manual review when duplicates have been confirmed as either true duplicates (and merged/deleted) or false positives.

Parameters

duplicates

object[]

Array of duplicate pairs to mark as resolved.

Returns

Promise<void>

A Promise that resolves when duplicates are resolved.

Throws

When IndexedDB is not initialized.

Example

// After manual review and resolution
const resolvedPairs = [
{ entityGuid: 'person-123', duplicateGuid: 'person-456' }
];

await adapter.resolvePotentialDuplicates(resolvedPairs);
console.log('Duplicate pairs marked as resolved');

Implementation of

EntityStorageAdapter.resolvePotentialDuplicates


clearStore()

clearStore(): Promise<void>

Defined in: storage/IndexedDbEntityStorageAdapter.ts:726

Clears all data from the entity store and potential duplicates store.

⚠️ WARNING: This permanently deletes all stored entities and duplicate pairs! Only use for testing or when intentionally resetting the local database.

Returns

Promise<void>

A Promise that resolves when the store is cleared.

Throws

When IndexedDB is not initialized or clear operation fails.

Example

// For testing environments only
if (process.env.NODE_ENV === 'test') {
await adapter.clearStore();
console.log('Test data cleared');
}

Implementation of

EntityStorageAdapter.clearStore