import { Callback } from "../core/callback" ; import { ResultCallback } from "../core/callback" ; import { IteratorCallback } from "../core/callback" ; import { InternalSession } from "../session" ; import { QueryDefinition } from "./queryDefinition" ; import { QueryKind } from "./queryKind" ; import { Constructor } from "../index" ; import { PersistenceError } from "../persistenceError" ; import { Observable } from "rx" ; import { Cursor } from "../persister" ; import { CollationOptions } from "../mapping/collationOptions" ; export interface QueryBuilder < T > { findAll ( callback ? ) : FindQuery < T > ; findAll ( criteria , callback ? ) : FindQuery < T > ; findOne ( callback ? ) : FindOneQuery < T > ; findOne ( criteria , callback ? ) : FindOneQuery < T > ; findOneById ( id , callback ? ) : FindOneQuery < T > ; findOneAndRemove ( callback ? ) : FindOneAndRemoveQuery < T > ; findOneAndRemove ( criteria , callback ? ) : FindOneAndRemoveQuery < T > ; findOneAndUpdate ( updateDocument , callback ? ) : FindOneAndUpdateQuery < T > ; findOneAndUpdate ( criteria , updateDocument , callback ? ) : FindOneAndUpdateQuery < T > ; findOneAndUpsert ( updateDocument , callback ? ) : FindOneAndUpdateQuery < T > ; findOneAndUpsert ( criteria , updateDocument , callback ? ) : FindOneAndUpdateQuery < T > ; removeAll ( callback ? ) : void ; removeAll ( criteria , callback ? ) : void ; removeOne ( callback ? ) : void ; removeOne ( criteria , callback ? ) : void ; updateAll ( updateDocument , callback ? ) : void ; updateAll ( criteria , updateDocument , callback ? ) : void ; updateOne ( updateDocument , callback ? ) : void ; updateOne ( criteria , updateDocument , callback ? ) : void ; upsert ( updateDocument , callback ? ) : void ; upsert ( criteria , updateDocument , callback ? ) : void ; distinct ( key , callback ) : void ; distinct ( key , criteria , callback ) : void ; count ( callback ? ) : CountQuery ; count ( criteria , callback ? ) : CountQuery ; } export interface QueryDocument { [ name ] : any ; } export interface Query < T > { /**
     * Executes the query if a callback was not passed to one of the other methods in the chain.
     */ execute ( callback ) : void ; /**
     * Returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) for the query.
     */ asPromise ( ) : Promise < T > ; } export interface CountQuery extends Query < number > { limit ( value , callback ? ) : CountQuery ; skip ( value , callback ? ) : CountQuery ; } export interface FindOneAndRemoveQuery < T > extends Query < T > { sort ( field , direction , callback ? ) : FindOneAndRemoveQuery < T > ; sort ( fields , callback ? ) : FindOneAndRemoveQuery < T > ; fetch ( path , callback ? ) : FindOneAndRemoveQuery < T > ; fetch ( paths , callback ? ) : FindOneAndRemoveQuery < T > ; /**
     * Return a reference instead of the Entity for unmanaged Entities.
     */ lazy ( callback ? ) : FindOneAndRemoveQuery < T > ; } export interface FindOneAndUpdateQuery < T > extends Query < T > { sort ( field , direction , callback ? ) : FindOneAndUpdateQuery < T > ; sort ( fields , callback ? ) : FindOneAndUpdateQuery < T > ; fetch ( path , callback ? ) : FindOneAndUpdateQuery < T > ; fetch ( paths , callback ? ) : FindOneAndUpdateQuery < T > ; returnUpdated ( callback ? ) : FindOneAndUpdateQuery < T > ; /**
     * Return a reference instead of the Entity for unmanaged Entities.
     */ lazy ( callback ? ) : FindOneAndUpdateQuery < T > ; } export interface FindOneQuery < T > extends Query < T > { fetch ( path , callback ? ) : FindOneQuery < T > ; fetch ( paths , callback ? ) : FindOneQuery < T > ; /**
     * Return a reference instead of the Entity for unmanaged Entities.
     */ lazy ( callback ? ) : FindOneQuery < T > ; } export interface FindQuery < T > extends Query < T [ ] > { sort ( field , direction , callback ? ) : FindQuery < T > ; sort ( fields , callback ? ) : FindQuery < T > ; fetch ( path , callback ? ) : FindQuery < T > ; fetch ( paths , callback ? ) : FindQuery < T > ; limit ( value , callback ? ) : FindQuery < T > ; collation ( value , callback ? ) : FindQuery < T > ; skip ( value , callback ? ) : FindQuery < T > ; /**
     * Return references instead of Entities for unmanaged Entities.
     */ lazy ( callback ? ) : FindQuery < T > ; batchSize ( value ) : FindQuery < T > ; each ( iterator , callback ) : void ; eachSeries ( iterator , callback ) : void ; /**
     * Returns an [Observable](http://reactivex.io/documentation/observable.html) for the query.
     */ asObservable ( ) : Observable < T > ; } hidden export class QueryBuilderImpl < T > implements QueryBuilder < T > { private _session : InternalSession ; private _entityCtr : Constructor < any > ; constructor ( session , entityCtr ) { this . _session = session ; this . _entityCtr = entityCtr ; } findAll ( callback ? ) ; findAll ( criteria , callback ? ) ; findAll ( criteriaOrCallback ? , callback ? ) { return this . _createFindQuery ( QueryKind . FindAll , criteriaOrCallback , callback ) ; } findOne ( callback ? ) ; findOne ( criteria , callback ? ) ; findOne ( criteriaOrCallback ? , callback ? ) { return this . _createFindQuery ( QueryKind . FindOne , criteriaOrCallback , callback ) ; } findOneById ( id , callback ? ) { var query = this . _createQuery ( QueryKind . FindOneById ) ; if ( id == null ) { query . error = new PersistenceError ( "Missing or invalid identifier." ) ; } query . id = id ; return query . handleCallback ( callback ) ; } findOneAndRemove ( callback ? ) ; findOneAndRemove ( criteria , callback ? ) ; findOneAndRemove ( criteriaOrCallback ? , callback ? ) { return this . _createRemoveQuery ( QueryKind . FindOneAndRemove , criteriaOrCallback , callback ) ; } findOneAndUpdate ( updateDocument , callback ? ) ; findOneAndUpdate ( criteria , updateDocument , callback ? ) ; findOneAndUpdate ( criteriaOrUpdateDocument , updateDocumentOrCallback , callback ? ) { return this . _createUpdateQuery ( QueryKind . FindOneAndUpdate , criteriaOrUpdateDocument , updateDocumentOrCallback , callback ) ; } findOneAndUpsert ( updateDocument , callback ? ) ; findOneAndUpsert ( criteria , updateDocument , callback ? ) ; findOneAndUpsert ( criteriaOrUpdateDocument , updateDocumentOrCallback , callback ? ) { return this . _createUpdateQuery ( QueryKind . FindOneAndUpsert , criteriaOrUpdateDocument , updateDocumentOrCallback , callback ) ; } removeAll ( callback ? ) ; removeAll ( criteria , callback ? ) ; removeAll ( criteriaOrCallback ? , callback ? ) { this . _createRemoveQuery ( QueryKind . RemoveAll , criteriaOrCallback , callback ) ; } removeOne ( callback ? ) ; removeOne ( criteria , callback ? ) ; removeOne ( criteriaOrCallback ? , callback ? ) { this . _createRemoveQuery ( QueryKind . RemoveOne , criteriaOrCallback , callback ) ; } updateAll ( updateDocument , callback ? ) ; updateAll ( criteria , updateDocument , callback ? ) ; updateAll ( criteriaOrUpdateDocument , updateDocumentOrCallback , callback ? ) { this . _createUpdateQuery ( QueryKind . UpdateAll , criteriaOrUpdateDocument , updateDocumentOrCallback , callback ) ; } updateOne ( updateDocument , callback ? ) ; updateOne ( criteria , updateDocument , callback ? ) ; updateOne ( criteriaOrUpdateDocument , updateDocumentOrCallback , callback ? ) { this . _createUpdateQuery ( QueryKind . UpdateOne , criteriaOrUpdateDocument , updateDocumentOrCallback , callback ) ; } upsert ( updateDocument , callback ? ) ; upsert ( criteria , updateDocument , callback ? ) ; upsert ( criteriaOrUpdateDocument , updateDocumentOrCallback , callback ? ) { this . _createUpdateQuery ( QueryKind . Upsert , criteriaOrUpdateDocument , updateDocumentOrCallback , callback ) ; } distinct ( key , callback ) ; distinct ( key , criteria , callback ) ; distinct ( key , criteriaOrCallback , callback ? ) { var query = this . _createQuery ( QueryKind . Distinct ) ; query . key = key ; if ( typeof criteriaOrCallback === "function" ) { query . criteria = { } ; callback = criteriaOrCallback ; } else { query . criteria = criteriaOrCallback || { } ; } query . handleCallback ( callback ) ; } count ( callback ? ) ; count ( criteria , callback ? ) ; count ( criteriaOrCallback ? , callback ? ) { var query = this . _createQuery ( QueryKind . Count ) ; if ( typeof criteriaOrCallback == "function" ) { callback = criteriaOrCallback ; query . criteria = { } ; } else { query . criteria = criteriaOrCallback || { } ; } return query . handleCallback ( callback ) ; } private _createUpdateQuery ( kind , criteriaOrUpdateDocument , updateDocumentOrCallback , callback ? ) { var query = this . _createQuery ( kind ) ; if ( typeof updateDocumentOrCallback == "function" || updateDocumentOrCallback === undefined ) { callback = updateDocumentOrCallback ; query . updateDocument = criteriaOrUpdateDocument ; query . criteria = { } ; } else { query . updateDocument = updateDocumentOrCallback ; query . criteria = criteriaOrUpdateDocument ; } return query . handleCallback ( callback ) ; } private _createRemoveQuery ( kind , criteriaOrCallback ? , callback ? ) { var query = this . _createQuery ( kind ) ; if ( typeof criteriaOrCallback == "function" ) { callback = criteriaOrCallback ; query . criteria = { } ; } else { query . criteria = criteriaOrCallback || { } ; } return query . handleCallback ( callback ) ; } private _createFindQuery ( kind , criteriaOrCallback ? , callback ? ) { var query = this . _createQuery ( kind ) ; if ( typeof criteriaOrCallback == "function" ) { callback = criteriaOrCallback ; query . criteria = { } ; } else { query . criteria = criteriaOrCallback || { } ; } return query . handleCallback ( callback ) ; } private _createQuery ( kind ) { return new QueryObject ( this . _session , this . _entityCtr , kind ) ; } } class QueryObject implements QueryDefinition , FindQuery < Object > , FindOneQuery < Object > , FindOneAndRemoveQuery < Object > , FindOneAndUpdateQuery < Object > , CountQuery { key : string ; id : any ; criteria : QueryDocument ; fields : QueryDocument ; updateDocument : QueryDocument ; isLazy : boolean ; wantsUpdated : boolean ; fetchPaths : string [ ] ; sortValue : [ string , number ] [ ] ; limitCount : number ; collationOptions : CollationOptions ; skipCount : number ; iterator : IteratorCallback < Object > ; batchSizeValue : number ; error : Error ; private _session : InternalSession ; private _entityCtr : Constructor < any > ; private _executed : boolean ; constructor ( session , entityCtr , public kind ) { this . _session = session ; this . _entityCtr = entityCtr ; } get readOnly ( ) : boolean { switch ( this . kind ) { case QueryKind . FindAll : case QueryKind . FindEach : case QueryKind . FindEachSeries : case QueryKind . FindCursor : case QueryKind . FindOne : case QueryKind . FindOneById : case QueryKind . Distinct : case QueryKind . Count : return true ; default : return false ; } } fetch ( path , callback ? ) { if ( ! this . fetchPaths ) { this . fetchPaths = [ ] ; } if ( typeof path === "string" ) { this . fetchPaths . push ( path ) ; } else { this . fetchPaths = this . fetchPaths . concat ( path ) ; } return this . handleCallback ( callback ) ; } sort ( field , directionOrCallback , callback ? ) { if ( ! this . sortValue ) { this . sortValue = [ ] ; } if ( typeof field === "string" ) { if ( typeof directionOrCallback === "number" ) { this . sortValue . push ( [ field , directionOrCallback ] ) ; } else { throw new PersistenceError ( "Expected second parameter to be the sort direction when first parameter is a string." ) ; } } else { if ( ! Array . isArray ( field ) ) { throw new PersistenceError ( "Expected first parameter to be a string or array" ) ; } this . sortValue = this . sortValue . concat ( field ) ; } if ( typeof directionOrCallback === "number" ) { return this . handleCallback ( callback ) ; } else { return this . handleCallback ( directionOrCallback ) ; } } returnUpdated ( callback ? ) { this . wantsUpdated = true ; return this . handleCallback ( callback ) ; } lazy ( callback ? ) { this . isLazy = true ; return this . handleCallback ( callback ) ; } limit ( value , callback ? ) { this . limitCount = value ; return this . handleCallback ( callback ) ; } collation ( value , callback ? ) { this . collationOptions = value ; return this . handleCallback ( callback ) ; } skip ( value , callback ? ) { this . skipCount = value ; return this . handleCallback ( callback ) ; } batchSize ( value , callback ? ) { this . batchSizeValue = value ; return this . handleCallback ( callback ) ; } each ( iterator , callback ) { if ( ! iterator ) { throw new PersistenceError ( "Missing required argument 'iterator'." ) ; } if ( ! callback ) { throw new PersistenceError ( "Missing required argument 'callback'." ) ; } this . kind = QueryKind . FindEach ; this . iterator = iterator ; this . handleCallback ( callback ) ; } eachSeries ( iterator , callback ) { if ( ! iterator ) { throw new PersistenceError ( "Missing required argument 'iterator'." ) ; } if ( ! callback ) { throw new PersistenceError ( "Missing required argument 'callback'." ) ; } this . kind = QueryKind . FindEachSeries ; this . iterator = iterator ; this . handleCallback ( callback ) ; } handleCallback ( callback ) { if ( callback ) { this . execute ( callback ) ; } return this ; } execute ( callback ) { if ( this . _executed ) { callback ( new PersistenceError ( "Query already executed. A callback can only be passed to one function in the chain." ) ) ; return ; } this . _executed = true ; if ( this . error ) { callback ( this . error ) ; return ; } this . _session . executeQuery ( this , callback ) ; } executeInternal ( callback ) { var mapping = this . _session . factory . getMappingForConstructor ( this . _entityCtr ) ; if ( ! mapping ) { callback ( new PersistenceError ( "Object type is not mapped as an entity." ) ) ; return ; } this . _session . getPersister ( mapping ) . executeQuery ( this , callback ) ; } asPromise ( ) { return new Promise ( ( resolve , reject ) => { this . execute ( ( err , result ) => { if ( err ) { reject ( err ) ; } else { resolve ( result ) ; } } ) ; } ) ; } asObservable ( ) { this . kind = QueryKind . FindCursor ; return Observable . create ( ( observer ) => { var cursor , disposed = false ; this . execute ( ( err , result ) => { if ( err ) { observer . onError ( err ) ; } else { cursor = result ; ( function next ( ) { cursor . next ( ( err , entity ) => { if ( disposed ) { cursor . close ( ) ; return ; } if ( err ) { observer . onError ( err ) ; return ; } if ( entity == null ) { observer . onCompleted ( ) ; return ; } observer . onNext ( entity ) ; next ( ) ; } ) ; } ) ( ) ; } } ) ; return ( ) => { disposed = true ; if ( cursor ) { cursor . close ( ) ; } } ; } ) ; } /**
     * Creates an object for logging purposes.
     */ toObject ( ) { return { kind : QueryKind [ this . kind ] , criteria : this . criteria , fields : this . fields , update : this . updateDocument , isLazy : this . isLazy , wantsUpdated : this . wantsUpdated , fetch : this . fetchPaths , sort : this . sortValue , limit : this . limitCount , skip : this . skipCount , batchSize : this . batchSizeValue } ; } }