Skip to content

Commit 6baf797

Browse files
committed
Merge pull request #29 from ibm-cds-labs/simple-search-service-update
#28 - handle spaces in field names
2 parents 18b9c6e + 2825886 commit 6baf797

File tree

4 files changed

+61
-22
lines changed

4 files changed

+61
-22
lines changed

lib/db.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,37 @@ cloudant.db.create("seams_settings", function(err,data) {
2828
// perform a search using Cloudant Search, returning the data
2929
// as an array of documents in 'rows'
3030
var cloudantSearch = function(opts, callback) {
31-
var facets = []
31+
var facets = [];
32+
var fieldMap = {};
3233
async.series([
3334

3435
// get the current schema
3536
function(cb) {
3637
schema.load(function(err, theSchema) {
3738
for(var i in theSchema.fields) {
39+
var n = theSchema.fields[i].name;
40+
var s = n.replace(/\s/g, '_');
41+
fieldMap[s] = n;
3842
if (theSchema.fields[i].facet == true) {
39-
facets.push(theSchema.fields[i].name);
43+
facets.push(s);
4044
}
4145
}
4246
cb(null, null);
4347
});
4448
},
49+
50+
// sanitize search query field names
51+
function(cb) {
52+
var q = opts.q;
53+
for (var s in fieldMap) {
54+
if (fieldMap[s] !== s) {
55+
q = q.replace('"' + fieldMap[s] + '":', (s+':'))
56+
.replace("'" + fieldMap[s] + "':", (s+':'));
57+
}
58+
}
59+
opts.q = q;
60+
cb(null, null);
61+
},
4562

4663
// do the search
4764
function(cb) {
@@ -61,11 +78,17 @@ var cloudantSearch = function(opts, callback) {
6178
}
6279
data.rows = rows;
6380
debug("Result",data.rows.length,"rows");
81+
for (var j in data.counts) {
82+
if (fieldMap[j] !== j) {
83+
data.counts[fieldMap[j]] = data.counts[j];
84+
delete data.counts[j];
85+
}
86+
}
6487
cb(err, data);
6588
});
6689
}
6790
], function(err, data) {
68-
callback(err, data[1])
91+
callback(err, data[2])
6992
});
7093

7194
};

lib/schema.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ var generateSearchIndex = function(schema, callback) {
6565
for (var i in schema.fields) {
6666
var f = schema.fields[i];
6767
if (f.name != "_id") {
68-
func += ' indy("' + f.name + '", doc["'+ f.name + '"], ' + f.facet + ');\n';
68+
var safename = f.name.replace(/\s/g,"_");
69+
func += ' indy("' + safename + '", doc["'+ f.name + '"], ' + f.facet + ');\n';
6970
}
7071
}
7172
func += ' delete doc._id;\n';

public/js/seams.js

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ seamsApp.controller('seamsController', ['$scope', '$route', '$routeParams', '$lo
202202
for(var i in $scope.$root.currentUpload.fields) {
203203
var d = $('select[name=' + $scope.$root.currentUpload.fields[i].safename + ']');
204204
var obj = {}
205-
obj.name = d.attr('name');
205+
obj.name = d.attr('data-original-name');
206206
obj.type = d.val();
207207
obj.facet = ($('#' + d.attr('name')).is(':checked') && !$('#' + d.attr('name')).prop("disabled"));
208208
fields.push(obj);
@@ -280,8 +280,8 @@ seamsApp.controller('seamsController', ['$scope', '$route', '$routeParams', '$lo
280280
html += "<tr>";
281281
var f = x.fields[i];
282282
html += "<td>" + f.name + "</td>\n";
283-
html += "<td>" + $scope.$root.typeWidget(f.safename,f.type) + "</td>\n";
284-
html += "<td>" + $scope.$root.facetWidget(f.safename,f.type,f.facet.toString()) + "</td>\n";
283+
html += "<td>" + $scope.$root.typeWidget(f) + "</td>\n";
284+
html += "<td>" + $scope.$root.facetWidget(f) + "</td>\n";
285285
for(var j in x.data) {
286286
var obj = x.data[j];
287287
var val = obj[f.name];
@@ -307,24 +307,28 @@ seamsApp.controller('seamsController', ['$scope', '$route', '$routeParams', '$lo
307307

308308
// returns the HTML to render a data type pull-down list
309309
// for field 'n' which has data type 't'
310-
$scope.$root.typeWidget = function(n,t) {
311-
var html = '<select name="' + n + '" + class="input_select" onchange="datatypechange(\'' + n +'\')">\n';
312-
var opts = [ "string", "number", "boolean", "arrayofstrings"];
310+
$scope.$root.typeWidget = function(f) {
311+
var n = f.safename;
312+
var t = f.type;
313+
var html = '<select name="' + n + '" class="input_select" onchange="datatypechange(\'' + n +'\')" data-original-name="' + f.name + '">\n';
314+
var opts = { "string":"String", "number":"Number", "boolean":"Boolean", "arrayofstrings":"Array of Strings" };
313315
for(var i in opts) {
314-
var j = opts[i];
315-
html += '<option value="' + j + '"';
316-
if (j == t) {
316+
html += '<option value="' + i + '"';
317+
if (i == t) {
317318
html += ' selected="selected"';
318319
}
319-
html += '>' + j + '</option>\n';
320+
html += '>' + opts[i] + '</option>\n';
320321
}
321322
html += '</select>\n';
322323
return html;
323324
};
324325

325326
// returns the HTML to render a checkbox for field 'n'
326327
// which is faceted or not (t)
327-
$scope.$root.facetWidget = function(n,t,v) {
328+
$scope.$root.facetWidget = function(f) {
329+
var n = f.safename;
330+
var t = f.type;
331+
var v = f.facet.toString();
328332
var html = '<input class="input_checkbox" type="checkbox" value="true" name="' + n + '" id="' + n + '"';
329333
if (t == "number" || t == "boolean") {
330334
html += ' disabled="disabled"';
@@ -413,7 +417,12 @@ seamsApp.controller('seamsController', ['$scope', '$route', '$routeParams', '$lo
413417
randomrow = Math.floor(Math.random() * previewData.rows.length);
414418
var text = previewData.rows[randomrow].doc[fieldname];
415419
if (text != null && typeof text !== 'undefined') {
416-
facet = fieldname + ":" + "\"" + text + "\"";
420+
if (fieldname.indexOf(' ') == -1) {
421+
facet = fieldname + ":" + "\"" + text + "\"";
422+
}
423+
else {
424+
facet = "\"" + fieldname + "\":" + "\"" + text + "\"";
425+
}
417426
params = {
418427
field: fieldname,
419428
value: text
@@ -680,14 +689,18 @@ seamsApp.directive('previewSearchHtml', function(){
680689

681690
scope.apiSearch = function(key, value) {
682691
if (typeof key != "undefined") {
683-
var query = key;
692+
var query = key.indexOf(' ') == -1 ? key : ('"' + key + '"');
684693
if (value) {
685694
query += ":\""+value+"\"";
686695
var search = scope.searchString();
696+
var spaceEncodedQ = query.replace(/\s/g, "\+");
687697

688698
if (search.indexOf(query) > -1) {
689699
query = search.replace(query, "").replace(" AND AND ", " AND ");
690700
}
701+
else if (search.indexOf(spaceEncodedQ) > -1) {
702+
query = search.replace(spaceEncodedQ, "").replace(" AND AND ", " AND ");
703+
}
691704
else {
692705
var regex = new RegExp(key+":\".*?\"", "i");
693706

@@ -715,7 +728,7 @@ seamsApp.directive('previewSearchHtml', function(){
715728
}
716729

717730
if ($('#q')) {
718-
$('#q').val(query);
731+
$('#q').val(query.replace(/\+/g, ' '));
719732
scope.$root.searchdirty = (query !== "*:*");
720733
}
721734

@@ -735,8 +748,10 @@ seamsApp.directive('previewSearchHtml', function(){
735748
};
736749

737750
scope.isSelected = function(facet, value) {
738-
var q = facet + ":\"" + value + '\"';
739-
return scope.searchDocs.rest_uri.indexOf(q) > -1;
751+
var q = (facet + ':"' + value + '"').replace(/\s/g, "\+");
752+
var quoted = ('"' + facet + '":"' + value + '"').replace(/\s/g, "\+");
753+
return scope.searchDocs.rest_uri.indexOf(q) > -1
754+
|| scope.searchDocs.rest_uri.indexOf(quoted) > -1;
740755
};
741756
}
742757
};

views/templates/search.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ <h1 class="type_heading"><mark class="type_mark">Preview Search</mark></h1>
2020
<div class="form_field" id="searchcontrol">
2121
<div class="form_addon-group">
2222
<!-- <span class="form_text-addon">https://.../search?q=</span> -->
23-
<input type="text" class="input_text" id="q" placeholder="" name="searchterm" ng-model="querystring" ng-change="searchdirty = querystring !== '*:*'">
24-
<span class="input_text-clear" ng-click="searchdirty = false;clearSearch();" ng-show="searchdirty">&times;</span>
23+
<input type="text" class="input_text" id="q" placeholder="" name="searchterm" ng-model="querystring" ng-change="$root.searchdirty = querystring !== '*:*'">
24+
<span class="input_text-clear" ng-click="$root.searchdirty = false;clearSearch();" ng-show="$root.searchdirty">&times;</span>
2525
<button type="submit" class="button_primary search_button" ng-click="search()"> Search </button>
2626
</div>
2727
</div>

0 commit comments

Comments
 (0)