import { ObjectMapping } from "./objectMapping" ; import { MappingRegistry } from "./mappingRegistry" ; import { Reference } from "../reference" ; import { MappingModel } from "./mappingModel" ; import { InternalSession } from "../session" ; import { ResultCallback } from "../core/callback" ; import { ReadContext } from "./readContext" ; import { WriteContext } from "./writeContext" ; import { PersistenceError } from "../persistenceError" ; var OriginalDocument = Symbol ( ) ; hidden export class ClassMapping extends ObjectMapping { private _baseClass : ClassMapping ; private _subclasses : ClassMapping [ ] ; private _discriminatorMap : Map < string , ClassMapping > ; private _registry : MappingRegistry ; inheritanceRoot : ClassMapping ; name : string ; discriminatorField : string ; classConstructor : Function ; param baseClass constructor ( baseClass ? ) { super ( ) ; this . flags |= MappingModel . MappingFlags . Class ; this . _baseClass = baseClass ; if ( ! baseClass ) { this . flags |= MappingModel . MappingFlags . InheritanceRoot ; this . inheritanceRoot = this ; } else { var previous = baseClass ; while ( baseClass ) { baseClass . _addSubClass ( this ) ; previous = baseClass ; baseClass = baseClass . _baseClass ; } this . inheritanceRoot = previous ; } } private _discriminatorValue : string ; get discriminatorValue ( ) : string { return this . _discriminatorValue ; } setDiscriminatorValue ( value ) { if ( typeof value !== "string" ) { throw new PersistenceError ( "Expected string for discriminator value." ) ; } this . _discriminatorValue = value ; this . _addDiscriminatorMapping ( value , this ) ; } setQueryDocumentDiscriminator ( obj ) { var discriminators ; if ( ( this . flags & MappingModel . MappingFlags . InheritanceRoot ) == 0 ) { discriminators = [ ] ; this . _getDescendantDiscriminators ( discriminators ) ; } if ( ! discriminators || discriminators . length == 0 ) { this . setQueryDocumentDiscriminator = < any > ( function ( ) { } ) ; return ; } var discriminator ; if ( discriminators . length == 1 ) { discriminator = discriminators [ 0 ] ; } else { discriminator = { '$in' : discriminators } ; } obj [ this . inheritanceRoot . discriminatorField ] = discriminator ; this . setQueryDocumentDiscriminator = < any > ( new Function ( "o" , "o['" + this . inheritanceRoot . discriminatorField + "'] = " + JSON . stringify ( discriminator ) ) ) ; } setDocumentDiscriminator ( obj ) { if ( this . _discriminatorValue === undefined ) { this . setDocumentDiscriminator = < any > ( function ( ) { } ) ; return ; } this . setDocumentDiscriminator = < any > ( new Function ( "o" , "o['" + this . inheritanceRoot . discriminatorField + "'] = \"" + this . _discriminatorValue + "\"" ) ) ; obj [ this . inheritanceRoot . discriminatorField ] = this . _discriminatorValue ; } getDocumentDiscriminator ( obj ) { this . getDocumentDiscriminator = < any > ( new Function ( "o" , "return o['" + this . inheritanceRoot . discriminatorField + "']" ) ) ; return obj [ this . inheritanceRoot . discriminatorField ] ; } private _getDescendantDiscriminators ( discriminators ) { if ( this . _discriminatorValue ) { discriminators . push ( this . _discriminatorValue ) ; } var subclasses = this . _subclasses ; if ( subclasses ) { for ( var i = 0 ; i < subclasses . length ; i ++ ) { var discriminatorValue = subclasses [ i ] . _discriminatorValue ; if ( discriminatorValue ) { discriminators . push ( discriminatorValue ) ; } } } } get hasSubClasses ( ) : boolean { return this . _subclasses && this . _subclasses . length > 0 ; } get hasBaseClass ( ) : boolean { return this . _baseClass !== undefined ; } private _addSubClass ( subclass ) { if ( ! this . _subclasses ) { this . _subclasses = [ ] ; } this . _subclasses . push ( subclass ) ; } private _addDiscriminatorMapping ( value , mapping ) { if ( ! this . _discriminatorMap ) { this . _discriminatorMap = new Map ( ) ; } if ( this . _discriminatorMap . has ( value ) ) { throw new PersistenceError ( "There is already a class in this inheritance hierarchy with a discriminator value of '" + value + "'." ) ; } this . _discriminatorMap . set ( value , mapping ) ; if ( this . _baseClass ) { this . _baseClass . _addDiscriminatorMapping ( value , mapping ) ; } } private _ensureRegistry ( ) { if ( ! this . _registry ) { this . _registry = new MappingRegistry ( ) ; this . _registry . addMapping ( this ) ; if ( this . _subclasses ) { var subclasses = this . _subclasses ; for ( var i = 0 , l = subclasses . length ; i < l ; i ++ ) { this . _registry . addMapping ( subclasses [ i ] ) ; } } } return this . _registry ; } read ( context , value ) { if ( value == null ) return null ; var mapping = this . getMapping ( context , value ) ; if ( mapping ) { return mapping . readClass ( context , value ) ; } } /**
     * Gets the mapping for the specified document. Note that this method can only be called on an inheritance root.
     */ getMapping ( context , document ) { var mapping = this . _getMappingForDocument ( document ) ; if ( mapping === undefined ) { context . addError ( `Unknown discriminator value '${ this . getDocumentDiscriminator ( document ) }' for class '${ this . name }'.` ) ; return ; } return mapping ; } private _getMappingForDocument ( document ) { var discriminatorValue = this . getDocumentDiscriminator ( document ) ; if ( discriminatorValue === undefined ) { return this ; } if ( this . _discriminatorMap ) { return this . _discriminatorMap . get ( discriminatorValue ) ; } } protected readClass ( context , value ) { var obj = this . readObject ( context , Object . create ( this . classConstructor . prototype ) , value , false ) ; if ( ( this . flags & MappingModel . MappingFlags . ImmutableEmbeddable ) == MappingModel . MappingFlags . ImmutableEmbeddable ) { obj [ OriginalDocument ] = value ; } return obj ; } write ( context , value ) { if ( value == null ) return null ; var originalDocument = value [ OriginalDocument ] ; if ( originalDocument != null ) { return originalDocument ; } var mapping = this . _ensureRegistry ( ) . getMappingForObject ( value ) ; return ( mapping || this ) . writeClass ( context , value , ! ! mapping ) ; } protected writeClass ( context , value , mappedConstructor ) { var document = { } ; if ( mappedConstructor ) { this . setDocumentDiscriminator ( document ) ; } else { this . setQueryDocumentDiscriminator ( document ) ; } return this . writeObject ( context , document , value ) ; } areEqual ( documentValue1 , documentValue2 ) { if ( documentValue1 === documentValue2 ) return true ; if ( documentValue1 == null || documentValue2 == null ) return false ; var mapping1 = this . _getMappingForDocument ( documentValue1 ) ; var mapping2 = this . _getMappingForDocument ( documentValue2 ) ; if ( mapping1 === undefined || mapping2 === undefined || mapping1 !== mapping2 ) { return false ; } return mapping1 . _areEqual ( documentValue1 , documentValue2 ) ; } private _areEqual ( documentValue1 , documentValue2 ) { return super . areEqual ( documentValue1 , documentValue2 ) ; } walk ( session , value , flags , entities , embedded , references ) { if ( ! value || typeof value !== "object" ) return ; return ( this . _ensureRegistry ( ) . getMappingForObject ( value ) || this ) . _walk ( session , value , flags , entities , embedded , references ) ; } private _walk ( session , value , flags , entities , embedded , references ) { super . walk ( session , value , flags , entities , embedded , references ) ; } fetch ( session , parentEntity , value , path , depth , callback ) { if ( ! value || typeof value !== "object" ) { process . nextTick ( ( ) => callback ( null , value ) ) ; return ; } return ( this . _ensureRegistry ( ) . getMappingForObject ( value ) || this ) . _fetch ( session , parentEntity , value , path , depth , callback ) ; } private _fetch ( session , parentEntity , value , path , depth , callback ) { super . fetch ( session , parentEntity , value , path , depth , callback ) ; } }