more robust JsonLinesDatabase

This commit is contained in:
Jan Prochazka
2022-01-29 12:15:55 +01:00
parent 89b3477446
commit 83f60f863c
2 changed files with 39 additions and 23 deletions

View File

@@ -119,7 +119,7 @@ module.exports = {
} }
} }
return _.uniq(apps); return _.intersection(_.uniq(apps), await fs.readdir(appdir()));
}, },
getUsedApps_meta: true, getUsedApps_meta: true,

View File

@@ -1,6 +1,9 @@
const AsyncLock = require('async-lock');
const fs = require('fs-extra'); const fs = require('fs-extra');
const uuidv1 = require('uuid/v1'); const uuidv1 = require('uuid/v1');
const lock = new AsyncLock();
// const lineReader = require('line-reader'); // const lineReader = require('line-reader');
// const { fetchNextLineFromReader } = require('./JsonLinesDatastore'); // const { fetchNextLineFromReader } = require('./JsonLinesDatastore');
@@ -8,31 +11,40 @@ class JsonLinesDatabase {
constructor(filename) { constructor(filename) {
this.filename = filename; this.filename = filename;
this.data = []; this.data = [];
this.loaded = false; this.loadedOk = false;
this.loadPerformed = false;
} }
async _read() { async _save() {
this.data = []; if (!this.loadedOk) {
if (!(await fs.exists(this.filename))) return; // don't override data
return;
}
await fs.writeFile(this.filename, this.data.map(x => JSON.stringify(x)).join('\n'));
}
async _ensureLoaded() {
if (!this.loadPerformed) {
await lock.acquire('reader', async () => {
if (!this.loadPerformed) {
if (!(await fs.exists(this.filename))) {
this.loadedOk = true;
this.loadPerformed = true;
return;
}
try { try {
const text = await fs.readFile(this.filename, { encoding: 'utf-8' }); const text = await fs.readFile(this.filename, { encoding: 'utf-8' });
this.data = text this.data = text
.split('\n') .split('\n')
.filter(x => x.trim()) .filter(x => x.trim())
.map(x => JSON.parse(x)); .map(x => JSON.parse(x));
this.loadedOk = true;
} catch (err) { } catch (err) {
console.error(`Error loading file ${this.filename}`, err); console.error(`Error loading file ${this.filename}`, err);
} }
this.loadPerformed = true;
} }
});
async _write() {
await fs.writeFile(this.filename, this.data.map(x => JSON.stringify(x)).join('\n'));
}
async _ensureLoaded() {
if (!this.loaded) {
this._read();
this.loaded = true;
} }
} }
@@ -48,7 +60,7 @@ class JsonLinesDatabase {
_id: uuidv1(), _id: uuidv1(),
}; };
this.data.push(elem); this.data.push(elem);
await this._write(); await this._save();
return elem; return elem;
} }
@@ -74,19 +86,23 @@ class JsonLinesDatabase {
async update(obj) { async update(obj) {
await this._ensureLoaded(); await this._ensureLoaded();
this.data = this.data.map(x => (x._id == obj._id ? obj : x)); this.data = this.data.map(x => (x._id == obj._id ? obj : x));
await this._write(); await this._save();
return obj;
} }
async patch(id, values) { async patch(id, values) {
await this._ensureLoaded(); await this._ensureLoaded();
this.data = this.data.map(x => (x._id == id ? { ...x, ...values } : x)); this.data = this.data.map(x => (x._id == id ? { ...x, ...values } : x));
await this._write(); await this._save();
return this.data.find(x => x._id == id);
} }
async remove(id) { async remove(id) {
await this._ensureLoaded(); await this._ensureLoaded();
const removed = this.data.find(x => x._id == id);
this.data = this.data.filter(x => x._id != id); this.data = this.data.filter(x => x._id != id);
await this._write(); await this._save();
return removed;
} }
// async _openReader() { // async _openReader() {