Skip to content

Commit

Permalink
JSCBC-275: Implemented support for FTS querying.
Browse files Browse the repository at this point in the history
This is implemented at both the bucket level as well as
at the cluster level using the new cluster level
authentication.

Change-Id: I226b6feec13b44a0834e58d0d062b2e0d5d41680
Reviewed-on: http://review.couchbase.org/64754
Reviewed-by: Mark Nunberg <mark.nunberg@couchbase.com>
Tested-by: Brett Lawson <brett19@gmail.com>
  • Loading branch information
brett19 committed Jun 7, 2016
1 parent 53de7de commit a3b6f94
Show file tree
Hide file tree
Showing 12 changed files with 1,060 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/binding.js
Expand Up @@ -40,6 +40,7 @@ var fs = require('fs');
/** @name CouchbaseBinding.CouchbaseImpl#durability */
/** @name CouchbaseBinding.CouchbaseImpl#viewQuery */
/** @name CouchbaseBinding.CouchbaseImpl#n1qlQuery */
/** @name CouchbaseBinding.CouchbaseImpl#ftsQuery */
/** @name CouchbaseBinding.CouchbaseImpl#lookupIn */
/** @name CouchbaseBinding.CouchbaseImpl#mutateIn */
/** @name CouchbaseBinding.CouchbaseImpl#_errorTest */
Expand Down
201 changes: 196 additions & 5 deletions lib/bucket.js
Expand Up @@ -15,6 +15,7 @@ var connStr = require('./connstr');
var ViewQuery = require('./viewquery');
var SpatialQuery = require('./spatialquery');
var N1qlQuery = require('./n1qlquery');
var SearchQuery = require('./searchquery');
var BucketManager = require('./bucketmgr');

var CONST = binding.Constants;
Expand Down Expand Up @@ -739,19 +740,205 @@ Bucket.prototype._n1ql = function(query, params, callback) {
return req;
};

/**
* @class Meta
* @classdesc
* The meta-information available from a view query response.
* @private
* @memberof Bucket.N1qlQueryResponse
*/
/**
* The status information for this query, includes properties
* such as total, failed and successful.
*
* @var {number} Bucket.FtsQueryResponse.Meta#status
* @since 2.1.7
* @uncommitted
*/
/**
* Any non-fatal errors that occured during query processing.
*
* @var {number} Bucket.FtsQueryResponse.Meta#errors
* @since 2.1.7
* @uncommitted
*/
/**
* The total number of hits that were available for this seach query.
*
* @var {number} Bucket.FtsQueryResponse.Meta#totalHits
* @since 2.1.7
* @uncommitted
*/
/**
* The resulting facet information for any facets that were specified
* in the search query.
*
* @var {number} Bucket.FtsQueryResponse.Meta#facets
* @since 2.1.7
* @uncommitted
*/
/**
* The time spent processing this query.
*
* @var {number} Bucket.FtsQueryResponse.Meta#took
* @since 2.1.7
* @uncommitted
*/
/**
* The maximum score out of all the results in this query.
*
* @var {number} Bucket.FtsQueryResponse.Meta#maxScore
* @since 2.1.7
* @uncommitted
*/

/**
* Emitted whenever a new row is available from a queries result set.
*
* @event Bucket.FtsQueryResponse#row
* @param {Object} row
* @param {Bucket.FtsQueryResponse.Meta} meta
*
* @since 2.1.7
* @uncommitted
*/
/**
* Emitted whenever all rows are available from a queries result set.
*
* @event Bucket.FtsQueryResponse#rows
* @param {Object[]} rows
* @param {Bucket.FtsQueryResponse.Meta} meta
*
* @since 2.1.7
* @uncommitted
*/
/**
* Emitted once a query has completed executing and emitting all rows.
*
* @event Bucket.FtsQueryResponse#end
* @param {Bucket.FtsQueryResponse.Meta} meta
*
* @since 2.1.7
* @uncommitted
*/
/**
* Emitted if an error occurs while executing a query.
*
* @event Bucket.FtsQueryResponse#error
* @param {Error} error
*
* @since 2.1.7
* @uncommitted
*/

/**
* An event emitter allowing you to bind to various query result set
* events.
*
* @constructor
*
* @private
* @memberof Bucket
* @extends events.EventEmitter
*
* @since 2.1.7
* @uncommitted
*/
function FtsQueryResponse() {
}
util.inherits(FtsQueryResponse, events.EventEmitter);
Bucket.FtsQueryResponse = FtsQueryResponse;

/**
* Executes a FTS http request.
*
* @param {SearchQuery} q
* @param {FtsQueryResponse} emitter
*
* @private
* @ignore
*/
Bucket.prototype._ftsReq = function(q, emitter) {
var rows = [];
this._cb.ftsQuery(
q,
function(errCode, val) {
if (errCode === -1) { // Row
var row = val;
if (rows) {
if (events.EventEmitter.listenerCount(emitter, 'rows') > 0) {
rows.push(row);
} else {
rows = null;
}
}
emitter.emit('row', row);
} else if (errCode === 0) { // Success
var meta = val;
if (meta instanceof Object) {
meta.totalHits = meta.total_hits;
meta.maxScore = meta.max_score;
delete meta.total_hits;
delete meta.max_score;
}
if (rows) {
emitter.emit('rows', rows, meta);
}
emitter.emit('end', meta);
} else { // Error
var err = new Error('An FTS error occured: ' + val);
emitter.emit('error', err);
}
});
};

/**
* Executes a FTS query from a SearchQuery.
*
* @param {SearchQuery} query
* @param {function} callback
* @private
* @ignore
*/
Bucket.prototype._fts = function(query, callback) {
var req = new FtsQueryResponse();

var invokeCb = callback;
if (!invokeCb) {
invokeCb = function(err) {
req.emit('error', err);
};
}

this._maybeInvoke(this._ftsReq.bind(this),
[query, req, invokeCb]);

if (callback) {
req.on('rows', function(rows, meta) {
callback(null, rows, meta);
});
req.on('error', function(err) {
callback(err, null, null);
});
}

return req;
};

/**
* Executes a previously prepared query object. This could be a
* {@link ViewQuery} or a {@link N1qlQuery}.
* {@link ViewQuery}, {@link N1qlQuery} or a {@link SearchQuery}.
*
* Note: N1qlQuery queries are currently an uncommitted interface and may be
* subject to change in 2.0.0's final release.
* Note: SearchQuery queries are currently an uncommitted interface and may be
* subject to change in a future release.
*
* @param {ViewQuery|N1qlQuery} query
* @param {ViewQuery|N1qlQuery|SearchQuery} query
* The query to execute.
* @param {Object|Array} [params]
* A list or map to do replacements on a N1QL query.
* @param {Bucket.QueryCallback} callback
* @returns {Bucket.ViewQueryResponse|Bucket.N1qlQueryResponse}
* @returns {Bucket.ViewQueryResponse|Bucket.N1qlQueryResponse|Bucket.FtsQueryResponse}
*
* @since 2.0.0
* @committed
Expand All @@ -772,6 +959,10 @@ Bucket.prototype.query = function(query, params, callback) {
return this._n1ql(
query, params, callback
);
} else if (query instanceof SearchQuery) {
return this._fts(
query, callback
);
} else {
throw new TypeError(
'First argument needs to be a ViewQuery, SpatialQuery or N1qlQuery.');
Expand Down
46 changes: 42 additions & 4 deletions lib/cluster.js
Expand Up @@ -5,6 +5,7 @@ var connstr = require('./connstr');
var Bucket = require('./bucket');
var ClusterManager = require('./clustermgr');
var N1qlQuery = require('./n1qlquery');
var SearchQuery = require('./searchquery');

function _arrayRemove(arr, element) {
var newArray = [];
Expand Down Expand Up @@ -202,20 +203,53 @@ Cluster.prototype._n1ql = function(query, params, callback) {
return req;
};

Cluster.prototype._ftsReq = function(q, emitter) {
var bucket = this.connectedBuckets[0];
bucket._ftsReq(q, emitter);
};

Cluster.prototype._fts = function(query, callback) {
var req = new Bucket.FtsQueryResponse();

var invokeCb = callback;
if (!invokeCb) {
invokeCb = function(err) {
req.emit('error', err);
};
}

this._maybeInvoke(this._ftsReq.bind(this),
[query, req, invokeCb]);

if (callback) {
req.on('rows', function(rows, meta) {
callback(null, rows, meta);
});
req.on('error', function(err) {
callback(err, null, null);
});
}

return req;
};

/**
* Executes a previously prepared query object. This must be a
* {@link N1qlQuery}.
* Executes a previously prepared query object. This could be a
* {@link N1qlQuery} or a {@link SearchQuery}.
*
* Note: You must have at least one bucket open (this is neccessary to
* have cluster mapping information), and additionally be using the new
* cluster-level authentication methods.
*
* Note: SearchQuery queries are currently an uncommitted interface and may be
* subject to change in a future release.
*
* @param {N1qlQuery} query
* @param {N1qlQuery|SearchQuery} query
* The query to execute.
* @param {Object|Array} [params]
* A list or map to do replacements on a N1QL query.
* @param {Bucket.QueryCallback} callback
* @returns {Bucket.N1qlQueryResponse}
* @returns {Bucket.N1qlQueryResponse|Bucket.FtsQueryResponse}
*
* @since 2.1.7
* @committed
Expand Down Expand Up @@ -253,6 +287,10 @@ Cluster.prototype.query = function(query, params, callback) {
return this._n1ql(
query, params, callback
);
} else if (query instanceof SearchQuery) {
return this._fts(
query, callback
);
} else {
throw new TypeError(
'First argument needs to be a N1qlQuery.');
Expand Down
2 changes: 2 additions & 0 deletions lib/couchbase.js
Expand Up @@ -6,6 +6,8 @@ module.exports.Cluster = require('./cluster');
module.exports.SpatialQuery = require('./spatialquery');
module.exports.ViewQuery = require('./viewquery');
module.exports.N1qlQuery = require('./n1qlquery');
module.exports.SearchQuery = require('./searchquery');
module.exports.SearchFacet = require('./searchquery_facets');
module.exports.MutationState = require('./mutationstate');
module.exports.Mock = require('./mock/couchbase');
module.exports.Error = binding.Error;
Expand Down

0 comments on commit a3b6f94

Please sign in to comment.