Added a Dependency injection model to load the DB asynchronously during the constructor

This commit is contained in:
Amaury 2021-07-05 15:11:22 +02:00
parent 8608e79859
commit b4e04b8f21
3 changed files with 4482 additions and 85 deletions

4413
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,32 +7,65 @@ import { SqliteTools } from "./sqlite-tools";
* Permit to manage a ListenerRSS array, data storage and event aggregation
*/
export class ListenerRssAggregator extends EventEmitter {
private listenerArray: Map<string, ListenerRss> = new Map(); // renomer listenerMap
private listenerMap: Map<string, ListenerRss>;
private looprunning: boolean = false;
private sqliteDb: SqliteTools;
constructor(path: string) {
constructor(args: {
sqliteDB: SqliteTools;
configInstantiated: Map<string, ListenerRss>;
}) {
super();
this.sqliteDb = new SqliteTools(path);
this.load();
this.sqliteDb = args.sqliteDB;
this.listenerMap = args.configInstantiated;
}
static async instantiateAggregator(
path: string
): Promise<{
sqliteDB: SqliteTools;
configInstantiated: Map<string, ListenerRss>;
}> {
const sqliteDB = new SqliteTools(path);
const configInstantiated = await this.loadDb(sqliteDB);
return { sqliteDB, configInstantiated };
}
/**
* @brief [private don't use it] create a sqlite instance for the specified path and load the data
*/
private static async loadDb(
sqliteDb: SqliteTools
): Promise<Map<string, ListenerRss>> {
const config = await this.extractConfig(sqliteDb);
const configInstantiated = new Map<string, ListenerRss>();
for (const obj of config)
configInstantiated.set(obj.address, new ListenerRss(obj));
return configInstantiated;
}
/**
* @brief [private don't use it] load the actual config inside the sqliteTools instance specified
*/
private static async extractConfig(
sqliteDb: SqliteTools
): Promise<ListenerRSSInfos[]> {
await sqliteDb.ensureTableExists();
return await sqliteDb.fetchAll();
}
async getAllConfigs(): Promise<ListenerRSSInfos[]> {
return await this.sqliteDb.fetchAll();
}
private async load() {
const configs = await this.getAllConfigs();
configs.forEach((config) => {
this.addNewListener(config);
});
return await ListenerRssAggregator.extractConfig(this.sqliteDb);
}
private addNewListener(info: ListenerRSSInfos): ListenerRss {
const newListener = new ListenerRss(info);
this.listenerArray.set(newListener.address, newListener);
this.listenerMap.set(newListener.address, newListener);
newListener.on("update", (obj) => this.emit("update", obj));
newListener.on("newEntries", (obj) => this.emit("newEntries", obj));
@ -42,7 +75,7 @@ export class ListenerRssAggregator extends EventEmitter {
}
private removeOldListener(adr: string): void {
const oldListener = this.listenerArray.get(adr);
const oldListener = this.listenerMap.get(adr);
if (!oldListener) return;
@ -51,18 +84,18 @@ export class ListenerRssAggregator extends EventEmitter {
.removeAllListeners("update")
.removeAllListeners("newEntries")
.removeAllListeners("error");
this.listenerArray.delete(adr);
this.listenerMap.delete(adr);
}
async registerListener(info: ListenerRSSInfos) {
if (this.listenerArray.has(info.address)) return;
if (this.listenerMap.has(info.address)) return;
const listener = this.addNewListener(info);
await this.sqliteDb.insertListener(listener);
}
async unregisterListener(adr: string): Promise<void> {
if (!this.listenerArray.has(adr)) return;
if (!this.listenerMap.has(adr)) return;
this.removeOldListener(adr);
await this.sqliteDb.deleteListener(adr);
@ -73,26 +106,28 @@ export class ListenerRssAggregator extends EventEmitter {
for (const newItem of expectedConfig.filter(
(item) => !actualConfig.includes(item)
))
)) {
this.registerListener(newItem);
}
for (const oldItem of actualConfig.filter(
(item) => !expectedConfig.includes(item)
))
)) {
this.unregisterListener(oldItem.address);
}
}
startAll(): void {
if (this.looprunning) return;
this.looprunning = true;
for (const item of this.listenerArray.values()) item.start();
for (const item of this.listenerMap.values()) item.start();
}
stopAll(): void {
if (!this.looprunning) return;
this.looprunning = false;
for (const item of this.listenerArray.values()) item.stop();
for (const item of this.listenerMap.values()) item.stop();
}
}

View File

@ -29,20 +29,20 @@ describe("test class ManageListener", function () {
it("should save the inserted objects", async function () {
await withFile(async ({ path }) => {
// given
const ml = new ListenerRssAggregator(path);
await ml.load();
const ml = new ListenerRssAggregator(
await ListenerRssAggregator.instantiateAggregator(path)
);
for (const item of dataWithoutHistory) await ml.registerListener(item);
await ml.saveOverride(dataWithoutHistory);
// when
ml.save();
const ml_bis = new ListenerRssAggregator(path);
await ml_bis.load();
const ml_bis = new ListenerRssAggregator(
await ListenerRssAggregator.instantiateAggregator(path)
);
// expect
expect(
ml_bis.listenerArray.map((listener) => listener.getProperty())
).to.be.eql(dataWithoutHistory);
expect(await ml_bis.getAllConfigs()).to.have.deep.members(
dataWithoutHistory
);
});
});
});
@ -60,8 +60,9 @@ describe("test class ManageListener", function () {
await withFile(async ({ path }) => {
// given
const clock = sinon.useFakeTimers();
const ml = new ListenerRssAggregator(path);
await ml.load();
const ml = new ListenerRssAggregator(
await ListenerRssAggregator.instantiateAggregator(path)
);
for (const item of dataWithoutHistory) await ml.registerListener(item);
const updateSpy = sinon.spy();
@ -89,12 +90,9 @@ describe("test class ManageListener", function () {
// here we're testing the first call
// when
await Promise.all([
events.once(ml.listenerArray[0], "update"),
events.once(ml.listenerArray[1], "update"),
events.once(ml.listenerArray[2], "update"),
]);
await events.once(ml, "update");
await events.once(ml, "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledThrice;
expect(newEntriesSpy).to.have.been.calledThrice;
@ -106,7 +104,7 @@ describe("test class ManageListener", function () {
// when
await clock.tickAsync(10000);
await events.once(ml.listenerArray[0], "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledOnce;
@ -118,10 +116,8 @@ describe("test class ManageListener", function () {
// when
await clock.tickAsync(10000);
await Promise.all([
events.once(ml.listenerArray[0], "update"),
events.once(ml.listenerArray[1], "update"),
]);
await events.once(ml, "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledTwice;
@ -133,10 +129,8 @@ describe("test class ManageListener", function () {
// when
await clock.tickAsync(10000);
await Promise.all([
events.once(ml.listenerArray[0], "update"),
events.once(ml.listenerArray[2], "update"),
]);
await events.once(ml, "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledTwice;
@ -150,8 +144,9 @@ describe("test class ManageListener", function () {
await withFile(async ({ path }) => {
// given
const clock = sinon.useFakeTimers();
const ml = new ListenerRssAggregator(path);
await ml.load();
const ml = new ListenerRssAggregator(
await ListenerRssAggregator.instantiateAggregator(path)
);
for (const item of dataWithHistory) await ml.registerListener(item);
const updateSpy = sinon.spy();
@ -179,11 +174,9 @@ describe("test class ManageListener", function () {
// here we're testing the first call
// when
await Promise.all([
events.once(ml.listenerArray[0], "update"),
events.once(ml.listenerArray[1], "update"),
events.once(ml.listenerArray[2], "update"),
]);
await events.once(ml, "update");
await events.once(ml, "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledThrice;
@ -210,7 +203,7 @@ describe("test class ManageListener", function () {
// when
await clock.tickAsync(10000);
await events.once(ml.listenerArray[0], "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledOnce;
@ -223,10 +216,8 @@ describe("test class ManageListener", function () {
// when
await clock.tickAsync(10000);
await Promise.all([
events.once(ml.listenerArray[0], "update"),
events.once(ml.listenerArray[1], "update"),
]);
await events.once(ml, "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledTwice;
@ -239,10 +230,8 @@ describe("test class ManageListener", function () {
// when
await clock.tickAsync(10000);
await Promise.all([
events.once(ml.listenerArray[0], "update"),
events.once(ml.listenerArray[2], "update"),
]);
await events.once(ml, "update");
await events.once(ml, "update");
//expect
expect(updateSpy).to.have.been.calledTwice;