@@ -19,6 +19,7 @@ module.exports = function(RED) {
19
19
var url = require ( 'url' ) ;
20
20
var querystring = require ( 'querystring' ) ;
21
21
var cfEnv = require ( "cfenv" ) ;
22
+ var Cloudant = require ( "cloudant" ) ;
22
23
23
24
var MAX_ATTEMPTS = 3 ;
24
25
@@ -64,31 +65,23 @@ module.exports = function(RED) {
64
65
} ) ;
65
66
66
67
RED . httpAdmin . post ( '/cloudant/:id' , function ( req , res ) {
67
- var body = "" ;
68
+ var newCreds = req . body ;
69
+ var credentials = RED . nodes . getCredentials ( req . params . id ) || { } ;
68
70
69
- req . on ( 'data' , function ( chunk ) {
70
- body += chunk ;
71
- } ) ;
72
-
73
- req . on ( 'end' , function ( ) {
74
- var newCreds = querystring . parse ( body ) ;
75
- var credentials = RED . nodes . getCredentials ( req . params . id ) || { } ;
76
-
77
- if ( newCreds . user == null || newCreds . user == "" ) {
78
- delete credentials . user ;
79
- } else {
80
- credentials . user = newCreds . user ;
81
- }
71
+ if ( newCreds . user == null || newCreds . user == "" ) {
72
+ delete credentials . user ;
73
+ } else {
74
+ credentials . user = newCreds . user ;
75
+ }
82
76
83
- if ( newCreds . password == "" ) {
84
- delete credentials . password ;
85
- } else {
86
- credentials . password = newCreds . password || credentials . password ;
87
- }
77
+ if ( newCreds . password == "" ) {
78
+ delete credentials . password ;
79
+ } else {
80
+ credentials . password = newCreds . password || credentials . password ;
81
+ }
88
82
89
- RED . nodes . addCredentials ( req . params . id , credentials ) ;
90
- res . send ( 200 ) ;
91
- } ) ;
83
+ RED . nodes . addCredentials ( req . params . id , credentials ) ;
84
+ res . send ( 200 ) ;
92
85
} ) ;
93
86
94
87
//
@@ -124,52 +117,59 @@ module.exports = function(RED) {
124
117
this . operation = n . operation ;
125
118
this . payonly = n . payonly || false ;
126
119
this . database = n . database ;
127
- this . cloudant = n . cloudant ;
128
- this . url = _getUrl ( this , n ) ;
129
-
130
- if ( this . url ) {
131
- var node = this ;
132
-
133
- var nano = require ( 'nano' ) ( this . url ) ;
134
- var db = nano . use ( node . database ) ;
120
+ this . cloudantConfig = RED . nodes . getNode ( n . cloudant ) ;
121
+
122
+ var node = this ;
123
+ var credentials = {
124
+ account : node . cloudantConfig . credentials . user ,
125
+ password : node . cloudantConfig . credentials . password
126
+ } ;
127
+
128
+ Cloudant ( credentials , function ( err , cloudant ) {
129
+ if ( err ) { node . error ( err ) ; }
130
+ else {
131
+ // check if the database exists and create it if it doesn't
132
+ createDatabase ( cloudant , node ) ;
133
+
134
+ node . on ( "input" , function ( msg ) {
135
+ handleMessage ( cloudant , node , msg ) ;
136
+ } ) ;
137
+ }
138
+ } ) ;
135
139
136
- // check if the database exists and create it if it doesn't
137
- nano . db . list ( function ( err , body ) {
140
+ function createDatabase ( cloudant , node ) {
141
+ cloudant . db . list ( function ( err , all_dbs ) {
138
142
if ( err ) { node . error ( err ) ; }
139
143
else {
140
- if ( body && body . indexOf ( node . database ) < 0 ) {
141
- nano . db . create ( node . database , function ( err , body ) {
142
- if ( err ) { node . error ( err ) ; }
143
- } ) ;
144
+ if ( all_dbs && all_dbs . indexOf ( node . database ) < 0 ) {
145
+ cloudant . db . create ( node . database ) ;
144
146
}
145
147
}
146
148
} ) ;
149
+ }
147
150
148
- node . on ( "input" , function ( msg ) {
149
- if ( node . operation === "insert" ) {
150
- var msg = node . payonly ? msg . payload : msg ;
151
- var root = node . payonly ? "payload" : "msg" ;
152
- var doc = parseMessage ( msg , root ) ;
151
+ function handleMessage ( cloudant , node , msg ) {
152
+ if ( node . operation === "insert" ) {
153
+ var msg = node . payonly ? msg . payload : msg ;
154
+ var root = node . payonly ? "payload" : "msg" ;
155
+ var doc = parseMessage ( msg , root ) ;
153
156
154
- insertDocument ( doc , db , MAX_ATTEMPTS , function ( err , body ) {
157
+ insertDocument ( cloudant , node , doc , MAX_ATTEMPTS , function ( err , body ) {
158
+ if ( err ) { node . error ( err ) ; }
159
+ } ) ;
160
+ }
161
+ else if ( node . operation === "delete" ) {
162
+ var doc = parseMessage ( msg . payload || msg , "" ) ;
163
+
164
+ if ( "_rev" in doc && "_id" in doc ) {
165
+ var db = cloudant . use ( node . database ) ;
166
+ db . destroy ( doc . _id , doc . _rev , function ( err , body ) {
155
167
if ( err ) { node . error ( err ) ; }
156
168
} ) ;
169
+ } else {
170
+ node . error ( "_rev and _id are required to delete a document" ) ;
157
171
}
158
- else if ( node . operation === "delete" ) {
159
- var doc = parseMessage ( msg . payload || msg , "" ) ;
160
-
161
- if ( "_rev" in doc && "_id" in doc ) {
162
- db . destroy ( doc . _id , doc . _rev , function ( err , body ) {
163
- if ( err ) { node . error ( err ) ; }
164
- } ) ;
165
- } else {
166
- node . error ( "_rev and _id are required to delete a document" ) ;
167
- }
168
- }
169
- } ) ;
170
-
171
- } else {
172
- this . error ( "missing cloudant configuration" ) ;
172
+ }
173
173
}
174
174
175
175
function parseMessage ( msg , root ) {
@@ -194,12 +194,13 @@ module.exports = function(RED) {
194
194
// beforehand. If the database doesn't exist, it will create one
195
195
// with the name specified in +db+. To prevent loops, it only tries
196
196
// +attempts+ number of times.
197
- function insertDocument ( doc , db , attempts , callback ) {
197
+ function insertDocument ( cloudant , node , doc , attempts , callback ) {
198
+ var db = cloudant . use ( node . database ) ;
198
199
db . insert ( doc , function ( err , body ) {
199
200
if ( err && err . status_code === 404 && attempts > 0 ) {
200
201
// status_code 404 means the database was not found
201
- return nano . db . create ( db . config . db , function ( ) {
202
- insertDocument ( doc , db , attempts - 1 , callback ) ;
202
+ return cloudant . db . create ( db . config . db , function ( ) {
203
+ insertDocument ( cloudant , node , doc , attempts - 1 , callback ) ;
203
204
} ) ;
204
205
}
205
206
@@ -212,60 +213,116 @@ module.exports = function(RED) {
212
213
function CloudantInNode ( n ) {
213
214
RED . nodes . createNode ( this , n ) ;
214
215
215
- this . cloudant = n . cloudant ;
216
- this . url = _getUrl ( this , n ) ;
217
- this . database = n . database ;
218
- this . search = n . search ;
219
- this . design = n . design ;
220
- this . index = n . index ;
221
- this . payloadIn = "" ;
222
-
223
- if ( this . url ) {
224
- var node = this ;
216
+ this . cloudantConfig = RED . nodes . getNode ( n . cloudant ) ;
217
+ this . database = n . database ;
218
+ this . search = n . search ;
219
+ this . design = n . design ;
220
+ this . index = n . index ;
221
+ this . inputId = "" ;
222
+
223
+ var node = this ;
224
+ var credentials = {
225
+ account : node . cloudantConfig . credentials . user ,
226
+ password : node . cloudantConfig . credentials . password
227
+ } ;
228
+
229
+ Cloudant ( credentials , function ( err , cloudant ) {
230
+ if ( err ) { node . error ( err ) ; }
231
+ else {
232
+ node . on ( "input" , function ( msg ) {
233
+ var db = cloudant . use ( node . database ) ;
234
+ var options = ( typeof msg . payload === "object" ) ? msg . payload : { } ;
235
+
236
+ if ( node . search === "_id_" ) {
237
+ var id = getDocumentId ( msg . payload ) ;
238
+ node . inputId = id ;
239
+
240
+ db . get ( id , function ( err , body ) {
241
+ sendDocumentOnPayload ( err , body , msg ) ;
242
+ } ) ;
243
+ }
244
+ else if ( node . search === "_idx_" ) {
245
+ options . query = options . query || options . q || formatSearchQuery ( msg . payload ) ;
246
+ options . include_docs = options . include_docs || true ;
247
+ options . limit = options . limit || 200 ;
225
248
226
- var nano = require ( 'nano' ) ( node . url ) ;
227
- var db = nano . use ( node . database ) ;
249
+ db . search ( node . design , node . index , options , function ( err , body ) {
250
+ sendDocumentOnPayload ( err , body , msg ) ;
251
+ } ) ;
252
+ }
253
+ else if ( node . search === "_all_" ) {
254
+ options . include_docs = options . include_docs || true ;
228
255
229
- node . on ( "input" , function ( msg ) {
230
- node . payloadIn = msg . payload ;
256
+ db . list ( options , function ( err , body ) {
257
+ sendDocumentOnPayload ( err , body , msg ) ;
258
+ } ) ;
259
+ }
260
+ } ) ;
261
+ }
262
+ } ) ;
231
263
232
- if ( node . search === "_id_" ) {
233
- var id = msg . payload ;
234
- db . get ( id , function ( err , body ) {
235
- sendDocumentOnPayload ( err , body , msg ) ;
236
- } ) ;
264
+ function getDocumentId ( payload ) {
265
+ if ( typeof payload === "object" ) {
266
+ if ( "_id" in payload || "id" in payload ) {
267
+ return payload . id || payload . _id ;
237
268
}
238
- else if ( node . search === "_idx_" ) {
239
- var query = { q : msg . payload , limit : 200 } ;
240
- db . search ( node . design , node . index , query , function ( err , body ) {
241
- sendDocumentOnPayload ( err , body , msg ) ;
242
- } ) ;
269
+ }
270
+
271
+ return payload ;
272
+ }
273
+
274
+ function formatSearchQuery ( query ) {
275
+ if ( typeof query === "object" ) {
276
+ // useful when passing the query on HTTP params
277
+ if ( "q" in query ) { return query . q ; }
278
+
279
+ var queryString = "" ;
280
+ for ( var key in query ) {
281
+ queryString += key + ":" + query [ key ] + " " ;
243
282
}
244
- } ) ;
283
+
284
+ return queryString . trim ( ) ;
285
+ }
286
+ return query ;
245
287
}
246
288
247
289
function sendDocumentOnPayload ( err , body , msg ) {
248
290
if ( ! err ) {
249
- msg . payload = body ;
250
- } else {
291
+ msg . cloudant = body ;
292
+
293
+ if ( "rows" in body ) {
294
+ msg . payload = body . rows .
295
+ map ( function ( el ) {
296
+ if ( el . doc . _id . indexOf ( "_design/" ) < 0 ) {
297
+ return el . doc ;
298
+ }
299
+ } ) .
300
+ filter ( function ( el ) {
301
+ return el !== null && el !== undefined ;
302
+ } ) ;
303
+ } else {
304
+ msg . payload = body ;
305
+ }
306
+ }
307
+ else {
251
308
msg . payload = null ;
252
309
253
310
if ( err . description === "missing" ) {
254
- node . warn ( "Document '" + node . payloadIn + "' not found in database '" +
311
+ node . warn ( "Document '" + node . inputId + "' not found in database '" +
255
312
node . database + "'." ) ;
256
313
} else {
257
314
node . error ( err . reason ) ;
258
315
}
259
316
}
260
-
317
+
261
318
node . send ( msg ) ;
262
319
}
263
320
}
264
321
RED . nodes . registerType ( "cloudant in" , CloudantInNode ) ;
265
322
266
323
function _getUrl ( node , n ) {
267
324
if ( n . service == "_ext_" ) {
268
- var cloudantConfig = RED . nodes . getNode ( node . cloudant ) ;
325
+ var cloudantConfig = RED . nodes . getNode ( node . cloudantConfig ) ;
269
326
if ( cloudantConfig ) {
270
327
return cloudantConfig . url ;
271
328
}
0 commit comments