UNPKG

@credo-ts/core

Version:

<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1

1 lines • 11.3 kB
{"version":3,"file":"Repository.mjs","names":[],"sources":["../../src/storage/Repository.ts"],"sourcesContent":["import type { AgentContext } from '../agent'\nimport type { EventEmitter } from '../agent/EventEmitter'\nimport { RecordDuplicateError, RecordNotFoundError } from '../error'\nimport { CachedStorageService } from '../modules/cache/CachedStorageService'\nimport { CacheModuleConfig } from '../modules/cache/CacheModuleConfig'\nimport { JsonTransformer } from '../utils'\nimport type { BaseRecord } from './BaseRecord'\nimport type { RecordDeletedEvent, RecordSavedEvent, RecordUpdatedEvent } from './RepositoryEvents'\nimport { RepositoryEventTypes } from './RepositoryEvents'\nimport type { BaseRecordConstructor, Query, QueryOptions, StorageService } from './StorageService'\n\n// biome-ignore lint/suspicious/noExplicitAny: no explanation\nexport class Repository<T extends BaseRecord<any, any, any>> {\n private storageService: StorageService<T>\n private recordClass: BaseRecordConstructor<T>\n private eventEmitter: EventEmitter\n\n public constructor(\n recordClass: BaseRecordConstructor<T>,\n storageService: StorageService<T>,\n eventEmitter: EventEmitter\n ) {\n this.recordClass = recordClass\n this.storageService = storageService\n this.eventEmitter = eventEmitter\n }\n\n private getStorageService(agentContext: AgentContext): StorageService<T> {\n try {\n if (agentContext.dependencyManager.isRegistered(CachedStorageService, true)) {\n return agentContext.resolve(CachedStorageService<T>)\n }\n\n return this.storageService\n } catch {\n return this.storageService\n }\n }\n\n public supportsLocking(agentContext: AgentContext): boolean {\n return this.getStorageService(agentContext).supportsLocking?.(agentContext) ?? false\n }\n\n /** @inheritDoc {StorageService#save} */\n public async save(agentContext: AgentContext, record: T): Promise<void> {\n await this.getStorageService(agentContext).save(agentContext, record)\n\n this.eventEmitter.emit<RecordSavedEvent<T>>(agentContext, {\n type: RepositoryEventTypes.RecordSaved,\n payload: {\n // Record in event should be static\n record: record.clone(),\n },\n })\n }\n\n /** @inheritDoc {StorageService#update} */\n public async update(agentContext: AgentContext, record: T): Promise<void> {\n await this.getStorageService(agentContext).update(agentContext, record)\n\n this.eventEmitter.emit<RecordUpdatedEvent<T>>(agentContext, {\n type: RepositoryEventTypes.RecordUpdated,\n payload: {\n // Record in event should be static\n record: record.clone(),\n },\n })\n }\n\n /** @inheritDoc {StorageService#updateByIdWithLock} */\n public async updateByIdWithLock(\n agentContext: AgentContext,\n id: string,\n updateCallback: (record: T) => Promise<T>\n ): Promise<T> {\n const storageService = this.getStorageService(agentContext)\n\n // NOTE: we might want to not do this, to allow the caller to handle it, (e.g. they might already\n // have the record and this would just re-fetch it again). Then we could just return null?\n // If a backend does not implement this method, we fall back to two separate calls to\n // getById and update\n if (!storageService.updateByIdWithLock) {\n const record = await this.getById(agentContext, id)\n const updatedRecord = await updateCallback(record)\n await this.update(agentContext, record)\n return updatedRecord\n }\n\n const updatedRecord = await storageService.updateByIdWithLock(agentContext, this.recordClass, id, updateCallback)\n this.eventEmitter.emit<RecordUpdatedEvent<T>>(agentContext, {\n type: RepositoryEventTypes.RecordUpdated,\n payload: {\n // Record in event should be static\n record: updatedRecord.clone(),\n },\n })\n\n return updatedRecord\n }\n\n /** @inheritDoc {StorageService#delete} */\n public async delete(agentContext: AgentContext, record: T): Promise<void> {\n await this.getStorageService(agentContext).delete(agentContext, record)\n\n this.eventEmitter.emit<RecordDeletedEvent<T>>(agentContext, {\n type: RepositoryEventTypes.RecordDeleted,\n payload: {\n // Record in event should be static\n record: record.clone(),\n },\n })\n }\n\n /**\n * Delete record by id. Throws {RecordNotFoundError} if no record is found\n * @param id the id of the record to delete\n * @returns\n */\n public async deleteById(agentContext: AgentContext, id: string): Promise<void> {\n await this.getStorageService(agentContext).deleteById(agentContext, this.recordClass, id)\n\n this.eventEmitter.emit<RecordDeletedEvent<T>>(agentContext, {\n type: RepositoryEventTypes.RecordDeleted,\n payload: {\n record: { id, type: this.recordClass.type },\n },\n })\n }\n\n /** @inheritDoc {StorageService#getById} */\n public async getById(agentContext: AgentContext, id: string): Promise<T> {\n return this.getStorageService(agentContext).getById(agentContext, this.recordClass, id)\n }\n\n /**\n * Find record by id. Returns null if no record is found\n * @param id the id of the record to retrieve\n * @returns\n */\n public async findById(agentContext: AgentContext, id: string): Promise<T | null> {\n try {\n return await this.getStorageService(agentContext).getById(agentContext, this.recordClass, id)\n } catch (error) {\n if (error instanceof RecordNotFoundError) return null\n\n throw error\n }\n }\n\n /** @inheritDoc {StorageService#getAll} */\n public async getAll(agentContext: AgentContext): Promise<T[]> {\n return this.getStorageService(agentContext).getAll(agentContext, this.recordClass)\n }\n\n /** @inheritDoc {StorageService#findByQuery} */\n public async findByQuery(agentContext: AgentContext, query: Query<T>, queryOptions?: QueryOptions): Promise<T[]> {\n return this.getStorageService(agentContext).findByQuery(agentContext, this.recordClass, query, queryOptions)\n }\n\n /**\n * Find a single record by query. Returns null if not found.\n * @param query the query\n * @param cacheKey optional cache key to use for caching. By default query results are not cached, but if a cache key is provided\n * as well as the record allows caching and the agent has a cached storage service enabled it will use the cache.\n * @returns the record, or null if not found\n * @throws {RecordDuplicateError} if multiple records are found for the given query\n */\n public async findSingleByQuery(\n agentContext: AgentContext,\n query: Query<T>,\n { cacheKey }: { cacheKey?: string } = {}\n ): Promise<T | null> {\n const cache = agentContext.resolve(CacheModuleConfig)\n const useCacheStorage = cache.useCachedStorageService ?? false\n\n if (useCacheStorage && cacheKey) {\n const recordId = (await cache?.cache.get<string>(agentContext, cacheKey)) ?? null\n if (recordId !== null) {\n const recordJson = await cache?.cache.get<T>(agentContext, recordId)\n if (recordJson) return JsonTransformer.fromJSON(recordJson, this.recordClass)\n }\n }\n\n const records = await this.findByQuery(agentContext, query)\n if (records.length > 1) {\n throw new RecordDuplicateError(`Multiple records found for given query '${JSON.stringify(query)}'`, {\n recordType: this.recordClass.type,\n })\n }\n\n if (records.length < 1) {\n return null\n }\n\n if (useCacheStorage && cacheKey) {\n await cache?.cache.set(agentContext, cacheKey, records[0].id)\n await cache?.cache.set(agentContext, records[0].id, records[0].toJSON())\n }\n\n return records[0]\n }\n\n /**\n * Find a single record by query. Throws if not found\n * @param query the query\n * @returns the record\n * @throws {RecordDuplicateError} if multiple records are found for the given query\n * @throws {RecordNotFoundError} if no record is found for the given query\n */\n public async getSingleByQuery(agentContext: AgentContext, query: Query<T>): Promise<T> {\n const record = await this.findSingleByQuery(agentContext, query)\n\n if (!record) {\n throw new RecordNotFoundError(`No record found for given query '${JSON.stringify(query)}'`, {\n recordType: this.recordClass.type,\n })\n }\n\n return record\n }\n}\n"],"mappings":"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"}