model-layer
Version:
135 lines (109 loc) • 3.43 kB
text/typescript
import {Type, IType, ITypeParams} from "./Type";
import {Model} from "../Model";
import {invalidValuesAsString} from "../utils";
import {value2json, equal, clone} from "./AnyType";
import {
InvalidOrValueError,
RequiredOrArrayError,
EmptyOrArrayError,
InvalidOrTypeError
} from "../errors";
type ElementType < T extends any[] > = (
// tslint:disable-next-line: no-shadowed-variable
T extends ReadonlyArray< infer ElementType > ?
ElementType :
never
);
type TypesOrModelsOrCollections = (
Array<
IType |
(new(...args: any) => Model<any>)
>
);
export interface IOrTypeParams extends ITypeParams {
or: TypesOrModelsOrCollections;
}
export interface IOrType<T extends IType> extends IType {
<TOrTypes extends TypesOrModelsOrCollections>(
params: IOrTypeParams &
{or: TOrTypes}
): ElementType< TOrTypes >;
TOutput: T["TOutput"];
TInput: T["TInput"];
TJson: T["TJson"];
}
export class OrType extends Type {
static prepareDescription(description: any, key: string) {
if ( description.type === "or" ) {
// prepare OR description
try {
description.or = description.or.map((childDescription: any) =>
Type.create( childDescription, key )
);
} catch (err) {
return;
}
}
}
or: Type[];
constructor({
or,
...otherParams
}: IOrTypeParams) {
super(otherParams);
if ( !Array.isArray(or) ) {
throw new RequiredOrArrayError({});
}
if ( !or.length ) {
throw new EmptyOrArrayError({});
}
for (let i = 0, n = or.length; i < n; i++) {
const elem = or[i];
if ( elem instanceof Type ) {
continue;
}
throw new InvalidOrTypeError({
index: i,
invalidValue: invalidValuesAsString(elem)
});
}
this.or = or as any;
}
prepare(originalValue: any, key: string, model: any) {
if ( originalValue == null ) {
return null;
}
let value;
let currentType: Type | null = null;
for (let i = 0, n = this.or.length; i < n; i++) {
const description = this.or[i];
try {
value = description.prepare(originalValue, key, model);
} catch (err) {
continue;
}
currentType = description;
break;
}
if ( !currentType ) {
const valueAsString = invalidValuesAsString( originalValue );
throw new InvalidOrValueError({
key,
invalidValue: valueAsString,
typesNames: this.or.map((childDescription) =>
childDescription.type
)
});
}
return value;
}
clone(value: any, stack: any) {
return clone(value, stack);
}
equal(selfValue: any, otherValue: any, stack: any) {
return equal(selfValue, otherValue, stack);
}
toJSON(value: any, stack: any) {
return value2json( value, stack );
}
}