Skip to content

Commit 3d5fcf4

Browse files
committed
Initial commit
0 parents  commit 3d5fcf4

File tree

6 files changed

+367
-0
lines changed

6 files changed

+367
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 elmagopy
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
## node-red-contrib-re2-postgres
2+
3+
A [Node-RED](http://nodered.org) node to query [PostgreSQL](http://www.postgresql.org/) based on original node by Kris Daniels and modified by Max Boar.
4+
This node clearly replaces original node to be compatible with latest Node-red version 1.0.4.
5+
this branch contains a modification for multiple select.
6+
ej;
7+
select * from table1 ; select * from table2;...
8+
9+
### Install
10+
11+
Run the following command in the root directory of your Node-RED install
12+
13+
npm install node-red-contrib-re2-postgres
14+
15+
The node-red postgres node uses a template node to set the query and uses msg.queryParameters as params for the query.
16+
Each property in msg.queryParameters can be used as $propertyName in the query, see the 'setup params' and 'format query' node in the example.
17+
The msg it then passed to the postgres node.
18+
If you want the output of the query, check the 'Receive output' box in the postgres node.
19+
If you want the output of the query been sent by row, check the 'One message per row' box in the postgres node.
20+
The result of the query is then set on the msg.payload property which can be sent to a http node.
21+
22+
### Changes
23+
24+
- Added compatibility with pg@7.
25+
- Added support for multiple rows per message when splitting resultset (test output before deploying existing sets).
26+
27+
### Example DB
28+
29+
CREATE TABLE public.table1
30+
(
31+
field1 character varying,
32+
field2 integer
33+
)
34+
WITH (
35+
OIDS=FALSE
36+
);
37+
ALTER TABLE public.table1
38+
OWNER TO postgres;
39+
40+
INSERT INTO public.table1(
41+
field1, field2)
42+
VALUES ('row1',1);
43+
INSERT INTO public.table1(
44+
field1, field2)
45+
VALUES ('row2',2);
46+
47+
### Example node-red flow
48+
49+
Import the flow below in an empty sheet in nodered
50+
51+
[{"id":"168f2030.e970e","type":"postgresdb","z":"d1b19967.2e4e68","hostname":"localhost","port":"5432","db":"postgres"},{"id":"37e19274.c81e6e","type":"inject","z":"d1b19967.2e4e68","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"00 12 * * *","once":false,"x":135,"y":78,"wires":[["ec61e7da.139e18"]]},{"id":"3bffa50b.c4005a","type":"template","z":"d1b19967.2e4e68","name":"format query","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"select * from table1 where field2 > $param1","x":528,"y":76,"wires":[["e3ff7e9.f1c008"]]},{"id":"e3ff7e9.f1c008","type":"postgres","z":"d1b19967.2e4e68","postgresdb":"168f2030.e970e","name":"","output":true,"outputs":1,"x":695,"y":72,"wires":[["9e662745.6199d8","208d526c.df72ae"]]},{"id":"9e662745.6199d8","type":"debug","z":"d1b19967.2e4e68","name":"query output","active":false,"console":"false","complete":"true","x":877,"y":198,"wires":[]},{"id":"208d526c.df72ae","type":"http request","z":"d1b19967.2e4e68","name":"","method":"POST","ret":"txt","url":"http://localhost:1880/incoming_data","x":1009,"y":79,"wires":[["e48e88e6.1b7178"]]},{"id":"e48e88e6.1b7178","type":"debug","z":"d1b19967.2e4e68","name":"http result","active":false,"console":"false","complete":"payload","x":1192,"y":79,"wires":[]},{"id":"ec61e7da.139e18","type":"function","z":"d1b19967.2e4e68","name":"setup params","func":"msg.queryParameters = msg.queryParameters || {};\nmsg.queryParameters.param1 = 1;\nreturn msg;","outputs":1,"noerr":0,"x":328,"y":74,"wires":[["3bffa50b.c4005a"]]},{"id":"f7a7d4a7.085828","type":"http in","z":"d1b19967.2e4e68","name":"","url":"/incoming_data","method":"post","swaggerDoc":"","x":231,"y":494,"wires":[["7b5aa85e.84a558","ac9432ad.536bd"]]},{"id":"687b82be.97847c","type":"http response","z":"d1b19967.2e4e68","name":"","x":835,"y":510,"wires":[]},{"id":"7b5aa85e.84a558","type":"debug","z":"d1b19967.2e4e68","name":"http input","active":false,"console":"false","complete":"payload","x":450,"y":602,"wires":[]},{"id":"ac9432ad.536bd","type":"function","z":"d1b19967.2e4e68","name":"reply to http call","func":"msg.payload='reply from http';\nreturn msg;","outputs":1,"noerr":0,"x":599,"y":444,"wires":[["687b82be.97847c"]]}]

lib/icons/postgres.png

582 Bytes
Loading

lib/pg.html

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<!--
2+
Copyright 2013 Kris Daniels.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
17+
<script type="text/x-red" data-template-name="postgresdb">
18+
<div class="form-row">
19+
<label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> Host</label>
20+
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
21+
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
22+
<input type="text" id="node-config-input-port" placeholder="5432" style="width:45px">
23+
</div>
24+
<div class="form-row">
25+
<label for="node-config-input-db"><i class="fa fa-briefcase"></i> Database</label>
26+
<input type="text" id="node-config-input-db" placeholder="test">
27+
</div>
28+
<div class="form-row">
29+
<label for="node-config-input-name"><i class="fa fa-user"></i> Username</label>
30+
<input type="text" id="node-config-input-user" placeholder="postgres">
31+
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
32+
<input type="password" id="node-config-input-password" placeholder="postgres">
33+
</div>
34+
<div class="form-row">
35+
<label>&nbsp;</label>
36+
<input type="checkbox" id="node-config-input-ssl" style="display: inline-block; width: auto; vertical-align: top;">
37+
<label for="node-config-input-ssl" style="width: 70%;">Use SSL</label>
38+
</div>
39+
</script>
40+
41+
<script type="text/javascript">
42+
RED.nodes.registerType('postgresdb',{
43+
category: 'config',
44+
color:"rgb(218, 196, 180)",
45+
defaults: {
46+
hostname: { value:"localhost",required:true},
47+
port: { value: 5432,required:true},
48+
db: { value:"postgres",required:true},
49+
ssl: { value:false }
50+
},
51+
credentials: {
52+
user: {type: "text"},
53+
password: {type: "password"}
54+
},
55+
label: function() {
56+
return this.name||this.hostname+":"+this.port+"/"+this.db;
57+
}
58+
});
59+
</script>
60+
61+
<script type="text/x-red" data-template-name="postgres">
62+
<div class="form-row">
63+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
64+
<input type="text" id="node-input-name" placeholder="Name">
65+
</div>
66+
<div class="form-row">
67+
<label for="node-input-postgresdb"><i class="fa fa-tag"></i> Server</label>
68+
<input type="text" id="node-input-postgresdb">
69+
</div>
70+
<div class="form-row">
71+
<label>&nbsp;</label>
72+
<input type="checkbox" id="node-input-output" placeholder="once" style="display: inline-block; width: auto; vertical-align: top;">
73+
<label for="node-input-output" style="width: 70%;">Receive query output ?</label>
74+
</div>
75+
<div class="form-row">
76+
<label>&nbsp;</label>
77+
<input type="checkbox" id="node-input-perrow" placeholder="once" style="display: inline-block; width: auto; vertical-align: top;">
78+
<label for="node-input-perrow" style="width: 70%;">Split resultset. </label>
79+
<label for="node-input-rowspermsg" style="margin-left: 40%; ">Rows per msg</label>
80+
<input type="text" id="node-input-rowspermsg" placeholder="1" style="width:45px" value="1" />
81+
</div>
82+
</script>
83+
84+
<script type="text/x-red" data-help-name="postgres">
85+
<p>A PostgreSql I/O node based on original node by Kris Daniels. </p>
86+
<p>Executes the query specified in msg.payload with optional query parameters in msg.queryParameters</p>
87+
<p>The queryParameters in the query must be specified as $propertyname</p>
88+
<p>See the node-postgres-named package for more info</p>
89+
<p>When receiving data from the query, the msg.payload on the output will be a json array of the returned records</p>
90+
91+
</script>
92+
93+
<script type="text/javascript">
94+
RED.nodes.registerType('postgres',{
95+
category: 'storage-output',
96+
color:"rgb(148, 226, 252)",
97+
defaults: {
98+
postgresdb: { type:"postgresdb",required:true},
99+
name: {value:""},
100+
output: {value:false},
101+
perrow: {value:false},
102+
rowspermsg: { value:1, validate:(v)=>(v >= 1) },
103+
outputs: {value:0}
104+
},
105+
inputs: 1,
106+
outputs: 0,
107+
icon: "postgres.png",
108+
align: "right",
109+
label: function() {
110+
return this.name||(this.sqlquery?this.sqlquery:"postgres");
111+
},
112+
labelStyle: function() {
113+
return this.name?"node_label_italic":"";
114+
},
115+
oneditprepare: function() {
116+
117+
$( "#node-input-output" ).prop( "checked", this.output );
118+
$( "#node-input-perrow" ).prop( "checked", this.perrow );
119+
$( "#node-input-rowspermsg" ).spinner({
120+
min:1
121+
});
122+
$( "#node-input-rowspermsg" ).value=this.rowspermsg;
123+
$("#node-input-name").focus();
124+
125+
},
126+
oneditsave: function() {
127+
128+
var hasOutput = $( "#node-input-output" ).prop( "checked" );
129+
this.outputs = hasOutput ? 1:0;
130+
var perRow = $( "#node-input-perrow" ).prop( "checked" );
131+
this.perrow = perRow;
132+
var rowspermsg = $( "#node-input-rowspermsg" ).value;
133+
this.rowspermsg = rowspermsg;
134+
}
135+
});
136+
137+
</script>

lib/pg.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
var pg = require('pg');
2+
var named = require('node-postgres-named');
3+
var Cursor = require('pg-cursor');
4+
var temp =[];
5+
module.exports=function(RED){
6+
7+
function PostgresDatabaseNode(n) {
8+
RED.nodes.createNode(this, n);
9+
this.hostname = n.hostname;
10+
this.port = n.port;
11+
this.db = n.db;
12+
this.ssl = n.ssl;
13+
14+
var credentials = this.credentials;
15+
if (credentials) {
16+
this.user = credentials.user;
17+
this.password = credentials.password;
18+
}
19+
}
20+
21+
RED.nodes.registerType("postgresdb", PostgresDatabaseNode, {
22+
credentials: {
23+
user: {type: "text"},
24+
password: {type: "password"}
25+
}
26+
});
27+
28+
29+
function PostgresNode(n) {
30+
RED.nodes.createNode(this, n);
31+
32+
var node = this;
33+
34+
node.topic = n.topic;
35+
node.postgresdb = n.postgresdb;
36+
node.postgresConfig = RED.nodes.getNode(this.postgresdb);
37+
node.sqlquery = n.sqlquery;
38+
node.output = n.output;
39+
node.perrow = n.perrow;
40+
node.rowspermsg = n.rowspermsg;
41+
42+
if (node.postgresConfig) {
43+
44+
var connectionConfig = {
45+
user: node.postgresConfig.user,
46+
password: node.postgresConfig.password,
47+
host: node.postgresConfig.hostname,
48+
port: node.postgresConfig.port,
49+
database: node.postgresConfig.db,
50+
ssl: node.postgresConfig.ssl
51+
};
52+
node.pgpool=new pg.Pool(connectionConfig);
53+
54+
var handleError = function(err, msg) {
55+
msg.error=err;
56+
node.error(err,msg);
57+
console.log(err);
58+
console.log(msg.payload);
59+
console.log(msg.queryParameters);
60+
};
61+
62+
node.on('input', function(msg) {
63+
node.pgpool.connect((err, client, done)=>{
64+
if (err) {
65+
handleError(err, msg);
66+
} else {
67+
named.patch(client);
68+
69+
if (!!!msg.queryParameters)
70+
msg.queryParameters = [];
71+
72+
if (!node.perrow){
73+
var q=client.query(
74+
msg.payload,
75+
msg.queryParameters,
76+
function(err, results) {
77+
done();
78+
if (err) {
79+
handleError(err, msg);
80+
} else {
81+
if (node.output && !node.perrow) {
82+
if (!results.length){
83+
msg.payload=results.rows;
84+
node.send(msg);
85+
temp=[];
86+
}else{
87+
for(i=0;i<results.length;i++){
88+
for(j=0;j<results[i].rows.length;j++){
89+
if(results[i].rows[j]!=null){
90+
temp.push(results[i].rows[j]);
91+
}
92+
}
93+
}
94+
msg.payload=temp;
95+
temp=[];
96+
node.send(msg);
97+
}
98+
}
99+
}
100+
}
101+
102+
);
103+
}
104+
else {
105+
var cur=client.query(new Cursor(msg.payload,msg.queryParameters));
106+
var sndrow=(err,rows)=>{
107+
if (!!err) {
108+
handleError(err,msg);
109+
done();
110+
}
111+
else {
112+
if (rows.length>0){
113+
node.send(Object.assign(Object.assign({},msg),{payload:((node.rowspermsg||1)>1)?rows:rows[0]}));
114+
cur.read(node.rowspermsg||1,sndrow);
115+
}
116+
else done();
117+
}
118+
}
119+
cur.read(node.rowspermsg||1,sndrow);
120+
}
121+
}
122+
});
123+
});
124+
} else {
125+
this.error("missing postgres configuration");
126+
}
127+
128+
this.on("close", function() {
129+
if (node.clientdb) node.clientdb.end();
130+
});
131+
}
132+
133+
RED.nodes.registerType("postgres", PostgresNode);
134+
}

package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "node-red-contrib-re2-postgres",
3+
"version": "0.0.1",
4+
"description": "A Node-RED node to query PostgreSQL based on original node by Kris Daniels and modified by Max Boar. This node clearly replaces original node to be compatible with latest Node-red versions.",
5+
"main": "pg.js",
6+
"scripts": {
7+
"test": "node pg.js"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/elmagopy/node-red-contrib-re2-postgres.git"
12+
},
13+
"keywords": [
14+
"node",
15+
"red",
16+
"postgres"
17+
],
18+
"author": "Cristian Helge Hansen Schupmann",
19+
"license": "MIT",
20+
"bugs": {
21+
"url": "https://github.com/elmagopy/node-red-contrib-re2-postgres/issues"
22+
},
23+
"homepage": "https://github.com/elmagopy/node-red-contrib-re2-postgres#readme"
24+
}

0 commit comments

Comments
 (0)