blow-collection
Version:
Simple in memory collection with Rx / Observable interface.
125 lines (103 loc) • 3.24 kB
text/typescript
'use strict';
import {Observable} from 'rxjs';
import {Query, QueryRaw, QueryWhere} from 'blow-query';
import * as uuid from 'node-uuid';
import * as _ from './helpers';
import {CollectionOptions} from './interfaces';
export class Collection<T> {
protected _data: T[];
protected _idKey: string;
protected _idGenerator: () => string | number;
constructor(options?: CollectionOptions) {
options = options || {};
this._idKey = options.idKey || '_id';
this._idGenerator = options.idGenerator || (() => uuid.v4());
this._data = [];
}
get size(): number {
return this._data.length;
}
protected get _data$(): Observable<T> {
return Observable.from(this._data);
}
protected _getId(data: any): any {
return _.get(data, this._idKey);
}
protected _setId(data: any, id?: any): any {
return _.set(data, this._idKey, id || this._idGenerator());
}
protected _hasId(data: any): boolean {
return _.has(data, this._idKey);
}
create(data: any): Observable<T> {
data = _.dropReference(data);
if (!this._hasId(data)) {
data = this._setId(data);
}
this._data.push(data);
return Observable.of(_.dropReference(data));
}
update(where: QueryWhere, data: any): Observable<number> {
return _.where(this._data$, where)
.map(row => Object.assign(row, data))
.count();
}
updateOrCreate(data: any): Observable<T> {
if (this._hasId(data)) {
return this.findById(this._getId(data))
.defaultIfEmpty()
.mergeMap(current => {
if (!current) {
return this.create(data);
} else {
Object.assign(current, data);
return Observable.of(_.dropReference(current));
}
});
} else {
return this.create(data);
}
}
count(where?: QueryWhere): Observable<number> {
where = where || {};
return _.where(this._data$, where).count();
}
destroy(where?: QueryWhere): Observable<number> {
where = where || {};
return _.where(this._data$, where, true)
.toArray()
.map(rows => {
const count = this._data.length - rows.length;
this._data = rows;
return count;
});
}
destroyById(id: any): Observable<boolean> {
const where = this._setId({}, id);
return this.destroy(where).map(num => !!num);
}
find(query?: QueryRaw | Query): Observable<T> {
query = _.prepareQuery(query);
return _.filter(this._data$, query).map(row => Object.assign({}, row));
}
findOne(query?: QueryRaw | Query): Observable<T> {
query = _.prepareQuery(query);
return this.find(Object.assign(query, { limit: 1 }));
}
findById(id: any): Observable<T> {
const where = this._setId({}, id);
return _.filter(this._data$, { where }).map(row => Object.assign({}, row));
}
findOrCreate(where: QueryWhere, data: any): Observable<T> {
return this.findOne({ where }).defaultIfEmpty().mergeMap(current => {
if (!current) {
return this.create(data);
} else {
return Observable.of(_.dropReference(current));
}
});
}
exists(id: any): Observable<boolean> {
return this.findById(id).map(row => !!row).defaultIfEmpty(false);
}
}