Update split node docs

This commit is contained in:
Nick O'Leary 2016-06-10 22:51:57 +01:00
parent 8f8df4971c
commit d82fe95076
3 changed files with 72 additions and 86 deletions

View File

@ -34,6 +34,18 @@
<li><b>array</b> - a message is sent for each element of the array</li>
<li><b>object</b> - a message is sent for each key/value pair of the object. <code>msg.parts.key</code> is set to the key of the property.</li>
</ul>
<p>Each message is sent with the <code>msg.parts</code> property set. This is
an object that provides any subsequent <i>join</i> node the necessary information
for it to reassemble the messages back into a single one. The object has the following
properties:</p>
<ul>
<li><b>id</b> - an identifier for the group of messages</li>
<li><b>index</b> - the position within the group</li>
<li><b>count</b> - the total number of messages in the group</li>
<li><b>type</b> - the type of message - string/array/object</li>
<li><b>ch</b> - for a string, the character used to split</li>
<li><b>key</b> - for an object, the key of the property this message was created from</li>
</ul>
</script>
<script type="text/javascript">
@ -67,7 +79,7 @@
</div>
<div class="node-row-custom">
<div class="form-row node-row-property">
<label>Join each </label>
<label>Combine each </label>
<input type="text" id="node-input-property" style="width:300px;">
<input type="hidden" id="node-input-propertyType">
</div>
@ -113,17 +125,30 @@
</script>
<script type="text/x-red" data-help-name="join">
<p>A function that joins <code>msg.payload</code> from multiple msgs to create a single msg out.</p>
<p>Other properties of the msg are not guaranteed as they could come from any of the incoming msgs.</p>
<p>An optional <i>count</i> can be set that waits for that many <code>payload</code> to arrive before passing on the new message.</p>
<p>An optional <i>timeout</i> can be set that can then send the incomplete message, drop the message or raise a catchable error.</p>
<p>An optional <i>join character</i> can be set that can be used for joining multiple payloads together and returns a
string rather than an array.</p>
<p>When used with a <b>split</b> node the <i>count</i> and <i>join character</i> are automatically set - but can be
overridden by values in the configuration.</p>
<p>Messages can be joined into an <i>array</i> or <i>object</i>. To be joined into an object the incoming message must
have either a <code>msg.key</code> or <code>msg.topic</code> property - or <code>msg.payload</code> should
be an object with properties.</p>
<p>A function that joins the a sequence of messages into a single message.</p>
<p>When paired with the <b>split</b> node, it will automatically join the messages
to reverse the split that was performed.</p>
<p>It can be used without the split node by configuring the required behaviour.</p>
<p>The type of the resulting message property can be a string, array or object. All of the other message
properties are taken from the last message received before the message is sent.</p>
<p>A <i>count</i> can be set for how many messages should be received before generating the output message</p>
<p>A <i>timeout</i> can be set to trigger sending the new message using whatever has been received so far.</p>
<p>If the node is set to construct a string, a <i>join character</i> can be set.</p>
<p>If the node is set to construct an object, the key used to store each received property can be taken from
an identified message property.</p>
<p>The automatic behaviour relies on the received messages to have <b>msg.parts</b> set.
The object has the following properties:</p>
<ul>
<li><b>id</b> - an identifier for the group of messages</li>
<li><b>index</b> - the position within the group</li>
<li><b>count</b> - the total number of messages in the group</li>
<li><b>type</b> - the type of message - string/array/object</li>
<li><b>ch</b> - for a string, the character used to split</li>
<li><b>key</b> - for an object, the key of the property this message was created from</li>
</ul>
</script>
<script type="text/javascript">
@ -174,7 +199,7 @@
types:['msg', {value:"full",label:"complete message",hasValue:false}]
})
$("#node-input-key").typedInput({
types:['msg']
types:['msg', {value:"merge",label:"",hasValue: false}]
})
$("#node-input-build").change();

View File

@ -38,7 +38,7 @@ module.exports = function(RED) {
msg.payload = a[i];
msg.parts.index = i;
msg.parts.count = a.length;
node.send(msg);
node.send(RED.util.cloneMessage(msg));
}
}
else if ((typeof msg.payload === "object") && !Buffer.isBuffer(msg.payload)) {
@ -52,7 +52,7 @@ module.exports = function(RED) {
msg.parts.key = p;
msg.parts.index = j;
msg.parts.count = l;
node.send(msg);
node.send(RED.util.cloneMessage(msg));
j += 1;
}
}
@ -70,8 +70,11 @@ module.exports = function(RED) {
this.mode = n.mode||"auto";
this.property = n.property||"payload";
this.propertyType = n.propertyType||"msg";
if (this.propertyType === 'full') {
this.property = "payload";
}
this.key = n.key||"topic";
this.timer = (this.mode === "auto") ? 0 : Number(n.timeout || 0);
this.timer = (this.mode === "auto") ? 0 : Number(n.timeout || 0)*1000;
this.timerr = n.timerr || "send";
this.count = Number(n.count || 0);
this.joiner = (n.joiner||"").replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\e/g,"\e").replace(/\\f/g,"\f").replace(/\\0/g,"\0");
@ -85,9 +88,9 @@ module.exports = function(RED) {
delete inflight[partId];
if (group.type === 'string') {
group.msg.payload = group.payload.join(group.joinChar);
RED.util.setMessageProperty(group.msg,node.property,group.payload.join(group.joinChar));
} else {
group.msg.payload = group.payload;
RED.util.setMessageProperty(group.msg,node.property,group.payload);
}
if (group.msg.hasOwnProperty('parts') && group.msg.parts.hasOwnProperty('parts')) {
group.msg.parts = group.msg.parts;
@ -101,7 +104,7 @@ module.exports = function(RED) {
try {
var property;
if (node.mode === 'auto' && (!msg.hasOwnProperty("parts")||!msg.parts.hasOwnProperty("id"))) {
// TODO: log warning - no msg.parts in auto mode, ignoring
node.warn("Message missing msg.parts property - cannot join in 'auto' mode")
return;
}
if (node.propertyType == "full") {
@ -143,7 +146,11 @@ try {
}
}
if (payloadType === 'object' && (propertyKey === null || propertyKey === undefined || propertyKey === "")) {
//TODO: log error - no key property found for object
if (node.mode === "auto") {
node.warn("Message missing 'msg.parts.key' property - cannot add to object");
} else {
node.warn("Message missing key property 'msg."+node.key+"' '- cannot add to object")
}
return;
}
if (!inflight.hasOwnProperty(partId)) {

View File

@ -58,7 +58,7 @@ describe('SPLIT node', function() {
});
});
it('should split a string into characters', function(done) {
it('should split a string into new-lines', function(done) {
var flow = [{id:"sn1", type:"split", wires:[["sn2"]]},
{id:"sn2", type:"helper"}];
helper.load(splitNode, flow, function() {
@ -74,7 +74,7 @@ describe('SPLIT node', function() {
if (msg.parts.index === 2) { msg.payload.should.equal("v"); }
if (msg.parts.index === 3) { msg.payload.should.equal("e"); done(); }
});
sn1.receive({payload:"Dave"});
sn1.receive({payload:"D\na\nv\ne"});
});
});
@ -146,7 +146,7 @@ describe('JOIN node', function() {
});
it('should join things into an array after a count', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], count:3, joiner:","},
var flow = [{id:"n1", type:"join", wires:[["n2"]], count:3, joiner:",",mode:"custom"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@ -160,7 +160,7 @@ describe('JOIN node', function() {
//msg.payload[2].a.should.equal(1);
done();
}
catch(e) { }//console.log(e); }
catch(e) {done(e);}
});
n1.receive({payload:1});
n1.receive({payload:true});
@ -169,7 +169,7 @@ describe('JOIN node', function() {
});
it('should join things into an object after a count', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], count:5, build:"object"},
var flow = [{id:"n1", type:"join", wires:[["n2"]], count:5, build:"object",mode:"custom"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@ -186,7 +186,7 @@ describe('JOIN node', function() {
msg.payload.g.should.have.property("f",6);
done();
}
catch(e) { }//console.log(e); }
catch(e) { done(e)}
});
n1.receive({payload:1, topic:"a"});
n1.receive({payload:"2", topic:"b"});
@ -198,7 +198,7 @@ describe('JOIN node', function() {
});
it('should join strings with a specifed character after a timeout', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:50, count:10, joiner:","},
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"string", timeout:0.05, count:10, joiner:",",mode:"custom"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@ -209,7 +209,7 @@ describe('JOIN node', function() {
msg.payload.should.equal("a,b,c");
done();
}
catch(e) { console.log(e); }
catch(e) { done(e) }
});
n1.receive({payload:"a"});
n1.receive({payload:"b"});
@ -218,7 +218,7 @@ describe('JOIN node', function() {
});
it('should join strings with a specifed character and complete when told to', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:5000, count:100, joiner:"\n"},
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"string", timeout:5, count:100, joiner:"\n",mode:"custom"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@ -229,7 +229,7 @@ describe('JOIN node', function() {
msg.payload.should.equal("Hello\nNodeRED\nWorld\n");
done();
}
catch(e) { console.log(e); }
catch(e) { done(e) }
});
n1.receive({payload:"Hello"});
n1.receive({payload:"NodeRED"});
@ -254,7 +254,7 @@ describe('JOIN node', function() {
msg.payload[3].should.equal(4);
done();
}
catch(e) { console.log(e); }
catch(e) { done(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:111}});
n1.receive({payload:2, parts:{index:1, count:4, id:111}});
@ -278,7 +278,7 @@ describe('JOIN node', function() {
msg.payload.should.have.property("d",4);
done();
}
catch(e) { console.log(e); }
catch(e) { done(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:222, key:"c", type:"object"}});
n1.receive({payload:2, parts:{index:1, count:4, id:222, key:"b", type:"object"}});
@ -287,31 +287,8 @@ describe('JOIN node', function() {
});
});
it.skip('should join split things, missing some after a timeout', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:50},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
(msg.payload[0] === undefined).should.be.true;
msg.payload[1].should.equal(2);
msg.payload[2].should.equal(3);
(msg.payload[3] === undefined).should.be.true;
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:333}});
n1.receive({payload:2, parts:{index:1, count:4, id:333}});
});
});
it('should join split things, send when told complete', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:250},
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:0.250},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@ -326,7 +303,7 @@ describe('JOIN node', function() {
msg.payload[3].should.equal(4);
done();
}
catch(e) { console.log(e); }
catch(e) { done(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:444} });
n1.receive({payload:2, parts:{index:1, count:4, id:444} });
@ -335,7 +312,7 @@ describe('JOIN node', function() {
});
it('should join split strings back into a word', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]]},
var flow = [{id:"n1", type:"join", mode:"auto", wires:[["n2"]]},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@ -347,35 +324,12 @@ describe('JOIN node', function() {
msg.payload.should.equal("abcd");
done();
}
catch(e) { console.log(e); }
catch(e) { done(e); }
});
n1.receive({payload:"a", parts:{index:0, count:4, ch:"", id:555}});
n1.receive({payload:"d", parts:{index:3, count:4, ch:"", id:555}});
n1.receive({payload:"c", parts:{index:2, count:4, ch:"", id:555}});
n1.receive({payload:"b", parts:{index:1, count:4, ch:"", id:555}});
n1.receive({payload:"a", parts:{type:'string',index:0, count:4, ch:"", id:555}});
n1.receive({payload:"d", parts:{type:'string',index:3, count:4, ch:"", id:555}});
n1.receive({payload:"c", parts:{type:'string',index:2, count:4, ch:"", id:555}});
n1.receive({payload:"b", parts:{type:'string',index:1, count:4, ch:"", id:555}});
});
});
it('should join split strings back overriding the join char', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], joiner:":"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
msg.payload.should.equal("a:b:c:d");
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:"a", parts:{index:0, count:4, ch:"", id:666}});
n1.receive({payload:"d", parts:{index:3, count:4, ch:"", id:666}});
n1.receive({payload:"c", parts:{index:2, count:4, ch:"", id:666}});
n1.receive({payload:"b", parts:{index:1, count:4, ch:"", id:666}});
});
});
});