Skip to content

Instantly share code, notes, and snippets.

@petersirka
Created March 13, 2022 12:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petersirka/76d934f60595d4976879f0009be4a18d to your computer and use it in GitHub Desktop.
Save petersirka/76d934f60595d4976879f0009be4a18d to your computer and use it in GitHub Desktop.
//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