node-collections-boilerplate-nahid/CachedCollection.js
"use strict";
const Collection = require('./Collection');
/**
* In memory version of collection.
*
* Since all the data is in memory, it also does basic facets analysis.
*/
class CachedCollection extends Collection
{
/**
* Builds up records in mmory.
* Sets up event listeners to keep everything up to date.
* @override
*/
async initialise()
{
let records = await super.initialise();
/**
* Mappint of primary key to records
* @type {Map<string,Record>}
*/
this.lookup = {};
// populate lookup list
for (let record of records)
{
let pkValue = record[this.primaryKey]
this.lookup[pkValue] = record;
}
// set up listeners
this.storage.on('create', record =>
{
console.log('NOTIFY CREATED', this.collectionName, record[this.primaryKey]);
this.lookup[record[this.primaryKey]] = record;
this.search.createRecord(record)
.then(x => x, console.log.bind(console));
});
this.storage.on('update', record =>
{
console.log('NOTIFY UPDATED', this.collectionName, record[this.primaryKey]);
this.lookup[record[this.primaryKey]] = record;
this.search.updateRecord(record)
.then(x => x, console.log.bind(console));
});
this.storage.on('delete', record =>
{
console.log('NOTIFY DELETED', this.collectionName, record[this.primaryKey]);
delete this.lookup[record[this.primaryKey]];
this.search.deleteRecord(record)
.then(x => x, console.log.bind(console));
});
// install updater
// see if storage has some clever way of receiving updates
this.storage.startRecordUpdateCheck()
return records;
}
/**
* @override
*/
createRecord(record)
{
this.lookup[record[this.primaryKey]] = record;
return super.createRecord(record);
}
/**
* @override
*/
async readRecord(record)
{
let read = this.lookup[record[this.primaryKey]];
if (!read)
{
record = await super.readRecord(record);
if (record)
{
this.lookup[record[this.primaryKey]] = record;
this.search.createRecord(record)
.then(x => x, console.log.bind(console));
}
return record;
}
else
{
return read;
}
}
/**
* @override
*/
updateRecord(record)
{
this.lookup[record[this.primaryKey]] = record;
return super.updateRecord(record);
}
/**
* @override
*/
deleteRecord(record)
{
try
{
delete this.lookup[record[this.primaryKey]];
}
catch (e)
{
console.log(e)
}
return super.deleteRecord(record);
}
/**
* @override
*/
searchRecords(query)
{
return new Promise((resolve, reject) =>
{
let offset = query.offset;
delete query.offset;
let limit = query.limit;
delete query.limit;
this.search.searchRecords(query)
.then(records =>
{
let results = {
results: records,
total: records.length,
offset: offset,
};
if (query.returnFacets)
{
let facets = {};
for (let facet of this.searchMeta.facets)
{
facets[facet] = {};
}
for (let id of records)
{
let record = this.lookup[id];
for (let facet of this.searchMeta.facets)
{
let facetValues = (record[facet] || []);
if (typeof facetValues === 'string')
{
let value = facetValues;
facets[facet][value] = (facets[facet][value] || 0) + 1;
}
else
{
for (let value of facetValues)
{
facets[facet][value] = (facets[facet][value] || 0) + 1;
}
}
}
}
results.facets = facets;
}
if (query.sort)
{
results.sort = query.sort;
results.order = query.order;
}
records = records.splice(offset, limit);
records = records.map(id =>
{
let query = {};
query[this.primaryKey] = id;
return this.readRecord(query);
});
Promise.all(records)
.then(records =>
{
results.results = records.map(x => this.stripRecord(x, query.extra));
resolve(results);
}, reject);
}, reject);
});
}
}
module.exports = CachedCollection;
CachedCollection.create = Collection.create;