@ortoo/angular-resource
Version:
Magical CRUD resource management for angular
134 lines (112 loc) • 2.98 kB
text/typescript
import { isObject } from 'lodash';
import { EventEmitter } from '../../emitter';
import { Database, LocalModel } from '../../types';
import { uuid } from '../../utils';
// These are the operators nedb supports
const simpleOperators = {
$and: true,
$exists: true,
$gt: true,
$gte: true,
$in: true,
$lt: true,
$lte: true,
$ne: true,
$nin: true,
$not: true,
$or: true,
$regex: true,
$size: true,
};
interface Callback {
(err?: Error, data?: any): void;
}
export function createWebWorkerDbFactory(worker: Worker) {
let workerEmitter = new EventEmitter();
worker.onmessage = (event: MessageEvent) => {
workerEmitter.emit('message', event);
};
class WebWorkerDb extends Database {
private worker: Worker;
private cbMaps: {[id: string]: Callback};
private dbid: string;
constructor() {
super();
this.worker = worker;
this.cbMaps = {};
this.dbid = uuid();
workerEmitter.addListener('message', (event: MessageEvent) => {
let data = event.data.data;
let error = event.data.error;
let id = event.data.id;
let cb = this.cbMaps[id];
if (cb) {
cb(error, data);
}
});
}
public update(res: LocalModel) {
if (res.$deleted) {
return this.runWorkerFunction('remove', res.$id);
} else {
let doc = res.$toObject();
// Stick on the internal id
doc.$id = res.$id;
return this.runWorkerFunction('update', doc);
}
}
public query(qry: any) {
return this.runWorkerFunction('query', qry) as Promise<string[]>;
}
public qryIsSimple(qry: any): boolean {
let simple = true;
if (Array.isArray(qry)) {
qry.forEach(val => {
let kosher = this.qryIsSimple(val);
if (!kosher) {
simple = false;
return false;
}
});
} else if (isObject(qry)) {
for (let key of Object.keys(qry)) {
let val = qry[key];
// The key is fine if it doesn't begin with $ or is a simple operator
let kosherKey = (key[0] !== '$') || simpleOperators[key];
if (!kosherKey) {
simple = false;
break;
}
let valKosher = this.qryIsSimple(val);
if (!valKosher) {
simple = false;
break;
}
}
}
return simple;
}
private runWorkerFunction(fnName: string, ...args: any[]) {
return new Promise((resolve, reject) => {
let id = uuid();
this.worker.postMessage({
fnName,
id,
dbid: this.dbid,
args,
});
this.cbMaps[id] = (err, resp) => {
delete this.cbMaps[id];
if (err) {
reject(err);
} else {
resolve(resp);
}
};
});
}
}
return () => {
return new WebWorkerDb() as Database;
};
}