UNPKG

jsmdb

Version:

JSMumps Database Component

380 lines (294 loc) 9.44 kB
/* * JSMumps Database API * * child.js: the child process * * * Copyright (C) 2017, 2021 Coherent Logic Development LLC * * Author: John P. Willis <jpw@coherent-logic.com> * */ const nodem = require('nodem'); const _ = require('underscore'); const log = require('jsmlog'); var current = { global: null, subscripts: [], isLocal: false }; var logLevel = process.argv[2]; var logger = new log.Logger({ logLevel: logLevel, moduleName: "jsmdb (worker, pid " + process.pid + ")" }) var db = new nodem.Gtm(); var result = db.open(); if(!result.ok) { sendMessage('INIT_ERROR', {message: "Error opening database"}); } else { logger.debug("opened M database with pid " + result.pid); } const nodemAPI = { getObject: function (opts) { var result = null; try { result = { data: nodemAPI.getObjectX(), ok: 1 }; } catch(ex) { result = { data: {}, ok: 0, ErrorMessage: ex, ErrorCode: "" }; } return result; }, getObjectX: function (subscripts, outputStruct) { if(subscripts) { var mSubscripts = fastClone(subscripts); } else { var mSubscripts = fastClone(current.subscripts); } if(!outputStruct) { var outStruct = {}; if(current.isLocal) { if(db.data({local: current.global}).defined % 10) { outStruct[""] = db.get({local: current.global}).data; } } else { if(db.data({global: current.global}).defined % 10) { outStruct[""] = db.get({global: current.global}).data; } } console.log(JSON.stringify(outStruct, null, 4)); } else { var outStruct = fastClone(outputStruct); } var lastResult = false; mSubscripts.push(""); while(!lastResult) { if(current.isLocal) { var order = db.order({local: current.global, subscripts: mSubscripts}); } else { var order = db.order({global: current.global, subscripts: mSubscripts}); } if(!order.ok) { logger.debug("getObjectX() failed on nodem order() call"); throw("NodeM error calling order()"); } if(order.result === "") { lastResult = true; continue; } mSubscripts = order.subscripts; var structSubs = mSubscripts.slice(current.subscripts.length); if(current.isLocal) { var data = db.data({local: current.global, subscripts: mSubscripts}); } else { var data = db.data({global: current.global, subscripts: mSubscripts}); } switch(data.defined) { case 11: if(current.isLocal) { var nodeValue = db.get({local: current.global, subscripts: mSubscripts}); } else { var nodeValue = db.get({global: current.global, subscripts: mSubscripts}); } if(!nodeValue.ok) { logger.debug("getObjectX() failed on nodem get() call"); throw("NodeM error calling get()"); } buildObject(outStruct, structSubs, nodeValue.data, true); _.extend(outStruct, nodemAPI.getObjectX(mSubscripts, outStruct)); break; case 10: _.extend(outStruct, nodemAPI.getObjectX(mSubscripts, outStruct)) break; case 1: if(current.isLocal) { buildObject(outStruct, structSubs, db.get({local: current.global, subscripts: mSubscripts}).data, false); } else { buildObject(outStruct, structSubs, db.get({global: current.global, subscripts: mSubscripts}).data, false); } break; } } return outStruct; }, setObject: function (opts) { var result = null; try { result = { data: nodemAPI.setObjectX(opts.data), ok: 1 }; } catch(ex) { result = { data: {}, ok: 0, ErrorMessage: "Error in setObject()", ErrorCode: "" }; } return result; }, setObjectX: function (inputObject, subscripts) { if(subscripts) { var subs = fastClone(subscripts); } else { var subs = fastClone(current.subscripts); } for(var key in inputObject) { subs.push(key); switch(typeof inputObject[key]) { case 'object': nodemAPI.setObjectX(inputObject[key], subs); break; case 'string': case 'number': var result = db.set({global: current.global, subscripts: subs, data: inputObject[key]}); if(!result.ok) { logger.debug("setObjectX() failed on nodem set() call"); throw("NodeM error calling set()"); } break; } subs.pop(); } return; }, get: function (opts) { return db.get({global: current.global, subscripts: current.subscripts}); }, set: function (opts) { return db.set({global: current.global, subscripts: current.subscripts, data: opts.data}); }, merge: function(opts) { return db.merge(opts); }, kill: function (opts) { return db.kill({global: current.global, subscripts: current.subscripts, data: opts.data}); }, lock: function (opts) { return db.lock({global: current.global, subscripts: current.subscripts, timeout: opts.timeout || 0}); }, unlock: function (opts) { return db.unlock({global: current.global, subscripts: current.subscripts}); }, data: function (opts) { return db.data({global: current.global, subscripts: current.subscripts}); }, order: function (opts) { return db.order({global: current.global, subscripts: current.subscripts}); }, query: function (opts) { return db.next_node({global: current.global, subscripts: current.subscripts}); }, function: function (opts) { return db.function({function: opts.func, arguments: opts.args}); }, procedure: function (opts) { return db.procedure({procedure: opts.proc, arguments: opts.args}) }, localDirectory: function (opts) { return db.localDirectory(); } }; function fastClone(obj) { return JSON.parse(JSON.stringify(obj)); } function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); } function buildObject(obj, keyArray, value, lastKeyEmpty) { if(lastKeyEmpty) { keyArray.push(""); } lastKeyIndex = keyArray.length - 1; for(var i = 0; i < lastKeyIndex; ++ i) { key = keyArray[i]; if (!(key in obj)) { obj[key] = {}; } obj = obj[key]; } obj[keyArray[lastKeyIndex]] = value; } function handleMessage(msg) { logger.debug("received " + msg.action); if(msg.action === "CP_SHUTDOWN") { logger.info("received CP_SHUTDOWN; closing database"); db.close({resetTerminal: true}); process.exit(); } if(!msg.options) { throw("Invalid message sent to worker process."); } current.global = msg.options.global || null; current.subscripts = msg.options.subscripts || []; for(key in msg.locals) { val = msg.locals[key]; db.set({ local: key, data: val }); } var result = nodemAPI[msg.action](msg.options); if(result.ok) { var locals = db.localDirectory(); result.locals = {}; locals.forEach((itm) => { if(db.data(itm) > 1) { current = { global: itm, subscripts: [], isLocal: true }; result.locals[itm] = nodemAPI.getObject().data; } else { result.locals[itm] = db.get(itm); } }); current.isLocal = false; //console.log(JSON.stringify(result, null, 4)); sendMessage('DBOP_COMPLETE', result); //TODO: pull in local symbol table //TODO: send message to parent containing local symbol table } else { var errObj = { message: result.ErrorMessage || "", code: result.ErrorCode || "" }; sendMessage('DBOP_ERROR', errObj); } } function sendMessage(type, data) { var msg = { type: type, data: data }; process.send(msg); } process.on('message', handleMessage);