YUKI Hiroshi
null+****@clear*****
Fri Aug 24 19:57:54 JST 2012
YUKI Hiroshi 2012-08-24 19:57:54 +0900 (Fri, 24 Aug 2012) New Revision: 2b2b8b73adc71aa9ca75bb78efcdf71328b9a9de https://github.com/groonga/gcs/commit/2b2b8b73adc71aa9ca75bb78efcdf71328b9a9de Log: Split SelectQuery implementation Added files: lib/select-query.js Modified files: lib/api/2011-02-01/search.js Modified: lib/api/2011-02-01/search.js (+0 -117) =================================================================== --- lib/api/2011-02-01/search.js 2012-08-24 19:24:55 +0900 (ee38d50) +++ lib/api/2011-02-01/search.js 2012-08-24 19:57:54 +0900 (e0c7356) @@ -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) { @@ -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(); Added: lib/select-query.js (+204 -0) 100644 =================================================================== --- /dev/null +++ lib/select-query.js 2012-08-24 19:57:54 +0900 (74abbef) @@ -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; -------------- next part -------------- HTML����������������������������... 下載