diff --git a/packages/core/lib/cache/doc.ts b/packages/core/lib/cache/doc.ts index 02b847a6..fb728456 100644 --- a/packages/core/lib/cache/doc.ts +++ b/packages/core/lib/cache/doc.ts @@ -36,7 +36,7 @@ function checkKeyIsValid(input: T) { * or any of these characters - _ $ + */ return /^[a-z]+$/.test(key[0]) && /^[a-z0-9-~_/$/+]+$/.test(key) - }, 'key is not valid')(input) + }, { status: 422, msg: 'key is not valid' })(input) } /** @@ -52,12 +52,12 @@ export const create = ( ttl?: string, ) => of({ store, key, value, ttl }) - .map(convertTTL) - .map(removeTTL) - .chain(checkKeyIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .map(convertTTL) + .map(removeTTL) + .chain(checkKeyIsValid) .chain(Async.fromPromise((input) => svc.createDoc(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) @@ -70,10 +70,10 @@ export const create = ( */ export const get = (store: string, key: string) => of({ store, key }) - .chain(checkKeyIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkKeyIsValid) .chain(Async.fromPromise((input) => svc.getDoc(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) @@ -94,12 +94,12 @@ export const update = ( ttl?: string, ) => of({ store, key, value, ttl }) - .map(convertTTL) - .map(removeTTL) - .chain(checkKeyIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .map(convertTTL) + .map(removeTTL) + .chain(checkKeyIsValid) .chain(Async.fromPromise((input) => svc.updateDoc(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) @@ -112,10 +112,10 @@ export const update = ( */ export const del = (store: string, key: string) => of({ store, key }) - .chain(checkKeyIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkKeyIsValid) .chain(Async.fromPromise((input) => svc.deleteDoc(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) diff --git a/packages/core/lib/cache/mod.test.ts b/packages/core/lib/cache/mod.test.ts index 80df330d..b5cea587 100644 --- a/packages/core/lib/cache/mod.test.ts +++ b/packages/core/lib/cache/mod.test.ts @@ -62,37 +62,41 @@ Deno.test('cache', async (t) => { }, ) - await t.step('should reject if the name is invalid', async (t) => { + await t.step('should resolve HyperErr if the name is invalid', async (t) => { await t.step('does not start with alphanumeric', async () => { await cache .createStore('_foo') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a space', async () => { await cache .createStore('foo bar') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a slash', async () => { await cache .createStore('foo/bar') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains non URI friendly character', async () => { await cache .createStore('foo?bar') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) }) @@ -108,37 +112,41 @@ Deno.test('cache', async (t) => { .toPromise() }) - await t.step('should reject if the name is invalid', async (t) => { + await t.step('should resolve HyperErr if the name is invalid', async (t) => { await t.step('does not start with alphanumeric', async () => { await cache .deleteStore('_foo') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a space', async () => { await cache .deleteStore('foo bar') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a slash', async () => { await cache .deleteStore('foo/bar') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains non URI friendly character', async () => { await cache .deleteStore('foo?bar') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) }) @@ -156,37 +164,41 @@ Deno.test('cache', async (t) => { .toPromise() }) - await t.step('should reject if the name is invalid', async (t) => { + await t.step('should resolve HyperErr if the name is invalid', async (t) => { await t.step('does not start with alphanumeric', async () => { await cache .queryStore('_foo', 'foo*') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a space', async () => { await cache .queryStore('foo bar', 'foo*') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a slash', async () => { await cache .queryStore('foo/bar', 'foo*') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains non URI friendly character', async () => { await cache .queryStore('foo?bar', 'foo*') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) }) @@ -228,12 +240,13 @@ Deno.test('cache', async (t) => { .toPromise() }) - await t.step('should reject if cache doc has an invalid key', async () => { + await t.step('should resolve HyperErr if cache doc has an invalid key', async () => { await cache .createDoc('store', 'Not_Valid', { beep: 'boop' }) .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) @@ -363,12 +376,13 @@ Deno.test('cache', async (t) => { .toPromise() }) - await t.step('should reject if cache doc has an invalid key', async () => { + await t.step('should resolve HyperErr if cache doc has an invalid key', async () => { await cache .updateDoc('store', 'Not_Valid', { beep: 'boop' }) .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) @@ -385,12 +399,13 @@ Deno.test('cache', async (t) => { .toPromise() }) - await t.step('should reject if cache doc has an invalid key', async () => { + await t.step('should resolve HyperErr if cache doc has an invalid key', async () => { await cache .deleteDoc('store', 'Not_Valid') .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) }) diff --git a/packages/core/lib/cache/store.ts b/packages/core/lib/cache/store.ts index 6132ca95..9172e57a 100644 --- a/packages/core/lib/cache/store.ts +++ b/packages/core/lib/cache/store.ts @@ -20,7 +20,7 @@ const checkNameIsValid = is((name: string) => { // cache names should only start with alphanumeric characters // should return a true or false return /^[a-z0-9]+$/.test(name[0]) && /^[a-z0-9-~_]+$/.test(name) -}, 'name is not valid') +}, { status: 422, msg: 'name is not valid' }) export const index = () => ask(({ svc }: ReaderEnvironment) => { @@ -37,10 +37,10 @@ export const index = () => export const create = (name: string) => of(name) .map(toLower) - .chain(checkNameIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkNameIsValid) .chain(Async.fromPromise((input) => svc.createStore(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) @@ -52,10 +52,10 @@ export const create = (name: string) => */ export const del = (name: string) => of(name) - .chain(checkNameIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkNameIsValid) .chain(Async.fromPromise((input) => svc.destroyStore(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) @@ -67,12 +67,12 @@ export const del = (name: string) => * @param {string} pattern */ export const query = (name: string, pattern: string) => - of(name) - .chain(checkNameIsValid) - .map((name) => ({ store: name, pattern })) + of({ store: name, pattern }) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(({ store }) => checkNameIsValid(store)) + .map(() => input) .chain(Async.fromPromise((input) => svc.listDocs(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) diff --git a/packages/core/lib/data/db.ts b/packages/core/lib/data/db.ts index 6d39a71c..c0e62113 100644 --- a/packages/core/lib/data/db.ts +++ b/packages/core/lib/data/db.ts @@ -17,17 +17,17 @@ const setDescending = (arg: T) => ({ descending: Boolean(arg.descending), }) -const checkNameIsValid = is(() => true, 'database name is not valid') +const checkNameIsValid = is(() => true, { status: 422, msg: 'database name is not valid' }) /** * @param {string} name */ export const create = (name: string) => of(name) - .chain(checkNameIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkNameIsValid) .chain(Async.fromPromise((input) => svc.createDatabase(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) @@ -39,10 +39,10 @@ export const create = (name: string) => */ export const remove = (name: string) => of(name) - .chain(checkNameIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkNameIsValid) .chain(Async.fromPromise((input) => svc.removeDatabase(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) diff --git a/packages/core/lib/queue/mod.test.ts b/packages/core/lib/queue/mod.test.ts index 28d13c39..cc49f0ea 100644 --- a/packages/core/lib/queue/mod.test.ts +++ b/packages/core/lib/queue/mod.test.ts @@ -77,7 +77,7 @@ Deno.test('queue', async (t) => { }, ) - await t.step('should reject if the name is invalid', async (t) => { + await t.step('should resolve HyperErr if the name is invalid', async (t) => { await t.step('contains a space', async () => { await queue .create({ @@ -86,8 +86,9 @@ Deno.test('queue', async (t) => { target: 'https://foo.bar', }) .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains a slash', async () => { @@ -98,8 +99,9 @@ Deno.test('queue', async (t) => { target: 'https://foo.bar', }) .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) await t.step('contains non URI friendly character', async () => { @@ -110,8 +112,9 @@ Deno.test('queue', async (t) => { target: 'https://foo.bar', }) .toPromise() - .then(() => assert(false)) - .catch(() => assert(true)) + .then((err: any) => { + assertEquals(err.status, 422) + }) }) }) }) diff --git a/packages/core/lib/queue/queue.ts b/packages/core/lib/queue/queue.ts index c09c5eaf..f025d836 100644 --- a/packages/core/lib/queue/queue.ts +++ b/packages/core/lib/queue/queue.ts @@ -24,7 +24,7 @@ function checkNameIsValid(input: T) { * or any of these characters - _ ~ */ return /^[a-z0-9-~_]+$/.test(name) - }, 'queue name is not valid!')(input) + }, { status: 422, msg: 'queue name is not valid!' })(input) } export const index = () => @@ -39,10 +39,10 @@ export const index = () => export const create = (input: Parameters[0]) => of(input) .map(over(lensProp('name'), toLower)) - .chain(checkNameIsValid) .chain((input) => ask(({ svc }: ReaderEnvironment) => { return Async.of(input) + .chain(checkNameIsValid) .chain(Async.fromPromise((input) => svc.create(input))) .bichain($resolveHyperErr, $logHyperErr) }).chain(lift) diff --git a/packages/core/lib/utils/err.test.js b/packages/core/lib/utils/err.test.js index e22a6816..c100ab70 100644 --- a/packages/core/lib/utils/err.test.js +++ b/packages/core/lib/utils/err.test.js @@ -89,7 +89,7 @@ test('HyperErrFrom - should map ZodError to HyperErr', async () => { assertEquals(err.ok, false) assertEquals(err.status, 500) - assertEquals(err.msg, 'Invalid Return \'ok\': Required.') + assertEquals(err.msg, "Invalid Return 'ok': Required.") const errWrongArgs = await fn({ name: 123 }).catch(HyperErrFrom) @@ -97,7 +97,7 @@ test('HyperErrFrom - should map ZodError to HyperErr', async () => { assertEquals(errWrongArgs.status, 422) assertEquals( errWrongArgs.msg, - 'Invalid Arguments \'name\': Expected string, received number.', + "Invalid Arguments 'name': Expected string, received number.", ) }) diff --git a/packages/core/lib/utils/mod.ts b/packages/core/lib/utils/mod.ts index a6a71513..5b36ba74 100644 --- a/packages/core/lib/utils/mod.ts +++ b/packages/core/lib/utils/mod.ts @@ -14,8 +14,9 @@ export const { ask, of, lift } = AsyncReader export * from './err.js' -const doValidate = (pred: (val: V) => boolean, msg: string) => (value: V) => - pred(value) ? Right(value) : Left(HyperErr(msg)) +const doValidate = + (pred: (val: V) => boolean, msg: Parameters[0]) => (value: V) => + pred(value) ? Right(value) : Left(HyperErr(msg)) /** * Given a predicate function and error message, * return a Resolved AsyncReader or Rejected AsyncReader. @@ -26,10 +27,10 @@ const doValidate = (pred: (val: V) => boolean, msg: string) => (val * If the predicate function returns false, then an Rejected AsyncReader containing * a HyperErr with the message */ -export const is = (pred: (val: V) => boolean, msg: string) => +export const is = (pred: (val: V) => boolean, msg: Parameters[0]) => // deno-lint-ignore ban-ts-comment // @ts-ignore - compose>(lift, eitherToAsync, doValidate(pred, msg)) + compose>(eitherToAsync, doValidate(pred, msg)) export const $logHyperErr = (res: V) => { if (isHyperErr(res)) console.log(res)