import { EventEmitter } from "events" ; import { ICollection , IDb , IDbFactory } from "@fluidframework/server-services-core" ; import * as _ from "lodash" ; export class TestCollection implements ICollection < any > { constructor ( public collection ) { } public async aggregate ( group , options ? ) { throw new Error ( "Method not implemented." ) ; } public async find ( query , sort ) { return this . findInternal ( query , sort ) ; } public async findAll ( ) { return this . collection ; } public findOne ( query ) { return Promise . resolve ( this . findOneInternal ( query ) ) ; } public async update ( filter , set , addToSet ) { const value = this . findOneInternal ( filter ) ; if ( ! value ) { return Promise . reject ( new Error ( "Not found" ) ) ; } _ . extend ( value , set ) ; } public async updateMany ( filter , set , addToSet ) { const values = this . findInternal ( filter ) ; try { values . forEach ( ( value ) => { if ( ! value ) { throw new Error ( "Not found" ) ; } _ . extend ( value , set ) ; } ) ; } catch ( e ) { return Promise . reject ( e ) ; } } public async upsert ( filter , set , addToSet ) { const value = this . findOneInternal ( filter ) ; if ( ! value ) { this . collection . push ( set ) ; } _ . extend ( value , set ) ; } public async insertOne ( value ) { if ( this . findOneInternal ( value ) !== null ) { return Promise . resolve ( "existing object" ) ; } return this . insertOneInternal ( value ) ; } public async findOrCreate ( query , value ) { const existing = this . findOneInternal ( query ) ; if ( existing ) { return { value : existing , existing : true } ; } return { value : this . insertOneInternal ( value ) , existing : false } ; } public async insertMany ( values , ordered ) { values . forEach ( ( value ) => { this . collection . push ( value ) ; } ) ; } public async deleteOne ( filter ) { const value = this . findOneInternal ( filter ) ; this . removeOneInternal ( value ) ; return value ; } public async deleteMany ( filter ) { const values = this . findInternal ( filter ) ; values . forEach ( ( value ) => { this . removeOneInternal ( value ) ; } ) ; return values ; } public async distinct ( key , filter ) { throw new Error ( "Method not implemented." ) ; } public createIndex ( index , unique ) { throw new Error ( "Method not implemented." ) ; } private insertOneInternal ( value ) { this . collection . push ( value ) ; return value ; } private removeOneInternal ( value ) { const index = this . collection . indexOf ( value ) ; if ( index >= 0 ) { this . collection . splice ( index , 1 ) ; } } private findOneInternal ( query ) { let returnValue ; if ( query . _id ) { returnValue = this . collection . find ( ( value ) => value . _id === query . _id ) ; } else { const found = this . findInternal ( query ) ; returnValue = found [ 0 ] ; } return returnValue === undefined ? null : returnValue ; } private findInternal ( query , sort ? ) { function getValueByKey ( propertyBag , key ) { const keys = key . split ( "." ) ; let value = propertyBag ; keys . forEach ( ( splitKey ) => { value = value [ splitKey ] ; } ) ; return value ; } const queryKeys = Object . keys ( query ) ; let filteredCollection = this . collection ; queryKeys . forEach ( ( key ) => { if ( ! query [ key ] ) { return ; } if ( query [ key ] . $gt > 0 || query [ key ] . $lt > 0 || query [ key ] . $lte > 0 ) { if ( query [ key ] . $gt > 0 ) { filteredCollection = filteredCollection . filter ( ( value ) => getValueByKey ( value , key ) > query [ key ] . $gt ) ; } if ( query [ key ] . $lt > 0 ) { filteredCollection = filteredCollection . filter ( ( value ) => getValueByKey ( value , key ) < query [ key ] . $lt ) ; } if ( query [ key ] . $lte > 0 ) { filteredCollection = filteredCollection . filter ( ( value ) => getValueByKey ( value , key ) <= query [ key ] . $lte ) ; } } else { filteredCollection = filteredCollection . filter ( ( value ) => getValueByKey ( value , key ) === query [ key ] ) ; } } ) ; if ( sort && Object . keys ( sort ) . length === 1 ) { function compare ( a , b ) { const sortKey = Object . keys ( sort ) [ 0 ] ; if ( sort [ sortKey ] === 1 ) { return getValueByKey ( a , sortKey ) - getValueByKey ( b , sortKey ) ; } else { return getValueByKey ( b , sortKey ) - getValueByKey ( a , sortKey ) ; } } filteredCollection = filteredCollection . sort ( compare ) ; } return filteredCollection ; } } export class TestDb implements IDb { private readonly emitter = new EventEmitter ( ) ; constructor ( private collections ) { } public close ( ) { return Promise . resolve ( ) ; } public on ( event , listener ) { this . emitter . on ( event , listener ) ; } public collection < T > ( name ) { if ( ! ( name in this . collections ) ) { this . collections [ name ] = [ ] ; } const collection = this . collections [ name ] ; return new TestCollection ( collection ) ; } } export interface ITestDbFactory extends IDbFactory { readonly testDatabase : IDb ; } export class TestDbFactory implements ITestDbFactory { public readonly testDatabase : IDb ; constructor ( collections ) { this . testDatabase = new TestDb ( collections ) ; } public connect ( ) { return Promise . resolve ( this . testDatabase ) ; } }