Navigation Menu

Skip to content

Commit

Permalink
Split SelectQuery implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
piroor committed Aug 24, 2012
1 parent f71d3f8 commit 2b2b8b7
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 117 deletions.
117 changes: 0 additions & 117 deletions lib/api/2011-02-01/search.js
@@ -1,9 +1,5 @@
// -*- indent-tabs-mode: nil; js2-basic-offset: 2 -*-

var Domain = require('../../database').Domain;
var nroonga = require('../../wrapped-nroonga');
var BooleanQueryTranslator = require('../../bq-translator').BooleanQueryTranslator;

var dummyRid = '000000000000000000000000000000000000000000000000000000000000000';

function formatFacets(data) {
Expand Down Expand Up @@ -123,119 +119,6 @@ function createErrorBody(options) {
};
}

function translateQueryToBooleanQuery(query) {
return "'" + query.replace(/(['\\])/g, '\\$1') + "'";
}

function SelectQuery(request, context) {
var domain = new Domain(request, context);
var query = request.query.q || '';
var booleanQuery = request.query.bq || '';
var filters = [];
var matchExpression = '';
var facets = request.query.facet;
var noResult = false;

var defaultFields;
var defaultField = domain.defaultSearchField;
if (defaultField)
defaultFields = [defaultField];
else
defaultFields = domain.searchableIndexFields.filter(function(field) {
return field.type == 'text';
});

var defaultFieldNames = defaultFields.map(function(field) {
return field.name;
});

if (query) {
var queryAsBooleanQuery = translateQueryToBooleanQuery(query);
var translator = new BooleanQueryTranslator(queryAsBooleanQuery);
translator.domain = domain;
translator.defaultFieldNames = defaultFieldNames;
try {
filters.push(translator.translate());
} catch (error) {
error.queryType = 'q';
throw error;
}
matchExpression = '(label ' + queryAsBooleanQuery + ')';
}

if (booleanQuery) {
var translator = new BooleanQueryTranslator(booleanQuery);
translator.domain = domain;
translator.defaultFieldNames = defaultFieldNames;
try {
filters.push(translator.translate());
} catch (error) {
error.queryType = 'bq';
throw error;
}
noResult = noResult || !translator.available;
if (matchExpression.length > 0) {
matchExpression = '(and ' + matchExpression + ' ' + booleanQuery + ')';
} else {
matchExpression = booleanQuery;
}
}

filters = filters.map(function(filter) {
return '(' + filter + ')';
});
var size = parseInt(request.query.size || '10', 10);
var start = parseInt(request.query.start || '0', 10);
var filter = filters.join(' && ');
var requestedOutputColumns = request.query['return-fields'] || '';
requestedOutputColumns = requestedOutputColumns.split(/\s*,\s*/);
var outputColumns = domain.resultReturnableIndexFields
.filter(function(field) {
return requestedOutputColumns.indexOf(field.name) > -1;
})
.map(function(field) {
return field.columnName;
});
outputColumns.unshift('_key');
var options = {
table: domain.tableName,
filter: filter,
limit: size,
offset: start,
output_columns: outputColumns.join(', ')
};

if (domain.hasSynonymsTableSync()) {
options.query_expansion = domain.synonymsTableName + '.synonyms';
}
if (filter) {
options.filter = filter;
}

if (facets) {
var facetReturnableFields = domain.facetReturnableIndexFields
.map(function(field) {
return field.name;
});
facets = facets.split(/\s*,\s*/)
.filter(function(field) {
return facetReturnableFields.indexOf(field) > -1;
});
options.drilldown = facets.join(',');
options.drilldown_sortby = '-_nsubrecs';
// TODO support sorting parameter
// TODO support facet-FIELD-top-n parameter
}

return {
selectOptions: options,
matchExpression: matchExpression,
start: start,
facets: facets,
noResult: noResult
};
}

exports.createHandler = function(context) {
return function(request, response) {
var startedAt = new Date();
Expand Down
204 changes: 204 additions & 0 deletions lib/select-query.js
@@ -0,0 +1,204 @@
var Domain = require('./database').Domain;
var BooleanQueryTranslator = require('./bq-translator').BooleanQueryTranslator;

function translateQueryToBooleanQuery(query) {
return "'" + query.replace(/(['\\])/g, '\\$1') + "'";
}

// this should be re-implemented as a class
function SelectQuery(request, context) {
this.request = request;
this.domain = new Domain(request, context);

this.filters = [];
this.matchExpression = '';
this.noResult = false;

this.parse();
}

SelectQuery.prototype = {
get query() {
return this.request.query.q || '';
},

get booleanQuery() {
return this.request.query.bq || '';
},

get size() {
if (this._size === undefined)
this._size = this.prepareSize();
return this._size;
},
prepareSize: function() {
return parseInt(this.request.query.size || '10', 10);
},

get start() {
if (this._start === undefined)
this._start = this.prepareStart();
return this._start;
},
prepareStart: function() {
return parseInt(this.request.query.start || '0', 10);
},

get returnFields() {
if (this._returnFields === undefined)
this._returnFields = this.prepareReturnFields();
return this._returnFields;
},
prepareReturnFields: function() {
var fields = this.request.query['return-fields'];
if (fields)
return fields.split(/\s*,\s*/);
else
return [];
},

get facets() {
if (this._facets === undefined)
this._facets = this.prepareFacets();
return this._facets;
},
prepareFacets: function() {
var facets = this.request.query.facet;
if (facets)
return facets.split(/\s*,\s*/);
else
return [];
},

get defaultFieldNames() {
if (this._defaultFieldNames === undefined)
this._defaultFieldNames = this.prepareDefaultFieldNames();
return this._defaultFieldNames;
},
prepareDefaultFieldNames: function() {
var defaultFields;
var defaultField = this.domain.defaultSearchField;
if (defaultField)
defaultFields = [defaultField];
else
defaultFields = this.domain.searchableIndexFields.filter(function(field) {
return field.type == 'text';
});

var defaultFieldNames = defaultFields.map(function(field) {
return field.name;
});
},

parse: function() {
var filters = [];
var matchExpression = '';

if (this.query) {
var queryAsBooleanQuery = translateQueryToBooleanQuery(this.query);
var translator = new BooleanQueryTranslator(queryAsBooleanQuery);
translator.domain = this.domain;
translator.defaultFieldNames = this.defaultFieldNames;
try {
filters.push(translator.translate());
} catch (error) {
error.queryType = 'q';
throw error;
}
matchExpression = '(label ' + queryAsBooleanQuery + ')';
}

if (this.booleanQuery) {
var translator = new BooleanQueryTranslator(this.booleanQuery);
translator.domain = this.domain;
translator.defaultFieldNames = this.defaultFieldNames;
try {
filters.push(translator.translate());
} catch (error) {
error.queryType = 'bq';
throw error;
}
this.noResult = !translator.available;
if (matchExpression.length > 0) {
matchExpression = '(and ' + matchExpression + ' ' + this.booleanQuery + ')';
} else {
matchExpression = this.booleanQuery;
}
}

this.filters = filters.map(function(filter) {
return '(' + filter + ')';
});
this.matchExpression = matchExpression;
},

// for groonga query
get filter() {
return this.filters.join(' && ');
},

get drilldownColumns() {
if (this._drilldownColumns === undefined)
this._drilldownColumns = this.prepareDrilldownColumns();
return this._drilldownColumns;
},
prepareDrilldownColumns: function() {
var facetReturnableFields = this.domain.facetReturnableIndexFields
.map(function(field) {
return field.name;
});
return this.facets
.filter(function(field) {
return facetReturnableFields.indexOf(field) > -1;
})
.map(function(field) {
return this.domain.getIndexField(field).columnName;
}, this);
},

get outputColumns() {
if (this._outputColumns === undefined)
this._outputColumns = this.prepareOutputColumns();
return this._outputColumns;
},
prepareOutputColumns: function() {
var returnFields = this.returnFields;
var columns = this.domain.resultReturnableIndexFields
.filter(function(field) {
return returnFields.indexOf(field.name) > -1;
})
.map(function(field) {
return field.columnName;
});
columns.unshift('_key');
return columns;
},

get selectOptions() {
if (this._selectOptions === undefined)
this._selectOptions = this.prepareSelectOptions();
return this._selectOptions;
},
prepareSelectOptions: function() {
var options = {
table: this.domain.tableName,
filter: this.filter,
limit: this.size,
offset: this.start,
output_columns: this.outputColumns.join(', ')
};

if (this.domain.hasSynonymsTableSync())
options.query_expansion = this.domain.synonymsTableName + '.synonyms';

if (this.facets.length) {
options.drilldown = this.drilldownColumns.join(',');
options.drilldown_sortby = '-_nsubrecs';
// TODO support sorting parameter
// TODO support facet-FIELD-top-n parameter
}
return options;
}
};

exports.SelectQuery = SelectQuery;

0 comments on commit 2b2b8b7

Please sign in to comment.