import { isValidEnumValue } from '@deepkit/core' ; import { PropertySchema , typedArrayNamesMap , UnionGuardsTypes } from '@deepkit/type' ; import { BaseParser } from './bson-parser' ; import { findValueInObject } from './continuation' ; import { BSONType } from './utils' ; export type BSONTypeGuard = ( elementType : BSONType , parser : BaseParser ) => boolean ; export type BSONTypeGuardFactory = ( property : PropertySchema ) => BSONTypeGuard ; export const bsonTypeGuards = new Map < UnionGuardsTypes , BSONTypeGuardFactory > ( ) ; export function registerBSONTypeGuard ( type , factory ) { bsonTypeGuards . set ( type , factory ) ; } registerBSONTypeGuard ( 'class' , ( property ) => { const schema = property . getResolvedClassSchema ( ) ; if ( schema . discriminant ) { const discriminant = schema . getProperty ( schema . discriminant ) ; const discriminantValue = discriminant . type === 'literal' ? discriminant . literalValue : discriminant . defaultValue ? discriminant . defaultValue ( ) : undefined ; if ( discriminantValue === undefined ) { throw new Error ( `Discriminant ${ schema . getClassPropertyName ( discriminant . name ) } has no default value.` ) ; } const checker = ( elementType , name ) => { return name === discriminant . name && ( elementType !== BSONType . OBJECT ) ; } ; return ( elementType , parser ) => { if ( elementType !== BSONType . OBJECT ) return false ; const v = findValueInObject ( parser , checker ) ; return v === discriminantValue ; } ; } for ( const property of schema . getProperties ( ) ) { if ( property . type !== 'literal' ) continue ; const checker = ( elementType , name ) => { return name === property . name && ( elementType !== BSONType . OBJECT ) ; } ; return ( elementType , parser ) => { if ( elementType !== BSONType . OBJECT ) return false ; const v = findValueInObject ( parser , checker ) ; return v === property . literalValue ; } ; } throw new Error ( `Type of property ${ property . name } (${ property . toString ( ) }, ${ schema . getClassName ( ) }) has no discriminant or literal set. Could not discriminate the value.` ) ; } ) ; registerBSONTypeGuard ( 'string' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . STRING ; } ; } ) ; registerBSONTypeGuard ( 'enum' , ( property ) => { return ( elementType , parser ) => { const validType = elementType === BSONType . STRING || elementType === BSONType . NUMBER ; if ( validType ) { const v = parser . peek ( elementType , property ) ; return undefined !== v && ! isValidEnumValue ( property . resolveClassType , v , property . allowLabelsAsValue ) ; } return false ; } ; } ) ; registerBSONTypeGuard ( 'objectId' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . OID ; } ; } ) ; registerBSONTypeGuard ( 'uuid' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . BINARY ; } ; } ) ; registerBSONTypeGuard ( 'arrayBuffer' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . BINARY ; } ; } ) ; function typedArrayGuard ( property ) { return ( elementType , parser ) => { return elementType === BSONType . BINARY ; } ; } for ( const name of typedArrayNamesMap . keys ( ) ) { registerBSONTypeGuard ( name , typedArrayGuard ) ; } registerBSONTypeGuard ( 'date' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . DATE ; } ; } ) ; registerBSONTypeGuard ( 'any' , ( property ) => { return ( elementType , parser ) => { return true ; } ; } ) ; registerBSONTypeGuard ( 'union' , ( property ) => { throw new Error ( 'Union typechecking not implemented. Nested unions thus not supported yet.' ) ; } ) ; registerBSONTypeGuard ( 'array' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . ARRAY ; } ; } ) ; registerBSONTypeGuard ( 'map' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . OBJECT ; } ; } ) ; registerBSONTypeGuard ( 'patch' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . OBJECT ; } ; } ) ; registerBSONTypeGuard ( 'partial' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . OBJECT ; } ; } ) ; registerBSONTypeGuard ( 'number' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . NUMBER || elementType === BSONType . INT || elementType === BSONType . LONG ; } ; } ) ; registerBSONTypeGuard ( 'bigint' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . BINARY ; } ; } ) ; registerBSONTypeGuard ( 'boolean' , ( property ) => { return ( elementType , parser ) => { return elementType === BSONType . BOOLEAN ; } ; } ) ; registerBSONTypeGuard ( 'literal' , ( property ) => { return ( elementType , parser ) => { const v = parser . peek ( elementType ) ; return v === property . literalValue ; } ; } ) ;