Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

Commit

Permalink
fix(list): enable querying lists
Browse files Browse the repository at this point in the history
related: #9
  • Loading branch information
adriancarriger committed May 18, 2017
1 parent e772ad9 commit f25a1c7
Show file tree
Hide file tree
Showing 19 changed files with 674 additions and 143 deletions.
4 changes: 2 additions & 2 deletions src/database.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { AngularFireOfflineDatabase } from './database/database';
export { AfoListObservable } from './database/afo-list-observable';
export { AfoObjectObservable } from './database/afo-object-observable';
export { AfoListObservable } from './database/list/afo-list-observable';
export { AfoObjectObservable } from './database/object/afo-object-observable';
41 changes: 33 additions & 8 deletions src/database/database.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { async, inject, TestBed } from '@angular/core/testing';
import { AngularFireDatabase } from 'angularfire2/database';
import { Subject } from 'rxjs/Rx';

import { AfoListObservable } from './afo-list-observable';
import { AfoObjectObservable } from './afo-object-observable';
import { AfoListObservable } from './list/afo-list-observable';
import { AfoObjectObservable } from './object/afo-object-observable';
import { AngularFireOfflineDatabase } from './database';
import { LocalForageToken } from './localforage';
import { LocalUpdateService } from './local-update-service';
import { LocalForageToken } from './offline-storage/localforage';
import { LocalUpdateService } from './offline-storage/local-update-service';
import { CacheItem, WriteCache } from './interfaces';

describe('Service: AngularFireOfflineDatabase', () => {
Expand Down Expand Up @@ -39,7 +39,7 @@ describe('Service: AngularFireOfflineDatabase', () => {
inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
const key = '/slug-2';
let newValue = [
{ val: () => { return 'xyz'; } }
{ val: () => { return 'xyz'; }, getPriority: () => {} }
];
service.processing.current = false;
service.list(key).subscribe(list => {
Expand All @@ -55,7 +55,7 @@ describe('Service: AngularFireOfflineDatabase', () => {
inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
const key = '/slug-2';
let newValue = [
{ val: () => { return 'xyz'; } }
{ val: () => { return 'xyz'; }, getPriority: () => {} }
];
service.list(key);
mockAngularFireDatabase.update('list', newValue);
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('Service: AngularFireOfflineDatabase', () => {
});
})));

it('get local list (2) - should not update value if loaded', done => {
it('get local list (2) - should not update value if loaded', done => {
inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
service.processing.current = false;
let returnedValue = false;
Expand All @@ -196,6 +196,18 @@ describe('Service: AngularFireOfflineDatabase', () => {
})();
});

it('should unsubscribe from a list',
async(inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
const key = '/slug-2';
let newValue = [
{ val: () => { return 'xyz'; }, getPriority: () => {} }
];
const list = service.list(key);
expect(list.isStopped).toBeFalsy();
list.unsubscribe();
expect(list.isStopped).toBeTruthy();
})));

describe('Wait while processing', () => {
it('1 - wait for a list', done => {
inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
Expand Down Expand Up @@ -445,7 +457,7 @@ describe('Service: AngularFireOfflineDatabase', () => {
inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
const key = '/slug-2';
let newValue = [
{ val: () => { return 'xyz'; } }
{ val: () => { return 'xyz'; }, getPriority: () => {} }
];

service.processing.current = false;
Expand All @@ -461,6 +473,18 @@ describe('Service: AngularFireOfflineDatabase', () => {
setTimeout(done);
})();
});

it('should reset', () => {
inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
service.list('/slug-2');
service.object('/slug-3');
expect(Object.keys(service.listCache).length).toBe(1);
expect(Object.keys(service.objectCache).length).toBe(1);
service.reset();
expect(Object.keys(service.listCache).length).toBe(0);
expect(Object.keys(service.objectCache).length).toBe(0);
})();
});
});

it('should return an unwrapped null value', async(inject([AngularFireOfflineDatabase], (service: AngularFireOfflineDatabase) => {
Expand Down Expand Up @@ -500,6 +524,7 @@ export class MockLocalForageService {
setItem(key, value) {
return new Promise(resolve => resolve(this.values[key] = value));
}
clear() { }
}

@Injectable()
Expand Down
26 changes: 17 additions & 9 deletions src/database/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
FirebaseObjectObservable } from 'angularfire2/database';
import { FirebaseListFactoryOpts, FirebaseObjectFactoryOpts } from 'angularfire2/interfaces';

import { AfoListObservable } from './afo-list-observable';
import { AfoObjectObservable } from './afo-object-observable';
import { AfoListObservable } from './list/afo-list-observable';
import { AfoObjectObservable } from './object/afo-object-observable';
import { AngularFireOfflineCache, CacheItem, WriteCache } from './interfaces';
import { LocalForageToken } from './localforage';
import { LocalUpdateService } from './local-update-service';
import { WriteComplete } from './offline-write';
import { LocalForageToken } from './offline-storage/localforage';
import { LocalUpdateService } from './offline-storage/local-update-service';
import { WriteComplete } from './offline-storage/offline-write';

/**
* @whatItDoes Wraps the [AngularFire2](https://github.com/angular/angularfire2) database methods
Expand Down Expand Up @@ -269,7 +269,10 @@ export class AngularFireOfflineDatabase {
*/
private setList(key: string, array: Array<any>) {
const primaryValue = array.reduce((p, c, i) => {
this.localForage.setItem(`read/object${key}/${c.key}`, c.val());
const itemValue = c.val();
const priority = c.getPriority();
if (priority) { itemValue.$priority = priority; }
this.localForage.setItem(`read/object${key}/${c.key}`, itemValue);
p[i] = c.key;
return p;
}, []);
Expand All @@ -290,18 +293,22 @@ export class AngularFireOfflineDatabase {
private setupList(key: string, options: FirebaseListFactoryOpts = {}) {
// Get Firebase ref
options.preserveSnapshot = true;
const usePriority = options && options.query && options.query.orderByPriority;
const ref: FirebaseListObservable<any[]> = this.af.list(key, options);
// Create cache
this.listCache[key] = {
loaded: false,
offlineInit: false,
sub: new AfoListObservable(ref, this.localUpdateService)
sub: new AfoListObservable(ref, this.localUpdateService, options)
};

// Firebase
const subscription = ref.subscribe(value => {
this.listCache[key].loaded = true;
const cacheValue = value.map(snap => unwrap(snap.key, snap.val(), () => !isNil(snap.val())));
const cacheValue = value.map(snap => {
const priority = usePriority ? snap.getPriority() : null;
return unwrap(snap.key, snap.val(), () => !isNil(snap.val()), priority);
});
if (this.processing.current) {
this.processing.listCache[key] = cacheValue;
} else {
Expand Down Expand Up @@ -343,12 +350,13 @@ export function isNil(obj: any): boolean {
/**
* Adds the properies of `$key`, `$value`, `$exists` as required by AngularFire2
*/
export function unwrap(key: string, value: any, exists) {
export function unwrap(key: string, value: any, exists, priority?) {
let unwrapped = !isNil(value) ? value : { $value: null };
if ((/string|number|boolean/).test(typeof value)) {
unwrapped = { $value: value };
}
unwrapped.$exists = exists;
unwrapped.$key = key;
if (priority) { unwrapped.$priority = priority; }
return unwrapped;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { async, inject, TestBed } from '@angular/core/testing';
import { Observable, ReplaySubject, Subject } from 'rxjs/Rx';

import { AfoListObservable } from './afo-list-observable';
import { LocalUpdateService } from './local-update-service';
import { LocalUpdateService } from '../offline-storage/local-update-service';

describe('List Observable', () => {
let listObservable: AfoListObservable<any>;
Expand Down Expand Up @@ -188,22 +188,22 @@ describe('List Observable', () => {
listObservable.emulate('remove', null, 'key-2');
});

it('should emulate a que for push', done => {
listObservable = new AfoListObservable<any>(ref, localUpdateService);
listObservable.que = [
{
method: 'push',
value: {title: 'item-1'},
key: 'key-1'
}
];
listObservable.subscribe(x => {
expect(x[0].title).toBe('item-1');
expect(x[0].$exists()).toBe(true);
done();
});
listObservable.uniqueNext([]);
});
// it('should emulate a que for push', done => {
// listObservable = new AfoListObservable<any>(ref, localUpdateService);
// listObservable.que = [
// {
// method: 'push',
// value: {title: 'item-1'},
// key: 'key-1'
// }
// ];
// listObservable.subscribe(x => {
// expect(x[0].title).toBe('item-1');
// expect(x[0].$exists()).toBe(true);
// done();
// });
// listObservable.uniqueNext([]);
// });
});

@Injectable()
Expand Down
Loading

0 comments on commit f25a1c7

Please sign in to comment.