/* eslint-disable no-unused-vars */
const Cloudy = require("./Cloudy");
const uuid = require("uuid/v4");
const reemit = require("re-emitter");
const EventEmitter = require("events");
const groupBy = require("lodash/groupBy");
const sumBy = require("lodash/sumBy");
const mapValues = require("lodash/mapValues");
/* eslint-disable no-unused-vars */
/**
* Map a bill's time into JS Date instance
* Helper function, so that it can be optimized
*/
function mapDates(bill) {
bill.time = new Date(bill.time);
return bill;
}
/** @typedef {*} OrbitDBAddress */
/**
* A bill
* @typedef {Object} Bill
* @property {number} amount - Amount, in decimals (e.g. HK$100.23 is 10023)
* @property {string} currency - ISO 4217 currency code (e.g. CNY for Renmibi)
* @property {Date} time - The time
* @property {string} name - user who paid (e.g. Isaac)
* @property {?string} comment - optional comment -- downstream applications please handle this carefully
* @property {string} _id - unique ID for the bill
*/
/**
* DAO for calendar objects (events, etc.)
* See {@link http://tutorials.jenkov.com/java-persistence/dao-design-pattern.html}
*/
class RunNumber extends EventEmitter {
/**
* @param {Cloudy} cloudy - ready Cloudy instance
* @param {DocumentStore} db - fully initialized DB instance
*/
constructor(cloudy, db) {
super();
/** @type {Cloudy} */
this.cloudy = cloudy;
/** @type {DocumentStore} */
this.db = db;
/** @type {Function} */
this._reemit = reemit(this.db.events, this, ["replicated", "replicate", "replicate.progress", "load", "load.progress", "ready", "write"]);
}
/**
* @param {Object} cloudyOptions
* @param {Object} storeOptions
* @returns {Promise<RunNumber>} Ready'd RunNumber instance
*/
static async create(cloudyOptions, storeOptions) {
const cloudy = await Cloudy.create(cloudyOptions);
const db = await cloudy.store("runNumber", storeOptions);
await db.load();
const runNumber = new RunNumber(cloudy, db);
return runNumber;
}
/**
* Interface to create / edit existing bill.
* @param {Bill} bill - bill to be saved. note that it might be mutated -- new events without ID attribute will be populated automatically
* @returns {Promise<Bill>} - the original bill reference. Might be mutated.
*/
async addBill(bill) {
if (!bill._id) {
bill._id = uuid();
}
if (!bill.time) {
bill.time = new Date();
}
await this.db.put(bill);
return bill;
}
/**
* Gets the events in an unspecified order
* @param {Function} filter - pick/reject unwanted bills
* @returns {Event[]} - array of events
*/
query(filter = (() => true)) {
return this.db.query(filter).map(mapDates);
}
/**
* @param {string} key
* @returns {Promise<any>}
*/
del(key) {
return this.db.del(key);
}
/**
* @param {string} key
* @returns {Bill}
*/
get(key) {
const vals = this.db.get(key);
if (vals.length === 0) {
throw new Error("Not found");
}
if (vals.length !== 1) {
throw new Error(`Undefined State: get() returned ${vals.length} values`);
}
return mapDates(vals[0]);
}
get address() {
return this.db.address;
}
}
module.exports = RunNumber;