import PouchDB from 'pouchdb' ; import { Album , Track , Artist } from 'compactd-models' ; export type ChangeCallback < T > = ( changes : PouchDB . Core . ChangesResponseChange < T > ) => void ; export type FeedCallback < T > = ( doc : T ) => void ; export default class LibraryProvider { private cache : { [ id ] : Promise < any > ; } ; private feeds : { [ key ] : boolean ; } ; private static sInstance = new LibraryProvider ( ) ; private constructor ( ) { this . cache = { } ; this . feeds = { } ; } async getDocument < T > ( db , id ) { const doc = new PouchDB < T > ( db ) . get ( id ) ; return doc ; } getTrack ( id ) { return this . getDocument < Track > ( 'tracks' , id ) ; } getArtist ( id ) { return this . getDocument < Artist > ( 'artists' , id ) ; } getAlbum ( id ) { return this . getDocument < Album > ( 'albums' , id ) ; } getAlbumCounters ( id ) { const tracks = new PouchDB < Artist > ( 'tracks' ) ; const opts = { startkey : id , endkey : id + '\uffff' } ; return Promise . all ( [ tracks . allDocs ( opts ) ] ) . then ( ( docs ) => { return docs . map ( ( doc ) => doc . rows . length ) ; } ) ; } getArtistCounters ( id ) { const albums = new PouchDB < Artist > ( 'albums' ) ; const tracks = new PouchDB < Artist > ( 'tracks' ) ; const opts = { startkey : id , endkey : id + '\uffff' } ; return Promise . all ( [ albums . allDocs ( opts ) , tracks . allDocs ( opts ) ] ) . then ( ( docs ) => { return docs . map ( ( doc ) => doc . rows . length ) ; } ) ; } onDocumentChanged < T > ( db , id , callback ) { const database = new PouchDB < T > ( db ) ; database . changes ( { since : 'now' , live : true , include_docs : true } ) . setMaxListeners ( 0 ) . on ( 'change' , ( val ) => { if ( ! id || id === val . id ) { callback ( val ) ; } } ) ; } cancelFeeds ( keys ) { if ( ! keys ) return ; keys . forEach ( ( k ) => this . feeds [ k ] = false ) ; } liveFeed < T > ( db , id , callback ) { const key = Date . now ( ) ; this . feeds [ key ] = true ; this . onDocumentChanged < T > ( db , id , ( changes ) => { if ( this . feeds [ key ] ) { callback ( changes . doc ) ; } } ) ; this . getDocument < T > ( db , id ) . then ( ( doc ) => { if ( this . feeds [ key ] ) { callback ( doc ) ; } } ) . catch ( ( err ) => { console . log ( 'couldnt find' , db , id ) ; } ) ; return key ; } onDocAdded ( db , cb ) { return new PouchDB ( db ) . changes ( { since : 'now' , live : true } ) . on ( 'change' , ( { changes , id } ) => { if ( changes [ 0 ] . rev . startsWith ( '1-' ) ) { cb ( id ) ; } } ) ; } onDocRemoved ( db , cb ) { return new PouchDB ( db ) . changes ( { since : 'now' , live : true } ) . on ( 'change' , ( { doc , id , deleted } ) => { if ( deleted ) { cb ( id ) ; } } ) ; } public static getInstance ( ) { return LibraryProvider . sInstance ; } }