Skip to content

Commit 3d8f86f

Browse files
committed
clean database name and fix fields that start with _ in the document
1 parent d168e72 commit 3d8f86f

File tree

2 files changed

+89
-9
lines changed

2 files changed

+89
-9
lines changed

77-cloudant-cf.html

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
service: { value: "", required: true },
187187
cloudant: { type: "cloudant", validate: validateServer},
188188
name: { value: "" },
189-
database: { value: "", required: true },
189+
database: { value: "", required: true, validate: validateDatabase },
190190
payonly: { value: false },
191191
operation: { value: "insert" }
192192
},
@@ -208,7 +208,7 @@
208208
service : { value: "", required: true },
209209
cloudant: { type: "cloudant", validate: validateServer },
210210
name : { value: "" },
211-
database: { value: "", required: true },
211+
database: { value: "", required: true, validate: validateDatabase },
212212
search : { value: "_id_", required: true },
213213
design : { value: "" },
214214
index : { value: "" }
@@ -286,6 +286,12 @@
286286
function validateServer(v) {
287287
return this.service != "_ext_" || v != "_ADD_";
288288
}
289+
290+
// https://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing
291+
function validateDatabase(v) {
292+
return (v.indexOf('_') !== 0) &&
293+
(v.search(/[A-Z\s\\/]/g) < 0)
294+
}
289295
</script>
290296

291297
<script type="text/x-red" data-help-name="cloudant out">
@@ -307,11 +313,25 @@
307313
</p>
308314
<p>
309315
It is also possible to <b>delete</b> documents from the database by
310-
providing values for <code>_id</b> and <code>_rev</code> and selecting
316+
providing values for <code>_id</code> and <code>_rev</code> and selecting
311317
the <b>remove</b> option for the node. You can pass these values in the
312318
<code>msg</code> object itself or as an object in the
313319
<code>msg.payload</code>.
314320
</p>
321+
<p>
322+
The <b>database name</b> must follow these rules:
323+
<ul>
324+
<li>No spaces</li>
325+
<li>All letters in small caps</li>
326+
<li>The first character can't be <code>_</code></li>
327+
</ul>
328+
</p>
329+
<p>
330+
Your document should avoid having top-level fields that start with
331+
<code>_</code>, with exceptions for <code>_id</code>, <code>_rev</code>
332+
and other <a href="https://wiki.apache.org/couchdb/HTTP_Document_API#Special_Fields">
333+
CouchDB reserved words</a>.
334+
</p>
315335
</script>
316336

317337
<script type="text/x-red" data-help-name="cloudant in">
@@ -338,15 +358,29 @@
338358
</p>
339359
<p>
340360
When querying using a <b>Search Index</b> you can pass the search
341-
parameters as an object in <code>msg.payload</code>. For example, you
342-
can pass an object like this: <code>{ query: "abc*", limit: 100 }</code>
361+
parameters as an object in <code>msg.payload</code>.
362+
</p>
363+
<p>
364+
For example, you can pass an object like this:
365+
<p>
366+
<code>{ query: "abc*", limit: 100 }</code>
367+
</p>
368+
<p>
343369
to change the value of <code>limit</code>. You can find more information
344-
on the accepted parameters in the <a
370+
about <b>Search Index</b> parameters in the <a
345371
href="https://docs.cloudant.com/api.html?http#queries" target="_blank">
346372
official Cloudant documentation</a>.
347373
</p>
348374
<p>
349375
The last method to retrieve documents is to simply get all of them by
350376
selecting the option <b>all documents</b>.
351377
</p>
378+
<p>
379+
The <b>database name</b> must follow these rules:
380+
<ul>
381+
<li>No spaces</li>
382+
<li>All letters in small caps</li>
383+
<li>The first character can't be <code>_</code></li>
384+
</ul>
385+
</p>
352386
</script>

77-cloudant-cf.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ module.exports = function(RED) {
116116

117117
this.operation = n.operation;
118118
this.payonly = n.payonly || false;
119-
this.database = n.database;
119+
this.database = _cleanDatabaseName(n.database, this);
120120
this.cloudantConfig = _getCloudantConfig(n);
121121

122122
var node = this;
@@ -187,9 +187,36 @@ module.exports = function(RED) {
187187
msg = JSON.parse('{"' + root + '":"' + msg + '"}');
188188
}
189189
}
190+
return cleanMessage(msg);
191+
}
192+
193+
// fix field values that start with _
194+
// https://wiki.apache.org/couchdb/HTTP_Document_API#Special_Fields
195+
function cleanMessage(msg) {
196+
for (var key in msg) {
197+
if (msg.hasOwnProperty(key) && !isFieldNameValid(key)) {
198+
// remove _ from the start of the field name
199+
var newKey = key.substring(1, msg.length);
200+
201+
msg[newKey] = msg[key];
202+
delete msg[key];
203+
204+
node.warn("Property '" + key + "' renamed to '" + newKey + "'.");
205+
}
206+
}
207+
190208
return msg;
191209
}
192210

211+
function isFieldNameValid(key) {
212+
var allowedWords = [
213+
'_id', '_rev', '_attachments', '_deleted', '_revisions',
214+
'_revs_info', '_conflicts', '_deleted_conflicts', '_local_seq'
215+
];
216+
217+
return key[0] !== '_' || allowedWords.indexOf(key) >= 0;
218+
}
219+
193220
// Inserts a document +doc+ in a database +db+ that migh not exist
194221
// beforehand. If the database doesn't exist, it will create one
195222
// with the name specified in +db+. To prevent loops, it only tries
@@ -214,7 +241,7 @@ module.exports = function(RED) {
214241
RED.nodes.createNode(this,n);
215242

216243
this.cloudantConfig = _getCloudantConfig(n);
217-
this.database = n.database;
244+
this.database = _cleanDatabaseName(n.database, this);
218245
this.search = n.search;
219246
this.design = n.design;
220247
this.index = n.index;
@@ -245,7 +272,7 @@ module.exports = function(RED) {
245272
options.query = options.query || options.q || formatSearchQuery(msg.payload);
246273
options.include_docs = options.include_docs || true;
247274
options.limit = options.limit || 200;
248-
275+
249276
if (options.sort) {
250277
options.sort = JSON.stringify(options.sort);
251278
}
@@ -331,4 +358,23 @@ module.exports = function(RED) {
331358
return appEnv.getService(n.service);
332359
}
333360
}
361+
362+
// remove invalid characters from the database name
363+
// https://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing
364+
function _cleanDatabaseName(database, node) {
365+
var newDatabase = database;
366+
367+
// caps are not allowed
368+
newDatabase = newDatabase.toLowerCase();
369+
// remove trailing underscore
370+
newDatabase = newDatabase.replace(/^_/, '');
371+
// remove spaces and slashed
372+
newDatabase = newDatabase.replace(/[\s\\/]+/g, '-');
373+
374+
if (newDatabase !== database) {
375+
node.warn("Database renamed as '" + newDatabase + "'.");
376+
}
377+
378+
return newDatabase;
379+
}
334380
};

0 commit comments

Comments
 (0)