edudb
Version:
A synchronous JSON based database
234 lines (213 loc) • 7.79 kB
JavaScript
const fs = require('fs');
const path = require('path');
class db {
// Set default config
constructor() {
this.root = '.\\db\\';
this.encoding = 'utf8';
} // DONE
/**
* Set initial configuration for the database to work.
* @param {object} options How to config the database.
* @param {string} options.root Root directory path. Default is '.\db'
* @param {string} options.encoding Encoding for the files to save and open. Default is 'utf-8'
* @returns {void}
*/
config(options) { // Config aren't stored localy
/** options = {
* root: path,
* encoding: string
* }
*/
if(options != undefined && typeof options == 'object') {
// For root
if(options.root == undefined) {
if(!fs.existsSync('.\\db')) {
fs.mkdir('.\\db\\', function(err) {if(err) throw "Error to create db root directory. Please create it manually at "+path.normalize(__dirname + '\\db\\')});
this.root = '.\\db\\';
}
} else {
options.root = path.normalize(options.root + "\\");
this.root = options.root;
if(!fs.existsSync(options.root)) {
fs.mkdir(options.root, function(err) {if(err) throw("Error to create db root directory. Pleace create it manually at "+options.root)});
}
}
// For encoding
options.encoding == undefined ? this.encoding = 'utf8' : this.encoding = options.encoding;
} else if(typeof options != 'object' && options != undefined) {
throw "Options to define db class must be an object.";
} else { // options == undefined
this.root = '.\\db\\';
this.encoding = 'utf8';
}
} // DONE
///// IN functions: to directories
/**
* To create a table in the database that will hold the information you want to put. Only works with objects.
* @param {string} name Name for the table. This is the name you will use to get the table. (see get())
* @param {object} options Options to create the table. At version 1.2.0, it only can read options.structure.
* @param {object} options.structure Index 0 in the table and works as guide for you while setting the next row.
* @returns {boolean} Returns true if file was created and false if it already existed.
*/
createTable(name, options) {
var path = this.root + name + '.json';
var data = [];
if(options != undefined) {
if(typeof options == 'object') {
if(options.structure != undefined && typeof options.structure == 'object') {
data[0] = options.structure;
} else {
throw "Structure in options must be an object!";
}
} else {
throw "Options must be an object to create a table!";
}
}
// Check if exists
if(!this.exists(name)) {
// Write file
data = JSON.stringify(data);
fs.writeFileSync(path, data, this.encoding);
return true;
} else {
return false;
}
} // DONE
/**
* Saves the table you indicated in the root directory for the database.
* @param {string} table Name of the table to save.
* @param {object} obj After you did get(), for this argument you must set that object.
* @returns {void} Will throw an error if there's no obj specified.
*/
save(table, obj) {
if(typeof obj == 'object' || typeof obj == 'array') {
obj = JSON.stringify(obj);
fs.writeFileSync(this.root + table + '.json', obj);
} else {
throw "Obj argument must be an object or an array.";
}
} // DONE
///// OUT functions: to client
/**
* To get access to a table and get the information, you must use this method. EduDB works with JSON files so you will get an easy to use object.
* @param {string} table Name of the table to get.
* @returns {object|undefined} Returns an array with all the rows of the table.
*/
get(table) {
var path = this.root + table + '.json';
if(this.exists(table)) {
return JSON.parse(fs.readFileSync(path, this.encoding));
} else {
//throw("Table \""+table+"\" doesn't exist!");
return undefined;
}
} // DONE
/**
* Get an array of all the tables created sorted by name. This is useful for automating your program working only with index.
* @returns {object} An array with the names of the tables.
*/
list() {
var result = [];
var files = fs.readdirSync(this.root, this.encoding);
for (var i = 0; i < files.length; i++) {
result.push(path.parse(files[i]).name);
}
return result;
} // DONE
/**
* Useful method for finding information in the whole database. The first parameter works in a strict way where the first index is the proporty and the next stands for its value.
* db.find([property1, whichValue1, property2, value2, ...propertyN, ...valueN]);
* @param {object} args Array indicating first the property to find and then the value. i.e.: ["name", "lasangreesroja", "id", 0]
* @param {string} [table] Optional. If indicated, will only search in the specifed table.
* @returns {object|undefined} If there's no property with that value, will return undefined. If found, will return an object with the table name where found (find().table), the entire row object (find().row) and the index of the row in the table (find().index).
*/
find(args, table) {
// Check syntax for args
if(args != undefined) {
if(typeof args == 'object') {
if(args.length != 0) {
if(args.length % 2 == 0) {
// Check 'table' argument
if(table != undefined && typeof table == 'string') {
var file = JSON.parse(fs.readFileSync(this.root + table + '.json', this.encoding));
if(typeof file == 'object') {
// Check every index of the array
for (var j = 0; j < file.length; j++) {
var paramSucceed = false;
// Check if has every property
properties:
for (var param = 0; param < args.length / 2; param++) {
if(file[j].hasOwnProperty(args[2 * param]) && file[j][args[2 * param]] == args[2 * param + 1]) {
paramSucceed = true;
} else {
// If hasn't property, try next row
paramSucceed = false;
break properties;
}
if(param == args.length/2 - 1 && paramSucceed) {
return {
table: table,
row: file[j],
index: j
}
}
}
}
}
} else {
var dir = this.list();
// Check every file in root
for (var i = 0; i < dir.length; i++) {
var file = JSON.parse(fs.readFileSync(this.root + dir[i] + '.json', this.encoding));
if(typeof file == 'object') {
// Check every index of the array
for (var j = 0; j < file.length; j++) {
var paramSucceed = false;
// Check if has every property
properties:
for (var param = 0; param < args.length / 2; param++) {
if(file[j].hasOwnProperty(args[2 * param]) && file[j][args[2 * param]] == args[2 * param + 1]) {
paramSucceed = true;
} else {
// If hasn't property, try next row
paramSucceed = false;
break properties;
}
if(param == args.length/2 - 1 && paramSucceed) {
return {
table: dir[i],
row: file[j],
index: j
}
}
}
}
}
}
}
} else {
throw "Array's length in find() must be pair for [attr, value, attr, value, ...]!";
}
}
} else {
throw "First argument in find() must be an array!";
}
}
} // DONE
/**
* Check if a table exists in the root directory.
* @param {string} table Name of the table to check
*/
exists(table) {
var path = this.root + table + '.json';
if(fs.existsSync(path)) {
return true;
} else {
return false;
}
} // DONE
}
// To import: const db = require('db');
// and that should be applying new db();
module.exports = new db();