Skip to content

Commit 4091776

Browse files
inverting response compatibility option in a search api
1 parent 7cfc4e1 commit 4091776

File tree

8 files changed

+63
-43
lines changed

8 files changed

+63
-43
lines changed

.github/README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ Both `dataApi` and `searchApi` can be omitted from a configuration. Their defaul
342342
| Property Name | Type | Description |
343343
|--------|--------|--------|
344344
| escapeSpecialCharacters | `boolean` | `v2.3.0+` **Works only with Search API 2.0**. Optional. Escapes special characters in the search string. |
345-
| disableResponseCompatibility | `boolean` | `v2.3.0+`. Disables forced compatibility of the responses between v1 and v2. It's highly recommended to enable this option, because all response properties are duplicated by default for compatibility reasons. |
345+
| enableResponseCompatibility | `boolean` | `v2.3.0+`. Enables compatibility of the responses between v1 and v2. Only enable this option temporarily, because it will force all response properties to be duplicated to achieve a full compatibility. |
346346

347347
## Request Examples
348348

@@ -2196,12 +2196,32 @@ All functions: Query, Suggest and Autocomplete, - can be called with a single `s
21962196
21972197
_Examples below follow Microsoft's official documenation._
21982198
2199-
> [!NOTE]
2199+
> [!IMPORTANT]
22002200
> All request properties are `camelCase`, even though in Dataverse Search API v2.0 they are lowercase.
22012201
2202-
> [!TIP]
2202+
> [!NOTE]
22032203
> All objects in requests and responses are automatically converted and encoded as necessary (per official documentation), simplifying developer's work to construct the request and process the response.
22042204
2205+
> [!TIP]
2206+
> To enable a full compatibility between Search API v1 and v2 responses, you can temporarily set `enableResponseCompatibility` to `true` (in a `searchApi` config, see the code snippet below). The downside is that this will force all properties in the responses to be duplicated which will consume more memory (and cpu), thus it is not enabled by default.
2207+
>
2208+
> This option can be useful to test if your search api v1.0 queries are compatible with v2.0 before rewriting your code. The main compatibility issue could be a `filter` value because its syntax has been changed by Microsoft.
2209+
>
2210+
> Another use-case could be if you would like to rewrite your code to be fully compatible with v2.0 without switching to v2.0 queries (by keeping `version: "1.0"`) and having to deal with exceptions because of the `filter` incompatibility.
2211+
2212+
To turn on the response compatibility:
2213+
2214+
```ts
2215+
const webApi = new DynamicsWebApi({
2216+
searchApi: {
2217+
// version: "2.0",
2218+
options: {
2219+
enableResponseCompatibility: true
2220+
}
2221+
}
2222+
})
2223+
```
2224+
22052225
### Query
22062226
22072227
The following table describes all parameters for a `query` request:

src/dynamics-web-api.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,10 +1121,10 @@ export type SearchApiOptions = {
11211121
*/
11221122
escapeSpecialCharacters?: boolean;
11231123
/**
1124-
* Disables compatibility of the responses between v1 and v2.
1125-
* Enabling this option is highly recommended, because all response properties are duplicated by default for compatibility reasons.
1124+
* Enables compatibility of the responses between v1 and v2.
1125+
* Only enable this option temporarily, because it will force all response properties to be duplicated to achieve a full compatibility.
11261126
*/
1127-
disableResponseCompatibility?: boolean;
1127+
enableResponseCompatibility?: boolean;
11281128
};
11291129

11301130
export interface ApiConfig<TOptions = any> {

src/requests/search/responseParsers/parseAutocompleteResponse.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function parseAutocompleteResponse(queryResponse: AutocompleteResponseInt
1717
response: responseValue,
1818
};
1919

20-
if (!config.disableSearchApiResponseCompatibility) {
20+
if (config.enableSearchApiResponseCompatibility) {
2121
toReturn.value = responseValue.Value;
2222
toReturn.querycontext = responseValue.QueryContext;
2323
}
@@ -28,10 +28,10 @@ export function parseAutocompleteResponse(queryResponse: AutocompleteResponseInt
2828
const toV2 = (): AutocompleteResponse => {
2929
// @ts-ignore we don't enforce to have all properties in the response if the compatibility is disabled
3030
const toReturn: AutocompleteResponse = {
31-
...queryResponse
32-
}
31+
...queryResponse,
32+
};
3333

34-
if (!config.disableSearchApiResponseCompatibility) {
34+
if (config.enableSearchApiResponseCompatibility) {
3535
toReturn.response = {
3636
Value: queryResponse.value,
3737
QueryContext: queryResponse.querycontext,

src/requests/search/responseParsers/parseQueryResponse.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function parseQueryResponse(queryResponse: QueryResponseInternal, config:
1717
response: responseValue,
1818
};
1919

20-
if (!config.disableSearchApiResponseCompatibility) {
20+
if (config.enableSearchApiResponseCompatibility) {
2121
toReturn.value = responseValue.Value;
2222
toReturn.facets = responseValue.Facets;
2323
toReturn.totalrecordcount = responseValue.Count;
@@ -33,7 +33,7 @@ export function parseQueryResponse(queryResponse: QueryResponseInternal, config:
3333
...queryResponse,
3434
};
3535

36-
if (!config.disableSearchApiResponseCompatibility) {
36+
if (config.enableSearchApiResponseCompatibility) {
3737
toReturn.response = {
3838
Count: queryResponse.totalrecordcount,
3939
Value: queryResponse.value,

src/requests/search/responseParsers/parseSuggestResponse.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function parseSuggestResponse(queryResponse: SuggestResponseInternal, con
1212
const toV1 = (): SuggestResponse => {
1313
const responseValue = JSON.parse(queryResponse.response, dateReviver) as SuggestResponse["response"];
1414

15-
if (!config.disableSearchApiResponseCompatibility) {
15+
if (config.enableSearchApiResponseCompatibility) {
1616
responseValue.Value?.forEach((item: SuggestResponseValue) => {
1717
item.document = item.Document;
1818
item.text = item.Text;
@@ -24,7 +24,7 @@ export function parseSuggestResponse(queryResponse: SuggestResponseInternal, con
2424
response: responseValue,
2525
};
2626

27-
if (!config.disableSearchApiResponseCompatibility) {
27+
if (config.enableSearchApiResponseCompatibility) {
2828
toReturn.value = responseValue.Value;
2929
toReturn.querycontext = responseValue.QueryContext;
3030
}
@@ -33,7 +33,7 @@ export function parseSuggestResponse(queryResponse: SuggestResponseInternal, con
3333
};
3434

3535
const toV2 = (): SuggestResponse => {
36-
if (!config.disableSearchApiResponseCompatibility) {
36+
if (config.enableSearchApiResponseCompatibility) {
3737
queryResponse.value?.forEach((item: SuggestResponseValue) => {
3838
item.Document = item.document;
3939
item.Text = item.text;
@@ -45,7 +45,7 @@ export function parseSuggestResponse(queryResponse: SuggestResponseInternal, con
4545
...queryResponse,
4646
};
4747

48-
if (!config.disableSearchApiResponseCompatibility) {
48+
if (config.enableSearchApiResponseCompatibility) {
4949
toReturn.response = {
5050
Value: queryResponse.value,
5151
QueryContext: queryResponse.querycontext,

src/utils/Config.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const apiConfigs: ApiType[] = ["dataApi", "searchApi", "serviceApi"];
1212
export interface InternalApiConfig extends ApiConfig {
1313
url: string;
1414
escapeSpecialCharacters?: boolean;
15-
disableSearchApiResponseCompatibility?: boolean;
15+
enableSearchApiResponseCompatibility?: boolean;
1616
}
1717

1818
export interface InternalConfig extends Config {
@@ -47,9 +47,9 @@ const mergeSearchApiOptions = (internalApiConfig: InternalApiConfig, options: Se
4747
internalApiConfig.escapeSpecialCharacters = options.escapeSpecialCharacters;
4848
}
4949

50-
if (options.disableResponseCompatibility != null) {
51-
ErrorHelper.boolParameterCheck(options.disableResponseCompatibility, FUNCTION_NAME, `config.searchApi.options.disableResponseCompatibility`);
52-
internalApiConfig.disableSearchApiResponseCompatibility = options.disableResponseCompatibility;
50+
if (options.enableResponseCompatibility != null) {
51+
ErrorHelper.boolParameterCheck(options.enableResponseCompatibility, FUNCTION_NAME, `config.searchApi.options.enableResponseCompatibility`);
52+
internalApiConfig.enableSearchApiResponseCompatibility = options.enableResponseCompatibility;
5353
}
5454
};
5555

tests/searchApi.parseQuery.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type { AutocompleteResponse, QueryResponse, SuggestResponse } from "../sr
77

88
describe("parseQueryResponse", () => {
99
it("returns undefined if response is undefined", () => {
10-
const result = parseQueryResponse(undefined!, { version: "2.0", url: "" });
10+
const result = parseQueryResponse(undefined!, { version: "2.0", url: "", enableSearchApiResponseCompatibility: true });
1111
expect(result).to.be.undefined;
1212
});
1313

@@ -31,7 +31,7 @@ describe("parseQueryResponse", () => {
3131
};
3232

3333
it("should parse the query response correctly", () => {
34-
const result = parseQueryResponse(queryResponse, { version: "2.0", url: "" });
34+
const result = parseQueryResponse(queryResponse, { version: "2.0", url: "", enableSearchApiResponseCompatibility: true });
3535
expect(result).to.deep.equal({
3636
...queryResponse,
3737
value: responseValue.Value,
@@ -54,7 +54,7 @@ describe("parseQueryResponse", () => {
5454
};
5555

5656
it("should parse the query response correctly", () => {
57-
const result = parseQueryResponse(queryResponse, { version: "1.0", url: "" });
57+
const result = parseQueryResponse(queryResponse, { version: "1.0", url: "", enableSearchApiResponseCompatibility: true });
5858
expect(result).to.deep.equal({
5959
...queryResponse,
6060
response: {
@@ -71,7 +71,7 @@ describe("parseQueryResponse", () => {
7171

7272
describe("parseSuggestResponse", () => {
7373
it("returns undefined if response is undefined", () => {
74-
const result = parseSuggestResponse(undefined!, { version: "2.0", url: "" });
74+
const result = parseSuggestResponse(undefined!, { version: "2.0", url: "", enableSearchApiResponseCompatibility: true });
7575
expect(result).to.be.undefined;
7676
});
7777

@@ -90,7 +90,7 @@ describe("parseSuggestResponse", () => {
9090
"@odata.context": "https://example.com/#QueryResponse",
9191
};
9292

93-
const result = parseSuggestResponse(queryResponse, { version: "2.0", url: "" });
93+
const result = parseSuggestResponse(queryResponse, { version: "2.0", url: "", enableSearchApiResponseCompatibility: true });
9494

9595
it("should parse the query response correctly", () => {
9696
expect(result).to.deep.equal({
@@ -114,7 +114,7 @@ describe("parseSuggestResponse", () => {
114114
"@odata.context": "https://example.com/#QueryResponse",
115115
};
116116

117-
const result = parseSuggestResponse(queryResponse, { version: "1.0", url: "" });
117+
const result = parseSuggestResponse(queryResponse, { version: "1.0", url: "", enableSearchApiResponseCompatibility: true });
118118

119119
it("should parse the query response correctly", () => {
120120
expect(result).to.deep.equal({
@@ -135,7 +135,7 @@ describe("parseSuggestResponse", () => {
135135

136136
describe("parseAutocompleteResponse", () => {
137137
it("returns undefined if response is undefined", () => {
138-
const result = parseAutocompleteResponse(undefined!, { version: "2.0", url: "" });
138+
const result = parseAutocompleteResponse(undefined!, { version: "2.0", url: "", enableSearchApiResponseCompatibility: true });
139139
expect(result).to.be.undefined;
140140
});
141141

@@ -154,7 +154,7 @@ describe("parseAutocompleteResponse", () => {
154154
"@odata.context": "https://example.com/#QueryResponse",
155155
};
156156

157-
const result = parseAutocompleteResponse(queryResponse, { version: "2.0", url: "" });
157+
const result = parseAutocompleteResponse(queryResponse, { version: "2.0", url: "", enableSearchApiResponseCompatibility: true });
158158

159159
it("should parse the autocomplete response correctly", () => {
160160
expect(result).to.deep.equal({
@@ -174,7 +174,7 @@ describe("parseAutocompleteResponse", () => {
174174
"@odata.context": "https://example.com/#QueryResponse",
175175
};
176176

177-
const result = parseAutocompleteResponse(queryResponse, { version: "1.0", url: "" });
177+
const result = parseAutocompleteResponse(queryResponse, { version: "1.0", url: "", enableSearchApiResponseCompatibility: true });
178178

179179
it("should parse the autocomplete response correctly", () => {
180180
expect(result).to.deep.equal({

tests/searchApi.spec.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ import * as mocks from "./stubs";
55
import { DynamicsWebApi, Query, Autocomplete, Suggest } from "../src/dynamics-web-api";
66

77
const dynamicsWebApiTest = new DynamicsWebApi({
8-
dataApi: {
9-
version: "8.2",
8+
searchApi: {
9+
options: {
10+
enableResponseCompatibility: true,
11+
},
1012
},
1113
});
1214

1315
const dynamicsWebApiSearchV2 = new DynamicsWebApi({
1416
searchApi: {
1517
version: "2.0",
18+
options: {
19+
enableResponseCompatibility: true,
20+
},
1621
},
1722
});
1823

19-
const dynamicsWebApiSearchV1NoCompatibility = new DynamicsWebApi({
20-
searchApi: {
21-
options: { disableResponseCompatibility: true },
22-
},
23-
});
24+
const dynamicsWebApiSearchV1NoCompatibility = new DynamicsWebApi();
2425

2526
const dynamicsWebApiSearchV2NoCompatibility = new DynamicsWebApi({
2627
searchApi: {
2728
version: "2.0",
28-
options: { disableResponseCompatibility: true },
2929
},
3030
});
3131

@@ -170,7 +170,7 @@ describe("dynamicsWebApi.query -", () => {
170170
});
171171
});
172172

173-
describe("v2.0 - disableResponseCompatibility = true", () => {
173+
describe("v2.0 - enableResponseCompatibility = false", () => {
174174
let scope;
175175
const searchQuery: Query = {
176176
search: "test",
@@ -205,7 +205,7 @@ describe("dynamicsWebApi.query -", () => {
205205
});
206206
});
207207

208-
describe("v1.0 - disableResponseCompatibility = true", () => {
208+
describe("v1.0 - enableResponseCompatibility = false", () => {
209209
let scope;
210210
const searchQuery: Query = {
211211
search: "test",
@@ -345,7 +345,7 @@ describe("dynamicsWebApi.suggest -", () => {
345345
});
346346
});
347347

348-
describe("v1.0 - disableResponseCompatibility = true", () => {
348+
describe("v1.0 - enableResponseCompatibility = false", () => {
349349
let scope;
350350
const suggestQuery: Suggest = {
351351
search: "test",
@@ -379,7 +379,7 @@ describe("dynamicsWebApi.suggest -", () => {
379379
});
380380
});
381381

382-
describe("v2.0 - disableResponseCompatibility = true", () => {
382+
describe("v2.0 - enableResponseCompatibility = false", () => {
383383
let scope;
384384
const suggestQuery: Suggest = {
385385
search: "test",
@@ -517,7 +517,7 @@ describe("dynamicsWebApi.autocomplete -", () => {
517517
expect(scope.isDone()).to.be.true;
518518
});
519519
});
520-
describe("v1.0 - disableResponseCompatibility = true", () => {
520+
describe("v1.0 - enableResponseCompatibility = false", () => {
521521
let scope;
522522
const autocompleteQuery: Autocomplete = {
523523
search: "test",
@@ -550,7 +550,7 @@ describe("dynamicsWebApi.autocomplete -", () => {
550550
expect(scope.isDone()).to.be.true;
551551
});
552552
});
553-
describe("v2.0 - disableResponseCompatibility = true", () => {
553+
describe("v2.0 - enableResponseCompatibility = false", () => {
554554
let scope;
555555
const autocompleteQuery: Autocomplete = {
556556
search: "test",

0 commit comments

Comments
 (0)