Skip to content

Commit

Permalink
[feat] add reach-like functionality to object (#37118) (#37139)
Browse files Browse the repository at this point in the history
* [feat] add reach-like functionality to object

In #36804 we need to validate a `Partial<HttpConfig>` object which may
or may not have all the required keys attached to it.  This is the type
of use-case for `Joi.reach`, so we should expose a reach-like method on
the object validation class so that you can return the validator for a
specific key on an object.

* [fix] change to validateKey

* [fix] use throw error matcher

* [fix] use same interface for validate

* [fix] change test name]
  • Loading branch information
toddself committed May 28, 2019
1 parent c0faaf7 commit 00ee700
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
12 changes: 12 additions & 0 deletions packages/kbn-config-schema/src/types/object_type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,15 @@ test('includes namespace in failure when wrong value type', () => {

expect(() => type.validate(value, {}, 'foo-namespace')).toThrowErrorMatchingSnapshot();
});

test('individual keys can validated', () => {
const type = schema.object({
foo: schema.boolean(),
});

const value = false;
expect(() => type.validateKey('foo', value)).not.toThrowError();
expect(() => type.validateKey('bar', '')).toThrowErrorMatchingInlineSnapshot(
`"bar is not a valid part of this schema"`
);
});
15 changes: 15 additions & 0 deletions packages/kbn-config-schema/src/types/object_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import typeDetect from 'type-detect';
import { AnySchema, internals } from '../internals';
import { Type, TypeOptions } from './type';
import { ValidationError } from '../errors';

export type Props = Record<string, Type<any>>;

Expand All @@ -31,6 +32,8 @@ export type TypeOf<RT extends Type<any>> = RT['type'];
export type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;

export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>> {
private props: Record<string, AnySchema>;

constructor(props: P, options: TypeOptions<{ [K in keyof P]: TypeOf<P[K]> }> = {}) {
const schemaKeys = {} as Record<string, AnySchema>;
for (const [key, value] of Object.entries(props)) {
Expand All @@ -44,6 +47,7 @@ export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>>
.default();

super(schema, options);
this.props = schemaKeys;
}

protected handleError(type: string, { reason, value }: Record<string, any>) {
Expand All @@ -57,4 +61,15 @@ export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>>
return reason[0];
}
}

validateKey(key: string, value: any) {
if (!this.props[key]) {
throw new Error(`${key} is not a valid part of this schema`);
}
const { value: validatedValue, error } = this.props[key].validate(value);
if (error) {
throw new ValidationError(error as any, key);
}
return validatedValue;
}
}

0 comments on commit 00ee700

Please sign in to comment.