From ff90f5132b0cfa7bf9f083ee54996dda5412be4e Mon Sep 17 00:00:00 2001 From: john gravois Date: Wed, 24 Apr 2019 15:59:17 -0700 Subject: [PATCH 1/3] fix(search): ensure no space is inserted between search fields and terms AFFECTS PACKAGES: @esri/arcgis-rest-portal ISSUES CLOSED: #545 --- .../src/util/SearchQueryBuilder.ts | 4 ++-- .../test/groups/search.test.ts | 2 +- .../test/items/search.test.ts | 4 ++-- .../test/util/SearchQueryBuilder.test.ts | 20 +++++++++---------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts b/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts index 0d30aeb22b..b42ae74137 100644 --- a/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts +++ b/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts @@ -27,7 +27,7 @@ import { IParamBuilder, warn } from "@esri/arcgis-rest-request"; * * Will search for items matching * ``` - * "owner: Patrick AND (type: "Web Mapping Application" OR type: "Mobile Application" OR type: Application) AND Demo App" + * "owner: Patrick AND (type:"Web Mapping Application" OR type:"Mobile Application" OR type:Application) AND Demo App" * ``` */ export class SearchQueryBuilder implements IParamBuilder { @@ -82,7 +82,7 @@ export class SearchQueryBuilder implements IParamBuilder { } if (field && field !== "*") { - this.q += `${field}: `; + this.q += `${field}:`; } return this.commit(); diff --git a/packages/arcgis-rest-portal/test/groups/search.test.ts b/packages/arcgis-rest-portal/test/groups/search.test.ts index eedc2e9e38..34d36cda09 100644 --- a/packages/arcgis-rest-portal/test/groups/search.test.ts +++ b/packages/arcgis-rest-portal/test/groups/search.test.ts @@ -55,7 +55,7 @@ describe("groups", () => { it("should make a simple, single search request with a builder", done => { fetchMock.once("*", GroupSearchResponse); - const expectedParam = "Trees AND owner: USFS"; + const expectedParam = "Trees AND owner:USFS"; const q = new SearchQueryBuilder() .match("Trees") .and() diff --git a/packages/arcgis-rest-portal/test/items/search.test.ts b/packages/arcgis-rest-portal/test/items/search.test.ts index 6fbac5875a..4acbc577e2 100644 --- a/packages/arcgis-rest-portal/test/items/search.test.ts +++ b/packages/arcgis-rest-portal/test/items/search.test.ts @@ -33,7 +33,7 @@ describe("search", () => { it("should make a simple, single search request with a builder", done => { fetchMock.once("*", SearchResponse); - const expectedParam = "DC AND typekeywords: hubSiteApplication"; + const expectedParam = "DC AND typekeywords:hubSiteApplication"; const q = new SearchQueryBuilder() .match("DC") .and() @@ -108,7 +108,7 @@ describe("search", () => { it("should pass through other requestOptions at the same time with a builder", done => { fetchMock.once("*", SearchResponse); - const expectedParam = "DC AND typekeywords: hubSiteApplication"; + const expectedParam = "DC AND typekeywords:hubSiteApplication"; const q = new SearchQueryBuilder() .match("DC") .and() diff --git a/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts b/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts index 5437e00d18..40b24d1cd5 100644 --- a/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts +++ b/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts @@ -31,7 +31,7 @@ describe("SearchQueryBuilder", () => { .match("test") .in("tags") .toParam(); - expect(query).toEqual("tags: test"); + expect(query).toEqual("tags:test"); }); it("should warp multi word search terms in quotes", () => { @@ -63,7 +63,7 @@ describe("SearchQueryBuilder", () => { .in("tags") .toParam(); - expect(query).toEqual("bar AND tags: foo"); + expect(query).toEqual("bar AND tags:foo"); }); it("should format a simple range", () => { @@ -72,7 +72,7 @@ describe("SearchQueryBuilder", () => { .to("z") .in("title") .toParam(); - expect(query).toEqual("title: [a TO z]"); + expect(query).toEqual("title:[a TO z]"); }); it("should format a simple group", () => { @@ -83,7 +83,7 @@ describe("SearchQueryBuilder", () => { .in("title") .endGroup() .toParam(); - expect(query).toEqual("(title: [a TO z])"); + expect(query).toEqual("(title:[a TO z])"); }); it("should boost the previous search", () => { @@ -110,7 +110,7 @@ describe("SearchQueryBuilder", () => { .toParam(); expect(query).toEqual( - `created: [${expectedDate1} TO ${expectedDate2}] AND tags: test` + `created:[${expectedDate1} TO ${expectedDate2}] AND tags:test` ); }); @@ -135,7 +135,7 @@ describe("SearchQueryBuilder", () => { .toParam(); expect(query).toEqual( - `owner: fred AND (type: "Web Mapping Application" OR type: "Mobile Application" OR type: Application) AND test` + `owner:fred AND (type:"Web Mapping Application" OR type:"Mobile Application" OR type:Application) AND test` ); }); @@ -162,11 +162,11 @@ describe("SearchQueryBuilder", () => { .in("*"); expect(myAppsQuery.toParam()).toEqual( - `owner: fred AND (type: "Web Mapping Application" OR type: "Mobile Application" OR type: Application)` + `owner:fred AND (type:"Web Mapping Application" OR type:"Mobile Application" OR type:Application)` ); expect(myTestAppsQuery.toParam()).toEqual( - `owner: fred AND (type: "Web Mapping Application" OR type: "Mobile Application" OR type: Application) AND test` + `owner:fred AND (type:"Web Mapping Application" OR type:"Mobile Application" OR type:Application) AND test` ); }); @@ -296,7 +296,7 @@ describe("SearchQueryBuilder", () => { .toParam(); expect(console.warn).toHaveBeenCalled(); - expect(query).toEqual("title: a"); + expect(query).toEqual("title:a"); }); it("should not allow .match().from().in(), and warn user", () => { @@ -307,7 +307,7 @@ describe("SearchQueryBuilder", () => { .toParam(); expect(console.warn).toHaveBeenCalled(); - expect(query).toEqual("title: test"); + expect(query).toEqual("title:test"); }); it("should", () => { From 39fc21379a3e78a27636d62cf46d86e23ad666a0 Mon Sep 17 00:00:00 2001 From: john gravois Date: Wed, 24 Apr 2019 16:06:35 -0700 Subject: [PATCH 2/3] fix(search): add support for untyped, grouped search strings AFFECTS PACKAGES: @esri/arcgis-rest-portal ISSUES CLOSED: #544 --- .../src/util/SearchQueryBuilder.ts | 3 ++- .../test/util/SearchQueryBuilder.test.ts | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts b/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts index b42ae74137..76d25604da 100644 --- a/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts +++ b/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts @@ -137,9 +137,10 @@ export class SearchQueryBuilder implements IParamBuilder { ); return this; } + this.commit(); this.openGroups--; this.q += ")"; - return this.commit(); + return this; } /** diff --git a/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts b/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts index 40b24d1cd5..cb73b48f38 100644 --- a/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts +++ b/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts @@ -16,7 +16,7 @@ describe("SearchQueryBuilder", () => { console.warn = originalWarn; }); - it("should return and empty string when called with no other functions", () => { + it("should return an empty string when called with no other functions", () => { const query = new SearchQueryBuilder().toParam(); expect(query).toEqual(""); }); @@ -86,6 +86,19 @@ describe("SearchQueryBuilder", () => { expect(query).toEqual("(title:[a TO z])"); }); + it("should format a more complex group", () => { + const query = new SearchQueryBuilder() + .startGroup() + .match("California") + .or() + .match("recent") + .endGroup() + .and() + .match("fires") + .toParam(); + expect(query).toEqual("(California OR recent) AND fires"); + }); + it("should boost the previous search", () => { const query = new SearchQueryBuilder() .match("test") From 36a6bca771dd4282af71dcf454828f58047b525b Mon Sep 17 00:00:00 2001 From: john gravois Date: Wed, 24 Apr 2019 16:29:57 -0700 Subject: [PATCH 3/3] fix(search): allow NOT as a standalone modifier AFFECTS PACKAGES: @esri/arcgis-rest-portal ISSUES CLOSED: #542 --- .../src/util/SearchQueryBuilder.ts | 15 ++++++++++----- .../test/util/SearchQueryBuilder.test.ts | 18 ++++++++++++++---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts b/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts index 76d25604da..c9d651e29d 100644 --- a/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts +++ b/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts @@ -176,15 +176,19 @@ export class SearchQueryBuilder implements IParamBuilder { } /** - * Joins two sets of queries with a `NOT` clause. + * Joins two sets of queries with a `NOT` clause. Another option for filtering results is the [prohibit operator '-'](https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm#ESRI_SECTION1_5C6C35DB9E4A4F4492C5B937BDA2BF67). * * ```js + * // omit results with "Rivers" in their title * const query = new SearchQueryBuilder() - * .match("Water") - * .in("title") * .not() * .match("Rivers") * .in("title") + * + * // equivalent + * const query = new SearchQueryBuilder() + * .match("Rivers") + * .in("-title") * ``` */ public not(this: SearchQueryBuilder) { @@ -283,7 +287,7 @@ export class SearchQueryBuilder implements IParamBuilder { this.commit(); - if (this.q === "") { + if (this.q === "" && modifier !== "not") { warn( `You have called \`${modifier}()\` without calling another method to modify your query first. Try calling \`match()\` first.` ); @@ -291,7 +295,8 @@ export class SearchQueryBuilder implements IParamBuilder { } this.currentModifer = modifier; - this.q += ` ${modifier.toUpperCase()} `; + this.q += this.q === "" ? "" : " "; + this.q += `${modifier.toUpperCase()} `; return this; } diff --git a/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts b/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts index cb73b48f38..304eef670f 100644 --- a/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts +++ b/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts @@ -152,6 +152,19 @@ describe("SearchQueryBuilder", () => { ); }); + it("should allow .not to be called without a preceding search value", () => { + const query = new SearchQueryBuilder() + .not() + .match("public") + .in("access") + .not() + .match("code attachment") + .in("type") + .toParam(); + + expect(query).toEqual(`NOT access:public NOT type:"code attachment"`); + }); + it("should clone searches for modification", () => { const myAppsQuery = new SearchQueryBuilder() .match("fred") @@ -195,11 +208,8 @@ describe("SearchQueryBuilder", () => { it("should not allow chains of logic modifiers, and warn user", () => { const query = new SearchQueryBuilder() - .not() .and() .or() - .not() - .or() .or() .toParam(); @@ -323,7 +333,7 @@ describe("SearchQueryBuilder", () => { expect(query).toEqual("title:test"); }); - it("should", () => { + it("should produce an empty string when no methods are called", () => { const query = new SearchQueryBuilder().toParam(); expect(query).toEqual(""); });