makit
Version:
Make in JavaScript done right!
115 lines (114 loc) • 3.45 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataBase = void 0;
const util_1 = require("util");
const logger_1 = require("../utils/logger");
const number_1 = require("../utils/number");
const l = logger_1.Logger.getOrCreate();
/**
* 一个简易的 JSON 非关系性数据库。它的构成如下:
*
* * 一个 DataBase 对象由若干个 Document 构成
* * 一个 Document 由若干个 Property 构成
*
* Note: sqlite 是各方面比较理想的替代品,但它有 Native Binding,
* 能否成功安装会受网络、操作系统、Node 版本的影响,移植性不够。
*/
class DataBase {
constructor(filepath, fs) {
this.filepath = filepath;
this.fs = fs;
this.data = {};
this.dirty = false;
this.readFromDisk();
}
/**
* 查询文档属性
*
* @param doc 文档名
* @param prop 属性名
* @param defaultValue 如果没有,则返回的默认值
*/
query(doc, prop, defaultValue) {
if (!this.data[doc]) {
return defaultValue;
}
const value = this.data[doc][prop];
return value !== undefined ? value : defaultValue;
}
/**
* 写入文档属性
*
* @param doc 文档名
* @param prop 属性名
* @param newValue 新的属性值
*/
write(doc, prop, newValue) {
l.debug('DTBS', () => `setting ${doc}.${prop} to ${util_1.inspect(newValue)}`);
this.dirty = true;
this.data[doc] = this.data[doc] || {};
this.data[doc][prop] = newValue;
return this.data[doc][prop];
}
/**
* 清空文档的所有属性,或清空数据库
*
* @param doc 文档名,如果不传则清空所有文档
*/
clear(doc) {
this.dirty = true;
if (doc)
this.data[doc] = {};
else
this.data = {};
}
/**
* 同步数据库到磁盘
*
* @throws 文件写入错误
*/
syncToDisk() {
if (!this.dirty) {
l.debug('DTBS', `documents clean, skip syncing`);
return false;
}
l.verbose('DTBS', () => `syncing to disk ${this.filepath}`);
const data = Buffer.from(JSON.stringify(this.data), 'utf8');
try {
// Note: should be synchronous to handle exit event,
// after which microtasks will not be scheduled or called.
this.fs.writeFileSync(this.filepath, data);
}
catch (err) {
err.message = 'Error sync to disk: ' + err.message;
throw err;
}
l.verbose('DTBS', () => `${number_1.humanReadable(data.length)} bytes written to ${this.filepath}`);
this.dirty = false;
return true;
}
readFromDisk() {
let str, data;
try {
str = this.fs.readFileSync(this.filepath, 'utf8');
}
catch (err) {
if (err.code === 'ENOENT') {
// ignore if not exists, will be created on first sync
str = '{}';
}
else {
throw err;
}
}
try {
data = JSON.parse(str);
}
catch (err) {
// ignore corrupted file, it will be regenerated anyway
}
if (typeof data === 'object' && data !== null)
this.data = data;
}
}
exports.DataBase = DataBase;