This is the first version of the code that I have attempted. I've tried a whole lot of other things like mutual exclusion, adding catch blocks everywhere, and Promise anti-patterns, but I can't seem to get over this mental or syntactical block:
populateJoins() {
let promises = [];
for (let c in this.columns) {
let transformColumn = this.columns[c];
if (transformColumn.joins) {
let joinPointer = this.databaseObject;
for (let j in transformColumn.joins) {
let join = transformColumn.joins[j];
if (joinPointer[join.as] != null) {
joinPointer = joinPointer.dataValues[join.as];
} else {
if (this.requestQuery[toCamelCase(join.as) + 'Id']) {
promises.push(
join.model.findOne({where: {id: this.requestQuery[toCamelCase(join.as) + 'Id']}})
.then((tmp) => {
joinPointer.dataValues[join.as] = tmp;
}));
} else if (joinPointer[toSnakeCase(join.as) + '_id']) {
promises.push(
join.model.findOne({where: {id: joinPointer[toSnakeCase(join.as) + '_id']}})
.then((tmp) => {
joinPointer.dataValues[join.as] = tmp;
}));
}
}
}
}
}
return Promises.all(promises);
}
And this is the structure of this.columns
:
child1Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child1'
}],
hidden: true
},
child2Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
}],
hidden: true
},
child1Status1Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child1'
},{
model: Database.getInstance().getModel('status1'),
as: 'Status1'
}],
hidden: true
},
child1Status2Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child1'
},{
model: Database.getInstance().getModel('status2'),
as: 'Grandchild2'
}],
hidden: true
},
serverName: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child2'
},{
model: Database.getInstance().getModel('grandchild'),
as: 'Grandchild'
},{
model: Database.getInstance().getModel('great_grandchild'),
as: 'GreatGrandchild'
}],
hidden: true
},
child2Status1Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
},{
model: Database.getInstance().getModel('status1'),
as: 'Grandchild1'
}],
hidden: true
},
child2Status2Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
},{
model: Database.getInstance().getModel('status2'),
as: 'Grandchild2'
}],
hidden: true
},
archetypeName: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
},{
model: Database.getInstance().getModel('archetype'),
as: 'Archetype'
},{
model: Database.getInstance().getModel('archetype'),
as: 'ArchetypeLink'
}],
hidden: true
},
So for things I've already learned, joinPointer[join.as] != null
will never prevent duplicate Child
database calls from firing because the property will not be populated until the promises finish resolving.
Similarly, none of the grandchildren will populate because they have to wait for the children to populate, and if the grandchildren fulfill first, then they will never make it into the child object. The same goes for great-grandchildren.
I read this answer, where he says, "If you already have them in an array then they are already executing." I understand that the contents of the Promise will already resolve, which is why in other code I always use numerical indices to populate objects, i.e. jsonObject['list'][i]['anotherList'][j] = ...;
, but I don't see how I can do this here.
I've been working on this for a while and haven't come up with a solution, so any workable code is more than appreciated.