I'm writing a object Factory Node module in ES6. I'm using the stamptit library https://github.com/stampit-org/stampit to get base objects started but enhance them and return my own objects through my factory.
Lets say I have these two files in '../../models/':
MYBASEJSONDATA.json
{
"addresses": {
"type": "ADDRESSJSONDATA.json",
"multi": true,
"required": true
},
.
.
.
}
ADDRESSJSONDATA.json
{
"street_name": "SAMPLE",
"zip_code": "75024"
.
.
.
}
This is my current code with some comments:
import stampit from 'stampit';
import * as fs from 'fs';
// Allows me to run Node's async internal functions as a generator
function runNodeFunc( gen, iter) {
(iter = gen((err, data) => (err && iter.throw(err)) ||
iter.next(data))).next();
}
// Loop through an object's keys and values
function* objectEntries(obj) {
let propKeys = Reflect.ownKeys(obj);
for(let propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
// function coroutine(generatorFunction) {
// return function (...args) {
// let generatorObject = generatorFunction(...args);
// generatorObject.next();
// return generatorObject;
// };
// }
function createModel(defModel) {
let model = stampit();
let customTypes = new Map(defModel.linked_custom_types);
for(let [key, value] of objectEntries(defModel)) {
if(customTypes.has(value.type)) {
// This does not work here because the runNodeFunc in getModels
// Does not pause execution
let cusMod = getModel(value.type);
model = model.props({[key]: cusMod});
} else {
// if it's a multi type create array
model = model.static({[key]: value.multi ? [] : ''});
}
}
}
function getModel(fileName) {
console.log(fileName);
// IDEALLY, this function would allow an external yield
runNodeFunc(function* readFile(resume) {
let mod = yield fs.readFile(`../../models/${fileName}.json`,
resume);
createModel(JSON.parse(mod));
});
}
getModel('MYBASEJSONDATA');
// export default BodhiModel;
Basically, each one of the json files is going to be used to construct a new object. For now I'm doing simple mappings using the subproperties of each file(for example, addresses.multi tells me that it will take many objects of the "ADDRESSJSONDATA" type), but the goal is to add more complexity to the objects.
I'm not too sure about using the 'stampit' library, I could very well just create my own objects and it feels redundant but that is a decision I can change later.
I would like to have a sort of recursive process to create these complex objects. I know I can implement that easily with a
yield *createModel(subType)
inside my createModel function so it would look something like this:
function createModel(fileName) {
let model = stampit();
// CALL getModels here! *1
let customTypes = new Map(defModel.linked_custom_types);
for(let [key, value] of objectEntries(defModel)) {
if(customTypes.has(value.type)) {
// ADD THIS HERE *2
let cusMod = yield *createModel(value.type);
model = model.props({[key]: cusMod});
} else {
model = model.static({[key]: value.multi ? [] : ''});
}
}
}
By adding *2, I'm passing the control. I've used to for tree traversals etc. But the tricky part is that in *1 I'm using that function which is surrounded by a helper function to use a generator to fetch the files. But this in itself does NOT pause execution since the getModels function is not a generator itself.
I've tried many ways, and I haven't found how I can keep the helper function runNodeFunc AND implement a recursive generator. If I have to just bite the bullet and wrap everything in a callback then I will, but I want to ask if this method of object creation is optimal and if I'm doing extra things that can be simplified. I'm also concerned with have generators create the object that this module is supposed to return.
I forgot to mention, there is a reference to "linked_custom_types" in the createModel function. These are just the nested objects for the particular main model being generated.