Created
March 13, 2022 12:20
-
-
Save petersirka/76d934f60595d4976879f0009be4a18d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//require('../index'); | |
// CONF.table_users = 'id:uid,name:string,dtcreated:date'; | |
// TABLE('users').find().callback(console.log); | |
// TABLE('users').insert({ id: UID(), name: 'Peter', dtcreated: NOW }); | |
const DELIMITER = '\0'; | |
const Fs = require('fs'); | |
const Path = require('path'); | |
function RDBMS(filename, potemkin) { | |
var t = this; | |
t.headersize = 1024 * 5; // 5 kB | |
t.filename = filename; | |
t.version = 1; | |
t.columns = {}; | |
t.commands = []; | |
t.keys = []; | |
t.ready = false; | |
if (!potemkin) { | |
t.next = function() { | |
var item = t.commands.shift(); | |
if (item) | |
t[item.name].apply(t, item.args); | |
}; | |
t.refresh(); | |
} | |
} | |
RDBMS.prototype.insert = function(data, callback) { | |
var self = this; | |
if (!self.ready) { | |
self.commands.push({ name: 'insert', args: arguments }); | |
return self; | |
} | |
var buffer = self.serialize(data); | |
Fs.appendFile(self.filename, buffer, function() { | |
callback && callback(); | |
self.next(); | |
}); | |
return self; | |
}; | |
RDBMS.prototype.refresh = function() { | |
var self = this; | |
Fs.open(self.filename, 'r+', function(err, fd) { | |
if (err) { | |
Fs.writeFile(self.filename, Buffer.alloc(0), function() { | |
self.refresh(); | |
}); | |
} else { | |
self.fd = fd; | |
self.load(self.next); | |
} | |
}); | |
}; | |
RDBMS.prototype.serializemeta = function(schema) { | |
var self = this; | |
var buffer = Buffer.alloc(self.headersize); | |
var chunks = []; | |
for (var key in schema) { | |
var val = schema[key]; | |
chunks.push(key + ':' + val); | |
} | |
var columns = Buffer.from(chunks.join(DELIMITER), 'utf8'); | |
buffer.write('TableDB'); | |
buffer.writeInt8(1, 7); // version | |
buffer.writeInt32BE(columns.length, 8); // size of columns | |
columns.copy(buffer, 12); | |
return buffer; | |
}; | |
RDBMS.prototype.parsemeta = function(buffer) { | |
var version = buffer.readInt8(7); | |
if (!version) | |
return; | |
var length = buffer.readInt32BE(8); | |
var arr = buffer.toString('utf8', 12, 12 + length).split(DELIMITER); | |
var columns = {}; | |
for (var item of arr) { | |
var kv = item.split(':'); | |
columns[kv[0]] = kv[1]; | |
} | |
return { version: version, columns: columns }; | |
}; | |
RDBMS.prototype.serialize = function(row) { | |
var self = this; | |
var arr = []; | |
for (var key in self.columns) { | |
var val = row[key]; | |
if (val == null) | |
val = ''; | |
else { | |
if (val instanceof Date) | |
val = val.getTime().toString(36); | |
else if (typeof(val) === 'boolean') | |
val = val ? 1 : 0; | |
val = val.toString(); | |
} | |
arr.push(val); | |
} | |
var data = arr.join(DELIMITER); | |
var meta = Buffer.alloc(5); | |
meta.writeInt8(1); | |
meta.writeInt32BE(data.length, 1); | |
return Buffer.concat([meta, Buffer.from(data, 'utf8')]); | |
}; | |
RDBMS.prototype.parse = function(buffer, fields) { | |
var self = this; | |
var state = buffer.readInt8(0); | |
if (state === 2) | |
return; | |
var size = buffer.readInt32BE(1); | |
var offset = 5; | |
var value = buffer.toString('utf8', offset, offset + size).split(DELIMITER); | |
var doc = {}; | |
var indexer = -1; | |
for (var key in self.meta) { | |
indexer++; | |
if (fields && !fields[key]) | |
continue; | |
var col = self.meta[key]; | |
switch (col) { | |
case 'date': | |
doc[key] = value[indexer] ? new Date(parseInt(value[indexer], 36)) : null; | |
break; | |
case 'number': | |
doc[key] = value[indexer] ? value[indexer] : null; | |
break; | |
case 'boolean': | |
doc[key] = value[indexer] === '1' ? true : value[indexer] === '0' ? false : null; | |
break; | |
case 'string': | |
default: | |
doc[key] = value[indexer]; | |
break; | |
} | |
} | |
return doc; | |
}; | |
RDBMS.prototype.create = function(schema, callback) { | |
var self = this; | |
Fs.writeFile(self.filename, self.serializemeta(schema), function() { | |
self.columns = schema; | |
callback && callback(); | |
}); | |
return self; | |
}; | |
RDBMS.prototype.load = function(callback) { | |
var self = this; | |
var buffer = Buffer.alloc(self.headersize); | |
Fs.read(self.fd, buffer, 0, buffer.length, 0, function() { | |
var meta = self.parsemeta(buffer); | |
if (meta) { | |
self.version = meta.version; | |
self.columns = meta.columns; | |
self.keys = Object.keys(self.columns); | |
self.ready = true; | |
} | |
callback && callback(); | |
self.next(); | |
}); | |
return self; | |
}; | |
RDBMS.create = function(filename, schema, callback) { | |
var self = this; | |
var db = new RDBMS(filename, true); | |
Fs.writeFile(filename, db.serializemeta(schema), callback); | |
return self; | |
}; | |
(function() { | |
// RDBMS.create(PATH.databases('users.tabledb'), { id: 'string', name: 'string', age: 'number', isremoved: 'boolean', date: 'date' }, console.log); | |
var rdbms = new RDBMS(Path.join('databases', 'users.tabledb')); | |
// rdbms.insert({ id: '123456', name: 'Peter', age: 33, isremoved: false, date: new Date() }); | |
// rdbms.create(rdbms.columns); | |
// return; | |
// var buf = rdbms.serialize({ id: UID(), name: 'Peter', isremoved: true, dtcreated: NOW }); | |
// console.log(rdbms.parse(buf)); | |
// var columns = rdbms.serializemeta(rdbms.columns); | |
// console.log(rdbms.parsemeta(columns)); | |
// console.log(buf.toString('ascii')); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment