Files
Hyperia/server/_/quilldb.js
2025-11-21 00:04:11 -06:00

87 lines
2.4 KiB
JavaScript

import chalk from 'chalk'
import path from 'path';
import fs from 'fs/promises';
import { pathToFileURL } from 'url';
function Node(node) {
let traits = [
"labels"
]
for(let i = 0; i < traits.length; i++) {
if(!node[traits[i]]) {
throw new Error(`Node is missing field "${traits[i]}": ${JSON.stringify(node)}`)
}
}
}
export default class QuillDB {
#nodes; get nodes() {return this.#nodes};
#edges; get edges() {return this.#edges};
#labels = {}; get labels() {return this.#labels}
constructor() {
this.loadData()
}
async loadData() {
const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8');
let dbJson;
try {
dbJson = JSON.parse(dbData);
} catch {
dbJson = []
}
this.#nodes = dbJson["nodes"];
this.#edges = dbJson["edges"];
let labelModels = await this.getLabelModels();
// Index by label
for (const [id, entry] of Object.entries(this.#nodes)) {
Node(entry)
this.#checkLabelSchemas(id, entry, labelModels)
}
for (const [id, entry] of Object.entries(this.#edges)) {
Edge(entry)
this.#checkLabelSchemas(id, entry, labelModels)
}
console.log(chalk.yellow("DB established."))
Object.preventExtensions(this);
}
async getLabelModels() {
const labelHandlers = {};
const labelDir = path.join(process.cwd(), 'server/db/model');
const files = await fs.readdir(labelDir);
for (const file of files) {
if (!file.endsWith('.js')) continue;
const label = path.basename(file, '.js');
const modulePath = path.join(labelDir, file);
const module = await import(pathToFileURL(modulePath).href);
labelHandlers[label] = module.default;
if (!this.#labels[label]) {
this.#labels[label] = [];
}
}
return labelHandlers
}
#checkLabelSchemas(id, entry, labelModels) {
entry.labels.forEach(label => {
const model = labelModels[label];
if (!model) {
throw new Error("Data has unknown label or missing model: " + label)
}
model(entry);
this.#labels[label].push(id);
});
}
async getAll() {
return { nodes: this.#nodes }
}
}