From fe109f15d84f3627b3c9867afdedc6de9351941a Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Fri, 20 Dec 2013 10:00:35 +0100 Subject: [PATCH 1/7] added postgres node --- storage/postgres/110-postgresout.html | 148 ++++++++++++++++++++++++++ storage/postgres/110-postgresout.js | 83 +++++++++++++++ storage/postgres/icons/postgres.png | Bin 0 -> 625 bytes 3 files changed, 231 insertions(+) create mode 100644 storage/postgres/110-postgresout.html create mode 100644 storage/postgres/110-postgresout.js create mode 100644 storage/postgres/icons/postgres.png diff --git a/storage/postgres/110-postgresout.html b/storage/postgres/110-postgresout.html new file mode 100644 index 00000000..ab3291cc --- /dev/null +++ b/storage/postgres/110-postgresout.html @@ -0,0 +1,148 @@ + + + + + + + + + + + diff --git a/storage/postgres/110-postgresout.js b/storage/postgres/110-postgresout.js new file mode 100644 index 00000000..bf882b6a --- /dev/null +++ b/storage/postgres/110-postgresout.js @@ -0,0 +1,83 @@ +/** + * Copyright 2013 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +// If you use this as a template, replace IBM Corp. with your own name. + +// Sample Node-RED node file + +// Require main module +var RED = require(process.env.NODE_RED_HOME+"/red/red"); +var pg=require('pg'); +var named=require('node-postgres-named'); + +function PostgresDatabaseNode(n) { + RED.nodes.createNode(this,n); + this.hostname = n.hostname; + this.port = n.port; + this.db = n.db; + this.username = n.username; + this.password = n.password; +} + +RED.nodes.registerType("postgresdb",PostgresDatabaseNode); + +function PostgresNode(n) { + RED.nodes.createNode(this,n); + + this.topic = n.topic; + this.postgresdb = n.postgresdb; + this.postgresConfig = RED.nodes.getNode(this.postgresdb); + this.sqlquery = n.sqlquery; + this.outputs = n.outputs; + + var node = this; + if(this.postgresConfig) + { + + var conString = 'postgres://'+this.postgresConfig.username +':' + this.postgresConfig.password + '@' + this.postgresConfig.hostname + ':' + this.postgresConfig.port + '/' + this.postgresConfig.db; + node.clientdb = new pg.Client(conString); + named.patch(node.clientdb); + + node.clientdb.connect(function(err){ + if(err) { node.error(err); } + else { + node.on('input', + function(msg){ + node.clientdb.query(node.sqlquery, + msg.payload, + function (err, results) { + if(err) { node.error(err); } + else { + if(node.outputs>0) + { + msg.payload = results.rows; + node.send(msg); + } + } + }); + }); + } + }); + } else { + this.error("missing postgres configuration"); + } + + this.on("close", function() { + if(node.clientdb) node.clientdb.end(); + }); +} + +RED.nodes.registerType("postgres",PostgresNode); diff --git a/storage/postgres/icons/postgres.png b/storage/postgres/icons/postgres.png new file mode 100644 index 0000000000000000000000000000000000000000..e46c31696bc4e2240ffe3450323e74c6ae0bbe33 GIT binary patch literal 625 zcmV-%0*?KOP)HWn7*8>A2= zPoR*(#?ID4Ng-Z2`D|v#*^}9G_Q^$X!NAO#%Ubi#|Ib1tYvF+7Tk2bNTU{%hi%RaO z+0u;pmE@e8iN6ygs6-Pu4SWN3*>3`iz|YLz01Lo(U>VqnYtwxb;8(jiL}viLR)SqD z1S78h0gQn!z`a63fA^_p)z^KPtEWoPRNA)M6#TZ38nckHwYMK?4KOY25eQ8(I4au( z9s{?_>Cc9%ou8YeFVsS8^B56MPbce|0o0Y21)zP49ZV{twXZ5lU%F6 zJHXY#;uYZ09EXQYVxc4p3Xj~jvHH0{@5uleslHJ!m#W36qDQlmG~}C8-7M_g)8Q0& z3as_KWBZ|>2c8dv_gehW?Sr&0d(}_s{jC1=-ELH=nfn4h$;NjxSWG^E8l+1-g}qaN z`?N%Xbv4~C#$ue>0`QxNagEwd@_w%dR+aT6nOr8t8`f+T2{!M~)G3zp*z~Z)vf&@w ze-m)ypaJJ4O^qDmNd0h}kP55 Date: Fri, 20 Dec 2013 10:18:22 +0100 Subject: [PATCH 2/7] added examples to node documentation --- storage/postgres/110-postgresout.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/storage/postgres/110-postgresout.html b/storage/postgres/110-postgresout.html index ab3291cc..4e984f5a 100644 --- a/storage/postgres/110-postgresout.html +++ b/storage/postgres/110-postgresout.html @@ -78,6 +78,16 @@

This node can be used to write and read from a Postgres database

To receive the results from a query, simply set the outputs to 1 and connect a node

The msg.payload on the output will be a json array of the returned records

+

+

Insert exampleb>

+

msg.payload = { 'sensorid': 1, 'value': 2 }

+

insert into table (field1, field2) values ($sensorid, $value)

+ +

+

Select exampleb>

+

msg.payload = { 'sensorid': 1, 'value': 2 }

+

select * from table where field1=$sensorid order by time desc limit 1

+ diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js index bf882b6a..36e02b05 100644 --- a/storage/postgres/110-postgres.js +++ b/storage/postgres/110-postgres.js @@ -1,5 +1,5 @@ /** - * Copyright 2013 IBM Corp. + * Copyright 2013 Kris Daniels. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,6 @@ * limitations under the License. **/ -// If you use this as a template, replace IBM Corp. with your own name. - -// Sample Node-RED node file - -// Require main module var RED = require(process.env.NODE_RED_HOME+"/red/red"); var pg=require('pg'); var named=require('node-postgres-named'); From 43c6bdb95ad71b9f7e691de467e8634e053c4f97 Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Sat, 21 Dec 2013 09:23:46 +0100 Subject: [PATCH 5/7] removed script editor from node config added support for script in msg.payload added support for query parameters in msg.queryParameters --- storage/postgres/110-postgres.html | 83 +++++------------------------- storage/postgres/110-postgres.js | 9 ++-- 2 files changed, 17 insertions(+), 75 deletions(-) diff --git a/storage/postgres/110-postgres.html b/storage/postgres/110-postgres.html index 09a887a8..033cc990 100644 --- a/storage/postgres/110-postgres.html +++ b/storage/postgres/110-postgres.html @@ -60,43 +60,18 @@
- - -
-
-
- - + + +
@@ -107,8 +82,7 @@ limit 1

defaults: { postgresdb: { type:"postgresdb",required:true}, name: {value:""}, - sqlquery: {value:"",required:true}, - outputs: {value:0} + output: {value:false} }, inputs:1, outputs:0, @@ -121,47 +95,14 @@ limit 1

return this.name?"node_label_italic":""; }, oneditprepare: function() { - $( "#node-input-outputs" ).spinner({ - min:0, - max:1 - }); - $( "#node-input-outputs" ).spinner( "value", this.outputs ); + $( "#node-input-output" ).prop( "checked", this.output ); + $("#node-input-name").focus(); - function functionDialogResize(ev,ui) { - $("#node-input-sqlquery-editor").css("height",(ui.size.height-235)+"px"); - }; - - $( "#dialog" ).on("dialogresize", functionDialogResize); - $( "#dialog" ).one("dialogopen", function(ev) { - var size = $( "#dialog" ).dialog('option','sizeCache-function'); - if (size) { - functionDialogResize(null,{size:size}); - } - }); - $( "#dialog" ).one("dialogclose", function(ev,ui) { - var height = $( "#dialog" ).dialog('option','height'); - $( "#dialog" ).off("dialogresize",functionDialogResize); - }); - var that = this; - require(["orion/editor/edit"], function(edit) { - that.editor = edit({ - parent:document.getElementById('node-input-sqlquery-editor'), - lang:"sql", - contents: $("#node-input-sqlquery").val() - }); - RED.library.create({ - url:"storage", // where to get the data from - type:"postgres", // the type of object the library is for - editor:that.editor, // the field name the main text body goes to - fields:['name','outputs'] - }); - $("#node-input-name").focus(); - - }); }, oneditsave: function() { - $("#node-input-sqlquery").val(this.editor.getText()) + var hasOutput = $( "#node-input-output" ).prop( "checked" ); + this.outputs = hasOutput ? 1: 0; delete this.editor; } }); diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js index 36e02b05..edd42c88 100644 --- a/storage/postgres/110-postgres.js +++ b/storage/postgres/110-postgres.js @@ -36,7 +36,7 @@ function PostgresNode(n) { this.postgresdb = n.postgresdb; this.postgresConfig = RED.nodes.getNode(this.postgresdb); this.sqlquery = n.sqlquery; - this.outputs = n.outputs; + this.output = n.output; var node = this; if(this.postgresConfig) @@ -51,12 +51,13 @@ function PostgresNode(n) { else { node.on('input', function(msg){ - node.clientdb.query(node.sqlquery, - msg.payload, + if(!msg.queryParameters) msg.queryParameters={}; + node.clientdb.query(msg.payload, + msg.queryParameters, function (err, results) { if(err) { node.error(err); } else { - if(node.outputs>0) + if(node.output) { msg.payload = results.rows; node.send(msg); From 497f08bba93a001872ffa01907fac99d3adbccfb Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Sat, 21 Dec 2013 11:01:19 +0100 Subject: [PATCH 6/7] moved credtials from config to credential store --- storage/postgres/110-postgres.html | 47 ++++++++++++++++++++++++---- storage/postgres/110-postgres.js | 50 ++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/storage/postgres/110-postgres.html b/storage/postgres/110-postgres.html index 033cc990..a4ea5e57 100644 --- a/storage/postgres/110-postgres.html +++ b/storage/postgres/110-postgres.html @@ -27,7 +27,7 @@
- +
@@ -40,12 +40,46 @@ defaults: { hostname: { value:"localhost",required:true}, port: { value: 5432,required:true}, - db: { value:"postgres",required:true}, - username: { value:"postgres", required:true }, - password: { value:"postgres", required:true } + db: { value:"postgres",required:true} }, label: function() { return this.name||this.hostname+":"+this.port+"/"+this.db; + }, + oneditprepare: function() { + + $.getJSON('postgresdb/'+this.id,function(data) { + if (data.user) { + $('#node-config-input-user').val(data.user); + } + if (data.hasPassword) { + $('#node-config-input-password').val('__PWRD__'); + } else { + $('#node-config-input-password').val(''); + } + }); + }, + oneditsave: function() { + + var newUser = $('#node-config-input-user').val(); + var newPass = $('#node-config-input-password').val(); + var credentials = {}; + credentials.user = newUser; + if (newPass != '__PWRD__') { + credentials.password = newPass; + } + $.ajax({ + url: 'postgresdb/'+this.id, + type: 'POST', + data: credentials, + success:function(result){} + }); + }, + ondelete: function() { + $.ajax({ + url: 'postgresdb/'+this.id, + type: 'DELETE', + success: function(result) {} + }); } }); @@ -98,12 +132,13 @@ $( "#node-input-output" ).prop( "checked", this.output ); $("#node-input-name").focus(); - + }, oneditsave: function() { + var hasOutput = $( "#node-input-output" ).prop( "checked" ); this.outputs = hasOutput ? 1: 0; - delete this.editor; + } }); diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js index edd42c88..4e2d41ee 100644 --- a/storage/postgres/110-postgres.js +++ b/storage/postgres/110-postgres.js @@ -17,14 +17,57 @@ var RED = require(process.env.NODE_RED_HOME+"/red/red"); var pg=require('pg'); var named=require('node-postgres-named'); +var querystring = require('querystring'); + +RED.app.get('/postgresdb/:id',function(req,res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")})); + } else { + res.send(JSON.stringify({})); + } +}); + +RED.app.delete('/postgresdb/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.post('/postgresdb/:id',function(req,res) { + var body = ""; + req.on('data', function(chunk) { + body+=chunk; + }); + req.on('end', function(){ + var newCreds = querystring.parse(body); + var credentials = RED.nodes.getCredentials(req.params.id)||{}; + if (newCreds.user == null || newCreds.user == "") { + delete credentials.user; + } else { + credentials.user = newCreds.user; + } + if (newCreds.password == "") { + delete credentials.password; + } else { + credentials.password = newCreds.password||credentials.password; + } + RED.nodes.addCredentials(req.params.id,credentials); + res.send(200); + }); +}); + function PostgresDatabaseNode(n) { RED.nodes.createNode(this,n); this.hostname = n.hostname; this.port = n.port; this.db = n.db; - this.username = n.username; - this.password = n.password; + + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.user = credentials.user; + this.password = credentials.password; + } } RED.nodes.registerType("postgresdb",PostgresDatabaseNode); @@ -39,10 +82,11 @@ function PostgresNode(n) { this.output = n.output; var node = this; + if(this.postgresConfig) { - var conString = 'postgres://'+this.postgresConfig.username +':' + this.postgresConfig.password + '@' + this.postgresConfig.hostname + ':' + this.postgresConfig.port + '/' + this.postgresConfig.db; + var conString = 'postgres://'+this.postgresConfig.user +':' + this.postgresConfig.password + '@' + this.postgresConfig.hostname + ':' + this.postgresConfig.port + '/' + this.postgresConfig.db; node.clientdb = new pg.Client(conString); named.patch(node.clientdb); From e72ced85e6f5ec18b8e6c3489a9d565ccba7a934 Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Sat, 21 Dec 2013 16:55:44 +0100 Subject: [PATCH 7/7] fixed bug with outputs not being set correctly after initial load --- storage/postgres/110-postgres.html | 60 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/storage/postgres/110-postgres.html b/storage/postgres/110-postgres.html index a4ea5e57..6fae6ac1 100644 --- a/storage/postgres/110-postgres.html +++ b/storage/postgres/110-postgres.html @@ -111,34 +111,36 @@