mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Update sort node for async use of jsonata
This commit is contained in:
parent
807b512ef7
commit
d8d82e2ba3
@ -17,7 +17,7 @@
|
|||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var _max_kept_msgs_count = undefined;
|
var _max_kept_msgs_count;
|
||||||
|
|
||||||
function max_kept_msgs_count(node) {
|
function max_kept_msgs_count(node) {
|
||||||
if (_max_kept_msgs_count === undefined) {
|
if (_max_kept_msgs_count === undefined) {
|
||||||
@ -32,30 +32,20 @@ module.exports = function(RED) {
|
|||||||
return _max_kept_msgs_count;
|
return _max_kept_msgs_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
function eval_jsonata(node, code, val) {
|
// function get_context_val(node, name, dval) {
|
||||||
try {
|
// var context = node.context();
|
||||||
return RED.util.evaluateJSONataExpression(code, val);
|
// var val = context.get(name);
|
||||||
}
|
// if (val === undefined) {
|
||||||
catch (e) {
|
// context.set(name, dval);
|
||||||
node.error(RED._("sort.invalid-exp"));
|
// return dval;
|
||||||
throw e;
|
// }
|
||||||
}
|
// return val;
|
||||||
}
|
// }
|
||||||
|
|
||||||
function get_context_val(node, name, dval) {
|
|
||||||
var context = node.context();
|
|
||||||
var val = context.get(name);
|
|
||||||
if (val === undefined) {
|
|
||||||
context.set(name, dval);
|
|
||||||
return dval;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
function SortNode(n) {
|
function SortNode(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
var node = this;
|
var node = this;
|
||||||
var pending = get_context_val(node, 'pending', {})
|
var pending = {};//get_context_val(node, 'pending', {})
|
||||||
var pending_count = 0;
|
var pending_count = 0;
|
||||||
var pending_id = 0;
|
var pending_id = 0;
|
||||||
var order = n.order || "ascending";
|
var order = n.order || "ascending";
|
||||||
@ -76,11 +66,10 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var dir = (order === "ascending") ? 1 : -1;
|
var dir = (order === "ascending") ? 1 : -1;
|
||||||
var conv = as_num
|
var conv = as_num ? function(x) { return Number(x); }
|
||||||
? function(x) { return Number(x); }
|
: function(x) { return x; };
|
||||||
: function(x) { return x; };
|
|
||||||
|
|
||||||
function gen_comp(key) {
|
function generateComparisonFunction(key) {
|
||||||
return function(x, y) {
|
return function(x, y) {
|
||||||
var xp = conv(key(x));
|
var xp = conv(key(x));
|
||||||
var yp = conv(key(y));
|
var yp = conv(key(y));
|
||||||
@ -90,74 +79,97 @@ module.exports = function(RED) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function send_group(group) {
|
function sortMessageGroup(group) {
|
||||||
var key = key_is_exp
|
var promise;
|
||||||
? function(msg) {
|
|
||||||
return eval_jsonata(node, key_exp, msg);
|
|
||||||
}
|
|
||||||
: function(msg) {
|
|
||||||
return RED.util.getMessageProperty(msg, key_prop);
|
|
||||||
};
|
|
||||||
var comp = gen_comp(key);
|
|
||||||
var msgs = group.msgs;
|
var msgs = group.msgs;
|
||||||
try {
|
if (key_is_exp) {
|
||||||
msgs.sort(comp);
|
var evaluatedDataPromises = msgs.map(msg => {
|
||||||
}
|
return new Promise((resolve,reject) => {
|
||||||
catch (e) {
|
RED.util.evaluateJSONataExpression(key_exp, msg, (err, result) => {
|
||||||
return; // not send when error
|
resolve({
|
||||||
}
|
item: msg,
|
||||||
for (var i = 0; i < msgs.length; i++) {
|
sortValue: result
|
||||||
var msg = msgs[i];
|
})
|
||||||
msg.parts.index = i;
|
});
|
||||||
node.send(msg);
|
})
|
||||||
}
|
});
|
||||||
}
|
promise = Promise.all(evaluatedDataPromises).then(evaluatedElements => {
|
||||||
|
// Once all of the sort keys are evaluated, sort by them
|
||||||
function sort_payload(msg) {
|
var comp = generateComparisonFunction(elem=>elem.sortValue);
|
||||||
var data = RED.util.getMessageProperty(msg, target_prop);
|
return evaluatedElements.sort(comp).map(elem=>elem.item);
|
||||||
if (Array.isArray(data)) {
|
});
|
||||||
var key = key_is_exp
|
} else {
|
||||||
? function(elem) {
|
var key = function(msg) {
|
||||||
return eval_jsonata(node, key_exp, elem);
|
return ;
|
||||||
}
|
}
|
||||||
: function(elem) { return elem; };
|
var comp = generateComparisonFunction(msg => RED.util.getMessageProperty(msg, key_prop));
|
||||||
var comp = gen_comp(key);
|
|
||||||
try {
|
try {
|
||||||
data.sort(comp);
|
msgs.sort(comp);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
return false;
|
return; // not send when error
|
||||||
}
|
}
|
||||||
return true;
|
promise = Promise.resolve(msgs);
|
||||||
}
|
}
|
||||||
return false;
|
return promise.then(msgs => {
|
||||||
|
for (var i = 0; i < msgs.length; i++) {
|
||||||
|
var msg = msgs[i];
|
||||||
|
msg.parts.index = i;
|
||||||
|
node.send(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_parts(parts) {
|
function sortMessageProperty(msg) {
|
||||||
if (parts.hasOwnProperty("id") &&
|
var data = RED.util.getMessageProperty(msg, target_prop);
|
||||||
parts.hasOwnProperty("index")) {
|
if (Array.isArray(data)) {
|
||||||
return true;
|
if (key_is_exp) {
|
||||||
|
// key is an expression. Evaluated the expression for each item
|
||||||
|
// to get its sort value. As this could be async, need to do
|
||||||
|
// it first.
|
||||||
|
var evaluatedDataPromises = data.map(elem => {
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
RED.util.evaluateJSONataExpression(key_exp, elem, (err, result) => {
|
||||||
|
resolve({
|
||||||
|
item: elem,
|
||||||
|
sortValue: result
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return Promise.all(evaluatedDataPromises).then(evaluatedElements => {
|
||||||
|
// Once all of the sort keys are evaluated, sort by them
|
||||||
|
// and reconstruct the original message item with the newly
|
||||||
|
// sorted values.
|
||||||
|
var comp = generateComparisonFunction(elem=>elem.sortValue);
|
||||||
|
data = evaluatedElements.sort(comp).map(elem=>elem.item);
|
||||||
|
RED.util.setMessageProperty(msg, target_prop,data);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
var comp = generateComparisonFunction(elem=>elem);
|
||||||
|
try {
|
||||||
|
data.sort(comp);
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear_pending() {
|
function removeOldestPending() {
|
||||||
|
var oldest;
|
||||||
|
var oldest_key;
|
||||||
for(var key in pending) {
|
for(var key in pending) {
|
||||||
node.log(RED._("sort.clear"), pending[key].msgs[0]);
|
if (pending.hasOwnProperty(key)) {
|
||||||
delete pending[key];
|
var item = pending[key];
|
||||||
}
|
if((oldest === undefined) ||
|
||||||
pending_count = 0;
|
(oldest.seq_no > item.seq_no)) {
|
||||||
}
|
oldest = item;
|
||||||
|
oldest_key = key;
|
||||||
function remove_oldest_pending() {
|
}
|
||||||
var oldest = undefined;
|
|
||||||
var oldest_key = undefined;
|
|
||||||
for(var key in pending) {
|
|
||||||
var item = pending[key];
|
|
||||||
if((oldest === undefined) ||
|
|
||||||
(oldest.seq_no > item.seq_no)) {
|
|
||||||
oldest = item;
|
|
||||||
oldest_key = key;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(oldest !== undefined) {
|
if(oldest !== undefined) {
|
||||||
@ -166,16 +178,18 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function process_msg(msg) {
|
function processMessage(msg) {
|
||||||
if (target_is_prop) {
|
if (target_is_prop) {
|
||||||
if (sort_payload(msg)) {
|
sortMessageProperty(msg).then(send => {
|
||||||
node.send(msg);
|
if (send) {
|
||||||
}
|
node.send(msg);
|
||||||
return;
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
var parts = msg.parts;
|
var parts = msg.parts;
|
||||||
if (!check_parts(parts)) {
|
if (!parts.hasOwnProperty("id") || !parts.hasOwnProperty("index")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var gid = parts.id;
|
var gid = parts.id;
|
||||||
@ -195,23 +209,29 @@ module.exports = function(RED) {
|
|||||||
pending_count++;
|
pending_count++;
|
||||||
if (group.count === msgs.length) {
|
if (group.count === msgs.length) {
|
||||||
delete pending[gid]
|
delete pending[gid]
|
||||||
send_group(group);
|
sortMessageGroup(group);
|
||||||
pending_count -= msgs.length;
|
pending_count -= msgs.length;
|
||||||
}
|
} else {
|
||||||
var max_msgs = max_kept_msgs_count(node);
|
var max_msgs = max_kept_msgs_count(node);
|
||||||
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
||||||
pending_count -= remove_oldest_pending();
|
pending_count -= removeOldestPending();
|
||||||
node.error(RED._("sort.too-many"), msg);
|
node.error(RED._("sort.too-many"), msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.on("input", function(msg) {
|
this.on("input", function(msg) {
|
||||||
process_msg(msg);
|
processMessage(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on("close", function() {
|
this.on("close", function() {
|
||||||
clear_pending();
|
for(var key in pending) {
|
||||||
})
|
if (pending.hasOwnProperty(key)) {
|
||||||
|
node.log(RED._("sort.clear"), pending[key].msgs[0]);
|
||||||
|
delete pending[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending_count = 0; })
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.nodes.registerType("sort", SortNode);
|
RED.nodes.registerType("sort", SortNode);
|
||||||
|
Loading…
Reference in New Issue
Block a user