From 292df7013dcc13e25d1fb60ce0ac81c945812fbb Mon Sep 17 00:00:00 2001 From: Evan Hahn Date: Mon, 18 Nov 2024 14:49:52 -0600 Subject: [PATCH] chore: use `NotFoundError` utility in more places (#965) This makes the following kind of change in a bunch of places: ```diff -throw new Error('Not found') +throw new NotFoundError() ``` I think this is a useful improvement on its own, but the changes to DataStore will also make [an upcoming change easier][0]. [0]: https://github.com/digidem/comapeo-core/issues/188 --- src/core-ownership.js | 5 ++--- src/datastore/index.js | 7 ++++--- src/errors.js | 4 ++-- src/mapeo-manager.js | 5 +++-- src/mapeo-project.js | 9 +++++---- test/errors.js | 17 +++++++++++++++++ 6 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 test/errors.js diff --git a/src/core-ownership.js b/src/core-ownership.js index 47bd65487..5a3832121 100644 --- a/src/core-ownership.js +++ b/src/core-ownership.js @@ -16,6 +16,7 @@ import pDefer from 'p-defer' import { NAMESPACES } from './constants.js' import { TypedEmitter } from 'tiny-typed-emitter' import { omit } from './lib/omit.js' +import { NotFoundError } from './errors.js' /** * @import { * CoreOwnershipWithSignatures, @@ -90,9 +91,7 @@ export class CoreOwnership extends TypedEmitter { const result = (await this.#dataType[kSelect]()) .where(or.apply(null, expressions)) .get() - if (!result) { - throw new Error('NotFound') - } + if (!result) throw new NotFoundError() return result.docId } diff --git a/src/datastore/index.js b/src/datastore/index.js index 19b9ddd86..dab7458f2 100644 --- a/src/datastore/index.js +++ b/src/datastore/index.js @@ -5,6 +5,7 @@ import pDefer from 'p-defer' import { discoveryKey } from 'hypercore-crypto' import { NAMESPACE_SCHEMAS } from '../constants.js' import { createMap } from '../utils.js' +import { NotFoundError } from '../errors.js' /** @import { MapeoDoc } from '@comapeo/schema' */ /** @@ -182,7 +183,7 @@ export class DataStore extends TypedEmitter { const coreRecord = this.#coreManager.getCoreByDiscoveryKey(coreDiscoveryKey) if (!coreRecord) throw new Error('Invalid versionId') const block = await coreRecord.core.get(index, { wait: false }) - if (!block) throw new Error('Not Found') + if (!block) throw new NotFoundError('Not Found') return decode(block, { coreDiscoveryKey, index }) } @@ -202,9 +203,9 @@ export class DataStore extends TypedEmitter { async readRaw(versionId) { const { coreDiscoveryKey, index } = parseVersionId(versionId) const coreRecord = this.#coreManager.getCoreByDiscoveryKey(coreDiscoveryKey) - if (!coreRecord) throw new Error('core not found') + if (!coreRecord) throw new NotFoundError('core not found') const block = await coreRecord.core.get(index, { wait: false }) - if (!block) throw new Error('Not Found') + if (!block) throw new NotFoundError() return block } diff --git a/src/errors.js b/src/errors.js index 223461383..65bd6c968 100644 --- a/src/errors.js +++ b/src/errors.js @@ -1,5 +1,5 @@ export class NotFoundError extends Error { - constructor() { - super('Not found') + constructor(message = 'Not found') { + super(message) } } diff --git a/src/mapeo-manager.js b/src/mapeo-manager.js index 71fb26843..5df3d83d9 100644 --- a/src/mapeo-manager.js +++ b/src/mapeo-manager.js @@ -51,6 +51,7 @@ import { kRequestFullStop, kRescindFullStopRequest, } from './sync/sync-api.js' +import { NotFoundError } from './errors.js' /** @import { ProjectSettingsValue as ProjectValue } from '@comapeo/schema' */ /** @import NoiseSecretStream from '@hyperswarm/secret-stream' */ /** @import { SetNonNullable } from 'type-fest' */ @@ -456,7 +457,7 @@ export class MapeoManager extends TypedEmitter { .get() if (!projectKeysTableResult) { - throw new Error(`NotFound: project ID ${projectPublicId} not found`) + throw new NotFoundError(`Project ID ${projectPublicId} not found`) } const { projectId } = projectKeysTableResult @@ -896,7 +897,7 @@ export class MapeoManager extends TypedEmitter { .get() if (!row) { - throw new Error(`NotFound: project ID ${projectPublicId} not found`) + throw new NotFoundError(`Project ID ${projectPublicId} not found`) } const { keysCipher, projectId, projectInfo } = row diff --git a/src/mapeo-project.js b/src/mapeo-project.js index 541995bc5..dcb719373 100644 --- a/src/mapeo-project.js +++ b/src/mapeo-project.js @@ -56,6 +56,7 @@ import { Logger } from './logger.js' import { IconApi } from './icon-api.js' import { readConfig } from './config-import.js' import TranslationApi from './translation-api.js' +import { NotFoundError } from './errors.js' /** @import { ProjectSettingsValue } from '@comapeo/schema' */ /** @import { CoreStorage, KeyPair, Namespace, ReplicationStream } from './types.js' */ @@ -654,7 +655,7 @@ export class MapeoProject extends TypedEmitter { const coreId = this.#coreManager .getCoreByDiscoveryKey(coreDiscoveryKey) ?.key.toString('hex') - if (!coreId) throw new Error('NotFound') + if (!coreId) throw new NotFoundError() return this.#coreOwnership.getOwner(coreId) } @@ -874,7 +875,7 @@ export class MapeoProject extends TypedEmitter { const fieldRefs = fieldNames.map((fieldName) => { const fieldRef = fieldNameToRef.get(fieldName) if (!fieldRef) { - throw new Error( + throw new NotFoundError( `field ${fieldName} not found (referenced by preset ${value.name})})` ) } @@ -886,7 +887,7 @@ export class MapeoProject extends TypedEmitter { } const iconRef = iconNameToRef.get(iconName) if (!iconRef) { - throw new Error( + throw new NotFoundError( `icon ${iconName} not found (referenced by preset ${value.name})` ) } @@ -933,7 +934,7 @@ export class MapeoProject extends TypedEmitter { }) ) } else { - throw new Error( + throw new NotFoundError( `docRef for ${value.docRefType} with name ${name} not found` ) } diff --git a/test/errors.js b/test/errors.js new file mode 100644 index 000000000..2e68dee80 --- /dev/null +++ b/test/errors.js @@ -0,0 +1,17 @@ +import test, { describe } from 'node:test' +import assert from 'node:assert/strict' +import { NotFoundError } from '../src/errors.js' + +describe('NotFoundError', () => { + test('subclasses Error', () => { + assert(new NotFoundError() instanceof Error) + }) + + test('with no error message', () => { + assert.equal(new NotFoundError().message, 'Not found') + }) + + test('with custom error message', () => { + assert.equal(new NotFoundError('foo').message, 'foo') + }) +})