0

Hey there StackOverflow people of the world! Thank you for helping me with my question, and I apologize if this question gets a bit long winded. I just want to be clear about all the details and constraints I am working with. I found a few other related questions but nothing that was really very clear about how to get around my specific problem, unless I am missing something. Related questions:[1, 2]

Question Setup:

This is what I have and how it works, my question will be about a problem I am having I've got a object that I've filled with named functions. The purpose of the object map is to contain many functions calls from multiple files. I am calling each function a "business rule" and they are typically very small functions that do a singular action with well-defined inputs and outputs. It also lets me chain the function calls sequentially with the output from functionCall1 becoming the input functionCall2.

All of my business rule definitions up to this point have been in a set of files that reside in a sub-folder called "Framework", but what I am trying to do now is allow the "Client" to define their own business rules in their own files and their own object map of function calls. What I would like to do is add all of the function calls to a single shared data storage.

What I am trying to avoid doing: I am NOT trying to serialize the function calls, neither am I trying to leverage the 'eval' capability of JS. I've tried working with this before and it gets really messy! Also I DO NOT want to declare a "class" object or use the "this" keyword for this reason: 10-most-common-javascript-mistakes

What is working: (NOTE: Greatly simplified as I currently have hundreds of "business rules")

// rulesLibrary.js

import * as stringParsing from './Rules/stringParsing';

export const rulesLibrary = {
  ['Echo']: (inputData, inputMetaData) => (inputData, inputMetaData),

  // Business Rules
  // ********************************
  // StringParsing rules in order
  // ********************************
  ['stringToBoolean']: (inputData, inputMetaData) => stringParsing.stringToBoolean(inputData, inputMetaData),
  ['stringToDataType']: (inputData, inputMetaData) => stringParsing.stringToDataType(inputData, inputMetaData),
}

// stringParsing.js

export const stringToBoolean = function(inputData, inputMetaData) {
  var returnData;
  // Function Body...
  return returnData;
};

export const stringToDataType = function(inputData, inputMetaData) {
  var returnData;
  // Function Body...
  return returnData;
};

// ruleBroker.js

import * as rules from './rulesLibrary';

export const processRules = function(inputData, inputMetaData, rulesToExecute) {
  var returnData = inputData;
  for (var rule in rulesToExecute) {
    if (rulesToExecute.hasOwnProperty(rule)) {
      var key = rule;
      var value = rulesToExecute[key];
      returnData = rules.rulesLibrary[value](returnData, inputMetaData);
    }
  }
  return returnData;
};

You can see in the code above the rulesLibrary is defining the functions in an object rulesLibrary = {}; which is also exported. Then in the ruleBroker we are calling the associated function: rules.rulesLibrary[value](returnData, inputMetaData)....and this works great.

My Goal

My goal is to rather than store all these functionName: functionCall on the rules.rulesLibrary, I want to store them on a singleton data storage object I am calling "D".

Here is the definition of "D":

// data.js

export var data = {};

What I have tried - Attempt 1

I first tried to assign all of the contents of the rules.rulesLibrary from the rulesLibrary.js directly to "D" like so in the ruleBroker.js file:

// NOTE: I am actually doing this inside a function so I can boot-strap the rules.rulesLibrary into `D`, before the application begins going about the business of calling business rules via the ruleBroker.

import * as rules from './rulesLibrary';
var D = require('../Resources/data');

D['BusinessRules'] = {};
D['BusinessRules'] = rules.rulesLibrary;

This did not work and attempting to console.log(JSON.stringify(D)); just gave me back:

D{BusinessRules} = {};

What I have tried -- Attempt 2

So I thought maybe I should try and define the business rules map named function calls directly on "D" like so in the rulesLibrary.js file:

// NOTE: I am again doing all of this inside a boot-strap function for the same reason as above.

export const initRulesLibrary = function() {
  D['BusinessRules'] = {};
  D['BusinessRules'] = {
    ['Echo']: (inputData, inputMetaData) => (inputData, inputMetaData),

    // Business Rules
    // ********************************
    // StringParsing rules in order
    // ********************************
    ['stringToBoolean']: (inputData, inputMetaData) => stringParsing.stringToBoolean(inputData, inputMetaData),
    ['stringToDataType']: (inputData, inputMetaData) => stringParsing.stringToDataType(inputData, inputMetaData),
  }
};

Again I get the same thing, contents of D are: D{BusinessRules} = {}.

Maybe console.log in combination with JSON.stringify doesn't work with function-objects? But then again, I do have rules that return a function-object and I have been able to stringify those function-objects in the past with this same code. Granted it's a function-object so I am not expecting it to look pretty when stringified, but that's not the point. The point should be that the function-object exists on 'D' and it clearly does not, what am I missing here? How can I get all my function-objects mapped on 'D' so that I can add/merge more function-object definitions to it?

Ultimately this is what I want to be able to do:

function addClientRules(clientRules) {
  Object.assign(D['BusinessRules'], clientRules['BusinessRules']);
};

Such that D now contains all of the system-defined business rules & all of the client defined business rules. Then in the ruleBroker, I would just call whatever business rule like this:

export const processRules = function(inputData, inputMetaData, rulesToExecute) {
  var returnData = inputData;
  for (var rule in rulesToExecute) {
    if (rulesToExecute.hasOwnProperty(rule)) {
      var key = rule;
      var value = rulesToExecute[key];
      // OLD WAY:
      // returnData = rules.rulesLibrary[value](returnData, inputMetaData);
      // NEW WAY:
      returnData = D['BusinessRules'][value](returnData, inputMetaData);
    }
  }
  return returnData;
};

Any ideas? Thoughts? Edits? Rants? Am I at least on the right track?

Thank you again for your help! Hopefully this will help someone else too!! :-D

Seth Eden
  • 1,142
  • 2
  • 20
  • 42

1 Answers1

0

Turns out I was already doing everything correctly to begin with. It's just that console.log & JSON.stringify don't work well with a object map of functions.

The function maps do contain the function calls, just don't expect your console.log even with JSON.stringify to dump that data in any way. You have to proceed with making the call as if it is there and verify that the execution is successful by putting console logs in the function that calls the rule and additionally putting console logs in the rule that is to be executed.

It does work and it's pretty cool when it does!!

I hope this can help someone else, please comment if you have any additional questions and/or if I can provide additional solution details.

Log of successful execution:

c.ccustomEcho resolves as: customEcho
BEGIN warden.executeBusinessRule function
businessRule is: customEcho
ruleInput is: Calling Custom Echo from application
ruleMetaData is: Calling Custom Echo from application
BEGIN ruleBroker.processRules function
inputData is: "Calling Custom Echo from application"
inputMetaData is: "something-nothing"
rulesToExecute are: {"0":"customEcho"}
BEGIN clientStringParsing.customEcho function
inputData is: Calling Custom Echo from application
inputMetaData is: something-nothing
returnData is: Calling Custom Echo from application clientStringParsing.customEcho
END clientStringParsing.customEcho function
returnData is: "Calling Custom Echo from application clientStringParsing.customEcho"
END ruleBroker.processRules function
returnData is: Calling Custom Echo from application clientStringParsing.customEcho
END warden.executeBusinessRule function

Cheers

~Seth

Seth Eden
  • 1,142
  • 2
  • 20
  • 42