/**
 * Created by tsturzl on 4/11/17.
 */ import Datastore from "./datastore" ; import { mergeSort , getSortType } from "./utils" ; import { isEmpty , flattenArr , rmArrDups } from "tedb-utils" ; export interface ICursor { sort ( sort ) : this ; skip ( skip ) : this ; limit ( limit ) : this ; exec ( ) : Promise < any [ ] | number > ; } /**
 * Simply used for $anding default inputs.
 */ export interface I$and { $and : any [ ] ; } export interface Ioptions { sort ? : any ; skip ? : number ; limit ? : number ; } /**
 * Database Cursor
 */ export default class Cursor implements ICursor { /** Reference to Datastore object */ private datastore : Datastore ; /** Query passed from `Datastore.find` or `count` */ private query : any ; /** Options for `exec` */ private options : Ioptions ; /** Is this a count operation? */ private count : boolean ; param datastore param query param count constructor ( datastore , query = { } , count ? ) { this . datastore = datastore ; this . query = query ; this . count = count || false ; this . options = { } ; } param sort public sort ( sort ) { this . options . sort = sort ; return this ; } param skip public skip ( skip ) { this . options . skip = skip ; return this ; } param limit public limit ( limit ) { this . options . limit = limit ; return this ; } /**
     * Execute the Cursor
     */ public exec ( ) { return new Promise < any [ ] | number > ( ( resolve , reject ) => { const promisesGetIds = [ ] ; if ( isEmpty ( this . query ) ) { promisesGetIds . push ( this . datastore . search ( ) ) ; } else { const searchKeys = Object . keys ( this . query ) ; if ( searchKeys . indexOf ( "$or" ) !== - 1 || searchKeys . indexOf ( "$and" ) !== - 1 ) { for ( const field in this . query ) { if ( this . query . hasOwnProperty ( field ) ) { promisesGetIds . push ( this . datastore . search ( field , this . query [ field ] ) ) ; } } } else { const searchValues = Object . values ( this . query ) ; const newQuery = { $and : [ ] } ; searchKeys . forEach ( ( v , i ) => { const obj = { } ; obj [ v ] = searchValues [ i ] ; newQuery . $and . push ( obj ) ; } ) ; promisesGetIds . push ( this . datastore . search ( "$and" , newQuery . $and ) ) ; } } const joined = Promise . all ( promisesGetIds ) ; joined . then ( ( idsArr ) : number | Promise < any [ ] > => { idsArr = flattenArr ( idsArr ) ; const ids = rmArrDups ( idsArr ) ; if ( this . count ) { return ids . length ; } else { return this . datastore . getDocs ( this . options , ids ) ; } } ) . then ( ( res ) => { if ( this . options . sort ) { try { const sortKey = Object . keys ( this . options . sort ) [ 0 ] ; if ( sortKey === "$created_at" ) { res . forEach ( ( doc ) => { doc . $created_at = this . datastore . getIdDate ( doc . _id ) ; } ) ; } const sortValue = this . options . sort [ sortKey ] ; const sortType = getSortType ( res , sortKey ) ; if ( sortType === "" ) { return res ; } else { if ( sortKey === "$created_at" ) { const removeCreatedAtField = mergeSort ( res , sortKey , sortValue , sortType ) ; removeCreatedAtField . forEach ( ( doc ) => delete doc . $created_at ) ; return removeCreatedAtField ; } else { return mergeSort ( res , sortKey , sortValue , sortType ) ; } } } catch ( e ) { return reject ( e ) ; } } else { return res ; } } ) . then ( resolve ) . catch ( reject ) ; } ) ; } }