1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add JSONata async support to Switch and Change nodes

This commit is contained in:
Nick O'Leary 2018-07-09 21:56:39 +01:00
parent b2f06b6777
commit 807b512ef7
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 195 additions and 145 deletions

View File

@ -77,12 +77,13 @@ module.exports = function(RED) {
function getProperty(node,msg) { function getProperty(node,msg) {
return new Promise((resolve,reject) => { return new Promise((resolve,reject) => {
if (node.propertyType === 'jsonata') { if (node.propertyType === 'jsonata') {
try { RED.util.evaluateJSONataExpression(node.property,msg,(err,value) => {
resolve(RED.util.evaluateJSONataExpression(node.property,msg)); if (err) {
} catch(err) { reject(RED._("switch.errors.invalid-expr",{error:err.message}));
// TODO: proper invalid expr message } else {
reject(err); resolve(value);
} }
});
} else { } else {
RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg,(err,value) => { RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg,(err,value) => {
if (err) { if (err) {
@ -100,18 +101,20 @@ module.exports = function(RED) {
if (rule.vt === 'prev') { if (rule.vt === 'prev') {
resolve(node.previousValue); resolve(node.previousValue);
} else if (rule.vt === 'jsonata') { } else if (rule.vt === 'jsonata') {
try { var exp = rule.v;
var exp = rule.v; if (rule.t === 'jsonata_exp') {
if (rule.t === 'jsonata_exp') { if (hasParts) {
if (hasParts) { exp.assign("I", msg.parts.index);
exp.assign("I", msg.parts.index); exp.assign("N", msg.parts.count);
exp.assign("N", msg.parts.count);
}
} }
resolve(RED.util.evaluateJSONataExpression(exp,msg));
} catch(err) {
reject(RED._("switch.errors.invalid-expr",{error:err.message}));
} }
RED.util.evaluateJSONataExpression(exp,msg,(err,value) => {
if (err) {
reject(RED._("switch.errors.invalid-expr",{error:err.message}));
} else {
resolve(value);
}
});
} else if (rule.vt === 'json') { } else if (rule.vt === 'json') {
resolve("json"); resolve("json");
} else if (rule.vt === 'null') { } else if (rule.vt === 'null') {
@ -134,11 +137,13 @@ module.exports = function(RED) {
if (rule.v2t === 'prev') { if (rule.v2t === 'prev') {
resolve(node.previousValue); resolve(node.previousValue);
} else if (rule.v2t === 'jsonata') { } else if (rule.v2t === 'jsonata') {
try { RED.util.evaluateJSONataExpression(rule.v2,msg,(err,value) => {
resolve(RED.util.evaluateJSONataExpression(rule.v2,msg)); if (err) {
} catch(err) { reject(RED._("switch.errors.invalid-expr",{error:err.message}));
reject(RED._("switch.errors.invalid-expr",{error:err.message})); } else {
} resolve(value);
}
});
} else if (typeof v2 !== 'undefined') { } else if (typeof v2 !== 'undefined') {
RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg, function(err,value) { RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg, function(err,value) {
if (err) { if (err) {

View File

@ -98,138 +98,183 @@ module.exports = function(RED) {
} }
} }
function applyRule(msg,rule) { function getToValue(msg,rule) {
return new Promise(function(resolve, reject){ var value = rule.to;
try { if (rule.tot === 'json') {
var property = rule.p; value = JSON.parse(rule.to);
var value = rule.to; } else if (rule.tot === 'bin') {
if (rule.tot === 'json') { value = Buffer.from(JSON.parse(rule.to))
value = JSON.parse(rule.to); }
} else if (rule.tot === 'bin') { if (rule.tot === "msg") {
value = Buffer.from(JSON.parse(rule.to)) value = RED.util.getMessageProperty(msg,rule.to);
} } else if (rule.tot === 'flow') {
var current; value = node.context().flow.get(rule.to);
var fromValue; } else if (rule.tot === 'global') {
var fromType; value = node.context().global.get(rule.to);
var fromRE; } else if (rule.tot === 'date') {
if (rule.tot === "msg") { value = Date.now();
value = RED.util.getMessageProperty(msg,rule.to); } else if (rule.tot === 'jsonata') {
} else if (rule.tot === 'flow') { return new Promise((resolve,reject) => {
value = node.context().flow.get(rule.to); RED.util.evaluateJSONataExpression(rule.to,msg, (err, value) => {
} else if (rule.tot === 'global') { if (err) {
value = node.context().global.get(rule.to); reject(RED._("change.errors.invalid-expr",{error:err.message}))
} else if (rule.tot === 'date') { } else {
value = Date.now(); resolve(value);
} else if (rule.tot === 'jsonata') {
try{
value = RED.util.evaluateJSONataExpression(rule.to,msg);
} catch(err) {
node.error(RED._("change.errors.invalid-expr",{error:err.message}),msg);
return;
} }
} });
if (rule.t === 'change') { });
if (rule.fromt === 'msg' || rule.fromt === 'flow' || rule.fromt === 'global') { }
if (rule.fromt === "msg") { return Promise.resolve(value);
fromValue = RED.util.getMessageProperty(msg,rule.from); }
} else if (rule.fromt === 'flow') { function getFromValue(msg,rule) {
fromValue = node.context().flow.get(rule.from); var fromValue;
} else if (rule.fromt === 'global') { var fromType;
fromValue = node.context().global.get(rule.from); var fromRE;
} if (rule.t === 'change') {
if (typeof fromValue === 'number' || fromValue instanceof Number) { if (rule.fromt === 'msg' || rule.fromt === 'flow' || rule.fromt === 'global') {
fromType = 'num'; return new Promise((resolve,reject) => {
} else if (typeof fromValue === 'boolean') { if (rule.fromt === "msg") {
fromType = 'bool' resolve(RED.util.getMessageProperty(msg,rule.from));
} else if (fromValue instanceof RegExp) { } else if (rule.fromt === 'flow' || rule.fromt === 'global') {
fromType = 're'; node.context()[rule.fromt].get(rule.from,(err,fromValue) => {
fromRE = fromValue; if (err) {
} else if (typeof fromValue === 'string') { reject(err);
fromType = 'str'; } else {
fromRE = fromValue.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); resolve(fromValue);
try {
fromRE = new RegExp(fromRE, "g");
} catch (e) {
valid = false;
reject(RED._("change.errors.invalid-from",{error:e.message}));
return;
} }
} else { });
reject(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)})); }
return }).then(fromValue => {
if (typeof fromValue === 'number' || fromValue instanceof Number) {
fromType = 'num';
} else if (typeof fromValue === 'boolean') {
fromType = 'bool'
} else if (fromValue instanceof RegExp) {
fromType = 're';
fromRE = fromValue;
} else if (typeof fromValue === 'string') {
fromType = 'str';
fromRE = fromValue.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
try {
fromRE = new RegExp(fromRE, "g");
} catch (e) {
reject(new Error(RED._("change.errors.invalid-from",{error:e.message})));
return;
} }
} else { } else {
fromType = rule.fromt; reject(new Error(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)})));
fromValue = rule.from; return;
fromRE = rule.fromRE;
} }
} return {
if (rule.pt === 'msg') { fromType,
if (rule.t === 'delete') { fromValue,
RED.util.setMessageProperty(msg,property,undefined); fromRE
} else if (rule.t === 'set') {
RED.util.setMessageProperty(msg,property,value);
} else if (rule.t === 'change') {
current = RED.util.getMessageProperty(msg,property);
if (typeof current === 'string') {
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
// str representation of exact from number/boolean
// only replace if they match exactly
RED.util.setMessageProperty(msg,property,value);
} else {
current = current.replace(fromRE,value);
RED.util.setMessageProperty(msg,property,current);
}
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
if (current == Number(fromValue)) {
RED.util.setMessageProperty(msg,property,value);
}
} else if (typeof current === 'boolean' && fromType === 'bool') {
if (current.toString() === fromValue) {
RED.util.setMessageProperty(msg,property,value);
}
}
} }
} });
else { } else {
var target; fromType = rule.fromt;
if (rule.pt === 'flow') { fromValue = rule.from;
target = node.context().flow; fromRE = rule.fromRE;
} else if (rule.pt === 'global') { }
target = node.context().global; }
} return Promise.resolve({
if (target) { fromType,
if (rule.t === 'delete') { fromValue,
target.set(property,undefined); fromRE
} else if (rule.t === 'set') {
target.set(property,value);
} else if (rule.t === 'change') {
current = target.get(property);
if (typeof current === 'string') {
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
// str representation of exact from number/boolean
// only replace if they match exactly
target.set(property,value);
} else {
current = current.replace(fromRE,value);
target.set(property,current);
}
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
if (current == Number(fromValue)) {
target.set(property,value);
}
} else if (typeof current === 'boolean' && fromType === 'bool') {
if (current.toString() === fromValue) {
target.set(property,value);
}
}
}
}
}
} catch(err) {/*console.log(err.stack)*/}
resolve(msg);
}); });
} }
function applyRule(msg,rule) {
var property = rule.p;
var current;
var fromValue;
var fromType;
var fromRE;
try {
return getToValue(msg,rule).then(value => {
return getFromValue(msg,rule).then(fromParts => {
fromValue = fromParts.fromValue;
fromType = fromParts.fromType;
fromRE = fromParts.fromRE;
if (rule.pt === 'msg') {
try {
if (rule.t === 'delete') {
RED.util.setMessageProperty(msg,property,undefined);
} else if (rule.t === 'set') {
RED.util.setMessageProperty(msg,property,value);
} else if (rule.t === 'change') {
current = RED.util.getMessageProperty(msg,property);
if (typeof current === 'string') {
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
// str representation of exact from number/boolean
// only replace if they match exactly
RED.util.setMessageProperty(msg,property,value);
} else {
current = current.replace(fromRE,value);
RED.util.setMessageProperty(msg,property,current);
}
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
if (current == Number(fromValue)) {
RED.util.setMessageProperty(msg,property,value);
}
} else if (typeof current === 'boolean' && fromType === 'bool') {
if (current.toString() === fromValue) {
RED.util.setMessageProperty(msg,property,value);
}
}
}
} catch(err) {}
return msg;
} else if (rule.pt === 'flow' || rule.pt === 'global') {
return new Promise((resolve,reject) => {
var target = node.context()[rule.pt];
var callback = err => {
if (err) {
reject(err);
} else {
resolve(msg);
}
}
if (rule.t === 'delete') {
target.set(property,undefined,callback);
} else if (rule.t === 'set') {
target.set(property,value,callback);
} else if (rule.t === 'change') {
target.get(property,(err,current) => {
if (err) {
reject(err);
return;
}
if (typeof current === 'string') {
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
// str representation of exact from number/boolean
// only replace if they match exactly
target.set(property,value,callback);
} else {
current = current.replace(fromRE,value);
target.set(property,current,callback);
}
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
if (current == Number(fromValue)) {
target.set(property,value,callback);
}
} else if (typeof current === 'boolean' && fromType === 'bool') {
if (current.toString() === fromValue) {
target.set(property,value,callback);
}
}
});
}
});
}
});
}).catch(err => {
node.error(err, msg);
return null;
});
} catch(err) {
return Promise.resolve(msg);
}
}
function applyRules(msg, currentRule) { function applyRules(msg, currentRule) {
var r = node.rules[currentRule]; var r = node.rules[currentRule];
var rulePromise; var rulePromise;