diff --git a/lib/models/make.js b/lib/models/make.js index 68a8a8a..27e4322 100644 --- a/lib/models/make.js +++ b/lib/models/make.js @@ -92,6 +92,8 @@ module.exports = function( environment, mongoInstance ) { published: { type: Boolean, "default": true, + es_type: "boolean", + es_indexed: true, es_index: "not_analyzed" }, tags: { diff --git a/lib/queryBuilder.js b/lib/queryBuilder.js index 58cad18..2a39165 100644 --- a/lib/queryBuilder.js +++ b/lib/queryBuilder.js @@ -136,147 +136,164 @@ module.exports = function( loginApi ) { } }; - // capture valid query generator keys - GENERATOR_KEYS = Object.keys( generators ); - - return { - build: function( query, callback ) { - if ( !( query && query.constructor === Object ) || !( callback && typeof callback === "function" ) ) { - throw new Error( "Check your arguments." ); - } + function buildQuery( query, customFilter, callback ) { + if ( typeof customFilter === "function" ) { + callback = customFilter; + customFilter = {}; + } + if ( !( query && query.constructor === Object ) || !( callback && typeof callback === "function" ) ) { + throw new Error( "Check your arguments." ); + } - query.limit = +query.limit; - query.page = +query.page; - - // baseQuery is the most basic query we can make. - // advancedQuery is used if we need to generate filters, and wraps around baseQuery. - var baseQuery = { - query: { - filtered: { - query: { - match_all: {} - }, - filter: { - missing: { - field: "deletedAt", - null_value: true - } - } - } - } - }, - advancedQuery = { - query: { - filtered: { - filter: { - bool: { - must: [], - should: [] - } - }, - query: baseQuery.query - } + query.limit = +query.limit; + query.page = +query.page; + + // baseQuery is the most basic query we can make. + // advancedQuery is used if we need to generate filters, and wraps around baseQuery. + var baseQuery = { + query: { + filtered: { + query: { + match_all: {} + }, + filter: customFilter } - }, - searchQuery = {}, - size = query.limit && isFinite( query.limit ) ? query.limit : DEFAULT_SEARCH_SIZE, - page = query.page && isFinite( query.page ) ? query.page : 1, - user = query.user, - sort = query.sortByField, - filterOccurence = query.or ? "should" : "must", - sortObj, - notRegexMatch; - - // If the request contains any of the filter generating keys, or defines a user search, use the advancedQuery object - if ( Object.keys( query ).some( hasGeneratorKey ) || user ) { - searchQuery = advancedQuery; - Object.keys( query ).forEach(function( key ){ - value = query[ key ]; - if ( generators[ key ] ) { - notRegexMatch = NOT_REGEX.exec( value ); - if ( notRegexMatch ) { - searchQuery.query.filtered.filter.bool[ filterOccurence ].push( generators[ key ]( notRegexMatch[ 1 ], true ) ); - } else { - searchQuery.query.filtered.filter.bool[ filterOccurence ].push( generators[ key ]( value ) ); + } + }, + advancedQuery = { + query: { + filtered: { + filter: { + bool: { + must: [], + should: [] + } + }, + query: baseQuery.query } } - }); - } else { - searchQuery = baseQuery; - } + }, + searchQuery = {}, + size = query.limit && isFinite( query.limit ) ? query.limit : DEFAULT_SEARCH_SIZE, + page = query.page && isFinite( query.page ) ? query.page : 1, + user = query.user, + sort = query.sortByField, + filterOccurence = query.or ? "should" : "must", + sortObj, + notRegexMatch; + + // If the request contains any of the filter generating keys, or defines a user search, use the advancedQuery object + if ( Object.keys( query ).some( hasGeneratorKey ) || user ) { + searchQuery = advancedQuery; + Object.keys( query ).forEach(function( key ){ + value = query[ key ]; + if ( generators[ key ] ) { + notRegexMatch = NOT_REGEX.exec( value ); + if ( notRegexMatch ) { + searchQuery.query.filtered.filter.bool[ filterOccurence ].push( generators[ key ]( notRegexMatch[ 1 ], true ) ); + } else { + searchQuery.query.filtered.filter.bool[ filterOccurence ].push( generators[ key ]( value ) ); + } + } + }); + } else { + searchQuery = baseQuery; + } - // set size and from and sort - if ( size > MAX_SEARCH_SIZE ) { - size = MAX_SEARCH_SIZE; - } else if ( size < 1 ) { - size = 1; - } - searchQuery.size = size; + // set size and from and sort + if ( size > MAX_SEARCH_SIZE ) { + size = MAX_SEARCH_SIZE; + } else if ( size < 1 ) { + size = 1; + } + searchQuery.size = size; - if ( page < 1 ) { - page = 1; - } - searchQuery.from = ( page - 1 ) * size; + if ( page < 1 ) { + page = 1; + } + searchQuery.from = ( page - 1 ) * size; - if ( sort ) { - sort = ( Array.isArray( sort ) ? sort : [ sort ] ).filter(function( pair ) { - return typeof pair === "string" && pair.length && VALID_SORT_FIELDS.indexOf( pair.split( "," )[ 0 ] ) !== -1; - }); + if ( sort ) { + sort = ( Array.isArray( sort ) ? sort : [ sort ] ).filter(function( pair ) { + return typeof pair === "string" && pair.length && VALID_SORT_FIELDS.indexOf( pair.split( "," )[ 0 ] ) !== -1; + }); - if ( sort.length ) { - searchQuery.sort = []; - sort.forEach(function( pair ){ - pair = pair.split( "," ); - sortObj = {}; - if ( pair[ 0 ] === "likes" ) { - sortObj._script = { - lang: "js", - order: pair[ 1 ], - script: "doc['likes.userId'].values.length", - type: "number" - }; - } else { - sortObj[ pair[ 0 ] ] = pair[ 1 ] || "desc"; - } - searchQuery.sort.push( sortObj ); - }); - } + if ( sort.length ) { + searchQuery.sort = []; + sort.forEach(function( pair ){ + pair = pair.split( "," ); + sortObj = {}; + if ( pair[ 0 ] === "likes" ) { + sortObj._script = { + lang: "js", + order: pair[ 1 ], + script: "doc['likes.userId'].values.length", + type: "number" + }; + } else { + sortObj[ pair[ 0 ] ] = pair[ 1 ] || "desc"; + } + searchQuery.sort.push( sortObj ); + }); } + } - if ( user ) { - notRegexMatch = NOT_REGEX.exec( user ); - if ( notRegexMatch ) { - user = notRegexMatch[ 1 ]; + if ( user ) { + notRegexMatch = NOT_REGEX.exec( user ); + if ( notRegexMatch ) { + user = notRegexMatch[ 1 ]; + } + loginApi.getUser( user, function( err, userData ) { + if ( err ) { + callback({ + error: err, + code: 500 + }); + return; } - loginApi.getUser( user, function( err, userData ) { - if ( err ) { - callback({ - error: err, - code: 500 - }); - return; - } - if ( !userData ) { - if ( searchQuery.query.filtered.filter.bool.should.length ) { - // If this is an OR filtered query, ignore the undefined user - callback( null, searchQuery ); - } else { - callback( { code: 404 } ); - } - return; + if ( !userData ) { + if ( searchQuery.query.filtered.filter.bool.should.length ) { + // If this is an OR filtered query, ignore the undefined user + callback( null, searchQuery ); + } else { + callback( { code: 404 } ); } + return; + } - var filter = generateFilter( "term", { - email: userData.email - }, !!notRegexMatch ); + var filter = generateFilter( "term", { + email: userData.email + }, !!notRegexMatch ); - searchQuery.query.filtered.filter.bool[ filterOccurence ].push( filter ); - callback( null, searchQuery ); - }); - } else { + searchQuery.query.filtered.filter.bool[ filterOccurence ].push( filter ); callback( null, searchQuery ); - } + }); + } else { + callback( null, searchQuery ); + } + } + + // capture valid query generator keys + GENERATOR_KEYS = Object.keys( generators ); + + return { + build: function( query, callback ) { + buildQuery( query, { + and: [ + { + missing: { + field: "deletedAt", + null_value: true + } + }, + { + term: { + published: true + } + } + ] + }, callback ); } }; }; diff --git a/test/queryBuilder/core.unit.js b/test/queryBuilder/core.unit.js index 6bb0509..7df7e5e 100644 --- a/test/queryBuilder/core.unit.js +++ b/test/queryBuilder/core.unit.js @@ -7,10 +7,19 @@ module.exports = function( qb ){ match_all: {} }, filter: { - missing: { - field: "deletedAt", - null_value: true - } + and: [ + { + missing: { + field: "deletedAt", + null_value: true + } + }, + { + term: { + published: true + } + } + ] } } }, diff --git a/test/queryBuilder/sort.unit.js b/test/queryBuilder/sort.unit.js index 9db965d..0f10b3e 100644 --- a/test/queryBuilder/sort.unit.js +++ b/test/queryBuilder/sort.unit.js @@ -7,10 +7,19 @@ module.exports = function( qb ) { match_all: {} }, filter: { - missing: { - field: "deletedAt", - null_value: true - } + and: [ + { + missing: { + field: "deletedAt", + null_value: true + } + }, + { + term: { + published: true + } + } + ] } } },