Adds config-schema nullable composite type (#41728)

The `nullable` type is very similar to the `maybe` type, except that
it validates nulls and undefined values to null, instead of undefined.
Eg,

    maybe(T): T | undefined
    nullable(T): T | null
This commit is contained in:
Patrick Mueller 2019-08-06 09:46:00 -04:00 committed by GitHub
parent 9f6188f314
commit 25026381ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 0 deletions

View file

@ -36,6 +36,7 @@ import {
MapOfOptions,
MapOfType,
MaybeType,
NullableType,
NeverType,
NumberOptions,
NumberType,
@ -100,6 +101,10 @@ function maybe<V>(type: Type<V>): Type<V | undefined> {
return new MaybeType(type);
}
function nullable<V>(type: Type<V>): Type<V | null> {
return new NullableType(type);
}
function object<P extends Props>(props: P, options?: ObjectTypeOptions<P>): ObjectType<P> {
return new ObjectType(props, options);
}
@ -191,6 +196,7 @@ export const schema = {
literal,
mapOf,
maybe,
nullable,
never,
number,
object,

View file

@ -4,4 +4,6 @@ exports[`fails if null 1`] = `"expected value of type [string] but got [null]"`;
exports[`includes namespace in failure 1`] = `"[foo-namespace]: expected value of type [string] but got [null]"`;
exports[`validates basic type 1`] = `"expected value of type [string] but got [number]"`;
exports[`validates contained type 1`] = `"value is [foo] but it must have a maximum length of [1]."`;

View file

@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`includes namespace in failure 1`] = `"[foo-namespace]: value is [foo] but it must have a maximum length of [1]."`;
exports[`validates basic type 1`] = `"expected value of type [string] but got [number]"`;
exports[`validates contained type 1`] = `"value is [foo] but it must have a maximum length of [1]."`;

View file

@ -26,6 +26,7 @@ export { ConditionalType, ConditionalTypeValue } from './conditional_type';
export { DurationOptions, DurationType } from './duration_type';
export { LiteralType } from './literal_type';
export { MaybeType } from './maybe_type';
export { NullableType } from './nullable_type';
export { MapOfOptions, MapOfType } from './map_type';
export { NumberOptions, NumberType } from './number_type';
export { ObjectType, ObjectTypeOptions, Props, TypeOf } from './object_type';

View file

@ -45,6 +45,12 @@ test('validates contained type', () => {
expect(() => type.validate('foo')).toThrowErrorMatchingSnapshot();
});
test('validates basic type', () => {
const type = schema.maybe(schema.string());
expect(() => type.validate(666)).toThrowErrorMatchingSnapshot();
});
test('fails if null', () => {
const type = schema.maybe(schema.string());
expect(() => type.validate(null)).toThrowErrorMatchingSnapshot();

View file

@ -0,0 +1,63 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { schema } from '..';
test('returns value if specified', () => {
const type = schema.nullable(schema.string());
expect(type.validate('test')).toEqual('test');
});
test('returns null if null', () => {
const type = schema.nullable(schema.string());
expect(type.validate(null)).toEqual(null);
});
test('returns null if undefined', () => {
const type = schema.nullable(schema.string());
expect(type.validate(undefined)).toEqual(null);
});
test('returns null even if contained type has a default value', () => {
const type = schema.nullable(
schema.string({
defaultValue: 'abc',
})
);
expect(type.validate(undefined)).toEqual(null);
});
test('validates contained type', () => {
const type = schema.nullable(schema.string({ maxLength: 1 }));
expect(() => type.validate('foo')).toThrowErrorMatchingSnapshot();
});
test('validates basic type', () => {
const type = schema.nullable(schema.string());
expect(() => type.validate(666)).toThrowErrorMatchingSnapshot();
});
test('includes namespace in failure', () => {
const type = schema.nullable(schema.string({ maxLength: 1 }));
expect(() => type.validate('foo', {}, 'foo-namespace')).toThrowErrorMatchingSnapshot();
});

View file

@ -0,0 +1,32 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Type } from './type';
export class NullableType<V> extends Type<V | null> {
constructor(type: Type<V>) {
super(
type
.getSchema()
.optional()
.allow(null)
.default(null)
);
}
}