From 796386102f6be20c55978c1deed54efbd943bb57 Mon Sep 17 00:00:00 2001 From: vinz51 Date: Tue, 18 Jul 2017 17:07:58 +0200 Subject: [PATCH 1/2] Add the new fullTextSearch method with the associated tests. --- src/ParseQuery.js | 42 ++++++++ src/__tests__/ParseQuery-test.js | 169 +++++++++++++++++++++---------- 2 files changed, 158 insertions(+), 53 deletions(-) diff --git a/src/ParseQuery.js b/src/ParseQuery.js index 796856c79..372241ba1 100644 --- a/src/ParseQuery.js +++ b/src/ParseQuery.js @@ -1032,6 +1032,37 @@ export default class ParseQuery { return this._addCondition(key, '$geoIntersects', { '$point': point }); } + /** + * Method to find by full text. + * The key and the search fields are required the others are optionals. + * @method fullTextSearch + * @param {String} key The key to structure the where query + * @param {String} search The string to search + * @param {String} language Determine the list of stop words + * @param {Boolean} caseSensitive Dis/en-able the case sensitive search + * @param {Boolean} diacriticSensitive Dis/en-able diacritic sensitive search + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + fullTextSearch(key: string, search: string, language: string, caseSensitive: boolean, diacriticSensitive: boolean): ParseQuery { + if (typeof key === 'undefined' || !key) { + throw new Error('A key is required.'); + } + if (typeof search === 'undefined' || !search) { + throw new Error('You have to add one string to search.'); + } + var options = { '$term': search }; + if (typeof language !== "undefined" || language !== null) { + options['$language'] = language; + } + if (typeof caseSensitive !== "undefined" || caseSensitive !== null) { + options['$caseSensitive'] = caseSensitive; + } + if (typeof diacriticSensitive !== "undefined" || diacriticSensitive !== null) { + options['$diacriticSensitive'] = diacriticSensitive; + } + return this._addCondition(key, '$text', { '$search': options }); + } + /** Query Orderings **/ /** @@ -1110,6 +1141,17 @@ export default class ParseQuery { return this; } + /** + * Method to sort the full text search by text score + * @method sortByTextScore + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + sortByTextScore() { + this.ascending('$score'); + this.select(['$score']); + return this; + } + /** Query Options **/ /** diff --git a/src/__tests__/ParseQuery-test.js b/src/__tests__/ParseQuery-test.js index d1d329b39..72a6b50c8 100644 --- a/src/__tests__/ParseQuery-test.js +++ b/src/__tests__/ParseQuery-test.js @@ -1338,7 +1338,7 @@ describe('ParseQuery', () => { }); - + it('overrides cached object with query results', (done) => { jest.dontMock("../ParseObject"); jest.resetModules(); @@ -1347,12 +1347,12 @@ describe('ParseQuery', () => { ParseQuery = require('../ParseQuery').default; ParseObject.enableSingleInstance(); - - var objectToReturn = { - objectId: 'T01', - name: 'Name', - other: 'other', - className:"Thing", + + var objectToReturn = { + objectId: 'T01', + name: 'Name', + other: 'other', + className:"Thing", createdAt: '2017-01-10T10:00:00Z' }; @@ -1368,10 +1368,10 @@ describe('ParseQuery', () => { var testObject; q.find().then((results) => { testObject = results[0]; - + expect(testObject.get("name")).toBe("Name"); expect(testObject.get("other")).toBe("other"); - + objectToReturn = { objectId: 'T01', name: 'Name2'}; var q2 = new ParseQuery("Thing"); return q2.find(); @@ -1393,13 +1393,13 @@ describe('ParseQuery', () => { ParseQuery = require('../ParseQuery').default; ParseObject.enableSingleInstance(); - - var objectToReturn = { - objectId: 'T01', - name: 'Name', - other: 'other', - tbd: 'exists', - className:"Thing", + + var objectToReturn = { + objectId: 'T01', + name: 'Name', + other: 'other', + tbd: 'exists', + className:"Thing", createdAt: '2017-01-10T10:00:00Z', subObject: {key1:"value", key2:"value2", key3:"thisWillGoAway"} }; @@ -1416,14 +1416,14 @@ describe('ParseQuery', () => { var testObject; return q.find().then((results) => { testObject = results[0]; - + expect(testObject.get("name")).toBe("Name"); expect(testObject.get("other")).toBe("other"); expect(testObject.has("tbd")).toBe(true); expect(testObject.get("subObject").key1).toBe("value"); expect(testObject.get("subObject").key2).toBe("value2"); expect(testObject.get("subObject").key3).toBe("thisWillGoAway"); - + var q2 = new ParseQuery("Thing"); q2.select("other", "tbd", "subObject.key1", "subObject.key3"); objectToReturn = { objectId: 'T01', other: 'other2', subObject:{key1:"updatedValue"}}; @@ -1442,7 +1442,7 @@ describe('ParseQuery', () => { expect(testObject.has("tbd")).toBe(false); expect(testObject.get("subObject").key1).toBe("updatedValue"); expect(testObject.get("subObject").key2).toBe("value2"); - expect(testObject.get("subObject").key3).toBeUndefined(); + expect(testObject.get("subObject").key3).toBeUndefined(); done(); }, (error) => { done.fail(error); @@ -1457,12 +1457,12 @@ describe('ParseQuery', () => { ParseQuery = require('../ParseQuery').default; ParseObject.enableSingleInstance(); - - var objectToReturn = { - objectId: 'T01', - name: 'Name', - other: 'other', - className:"Thing", + + var objectToReturn = { + objectId: 'T01', + name: 'Name', + other: 'other', + className:"Thing", createdAt: '2017-01-10T10:00:00Z' }; @@ -1478,10 +1478,10 @@ describe('ParseQuery', () => { var testObject; q.first().then((result) => { testObject = result; - + expect(testObject.get("name")).toBe("Name"); expect(testObject.get("other")).toBe("other"); - + objectToReturn = { objectId: 'T01', name: 'Name2'}; var q2 = new ParseQuery("Thing"); return q2.first(); @@ -1503,13 +1503,13 @@ describe('ParseQuery', () => { ParseQuery = require('../ParseQuery').default; ParseObject.enableSingleInstance(); - - var objectToReturn = { - objectId: 'T01', - name: 'Name', - other: 'other', - tbd: 'exists', - className:"Thing", + + var objectToReturn = { + objectId: 'T01', + name: 'Name', + other: 'other', + tbd: 'exists', + className:"Thing", subObject: {key1:"value", key2:"value2", key3:"thisWillGoAway"}, createdAt: '2017-01-10T10:00:00Z', }; @@ -1526,11 +1526,11 @@ describe('ParseQuery', () => { var testObject; return q.first().then((result) => { testObject = result; - + expect(testObject.get("name")).toBe("Name"); expect(testObject.get("other")).toBe("other"); expect(testObject.has("tbd")).toBe(true); - + var q2 = new ParseQuery("Thing"); q2.select("other", "tbd", "subObject.key1", "subObject.key3"); objectToReturn = { objectId: 'T01', other: 'other2', subObject:{key1:"updatedValue"}}; @@ -1546,10 +1546,10 @@ describe('ParseQuery', () => { }).then(() => { expect(testObject.get("name")).toBe("Name"); expect(testObject.get("other")).toBe("other2"); - expect(testObject.has("tbd")).toBe(false); + expect(testObject.has("tbd")).toBe(false); expect(testObject.get("subObject").key1).toBe("updatedValue"); expect(testObject.get("subObject").key2).toBe("value2"); - expect(testObject.get("subObject").key3).toBeUndefined(); + expect(testObject.get("subObject").key3).toBeUndefined(); done(); }, (error) => { done.fail(error); @@ -1593,12 +1593,12 @@ describe('ParseQuery', () => { ParseQuery = require('../ParseQuery').default; ParseObject.enableSingleInstance(); - - var objectToReturn = { - objectId: 'T01', - name: 'Name', - tbd: 'exists', - className:"Thing", + + var objectToReturn = { + objectId: 'T01', + name: 'Name', + tbd: 'exists', + className:"Thing", createdAt: '2017-01-10T10:00:00Z' }; @@ -1615,7 +1615,7 @@ describe('ParseQuery', () => { var testObject; return q.find().then((results) => { testObject = results[0]; - + expect(testObject.get("name")).toBe("Name"); expect(testObject.has("other")).toBe(false); expect(testObject.has("subObject")).toBe(false); @@ -1635,12 +1635,12 @@ describe('ParseQuery', () => { ParseQuery = require('../ParseQuery').default; ParseObject.enableSingleInstance(); - - var objectToReturn = { - objectId: 'T01', - name: 'Name', - tbd: 'exists', - className:"Thing", + + var objectToReturn = { + objectId: 'T01', + name: 'Name', + tbd: 'exists', + className:"Thing", subObject1: {foo:"bar"}, subObject2: {foo:"bar"}, subObject3: {foo:"bar"}, @@ -1660,7 +1660,7 @@ describe('ParseQuery', () => { var testObject; return q.find().then((results) => { testObject = results[0]; - + expect(testObject.has("subObject1")).toBe(true); expect(testObject.has("subObject2")).toBe(true); expect(testObject.has("subObject3")).toBe(true); @@ -1675,7 +1675,7 @@ describe('ParseQuery', () => { expect(testObject.has("subObject2")).toBe(false); //selected and not returned expect(testObject.has("subObject3")).toBe(true); //not selected, so should still be there expect(testObject.has("subObject4")).toBe(true); //selected and just added - expect(testObject.has("subObject5")).toBe(true); + expect(testObject.has("subObject5")).toBe(true); expect(testObject.get("subObject5").subSubObject).toBeDefined(); expect(testObject.get("subObject5").subSubObject.bar).toBeDefined(); //not selected but a sibiling was, so should still be there }).then(() => { @@ -1685,4 +1685,67 @@ describe('ParseQuery', () => { }); }); + it('full text search with one parameter', () => { + let query = new ParseQuery('Item'); + + query.fullTextSearch('size', 'small'); + + expect(query.toJSON()).toEqual({ + where: { + size: { + $text: { + $search: { + $term: "small" + } + } + } + } + }); + }); + + it('full text search with all parameters', () => { + let query = new ParseQuery('Item'); + + query.fullTextSearch('size', 'medium', 'en', false, true); + + expect(query.toJSON()).toEqual({ + where: { + size: { + $text: { + $search: { + $term: "medium", + $language: "en", + $caseSensitive: false, + $diacriticSensitive: true + } + } + } + } + }); + + }); + + it('add the score for the full text search', () => { + let query = new ParseQuery('Item'); + + query.fullTextSearch('size', 'medium', 'fr'); + query.sortByTextScore(); + + expect(query.toJSON()).toEqual({ + where: { + size: { + $text: { + $search: { + $term: "medium", + $language: "fr" + } + } + } + }, + keys : "$score", + order : "$score" + }); + + }); + }); From 1012bb0c8785c89d823b0287f3f1b68f60ff298d Mon Sep 17 00:00:00 2001 From: SebC99 Date: Fri, 3 Nov 2017 11:04:26 +0100 Subject: [PATCH 2/2] Fix inadequate if statements --- src/ParseQuery.js | 62 +++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/ParseQuery.js b/src/ParseQuery.js index 372241ba1..c05fd0587 100644 --- a/src/ParseQuery.js +++ b/src/ParseQuery.js @@ -1032,37 +1032,37 @@ export default class ParseQuery { return this._addCondition(key, '$geoIntersects', { '$point': point }); } - /** - * Method to find by full text. - * The key and the search fields are required the others are optionals. - * @method fullTextSearch - * @param {String} key The key to structure the where query - * @param {String} search The string to search - * @param {String} language Determine the list of stop words - * @param {Boolean} caseSensitive Dis/en-able the case sensitive search - * @param {Boolean} diacriticSensitive Dis/en-able diacritic sensitive search - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - fullTextSearch(key: string, search: string, language: string, caseSensitive: boolean, diacriticSensitive: boolean): ParseQuery { - if (typeof key === 'undefined' || !key) { - throw new Error('A key is required.'); - } - if (typeof search === 'undefined' || !search) { - throw new Error('You have to add one string to search.'); - } - var options = { '$term': search }; - if (typeof language !== "undefined" || language !== null) { - options['$language'] = language; - } - if (typeof caseSensitive !== "undefined" || caseSensitive !== null) { - options['$caseSensitive'] = caseSensitive; - } - if (typeof diacriticSensitive !== "undefined" || diacriticSensitive !== null) { - options['$diacriticSensitive'] = diacriticSensitive; - } - return this._addCondition(key, '$text', { '$search': options }); - } - + /** + * Method to find by full text. + * The key and the search fields are required the others are optionals. + * @method fullTextSearch + * @param {String} key The key to structure the where query + * @param {String} search The string to search + * @param {String} language Determine the list of stop words + * @param {Boolean} caseSensitive Dis/en-able the case sensitive search + * @param {Boolean} diacriticSensitive Dis/en-able diacritic sensitive search + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + fullTextSearch(key: string, search: string, language: string, caseSensitive: boolean, diacriticSensitive: boolean): ParseQuery { + if (!key) { + throw new Error('A key is required.'); + } + if (typeof search !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + var options = { '$term': search }; + if (typeof language === 'string') { + options['$language'] = language; + } + if (typeof caseSensitive === "boolean") { + options['$caseSensitive'] = caseSensitive; + } + if (typeof diacriticSensitive === "boolean") { + options['$diacriticSensitive'] = diacriticSensitive; + } + return this._addCondition(key, '$text', { '$search': options }); + } + /** Query Orderings **/ /**