This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new b6daa632d8c fix SET statements apearing in JSON queries (#18026)
b6daa632d8c is described below
commit b6daa632d8caa0e0ae2e897e1c71367e42a26fc0
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Wed May 21 12:47:38 2025 +0100
fix SET statements apearing in JSON queries (#18026)
---
licenses.yaml | 2 +-
web-console/.gitignore | 1 +
web-console/package-lock.json | 14 +-
web-console/package.json | 2 +-
.../workbench-query/workbench-query.spec.ts | 217 +++++++++++++++++++++
.../workbench-query/workbench-query.ts | 14 +-
6 files changed, 237 insertions(+), 13 deletions(-)
diff --git a/licenses.yaml b/licenses.yaml
index 9509f442d24..1a2f66f94c9 100644
--- a/licenses.yaml
+++ b/licenses.yaml
@@ -5762,7 +5762,7 @@ license_category: binary
module: web-console
license_name: Apache License version 2.0
copyright: Imply Data
-version: 1.1.1
+version: 1.1.4
---
diff --git a/web-console/.gitignore b/web-console/.gitignore
index 8b06a648032..6467fb50aee 100644
--- a/web-console/.gitignore
+++ b/web-console/.gitignore
@@ -5,6 +5,7 @@ public/
private/
lib/*.css
coverage/
+.claude/
coordinator-console/
pages/
diff --git a/web-console/package-lock.json b/web-console/package-lock.json
index 006e331466c..cfce9178855 100644
--- a/web-console/package-lock.json
+++ b/web-console/package-lock.json
@@ -30,7 +30,7 @@
"d3-shape": "^3.2.0",
"d3-time-format": "^4.1.0",
"date-fns": "^2.28.0",
- "druid-query-toolkit": "^1.1.1",
+ "druid-query-toolkit": "^1.1.4",
"echarts": "^5.5.1",
"file-saver": "^2.0.5",
"hjson": "^3.2.2",
@@ -7067,9 +7067,9 @@
}
},
"node_modules/druid-query-toolkit": {
- "version": "1.1.1",
- "resolved":
"https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.1.1.tgz",
- "integrity":
"sha512-+DtPaCf7WPitr/G1YKUWsYGy4vrDzybQUqbFpyGMKIkqwcmTdCS10qfb9+eGKUu/3EIx4FVBoXFeRcMCdJ73Ow==",
+ "version": "1.1.4",
+ "resolved":
"https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.1.4.tgz",
+ "integrity":
"sha512-yppL7d/5PRUojDtOviU/0gK+wI5OP43FptRIFbZ6Trm8ngGEkLeqnLLT5rqGPkcPB23OvppcU9jKtdicWg2KhQ==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.5.2"
@@ -23311,9 +23311,9 @@
}
},
"druid-query-toolkit": {
- "version": "1.1.1",
- "resolved":
"https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.1.1.tgz",
- "integrity":
"sha512-+DtPaCf7WPitr/G1YKUWsYGy4vrDzybQUqbFpyGMKIkqwcmTdCS10qfb9+eGKUu/3EIx4FVBoXFeRcMCdJ73Ow==",
+ "version": "1.1.4",
+ "resolved":
"https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.1.4.tgz",
+ "integrity":
"sha512-yppL7d/5PRUojDtOviU/0gK+wI5OP43FptRIFbZ6Trm8ngGEkLeqnLLT5rqGPkcPB23OvppcU9jKtdicWg2KhQ==",
"requires": {
"tslib": "^2.5.2"
}
diff --git a/web-console/package.json b/web-console/package.json
index ac3f4891b17..ca9c78c0538 100644
--- a/web-console/package.json
+++ b/web-console/package.json
@@ -71,7 +71,7 @@
"d3-shape": "^3.2.0",
"d3-time-format": "^4.1.0",
"date-fns": "^2.28.0",
- "druid-query-toolkit": "^1.1.1",
+ "druid-query-toolkit": "^1.1.4",
"echarts": "^5.5.1",
"file-saver": "^2.0.5",
"hjson": "^3.2.2",
diff --git
a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
index 8456b0d065d..ec224cf29aa 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
@@ -469,4 +469,221 @@ describe('WorkbenchQuery', () => {
).toEqual("End of input while parsing an object (missing '}') at line
2,9 >>> lol: 1 ...");
});
});
+
+ describe('#changeQueryStringContext', () => {
+ it('modifies SQL query string with SET statements', () => {
+ const workbenchQuery = WorkbenchQuery.blank().changeQueryString('SELECT
* FROM wikipedia');
+
+ const newContext = { maxNumTasks: 3, useCache: false };
+ const updatedQuery = workbenchQuery.changeQueryStringContext(newContext);
+
+ expect(updatedQuery.getQueryString()).toContain('SET maxNumTasks = 3');
+ expect(updatedQuery.getQueryString()).toContain('SET useCache = FALSE');
+ expect(updatedQuery.getQueryString()).toContain('SELECT * FROM
wikipedia');
+ });
+
+ it('updates existing SET statements in SQL query', () => {
+ const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sane`
+ SET maxNumTasks = 2;
+ SELECT * FROM wikipedia
+ `);
+
+ const newContext = { maxNumTasks: 5, finalizeAggregations: true };
+ const updatedQuery = workbenchQuery.changeQueryStringContext(newContext);
+
+ expect(updatedQuery.getQueryString()).toContain('SET maxNumTasks = 5');
+ expect(updatedQuery.getQueryString()).toContain('SET
finalizeAggregations = TRUE');
+ expect(updatedQuery.getQueryString()).toContain('SELECT * FROM
wikipedia');
+ });
+
+ it('works with JSON queries by modifying queryContext instead', () => {
+ const jsonQuery = sane`
+ {
+ "queryType": "topN",
+ "dataSource": "test"
+ }
+ `;
+
+ const workbenchQuery = WorkbenchQuery.blank()
+ .changeQueryString(jsonQuery)
+ .changeQueryContext({ originalContext: true });
+
+ const newContext = { maxNumTasks: 3, useCache: false };
+ const updatedQuery = workbenchQuery.changeQueryStringContext(newContext);
+
+ expect(updatedQuery.queryContext).toEqual(newContext);
+ expect(updatedQuery.getQueryString()).toEqual(jsonQuery);
+ });
+
+ it('handles empty context object', () => {
+ const workbenchQuery = WorkbenchQuery.blank().changeQueryString('SELECT
* FROM wikipedia');
+
+ const updatedQuery = workbenchQuery.changeQueryStringContext({});
+
+ expect(updatedQuery.getQueryString()).toBe('SELECT * FROM wikipedia');
+ });
+
+ it('preserves original queryContext when working with JSON', () => {
+ const jsonQuery = '{"queryType": "timeseries"}';
+ const workbenchQuery = WorkbenchQuery.blank()
+ .changeQueryString(jsonQuery)
+ .changeQueryContext({ existing: 'value' });
+
+ const updatedQuery = workbenchQuery.changeQueryStringContext({ new:
'context' });
+
+ expect(updatedQuery.queryContext).toEqual({ new: 'context' });
+ });
+ });
+
+ describe('#getQueryStringContext', () => {
+ it('extracts context from SQL SET statements', () => {
+ const queryWithSets = sane`
+ SET maxNumTasks = 3;
+ SET useCache = false;
+ SET stringParam = 'test';
+ SELECT * FROM wikipedia
+ `;
+
+ const workbenchQuery =
WorkbenchQuery.blank().changeQueryString(queryWithSets);
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual({
+ maxNumTasks: 3,
+ useCache: false,
+ stringParam: 'test',
+ });
+ });
+
+ it('returns empty object when no SET statements in SQL', () => {
+ const workbenchQuery = WorkbenchQuery.blank().changeQueryString('SELECT
* FROM wikipedia');
+
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual({});
+ });
+
+ it('returns queryContext for JSON queries', () => {
+ const jsonQuery = '{"queryType": "topN"}';
+ const contextValue = { maxNumTasks: 5, useCache: true };
+
+ const workbenchQuery = WorkbenchQuery.blank()
+ .changeQueryString(jsonQuery)
+ .changeQueryContext(contextValue);
+
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual(contextValue);
+ });
+
+ it('handles mixed SET statements and regular SQL', () => {
+ const queryWithMixedContent = sane`
+ -- Comment
+ SET timeout = 30000;
+ SET maxRows = 1000;
+
+ SELECT COUNT(*)
+ FROM wikipedia
+ WHERE channel = 'en'
+ `;
+
+ const workbenchQuery =
WorkbenchQuery.blank().changeQueryString(queryWithMixedContent);
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual({
+ timeout: 30000,
+ maxRows: 1000,
+ });
+ });
+
+ it('returns empty object for malformed JSON queries', () => {
+ const malformedJson = '{ "queryType": "topN"';
+ const workbenchQuery = WorkbenchQuery.blank()
+ .changeQueryString(malformedJson)
+ .changeQueryContext({ fallback: true });
+
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual({ fallback: true });
+ });
+
+ it('handles various data types in SET statements', () => {
+ const queryWithVariousTypes = sane`
+ SET stringParam = 'text';
+ SET numberParam = 42;
+ SET booleanParam = TRUE;
+ SET nullParam = NULL;
+ SELECT * FROM test
+ `;
+
+ const workbenchQuery =
WorkbenchQuery.blank().changeQueryString(queryWithVariousTypes);
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual({
+ stringParam: 'text',
+ numberParam: 42,
+ booleanParam: true,
+ nullParam: null,
+ });
+ });
+ });
+
+ describe('changeQueryStringContext and getQueryStringContext symmetry', ()
=> {
+ it('maintains symmetry for SQL queries', () => {
+ const originalQuery = 'SELECT * FROM wikipedia';
+ const testContext = { maxNumTasks: 3, useCache: false, timeout: 30000 };
+
+ const workbenchQuery =
WorkbenchQuery.blank().changeQueryString(originalQuery);
+ const updatedQuery =
workbenchQuery.changeQueryStringContext(testContext);
+ const extractedContext = updatedQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual(testContext);
+ });
+
+ it('maintains symmetry for JSON queries', () => {
+ const jsonQuery = '{"queryType": "topN", "dataSource": "test"}';
+ const testContext = { maxNumTasks: 5, finalizeAggregations: true };
+
+ const workbenchQuery =
WorkbenchQuery.blank().changeQueryString(jsonQuery);
+ const updatedQuery =
workbenchQuery.changeQueryStringContext(testContext);
+ const extractedContext = updatedQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual(testContext);
+ });
+
+ it('roundtrip preserves simple context values for SQL queries', () => {
+ const simpleContext = {
+ stringValue: 'test',
+ numberValue: 42,
+ booleanValue: true,
+ nullValue: null,
+ };
+
+ const workbenchQuery = WorkbenchQuery.blank()
+ .changeQueryString('SELECT * FROM test')
+ .changeQueryStringContext(simpleContext);
+
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual(simpleContext);
+ });
+
+ it('roundtrip preserves complex context values for JSON queries', () => {
+ const complexContext = {
+ stringValue: 'test',
+ numberValue: 42,
+ booleanValue: true,
+ nullValue: null,
+ arrayValue: [1, 2, 3],
+ objectValue: { nested: { key: 'value' } },
+ };
+
+ const workbenchQuery = WorkbenchQuery.blank()
+ .changeQueryString('{"queryType": "topN"}')
+ .changeQueryStringContext(complexContext);
+
+ const extractedContext = workbenchQuery.getQueryStringContext();
+
+ expect(extractedContext).toEqual(complexContext);
+ });
+ });
});
diff --git a/web-console/src/druid-models/workbench-query/workbench-query.ts
b/web-console/src/druid-models/workbench-query/workbench-query.ts
index 44ec5e70f0a..53b1b60634a 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.ts
@@ -286,13 +286,19 @@ export class WorkbenchQuery {
}
public changeQueryStringContext(queryContext: QueryContext): WorkbenchQuery {
- const { queryString } = this;
- return
this.changeQueryString(SqlSetStatement.setContextInText(queryString,
queryContext));
+ if (this.isJsonLike()) {
+ // JSON query: set the inner context instead of modifying the query
string
+ return this.changeQueryContext(queryContext);
+ }
+ return
this.changeQueryString(SqlSetStatement.setContextInText(this.queryString,
queryContext));
}
public getQueryStringContext(): QueryContext {
- const { queryString } = this;
- return SqlSetStatement.getContextFromText(queryString);
+ if (this.isJsonLike()) {
+ // JSON query: return the inner context for symmetry with
changeQueryStringContext
+ return this.queryContext;
+ }
+ return SqlSetStatement.getContextFromText(this.queryString);
}
public changeQueryContext(queryContext: QueryContext): WorkbenchQuery {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]