import * as async from "async" ; import { InternalMapping } from "./internalMapping" ; import { MappingBase } from "./mappingBase" ; import { Reference } from "../reference" ; import { MappingModel } from "./mappingModel" ; import { InternalSession } from "../session" ; import { ResultCallback } from "../core/callback" ; import { EntityMapping } from "./entityMapping" ; import { ResolveContext } from "./resolveContext" ; import { TupleMapping } from "./tupleMapping" ; import { ReadContext } from "./readContext" ; import { Observer } from "../observer" ; import { WriteContext } from "./writeContext" ; import { PersistenceError } from "../persistenceError" ; hidden export class ArrayMapping extends MappingBase { constructor ( public elementMapping ) { super ( MappingModel . MappingFlags . Array ) ; } read ( context , value ) { if ( value == null ) return null ; if ( ! Array . isArray ( value ) ) { context . addError ( "Expected array." ) ; return ; } var result = new Array ( value . length ) , mapping = this . elementMapping ; for ( var i = 0 , l = value . length ; i < l ; i ++ ) { result [ i ] = mapping . read ( context , value [ i ] ) ; } if ( context . observer ) { context . observer . watch ( result ) ; } return result ; } write ( context , value ) { if ( value == null ) return null ; if ( ! Array . isArray ( value ) ) { context . addError ( "Expected array." ) ; return ; } var result = new Array ( value . length ) , mapping = this . elementMapping ; for ( var i = 0 , l = value . length ; i < l ; i ++ ) { result [ i ] = mapping . write ( context , value [ i ] ) ; } return result ; } watch ( value , observer , visited ) { if ( ! value || ! Array . isArray ( value ) ) return ; observer . watch ( value ) ; for ( var i = 0 , l = value . length ; i < l ; i ++ ) { this . elementMapping . watch ( value [ i ] , observer , visited ) ; } } areEqual ( documentValue1 , documentValue2 ) { if ( documentValue1 === documentValue2 ) return true ; if ( documentValue1 == null || documentValue2 == null ) return false ; if ( ! Array . isArray ( documentValue1 ) || ! Array . isArray ( documentValue2 ) || documentValue1 . length != documentValue2 . length ) { return false ; } var mapping = this . elementMapping ; for ( var i = 0 , l = documentValue1 . length ; i < l ; i ++ ) { var fieldValue1 = documentValue1 [ i ] ; var fieldValue2 = documentValue2 [ i ] ; if ( fieldValue1 !== fieldValue2 && ! mapping . areEqual ( fieldValue1 , fieldValue2 ) ) { return false ; } } return true ; } walk ( session , value , flags , entities , embedded , references ) { if ( ! Array . isArray ( value ) ) { return ; } var mapping = this . elementMapping ; for ( var i = 0 , l = value . length ; i < l ; i ++ ) { mapping . walk ( session , value [ i ] , flags , entities , embedded , references ) ; } } fetch ( session , parentEntity , value , path , depth , callback ) { if ( ! Array . isArray ( value ) || value . length == 0 ) { process . nextTick ( ( ) => callback ( null , value ) ) ; return ; } var mapping = this . elementMapping ; async . map ( value , ( item , done ) => mapping . fetch ( session , parentEntity , item , path , depth , done ) , callback ) ; } fetchInverse ( session , parentEntity , propertyName , path , depth , callback ) { if ( ! parentEntity ) { return callback ( new PersistenceError ( "Parent entity required to resolve inverse relationship." ) ) ; } if ( ! ( this . elementMapping . flags & MappingModel . MappingFlags . Entity ) ) { return callback ( new PersistenceError ( "Element mapping must be an entity to resolve inverse relationship." ) ) ; } session . getPersister ( < EntityMapping > this . elementMapping ) . findInverseOf ( parentEntity , propertyName , ( err , value ) => { if ( err ) return callback ( err ) ; this . fetch ( session , this , value , path , depth , callback ) ; } ) ; } protected resolveCore ( context ) { var property = context . currentProperty , index ; if ( property == "$" || ( ( index = parseInt ( property ) ) === index ) ) { if ( context . resolveProperty ( this . elementMapping , property ) ) { return ; } } this . elementMapping . resolve ( context ) ; } private _nestedDepth : number ; /**
     * Gets the maximum depth of nested array and tuple mappings
     */ get nestedDepth ( ) : number { if ( this . _nestedDepth !== undefined ) { this . _nestedDepth = this . _findNestedDepth ( 0 , this ) ; } return this . _nestedDepth ; } private _findNestedDepth ( depth , mapping ) { if ( mapping . flags & MappingModel . MappingFlags . Array ) { return this . _findNestedDepth ( depth + 1 , ( < ArrayMapping > mapping ) . elementMapping ) ; } else if ( mapping . flags & MappingModel . MappingFlags . Tuple ) { var elementMappings = ( < TupleMapping > mapping ) . elementMappings ; for ( var i = 0 , l = elementMappings . length ; i < l ; i ++ ) { depth = Math . max ( depth , this . _findNestedDepth ( depth + 1 , elementMappings [ i ] ) ) ; } } return depth ; } }