UNPKG

zoomdb

Version:

A simple local storage database.

294 lines (287 loc) 10.6 kB
const fs = require("fs"); class Database { constructor(options) { this.path = options.path; this.schemaName = options.schema.name; this.schemaData = options.schema; } getData() { const data = fs.readFileSync(this.path, "utf-8"); if (data !== "") return JSON.parse(data); return data; } async handleData(data, schema = this.schemaData) { if (!schema || !schema.required) throw new Error("Invalid schema provided."); const errors = []; Object.keys(schema.required).forEach(async (key) => { const fieldSchema = schema.required[key]; const dataType = fieldSchema.type; const dataValue = data[key]; if (typeof dataValue === "undefined") { if (fieldSchema.required) errors.push(`Field '${key}' is required.`); } else { if (!fieldSchema.type) throw new Error("Must put a type object"); if (dataType === "array" && !Array.isArray(dataValue)) errors.push(`Field '${key}' must be an array.`); else if (dataType === "object" && typeof dataValue !== "object") errors.push(`Field '${key}' must be an object.`); else if (typeof dataValue !== dataType) errors.push(`Field '${key}' must be of type '${dataType}'.`); else if (dataType === "object" && fieldSchema.properties) { try { await this.handleData(dataValue, { required: fieldSchema.properties, }); } catch (innerErrors) { console.log(innerErrors); errors.push( ...innerErrors .split("\n") .map((error) => `Field '${key}.${error}`) ); } } } }); if (errors.length > 0) throw new Error(errors.join("\n")); } new(data) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { currentData.push({ [this.schemaName]: { required: sc.required, data: [data] }, }); } else { currentData .find((s) => s[this.schemaName]) [this.schemaName].data.push(data); } fs.writeFileSync(this.path, JSON.stringify(currentData, null, 2)); return data; } catch (error) { throw new Error(error); } } delete(data) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { return; } else { const test = currentData .filter((item) => item[this.schemaName] && item[this.schemaName].data) .map((item) => item[this.schemaName].data.filter((element) => { return dataKeys.every((key) => element[key] !== data[key]); }) ) .flat(); currentData.find((s) => s[this.schemaName])[this.schemaName].data = test; } fs.writeFileSync(this.path, JSON.stringify(currentData, null, 2)); } catch (error) { throw new Error(error); } } deleteOne(data) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { return; } else { const test = currentData .filter((item) => item[this.schemaName] && item[this.schemaName].data) .map((item) => item[this.schemaName].data.find((element) => { return dataKeys.every((key) => element[key] === data[key]); }) ) .flat()[0]; const index = currentData .find((s) => s[this.schemaName]) [this.schemaName].data.indexOf(test); if (index !== -1) { currentData .find((s) => s[this.schemaName]) [this.schemaName].data.splice(index, 1); } } fs.writeFileSync(this.path, JSON.stringify(currentData, null, 2)); } catch (error) { throw new Error(error); } } find(data = {}) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { return []; } else { let filteredData = currentData .filter((item) => item[this.schemaName] && item[this.schemaName].data) .map((item) => item[this.schemaName].data.filter((element) => { return dataKeys.every((key) => element[key] === data[key]); }) ) .flat(); // flatten the array return filteredData; } } catch (error) { throw new Error(error); } } findOne(data = {}) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { return []; } else { let filteredData = currentData .filter((item) => item[this.schemaName] && item[this.schemaName].data) .map((item) => item[this.schemaName].data.find((element) => { return dataKeys.every((key) => element[key] === data[key]); }) ) .flat(); // flatten the array return filteredData; } } catch (error) { throw new Error(error); } } update(data = {}, newData = {}) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); this.handleData(newData); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { return; } else { currentData.map((item) => { if (item[this.schemaName] && item[this.schemaName].data) { item[this.schemaName].data = item[this.schemaName].data.map( (element) => { if (dataKeys.every((key) => element[key] === data[key])) { return { ...element, ...newData }; // Update data with newData } else { return element; } } ); } return item; }); } fs.writeFileSync(this.path, JSON.stringify(currentData, null, 2)); } catch (error) { throw new Error(error); } } updateOne(data = {}, newData = {}) { try { if (!data) throw new Error("Should put the schema name and data!"); if (typeof data !== "object") throw new Error("data must be object"); this.handleData(data); this.handleData(newData); let currentData = this.getData(); if (currentData == "" || !currentData) currentData = []; if (!currentData.find((s) => s[this.schemaName])) { return; } else { currentData.some((item) => { if (item[this.schemaName] && item[this.schemaName].data) { const foundIndex = item[this.schemaName].data.findIndex((element) => dataKeys.every((key) => element[key] === data[key]) ); if (foundIndex !== -1) { item[this.schemaName].data[foundIndex] = { ...item[this.schemaName].data[foundIndex], ...newData, }; return true; // stop searching } } return false; }); } fs.writeFileSync(this.path, JSON.stringify(currentData, null, 2)); } catch (error) { throw new Error(error); } } } class SetUp { constructor(options) { this.path = options.path; if (!this.path) throw new Error("Faild setup, please set the path!"); } async handelModel(schema) { Object.keys(schema).forEach(async (field) => { const fieldType = schema[field].type; if (!fieldType) throw new Error(`يجب أن يحتوي ${field} على مفتاح "type".`); const validTypes = ["string", "number", "boolean", "object", "array"]; if (!validTypes.includes(fieldType)) throw new Error( `نوع غير صالح لـ ${field}. يجب أن يكون أحد الأنواع التالية: ${validTypes.join( ", " )}.` ); if (fieldType == "object") { if (!schema[field].properties) throw new Error( "If the type == object should put a properties object" ); if (typeof schema[field].properties !== "object") throw new Error("properties must be Object!"); await this.handelModel(schema[field].properties); } }); } model(name, schema) { try { name = typeof name === "string" ? name : undefined; schema = typeof schema === "object" ? schema : undefined; if (!name || !schema) throw new Error("يجب تحديد اسم النموذج ومخطط البيانات."); if (Object.keys(schema).length === 0) throw new Error("لا يمكن تحديد مخطط بيانات فارغ."); this.handelModel(schema); return new Database({ path: this.path, schema: { name, required: schema, data: [] }, }); } catch (error) { throw new Error(error); } } } module.exports = SetUp;