shelfdb
Version:
Node.JS custom database and abstract class library
417 lines (358 loc) • 11.2 kB
JavaScript
// Generated by CoffeeScript 2.0.2
var BSON, BSONSerializer, DBSerializable, Database, DatabaseSerializer, GZIP, JSONSerializer, YAML, YAMLSerializer, _serTypes, abstractClass, compjs, compressed, compressions, fs, gzipped, isImplementation, zlib,
indexOf = [].indexOf;
fs = require('fs');
YAML = require('js-yaml');
BSON = new (require('bson'))();
GZIP = require('pako');
zlib = require('zlib');
({abstractClass, isImplementation} = require('./abstraction.js'));
compjs = require('compressjs');
DatabaseSerializer = (function() {
class DatabaseSerializer {};
DatabaseSerializer.prototype.F_serialize = null;
DatabaseSerializer.prototype.F_deserialize = null;
return DatabaseSerializer;
})();
DatabaseSerializer = abstractClass(DatabaseSerializer, function(cls) {
return cls.database = function(filename, debug) {
return new Database(filename, cls, debug);
};
});
JSONSerializer = (function() {
class JSONSerializer {};
JSONSerializer.prototype.serialize = JSON.stringify;
JSONSerializer.prototype.deserialize = JSON.parse;
return JSONSerializer;
})();
YAMLSerializer = (function() {
class YAMLSerializer {
serialize(o) {
return YAML.safeDump(o, {
indent: 4,
lineWidth: 175
});
}
};
YAMLSerializer.prototype.deserialize = YAML.safeLoad;
return YAMLSerializer;
})();
BSONSerializer = (function() {
class BSONSerializer {};
BSONSerializer.prototype.serialize = BSON.serialize;
BSONSerializer.prototype.deserialize = BSON.deserialize;
return BSONSerializer;
})();
JSONSerializer = DatabaseSerializer.apply(JSONSerializer);
YAMLSerializer = DatabaseSerializer.apply(YAMLSerializer);
BSONSerializer = DatabaseSerializer.apply(BSONSerializer);
gzipped = function(ser) { // for compatibility purposes
var GZipped;
GZipped = class GZipped {
serialize(o) {
return new Buffer(GZIP.deflate(ser.prototype.serialize(o)));
}
deserialize(o) {
return ser.prototype.deserialize(new Buffer(GZIP.inflate(o)));
}
};
GZipped.name += ser.name;
GZipped = DatabaseSerializer.apply(GZipped);
return GZipped;
};
compressions = {
gzip: [zlib.gzipSync, zlib.gunzipSync],
inflate: [zlib.deflateSync, zlib.inflateSync],
bzip2: [compjs.Bzip2.compressFile, compjs.Bzip2.decompressFile],
bwtc: [compjs.BWTC.compressFile, compjs.BWTC.decompressFile],
lzp3: [compjs.Lzp3.compressFile, compjs.Lzp3.decompressFile],
ppm: [compjs.PPM.compressFile, compjs.PPM.decompressFile]
};
compressed = function(ser, compression) {
var Compressed;
if (compressions[compression = compression.toLowerCase()] == null) {
throw new Error("No such compression currently available with shelfdb!");
}
Compressed = class Compressed {
serialize(o) {
return new Buffer(compressions[compression][0](new Buffer(ser.prototype.serialize(o))));
}
deserialize(o) {
return ser.prototype.deserialize(new Buffer(compressions[compression][1](o)));
}
};
Compressed.name += ser.name;
Compressed = DatabaseSerializer.apply(Compressed);
return Compressed;
};
// =======================
_serTypes = {};
DBSerializable = (function() {
class DBSerializable {};
DBSerializable.prototype.F_toObject = null;
DBSerializable.prototype.S_fromObject = null;
return DBSerializable;
})();
DBSerializable = abstractClass(DBSerializable, function(cls) {
return _serTypes[cls.name] = cls;
});
// =======================
Database = class Database {
constructor(filename1, serializer, debug1) {
var err;
this.objectFrom = this.objectFrom.bind(this);
this.unfreeze = this.unfreeze.bind(this);
this._loadFile = this._loadFile.bind(this);
this.load = this.load.bind(this);
this.save = this.save.bind(this);
this.serialize = this.serialize.bind(this);
this.put = this.put.bind(this);
this.get = this.get.bind(this);
this.append = this.append.bind(this);
this.filename = filename1;
this.serializer = serializer;
this.debug = debug1;
if (this.debug == null) {
this.debug = false;
}
try {
if (fs.statSync(this.filename).isFile()) {
this.data = this.serializer.deserialize(fs.readFileSync(this.filename));
} else {
throw new Error("If you are seeing this, something is wrong with this control block.");
}
} catch (error) {
err = error;
this.data = {};
}
if ((typeof this.serializer) === 'function') {
this.serializer = new this.serializer();
}
}
objectFrom(obj, pkey, parent) {
var arr, i, k, len, o, ref, ref1, res, v;
if (parent == null) {
parent = null;
}
if (pkey == null) {
pkey = null;
}
if (this.debug === 2) {
console.log("Attempting to get object from:");
console.log(obj);
}
res = {
spec: {
serialization: null,
type: null,
primitive: false
},
obj: null
};
if ((obj != null) && isImplementation(obj.constructor, DBSerializable)) {
res.spec.type = "DBSerializable";
res.spec.serialization = obj.constructor.name;
if (this.debug === 1) {
console.log(`Found DBSerializable of type ${obj.constructor.name}${(pkey != null ? ` (and key '${pkey}')` : '')}`);
}
res.obj = {};
ref = obj.toObject();
for (k in ref) {
v = ref[k];
res.obj[k] = this.objectFrom(v, k, obj);
}
} else if (obj == null) {
res.spec.type = "nil";
res.spec.primitive = true;
res.obj = obj;
} else if ((typeof obj) !== 'object') {
if ((ref1 = typeof obj) !== 'string' && ref1 !== 'number' && ref1 !== 'boolean') {
throw new Error(`${obj}${(parent != null ? ` (from key '${pkey}' in parent with keys '${Object.keys(parent).join(', ')}')` : "")} must be a primitive, non-instance object, array, or implement the abstract type DBSerializable!`);
} else {
res.obj = obj;
res.spec.type = typeof obj;
res.spec.primitive = true;
}
} else if (Array.isArray(obj)) {
arr = [];
for (i = 0, len = obj.length; i < len; i++) {
o = obj[i];
arr.push(this.objectFrom(o));
}
res.obj = arr;
res.spec.type = 'array';
res.spec.primitive = false;
} else if (obj === null) { // includes undefined
res.obj = null;
res.spec.primitive = true;
} else {
if (res.spec.type == null) {
res.spec.type = "object";
}
res.obj = {};
for (k in obj) {
v = obj[k];
res.obj[k] = this.objectFrom(v, k, obj);
}
}
return res;
}
unfreeze(d) {
var e, i, item, k, len, ref, ref1, ref2, ref3, ref4, res, ud, v;
try {
res = null;
if (d.spec.type === "DBSerializable") {
ud = {};
ref = d.obj;
for (k in ref) {
v = ref[k];
ud[k] = this.unfreeze(v);
}
if ((d.spec.serialization != null) && (ref1 = d.spec.serialization, indexOf.call(Object.keys(_serTypes), ref1) >= 0)) {
res = _serTypes[d.spec.serialization].fromObject(ud);
} else if (ref2 = d.spec.serialization, indexOf.call(Object.keys(_serTypes), ref2) < 0) {
throw new Error(`DBSerializable-based object '${d.obj}' specifies an unsupported serialization type '${d.spec.serialization}'! (try loading the module with the serialization)`);
} else {
throw new Error(`DBSerializable-based object '${d.obj}' does not specify the serializing class in its spec structure`);
}
} else if (d.spec.primitive) {
res = d.obj;
} else if (d.spec.type === "array") {
res = [];
ref3 = d.obj;
for (i = 0, len = ref3.length; i < len; i++) {
item = ref3[i];
res.push(this.unfreeze(item));
}
} else if (d.spec.type === "object") {
res = {};
ref4 = d.obj;
for (k in ref4) {
v = ref4[k];
res[k] = this.unfreeze(v);
}
} else {
throw new Error(`Object '${d.obj}' does not specify a supported spec structure type ('${d.spec.type}' is a currently unsupported format)`);
}
return res;
} catch (error) {
e = error;
if (d.spec != null) {
if (!d.spec.primitive) {
console.log(`Error unfreezing object with keys '${Object.keys(d.obj).join(', ')}' and spec..`);
console.log(d.spec);
} else {
console.log(`Error unfreezing object '${d.obj}' with spec...`);
console.log(d.spec);
}
} else {
console.log("Error unfreezing object...");
console.log(d);
}
throw e;
}
}
_loadFile() {
var data, err;
try {
if (!fs.statSync(this.filename).isFile()) {
throw new Error("If you are seeing this, something is wrong with this control block.");
}
} catch (error) {
err = error;
return this.data || {};
}
data = this.serializer.deserialize(fs.readFileSync(this.filename));
return this.unfreeze(data);
}
load() {
return this.data = this._loadFile();
}
save() {
return fs.writeFileSync(this.filename, this.serialize(this.data));
}
serialize(obj) {
return this.serializer.serialize(this.objectFrom(obj));
}
parsePath(path, separator) {
if ((typeof path) === "string") {
path = path.match(new RegExp(`(?:\\\\.|[^\\${separator[0]}])+`, 'g')).map(function(x) {
return x.split("\\.").join(".");
});
}
return path;
}
put(path, value, separator, obj) {
var first;
if (separator == null) {
separator = '.';
}
path = this.parsePath(path, separator);
first = false;
if (obj == null) {
this.load();
first = true;
obj = this.data;
}
if (path.length > 1) {
if (obj[path[0]] == null) {
obj[path[0]] = {};
}
obj[path[0]] = this.put(path.slice(1), value, separator, obj[path[0]]);
} else {
obj[path[0]] = value;
}
if (first) {
this.data = obj;
this.save();
return path.map(function(x) {
return x.split('.').join('\\.');
}).join(".");
} else {
return obj;
}
}
get(path, separator) {
var i, len, o, p;
if (separator == null) {
separator = '.';
}
this.load();
path = this.parsePath(path, separator);
o = this.data;
for (i = 0, len = path.length; i < len; i++) {
p = path[i];
if (o[p] == null) {
return null;
}
o = o[p];
}
return o;
}
append(path, value, separator) {
var o;
o = this.get(path, separator);
if (o == null) {
o = [value];
} else if (typeof o !== "array") {
return null;
} else {
o.push(value);
}
return this.put(path, o, separator);
}
};
module.exports = {
DBSerializable: DBSerializable,
Database: Database,
DatabaseSerializer: DatabaseSerializer,
JSONSerializer: JSONSerializer,
YAMLSerializer: YAMLSerializer,
BSONSerializer: BSONSerializer,
gzipped: gzipped,
compressed: compressed,
compressions: compressions,
// entry point inheritance
abstractClass: abstractClass,
isImplementation: isImplementation
};