@dynatrace-sdk/client-query 1.19.0 → 1.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  @dynatrace-sdk/client-query
4
4
 
5
+ ## 1.20.2
6
+
7
+ ### Patch Changes
8
+
9
+ - Improve performance of date transformations. (APPDEV-12840)
10
+
11
+ ## 1.20.1
12
+
13
+ ### Patch Changes
14
+
15
+ - Improve performance of payload transformations. (APPDEV-12840)
16
+ - Remove generatedAt property from metadata file. (APPDEV-12696)
17
+
18
+ ## 1.20.0
19
+
20
+ ### Minor changes
21
+
22
+ - Add request body parameter `includeTypes` to `ExecuteRequest`
23
+ - Add header `dt-client-context` to all query endpoints
24
+ - Add `enforce-query-consumption-limit` header to `/query:execute` and `/query:autocomplete` endpoints
25
+
5
26
  ## 1.19.0
6
27
 
7
28
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @dynatrace-sdk/client-query
2
2
 
3
- [![npm](https://img.shields.io/badge/npm-v1.19.0-blue)](https://www.npmjs.com/package/@dynatrace-sdk/client-query/v/1.19.0)
3
+ [![npm](https://img.shields.io/badge/npm-v1.20.2-blue)](https://www.npmjs.com/package/@dynatrace-sdk/client-query/v/1.20.2)
4
4
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
5
 
6
6
  Exposes an API to fetch records stored in Grail
@@ -88,9 +88,11 @@ a link to docs, etc.
88
88
 
89
89
  #### Parameters
90
90
 
91
- | Name | Type |
92
- | --- | --- |
93
- |config.body<sup>*required</sup>|<a href="#autocompleterequest" target="_blank" rel="noopener noreferrer">AutocompleteRequest</a>|
91
+ | Name | Type | Description |
92
+ | --- | --- | --- |
93
+ |config.body<sup>*required</sup>|<a href="#autocompleterequest" target="_blank" rel="noopener noreferrer">AutocompleteRequest</a>| |
94
+ |config.dtClientContext|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. |
95
+ |config.enforceQueryConsumptionLimit|[boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean)|If set, query consumption limit will be enforced. |
94
96
 
95
97
 
96
98
 
@@ -341,9 +343,10 @@ When displaying the query, pick one option. You may use the other options for ho
341
343
 
342
344
  #### Parameters
343
345
 
344
- | Name | Type |
345
- | --- | --- |
346
- |config.body<sup>*required</sup>|<a href="#parserequest" target="_blank" rel="noopener noreferrer">ParseRequest</a>|
346
+ | Name | Type | Description |
347
+ | --- | --- | --- |
348
+ |config.body<sup>*required</sup>|<a href="#parserequest" target="_blank" rel="noopener noreferrer">ParseRequest</a>| |
349
+ |config.dtClientContext|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. |
347
350
 
348
351
 
349
352
 
@@ -409,9 +412,10 @@ submitting the query for execution.
409
412
 
410
413
  #### Parameters
411
414
 
412
- | Name | Type |
413
- | --- | --- |
414
- |config.body<sup>*required</sup>|<a href="#verifyrequest" target="_blank" rel="noopener noreferrer">VerifyRequest</a>|
415
+ | Name | Type | Description |
416
+ | --- | --- | --- |
417
+ |config.body<sup>*required</sup>|<a href="#verifyrequest" target="_blank" rel="noopener noreferrer">VerifyRequest</a>| |
418
+ |config.dtClientContext|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. |
415
419
 
416
420
 
417
421
 
@@ -513,6 +517,7 @@ It is guaranteed that every field of every record will have a corresponding type
513
517
 
514
518
  | Name | Type | Description |
515
519
  | --- | --- | --- |
520
+ |config.dtClientContext|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. |
516
521
  |config.enrich|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|If set additional data will be available in the metadata section. |
517
522
  |config.requestToken<sup>*required</sup>|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The request-token of the query. |
518
523
 
@@ -523,7 +528,7 @@ It is guaranteed that every field of every record will have a corresponding type
523
528
 
524
529
  | Return type | Description |
525
530
  |---|---|
526
- |Promise&lt;QueryPollResponse | void&gt;|The query already finished.|
531
+ |Promise&lt;QueryPollResponse \| void&gt;|The query already finished.|
527
532
 
528
533
 
529
534
  #### Throws
@@ -609,6 +614,8 @@ It is guaranteed that every field of every record will have a corresponding type
609
614
  | Name | Type | Description |
610
615
  | --- | --- | --- |
611
616
  |config.body<sup>*required</sup>|<a href="#executerequest">ExecuteRequest</a>| |
617
+ |config.dtClientContext|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. |
618
+ |config.enforceQueryConsumptionLimit|[boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean)|If set, query consumption limit will be enforced. |
612
619
  |config.enrich|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|If set additional data will be available in the metadata section. |
613
620
 
614
621
 
@@ -704,6 +711,7 @@ It is guaranteed that every field of every record will have a corresponding type
704
711
 
705
712
  | Name | Type | Description |
706
713
  | --- | --- | --- |
714
+ |config.dtClientContext|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. |
707
715
  |config.enrich|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|If set additional data will be available in the metadata section. |
708
716
  |config.requestTimeoutMilliseconds|[number](https://developer.mozilla.org/en-US/docs/Glossary/Number)|The time a client is willing to wait for the query result. In case the query finishes within the specified timeout, the query result is returned. Otherwise, the query status is returned. |
709
717
  |config.requestToken<sup>*required</sup>|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The request-token of the query. |
@@ -890,12 +898,13 @@ Detailed information about the error.
890
898
  |enablePreview|[boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean)|Request preview results. If a preview is available within the requestTimeoutMilliseconds, then it will be returned as part of the response. |
891
899
  |fetchTimeoutSeconds|[number](https://developer.mozilla.org/en-US/docs/Glossary/Number)|The query will stop reading data after reaching the fetch-timeout. The query execution will continue, providing a partial result based on the read data. |
892
900
  |filterSegments|<a href="#filtersegments">FilterSegments</a>|Represents a collection of filter segments. |
901
+ |includeTypes|[boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean)|Parameter to exclude the type information from the query result. In case not specified, the type information will be included. <i>default:</i> <code>true</code>|
893
902
  |locale|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The query locale. If none specified, then a language/country neutral locale is chosen. The input values take the ISO-639 Language code with an optional ISO-3166 country code appended to it with an underscore. For instance, both values are valid 'en' or 'en_US'. |
894
903
  |maxResultBytes|[number](https://developer.mozilla.org/en-US/docs/Glossary/Number)|The maximum number of result bytes that this query will return. |
895
904
  |maxResultRecords|[number](https://developer.mozilla.org/en-US/docs/Glossary/Number)|The maximum number of result records that this query will return. |
896
905
  |query<sup>*required</sup>|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The full query string. |
897
906
  |queryOptions|<a href="#queryoptions" target="_blank" rel="noopener noreferrer">QueryOptions</a>|Query options enhance query functionality for Dynatrace internal services. |
898
- |requestTimeoutMilliseconds|[number](https://developer.mozilla.org/en-US/docs/Glossary/Number)|The time a client is willing to wait for the query result. In case the query finishes within the specified timeout, the query result is returned. Otherwise, the requestToken is returned, allowing polling for the result. |
907
+ |requestTimeoutMilliseconds|[number](https://developer.mozilla.org/en-US/docs/Glossary/Number)|The maximum time the response will be delayed to wait for a result. (This excludes the sending time and time spent in any services between the query-frontend and the client.) If the query finishes within the specified timeout, the query result is returned. Otherwise, the requestToken is returned, allowing polling for the result. |
899
908
  |timezone|[string](https://developer.mozilla.org/en-US/docs/Glossary/String)|The query timezone. If none is specified, UTC is used as fallback. The list of valid input values matches that of the IANA Time Zone Database (TZDB). It accepts values in their canonical names like 'Europe/Paris', the abbreviated version like CET or the UTC offset format like '+01:00' |
900
909
 
901
910
  ### FieldType
package/cjs/index.js CHANGED
@@ -123,49 +123,93 @@ function mergeKeys(key1, key2) {
123
123
  return key1;
124
124
  return `${key1}.${key2}`;
125
125
  }
126
- function matchKey(key, keys) {
127
- const match = keys.find((k) => {
128
- const ruleKey = Array.isArray(k) ? k[0] : k;
129
- if (key === ruleKey) {
130
- return true;
126
+ function matchKey(key, rules, cache) {
127
+ if (cache.has(key)) {
128
+ return cache.get(key);
129
+ }
130
+ for (const rule of rules) {
131
+ const pattern = Array.isArray(rule) ? rule[0] : rule;
132
+ const config = Array.isArray(rule) ? rule[1] : defaultRuleConfig;
133
+ if (key === pattern) {
134
+ const result = [pattern, config];
135
+ cache.set(key, result);
136
+ return result;
131
137
  }
132
- if (!key || !ruleKey) {
133
- return false;
138
+ let i = 0;
139
+ let j = 0;
140
+ const keyLen = key.length;
141
+ const patternLen = pattern.length;
142
+ let isMatch = true;
143
+ while (i < keyLen && j < patternLen) {
144
+ let keyPartEnd = key.indexOf(".", i);
145
+ let patternPartEnd = pattern.indexOf(".", j);
146
+ if (keyPartEnd === -1)
147
+ keyPartEnd = keyLen;
148
+ if (patternPartEnd === -1)
149
+ patternPartEnd = patternLen;
150
+ const keyPart = key.slice(i, keyPartEnd);
151
+ const patternPart = pattern.slice(j, patternPartEnd);
152
+ if (patternPart !== "*" && patternPart !== "**" && keyPart !== patternPart) {
153
+ isMatch = false;
154
+ break;
155
+ }
156
+ i = keyPartEnd + 1;
157
+ j = patternPartEnd + 1;
134
158
  }
135
- const [keyParts, ruleKeyParts] = [key.split("."), ruleKey.split(".")];
136
- const [keyPartsReversed, ruleKeyPartsReversed] = [[...keyParts].reverse(), [...ruleKeyParts].reverse()];
137
- let wildcard = false;
138
- let matchResult = true;
139
- keyParts.forEach((keyPart, idx) => {
140
- if (keyPart !== ruleKeyParts[idx] && !wildcard) {
141
- if (ruleKeyParts[idx] === "**") {
142
- wildcard = true;
143
- } else if (ruleKeyParts[idx] === "*") {
144
- wildcard = true;
145
- } else {
146
- matchResult = false;
159
+ if (isMatch) {
160
+ if (j < patternLen) {
161
+ const remaining = pattern.slice(j);
162
+ if (remaining !== "**" && remaining !== "*") {
163
+ isMatch = false;
147
164
  }
148
165
  }
149
- });
150
- wildcard = false;
151
- keyPartsReversed.forEach((keyPart, idx) => {
152
- if (keyPart !== ruleKeyPartsReversed[idx] && !wildcard) {
153
- if (ruleKeyPartsReversed[idx] === "**") {
154
- wildcard = true;
155
- } else if (ruleKeyPartsReversed[idx] === "*") {
156
- wildcard = true;
157
- } else {
158
- matchResult = false;
159
- }
166
+ if (i < keyLen && pattern.slice(j - 1) !== "**") {
167
+ isMatch = false;
160
168
  }
161
- });
162
- return matchResult;
163
- });
164
- if (match) {
165
- return Array.isArray(match) ? match : [match, defaultRuleConfig];
169
+ }
170
+ if (isMatch) {
171
+ const result = [pattern, config];
172
+ cache.set(key, result);
173
+ return result;
174
+ }
166
175
  }
176
+ cache.set(key, null);
167
177
  return null;
168
178
  }
179
+ var potentialMatchForRoot = (pattern, key) => pattern.startsWith(key) || pattern.startsWith("*") || pattern.startsWith("**");
180
+ var potentialMatch = (pattern, key) => pattern.startsWith(key) || pattern.includes("*") || pattern.includes("**");
181
+ function partialMatch(key, keyPatterns) {
182
+ const keyPatternsLen = keyPatterns.length;
183
+ if (!key.includes(".")) {
184
+ for (let i = 0; i < keyPatternsLen; i++) {
185
+ const pattern = keyPatterns[i];
186
+ if (potentialMatchForRoot(pattern, key))
187
+ return true;
188
+ }
189
+ return false;
190
+ }
191
+ let dotIndex = -1;
192
+ let currentKeyEnd = 0;
193
+ while ((dotIndex = key.indexOf(".", currentKeyEnd)) !== -1) {
194
+ const currentKey = key.slice(0, dotIndex);
195
+ const isRoot = !currentKey.includes(".");
196
+ for (let i = 0; i < keyPatternsLen; i++) {
197
+ const pattern = keyPatterns[i];
198
+ if (isRoot) {
199
+ if (potentialMatchForRoot(pattern, currentKey))
200
+ return true;
201
+ } else if (potentialMatch(pattern, currentKey))
202
+ return true;
203
+ }
204
+ currentKeyEnd = dotIndex + 1;
205
+ }
206
+ for (let i = 0; i < keyPatternsLen; i++) {
207
+ const pattern = keyPatterns[i];
208
+ if (potentialMatch(pattern, key))
209
+ return true;
210
+ }
211
+ return false;
212
+ }
169
213
  var dateTimePattern = /^((?:(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?))(Z|[+-]\d{2}:\d{2})?)$/i;
170
214
  function isDateLike(value) {
171
215
  if (typeof value === "string") {
@@ -184,37 +228,48 @@ function transformValue(value, rules, direction) {
184
228
  }
185
229
  return value;
186
230
  }
187
- function transform(direction, object, keys) {
188
- function walk(obj, currentKey = "") {
189
- if (Array.isArray(obj)) {
190
- obj.forEach((item, idx) => {
191
- const match = matchKey(currentKey, keys);
192
- if (typeof item === "object" && item !== null) {
193
- walk(item, currentKey);
194
- } else if (match) {
195
- obj[idx] = transformValue(obj[idx], match[1], direction);
196
- }
197
- });
198
- }
199
- if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
200
- for (const key of Object.keys(obj)) {
201
- const mergedKey = mergeKeys(currentKey, key);
202
- const match = matchKey(mergedKey, keys);
203
- if (match) {
204
- obj[key] = transformValue(obj[key], match[1], direction);
205
- }
206
- walk(obj[key], mergedKey);
231
+ function walk(obj, direction, rules, rulesCache, keyPatterns, currentKey = "") {
232
+ if (rules.length <= 0) {
233
+ return obj;
234
+ }
235
+ if (!partialMatch(currentKey, keyPatterns)) {
236
+ return obj;
237
+ }
238
+ if (Array.isArray(obj)) {
239
+ const match = matchKey(currentKey, rules, rulesCache);
240
+ obj.forEach((item, idx) => {
241
+ if (typeof item === "object" && item !== null) {
242
+ walk(item, direction, rules, rulesCache, keyPatterns, currentKey);
243
+ } else if (match) {
244
+ obj[idx] = transformValue(obj[idx], match[1], direction);
207
245
  }
246
+ });
247
+ }
248
+ if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
249
+ for (const key of Object.keys(obj)) {
250
+ const mergedKey = mergeKeys(currentKey, key);
251
+ const match = matchKey(mergedKey, rules, rulesCache);
252
+ if (match) {
253
+ obj[key] = transformValue(obj[key], match[1], direction);
254
+ }
255
+ walk(obj[key], direction, rules, rulesCache, keyPatterns, mergedKey);
208
256
  }
209
- return obj;
210
257
  }
211
- return walk(object);
258
+ return obj;
212
259
  }
213
- function transformRequest(object, keys) {
214
- return transform("from", object, keys);
260
+ function flattenKeyPatterns(keyPatterns) {
261
+ return keyPatterns.map((k) => Array.isArray(k) ? k[0] : k);
215
262
  }
216
- function transformResponse(object, keys) {
217
- return transform("to", object, keys);
263
+ function transform(direction, object, rules) {
264
+ const flatKeyPatterns = flattenKeyPatterns(rules);
265
+ const rulesCache = /* @__PURE__ */ new Map();
266
+ return walk(object, direction, rules, rulesCache, flatKeyPatterns);
267
+ }
268
+ function transformRequest(object, rules) {
269
+ return transform("from", object, rules);
270
+ }
271
+ function transformResponse(object, rules) {
272
+ return transform("to", object, rules);
218
273
  }
219
274
 
220
275
  // packages/client/query/src/lib/apis/query-assistance-api.ts
@@ -263,6 +318,9 @@ var QueryAssistanceClient = class {
263
318
  throw new import_shared_errors3.ApiClientError("API client error", "API client call is missing mandatory config parameter");
264
319
  }
265
320
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
321
+ const headerParameters = {
322
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
323
+ };
266
324
  try {
267
325
  const response = await this.httpClient.send({
268
326
  url: `/platform/storage/query/v1/query:verify`,
@@ -271,7 +329,8 @@ var QueryAssistanceClient = class {
271
329
  body: encodedBody,
272
330
  headers: {
273
331
  "Content-Type": "application/json",
274
- Accept: "application/json"
332
+ Accept: "application/json",
333
+ ...headerParameters
275
334
  },
276
335
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
277
336
  statusValidator: (status) => {
@@ -599,6 +658,9 @@ var QueryAssistanceClient = class {
599
658
  throw new import_shared_errors3.ApiClientError("API client error", "API client call is missing mandatory config parameter");
600
659
  }
601
660
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
661
+ const headerParameters = {
662
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
663
+ };
602
664
  try {
603
665
  const response = await this.httpClient.send({
604
666
  url: `/platform/storage/query/v1/query:parse`,
@@ -607,7 +669,8 @@ var QueryAssistanceClient = class {
607
669
  body: encodedBody,
608
670
  headers: {
609
671
  "Content-Type": "application/json",
610
- Accept: "application/json"
672
+ Accept: "application/json",
673
+ ...headerParameters
611
674
  },
612
675
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
613
676
  statusValidator: (status) => {
@@ -782,6 +845,12 @@ var QueryAssistanceClient = class {
782
845
  throw new import_shared_errors3.ApiClientError("API client error", "API client call is missing mandatory config parameter");
783
846
  }
784
847
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
848
+ const headerParameters = {
849
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) },
850
+ ...config.enforceQueryConsumptionLimit !== void 0 && {
851
+ "enforce-query-consumption-limit": String(config.enforceQueryConsumptionLimit)
852
+ }
853
+ };
785
854
  try {
786
855
  const response = await this.httpClient.send({
787
856
  url: `/platform/storage/query/v1/query:autocomplete`,
@@ -790,7 +859,8 @@ var QueryAssistanceClient = class {
790
859
  body: encodedBody,
791
860
  headers: {
792
861
  "Content-Type": "application/json",
793
- Accept: "application/json"
862
+ Accept: "application/json",
863
+ ...headerParameters
794
864
  },
795
865
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
796
866
  statusValidator: (status) => {
@@ -1045,12 +1115,16 @@ var QueryExecutionClient = class {
1045
1115
  },
1046
1116
  { explode: { "request-token": false, "request-timeout-milliseconds": false } }
1047
1117
  );
1118
+ const headerParameters = {
1119
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
1120
+ };
1048
1121
  try {
1049
1122
  const response = await this.httpClient.send({
1050
1123
  url: `/platform/storage/query/v1/query:poll${query}`,
1051
1124
  method: "GET",
1052
1125
  headers: {
1053
- Accept: "application/json"
1126
+ Accept: "application/json",
1127
+ ...headerParameters
1054
1128
  },
1055
1129
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
1056
1130
  statusValidator: (status) => {
@@ -1247,6 +1321,12 @@ var QueryExecutionClient = class {
1247
1321
  }
1248
1322
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
1249
1323
  const query = toQueryString({ enrich: config.enrich });
1324
+ const headerParameters = {
1325
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) },
1326
+ ...config.enforceQueryConsumptionLimit !== void 0 && {
1327
+ "enforce-query-consumption-limit": String(config.enforceQueryConsumptionLimit)
1328
+ }
1329
+ };
1250
1330
  try {
1251
1331
  const response = await this.httpClient.send({
1252
1332
  url: `/platform/storage/query/v1/query:execute${query}`,
@@ -1255,7 +1335,8 @@ var QueryExecutionClient = class {
1255
1335
  body: encodedBody,
1256
1336
  headers: {
1257
1337
  "Content-Type": "application/json",
1258
- Accept: "application/json"
1338
+ Accept: "application/json",
1339
+ ...headerParameters
1259
1340
  },
1260
1341
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
1261
1342
  statusValidator: (status) => {
@@ -1617,12 +1698,16 @@ var QueryExecutionClient = class {
1617
1698
  { "request-token": config.requestToken, enrich: config.enrich },
1618
1699
  { explode: { "request-token": false } }
1619
1700
  );
1701
+ const headerParameters = {
1702
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
1703
+ };
1620
1704
  try {
1621
1705
  const response = await this.httpClient.send({
1622
1706
  url: `/platform/storage/query/v1/query:cancel${query}`,
1623
1707
  method: "POST",
1624
1708
  headers: {
1625
- Accept: "application/json"
1709
+ Accept: "application/json",
1710
+ ...headerParameters
1626
1711
  },
1627
1712
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
1628
1713
  statusValidator: (status) => {
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "dynagen": {
3
- "version": "0.18.0",
4
- "generatedAt": "2025-03-12T14:13:49.759Z",
3
+ "version": "0.19.2",
5
4
  "template": {
6
5
  "name": "@dynatrace-sdk/template-typescript-client",
7
- "version": "0.33.2"
6
+ "version": "0.33.7"
8
7
  },
9
8
  "featureFlags": {
10
9
  "typeguards": true
@@ -12,7 +11,7 @@
12
11
  },
13
12
  "spec": {
14
13
  "title": "DQL Query",
15
- "version": "1.14.0",
14
+ "version": "1.15.0",
16
15
  "baseUrl": "/platform/storage/query/v1"
17
16
  }
18
17
  }
package/esm/index.js CHANGED
@@ -88,49 +88,93 @@ function mergeKeys(key1, key2) {
88
88
  return key1;
89
89
  return `${key1}.${key2}`;
90
90
  }
91
- function matchKey(key, keys) {
92
- const match = keys.find((k) => {
93
- const ruleKey = Array.isArray(k) ? k[0] : k;
94
- if (key === ruleKey) {
95
- return true;
91
+ function matchKey(key, rules, cache) {
92
+ if (cache.has(key)) {
93
+ return cache.get(key);
94
+ }
95
+ for (const rule of rules) {
96
+ const pattern = Array.isArray(rule) ? rule[0] : rule;
97
+ const config = Array.isArray(rule) ? rule[1] : defaultRuleConfig;
98
+ if (key === pattern) {
99
+ const result = [pattern, config];
100
+ cache.set(key, result);
101
+ return result;
96
102
  }
97
- if (!key || !ruleKey) {
98
- return false;
103
+ let i = 0;
104
+ let j = 0;
105
+ const keyLen = key.length;
106
+ const patternLen = pattern.length;
107
+ let isMatch = true;
108
+ while (i < keyLen && j < patternLen) {
109
+ let keyPartEnd = key.indexOf(".", i);
110
+ let patternPartEnd = pattern.indexOf(".", j);
111
+ if (keyPartEnd === -1)
112
+ keyPartEnd = keyLen;
113
+ if (patternPartEnd === -1)
114
+ patternPartEnd = patternLen;
115
+ const keyPart = key.slice(i, keyPartEnd);
116
+ const patternPart = pattern.slice(j, patternPartEnd);
117
+ if (patternPart !== "*" && patternPart !== "**" && keyPart !== patternPart) {
118
+ isMatch = false;
119
+ break;
120
+ }
121
+ i = keyPartEnd + 1;
122
+ j = patternPartEnd + 1;
99
123
  }
100
- const [keyParts, ruleKeyParts] = [key.split("."), ruleKey.split(".")];
101
- const [keyPartsReversed, ruleKeyPartsReversed] = [[...keyParts].reverse(), [...ruleKeyParts].reverse()];
102
- let wildcard = false;
103
- let matchResult = true;
104
- keyParts.forEach((keyPart, idx) => {
105
- if (keyPart !== ruleKeyParts[idx] && !wildcard) {
106
- if (ruleKeyParts[idx] === "**") {
107
- wildcard = true;
108
- } else if (ruleKeyParts[idx] === "*") {
109
- wildcard = true;
110
- } else {
111
- matchResult = false;
124
+ if (isMatch) {
125
+ if (j < patternLen) {
126
+ const remaining = pattern.slice(j);
127
+ if (remaining !== "**" && remaining !== "*") {
128
+ isMatch = false;
112
129
  }
113
130
  }
114
- });
115
- wildcard = false;
116
- keyPartsReversed.forEach((keyPart, idx) => {
117
- if (keyPart !== ruleKeyPartsReversed[idx] && !wildcard) {
118
- if (ruleKeyPartsReversed[idx] === "**") {
119
- wildcard = true;
120
- } else if (ruleKeyPartsReversed[idx] === "*") {
121
- wildcard = true;
122
- } else {
123
- matchResult = false;
124
- }
131
+ if (i < keyLen && pattern.slice(j - 1) !== "**") {
132
+ isMatch = false;
125
133
  }
126
- });
127
- return matchResult;
128
- });
129
- if (match) {
130
- return Array.isArray(match) ? match : [match, defaultRuleConfig];
134
+ }
135
+ if (isMatch) {
136
+ const result = [pattern, config];
137
+ cache.set(key, result);
138
+ return result;
139
+ }
131
140
  }
141
+ cache.set(key, null);
132
142
  return null;
133
143
  }
144
+ var potentialMatchForRoot = (pattern, key) => pattern.startsWith(key) || pattern.startsWith("*") || pattern.startsWith("**");
145
+ var potentialMatch = (pattern, key) => pattern.startsWith(key) || pattern.includes("*") || pattern.includes("**");
146
+ function partialMatch(key, keyPatterns) {
147
+ const keyPatternsLen = keyPatterns.length;
148
+ if (!key.includes(".")) {
149
+ for (let i = 0; i < keyPatternsLen; i++) {
150
+ const pattern = keyPatterns[i];
151
+ if (potentialMatchForRoot(pattern, key))
152
+ return true;
153
+ }
154
+ return false;
155
+ }
156
+ let dotIndex = -1;
157
+ let currentKeyEnd = 0;
158
+ while ((dotIndex = key.indexOf(".", currentKeyEnd)) !== -1) {
159
+ const currentKey = key.slice(0, dotIndex);
160
+ const isRoot = !currentKey.includes(".");
161
+ for (let i = 0; i < keyPatternsLen; i++) {
162
+ const pattern = keyPatterns[i];
163
+ if (isRoot) {
164
+ if (potentialMatchForRoot(pattern, currentKey))
165
+ return true;
166
+ } else if (potentialMatch(pattern, currentKey))
167
+ return true;
168
+ }
169
+ currentKeyEnd = dotIndex + 1;
170
+ }
171
+ for (let i = 0; i < keyPatternsLen; i++) {
172
+ const pattern = keyPatterns[i];
173
+ if (potentialMatch(pattern, key))
174
+ return true;
175
+ }
176
+ return false;
177
+ }
134
178
  var dateTimePattern = /^((?:(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?))(Z|[+-]\d{2}:\d{2})?)$/i;
135
179
  function isDateLike(value) {
136
180
  if (typeof value === "string") {
@@ -149,37 +193,48 @@ function transformValue(value, rules, direction) {
149
193
  }
150
194
  return value;
151
195
  }
152
- function transform(direction, object, keys) {
153
- function walk(obj, currentKey = "") {
154
- if (Array.isArray(obj)) {
155
- obj.forEach((item, idx) => {
156
- const match = matchKey(currentKey, keys);
157
- if (typeof item === "object" && item !== null) {
158
- walk(item, currentKey);
159
- } else if (match) {
160
- obj[idx] = transformValue(obj[idx], match[1], direction);
161
- }
162
- });
163
- }
164
- if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
165
- for (const key of Object.keys(obj)) {
166
- const mergedKey = mergeKeys(currentKey, key);
167
- const match = matchKey(mergedKey, keys);
168
- if (match) {
169
- obj[key] = transformValue(obj[key], match[1], direction);
170
- }
171
- walk(obj[key], mergedKey);
196
+ function walk(obj, direction, rules, rulesCache, keyPatterns, currentKey = "") {
197
+ if (rules.length <= 0) {
198
+ return obj;
199
+ }
200
+ if (!partialMatch(currentKey, keyPatterns)) {
201
+ return obj;
202
+ }
203
+ if (Array.isArray(obj)) {
204
+ const match = matchKey(currentKey, rules, rulesCache);
205
+ obj.forEach((item, idx) => {
206
+ if (typeof item === "object" && item !== null) {
207
+ walk(item, direction, rules, rulesCache, keyPatterns, currentKey);
208
+ } else if (match) {
209
+ obj[idx] = transformValue(obj[idx], match[1], direction);
172
210
  }
211
+ });
212
+ }
213
+ if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
214
+ for (const key of Object.keys(obj)) {
215
+ const mergedKey = mergeKeys(currentKey, key);
216
+ const match = matchKey(mergedKey, rules, rulesCache);
217
+ if (match) {
218
+ obj[key] = transformValue(obj[key], match[1], direction);
219
+ }
220
+ walk(obj[key], direction, rules, rulesCache, keyPatterns, mergedKey);
173
221
  }
174
- return obj;
175
222
  }
176
- return walk(object);
223
+ return obj;
177
224
  }
178
- function transformRequest(object, keys) {
179
- return transform("from", object, keys);
225
+ function flattenKeyPatterns(keyPatterns) {
226
+ return keyPatterns.map((k) => Array.isArray(k) ? k[0] : k);
180
227
  }
181
- function transformResponse(object, keys) {
182
- return transform("to", object, keys);
228
+ function transform(direction, object, rules) {
229
+ const flatKeyPatterns = flattenKeyPatterns(rules);
230
+ const rulesCache = /* @__PURE__ */ new Map();
231
+ return walk(object, direction, rules, rulesCache, flatKeyPatterns);
232
+ }
233
+ function transformRequest(object, rules) {
234
+ return transform("from", object, rules);
235
+ }
236
+ function transformResponse(object, rules) {
237
+ return transform("to", object, rules);
183
238
  }
184
239
 
185
240
  // packages/client/query/src/lib/apis/query-assistance-api.ts
@@ -228,6 +283,9 @@ var QueryAssistanceClient = class {
228
283
  throw new ApiClientError("API client error", "API client call is missing mandatory config parameter");
229
284
  }
230
285
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
286
+ const headerParameters = {
287
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
288
+ };
231
289
  try {
232
290
  const response = await this.httpClient.send({
233
291
  url: `/platform/storage/query/v1/query:verify`,
@@ -236,7 +294,8 @@ var QueryAssistanceClient = class {
236
294
  body: encodedBody,
237
295
  headers: {
238
296
  "Content-Type": "application/json",
239
- Accept: "application/json"
297
+ Accept: "application/json",
298
+ ...headerParameters
240
299
  },
241
300
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
242
301
  statusValidator: (status) => {
@@ -564,6 +623,9 @@ var QueryAssistanceClient = class {
564
623
  throw new ApiClientError("API client error", "API client call is missing mandatory config parameter");
565
624
  }
566
625
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
626
+ const headerParameters = {
627
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
628
+ };
567
629
  try {
568
630
  const response = await this.httpClient.send({
569
631
  url: `/platform/storage/query/v1/query:parse`,
@@ -572,7 +634,8 @@ var QueryAssistanceClient = class {
572
634
  body: encodedBody,
573
635
  headers: {
574
636
  "Content-Type": "application/json",
575
- Accept: "application/json"
637
+ Accept: "application/json",
638
+ ...headerParameters
576
639
  },
577
640
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
578
641
  statusValidator: (status) => {
@@ -747,6 +810,12 @@ var QueryAssistanceClient = class {
747
810
  throw new ApiClientError("API client error", "API client call is missing mandatory config parameter");
748
811
  }
749
812
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
813
+ const headerParameters = {
814
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) },
815
+ ...config.enforceQueryConsumptionLimit !== void 0 && {
816
+ "enforce-query-consumption-limit": String(config.enforceQueryConsumptionLimit)
817
+ }
818
+ };
750
819
  try {
751
820
  const response = await this.httpClient.send({
752
821
  url: `/platform/storage/query/v1/query:autocomplete`,
@@ -755,7 +824,8 @@ var QueryAssistanceClient = class {
755
824
  body: encodedBody,
756
825
  headers: {
757
826
  "Content-Type": "application/json",
758
- Accept: "application/json"
827
+ Accept: "application/json",
828
+ ...headerParameters
759
829
  },
760
830
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
761
831
  statusValidator: (status) => {
@@ -1020,12 +1090,16 @@ var QueryExecutionClient = class {
1020
1090
  },
1021
1091
  { explode: { "request-token": false, "request-timeout-milliseconds": false } }
1022
1092
  );
1093
+ const headerParameters = {
1094
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
1095
+ };
1023
1096
  try {
1024
1097
  const response = await this.httpClient.send({
1025
1098
  url: `/platform/storage/query/v1/query:poll${query}`,
1026
1099
  method: "GET",
1027
1100
  headers: {
1028
- Accept: "application/json"
1101
+ Accept: "application/json",
1102
+ ...headerParameters
1029
1103
  },
1030
1104
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
1031
1105
  statusValidator: (status) => {
@@ -1222,6 +1296,12 @@ var QueryExecutionClient = class {
1222
1296
  }
1223
1297
  const encodedBody = this.shouldTransformDates ? transformRequest(config.body, []) : config.body;
1224
1298
  const query = toQueryString({ enrich: config.enrich });
1299
+ const headerParameters = {
1300
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) },
1301
+ ...config.enforceQueryConsumptionLimit !== void 0 && {
1302
+ "enforce-query-consumption-limit": String(config.enforceQueryConsumptionLimit)
1303
+ }
1304
+ };
1225
1305
  try {
1226
1306
  const response = await this.httpClient.send({
1227
1307
  url: `/platform/storage/query/v1/query:execute${query}`,
@@ -1230,7 +1310,8 @@ var QueryExecutionClient = class {
1230
1310
  body: encodedBody,
1231
1311
  headers: {
1232
1312
  "Content-Type": "application/json",
1233
- Accept: "application/json"
1313
+ Accept: "application/json",
1314
+ ...headerParameters
1234
1315
  },
1235
1316
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
1236
1317
  statusValidator: (status) => {
@@ -1592,12 +1673,16 @@ var QueryExecutionClient = class {
1592
1673
  { "request-token": config.requestToken, enrich: config.enrich },
1593
1674
  { explode: { "request-token": false } }
1594
1675
  );
1676
+ const headerParameters = {
1677
+ ...config.dtClientContext !== void 0 && { "dt-client-context": String(config.dtClientContext) }
1678
+ };
1595
1679
  try {
1596
1680
  const response = await this.httpClient.send({
1597
1681
  url: `/platform/storage/query/v1/query:cancel${query}`,
1598
1682
  method: "POST",
1599
1683
  headers: {
1600
- Accept: "application/json"
1684
+ Accept: "application/json",
1685
+ ...headerParameters
1601
1686
  },
1602
1687
  abortSignal: config instanceof EventTarget ? config : config.abortSignal,
1603
1688
  statusValidator: (status) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynatrace-sdk/client-query",
3
- "version": "1.19.0",
3
+ "version": "1.20.2",
4
4
  "description": "Exposes an API to fetch records stored in Grail.",
5
5
  "license": "Apache-2.0",
6
6
  "dependencies": {
@@ -48,6 +48,7 @@ export declare class QueryAssistanceClient {
48
48
  */
49
49
  queryVerify(config: {
50
50
  body: VerifyRequest;
51
+ /** The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. */ dtClientContext?: string;
51
52
  abortSignal?: AbortSignal;
52
53
  }): Promise<VerifyResponse>;
53
54
  /**
@@ -264,6 +265,7 @@ export declare class QueryAssistanceClient {
264
265
  */
265
266
  queryParse(config: {
266
267
  body: ParseRequest;
268
+ /** The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. */ dtClientContext?: string;
267
269
  abortSignal?: AbortSignal;
268
270
  }): Promise<DQLNode>;
269
271
  /**
@@ -324,6 +326,8 @@ export declare class QueryAssistanceClient {
324
326
  */
325
327
  queryAutocomplete(config: {
326
328
  body: AutocompleteRequest;
329
+ /** The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. */ dtClientContext?: string;
330
+ /** If set, query consumption limit will be enforced. */ enforceQueryConsumptionLimit?: boolean;
327
331
  abortSignal?: AbortSignal;
328
332
  }): Promise<AutocompleteResponse>;
329
333
  }
@@ -70,6 +70,7 @@ export declare class QueryExecutionClient {
70
70
  /** The request-token of the query. */ requestToken: string;
71
71
  /** The time a client is willing to wait for the query result. In case the query finishes within the specified timeout, the query result is returned. Otherwise, the query status is returned. */ requestTimeoutMilliseconds?: number;
72
72
  /** If set additional data will be available in the metadata section. */ enrich?: string;
73
+ /** The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. */ dtClientContext?: string;
73
74
  abortSignal?: AbortSignal;
74
75
  }): Promise<QueryPollResponse>;
75
76
  /**
@@ -132,6 +133,8 @@ export declare class QueryExecutionClient {
132
133
  queryExecute(config: {
133
134
  body: ExecuteRequest;
134
135
  /** If set additional data will be available in the metadata section. */ enrich?: string;
136
+ /** The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. */ dtClientContext?: string;
137
+ /** If set, query consumption limit will be enforced. */ enforceQueryConsumptionLimit?: boolean;
135
138
  abortSignal?: AbortSignal;
136
139
  }): Promise<QueryStartResponse>;
137
140
  /**
@@ -189,6 +192,7 @@ export declare class QueryExecutionClient {
189
192
  queryCancel(config: {
190
193
  /** The request-token of the query. */ requestToken: string;
191
194
  /** If set additional data will be available in the metadata section. */ enrich?: string;
195
+ /** The dt-client-context header is an optional string parameter used for monitoring purposes. When included in a request, it helps retrieve information about the execution of the query. It shouldn't hold sensitive information. */ dtClientContext?: string;
192
196
  abortSignal?: AbortSignal;
193
197
  }): Promise<QueryPollResponse | void>;
194
198
  }
@@ -34,7 +34,7 @@ export interface ExecuteRequest {
34
34
  */
35
35
  fetchTimeoutSeconds?: number;
36
36
  /**
37
- * The time a client is willing to wait for the query result. In case the query finishes within the specified timeout, the query result is returned. Otherwise, the requestToken is returned, allowing polling for the result.
37
+ * The maximum time the response will be delayed to wait for a result. (This excludes the sending time and time spent in any services between the query-frontend and the client.) If the query finishes within the specified timeout, the query result is returned. Otherwise, the requestToken is returned, allowing polling for the result.
38
38
  */
39
39
  requestTimeoutMilliseconds?: number;
40
40
  /**
@@ -57,4 +57,8 @@ export interface ExecuteRequest {
57
57
  * Represents a collection of filter segments.
58
58
  */
59
59
  filterSegments?: FilterSegments;
60
+ /**
61
+ * Parameter to exclude the type information from the query result. In case not specified, the type information will be included.
62
+ */
63
+ includeTypes?: boolean;
60
64
  }
@@ -2,6 +2,7 @@ type TransformRuleConfig = {
2
2
  force?: boolean;
3
3
  datetime?: boolean;
4
4
  };
5
- export declare function transformRequest<T = any>(object: T, keys: Array<string | [string, TransformRuleConfig]>): T;
6
- export declare function transformResponse<T = any>(object: T, keys: Array<string | [string, TransformRuleConfig]>): T;
5
+ type TransformRulesParam = Array<string | [string, TransformRuleConfig]>;
6
+ export declare function transformRequest<T = any>(object: T, rules: TransformRulesParam): T;
7
+ export declare function transformResponse<T = any>(object: T, rules: TransformRulesParam): T;
7
8
  export {};