From e939b5afa045e7136c6b6fa5a9330935c3e8e3a7 Mon Sep 17 00:00:00 2001 From: Antoine Boyer Date: Mon, 29 Sep 2025 15:42:43 -0700 Subject: [PATCH 1/6] Add ARRAY query parameter supprot in workbench view --- .../query-parameters-dialog.spec.tsx | 17 ++++++++ .../query-parameters-dialog.tsx | 42 +++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.spec.tsx b/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.spec.tsx index dfd749307ad5..ca563fa635c5 100644 --- a/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.spec.tsx +++ b/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.spec.tsx @@ -29,6 +29,23 @@ describe('QueryParametersDialog', () => { { type: 'TIMESTAMP', value: '2022-02-02 01:02:03' }, { type: 'BIGINT', value: 42 }, { type: 'DOUBLE', value: 1.618 }, + { type: 'ARRAY', value: [-25.7, null, 36.85] }, + ]} + onQueryParametersChange={() => {}} + onClose={() => {}} + />, + ); + + expect(comp).toMatchSnapshot(); + }); + + it('handles ARRAY type parameters correctly', () => { + const comp = shallow( + {}} onClose={() => {}} diff --git a/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx b/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx index 49a9ebb587df..596f87e12216 100644 --- a/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx +++ b/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx @@ -40,7 +40,26 @@ import { deepSet, oneOf, tickIcon, without } from '../../../utils'; import './query-parameters-dialog.scss'; -const TYPES = ['VARCHAR', 'TIMESTAMP', 'BIGINT', 'DOUBLE', 'FLOAT']; +const TYPES = ['VARCHAR', 'TIMESTAMP', 'BIGINT', 'DOUBLE', 'FLOAT', 'ARRAY']; + +function parseArrayValue(input: string): any[] | string { + try { + const parsed = JSON.parse(input); + if (Array.isArray(parsed)) { + return parsed; + } + return input; + } catch { + return input; + } +} + +function formatArrayValue(value: any): string { + if (Array.isArray(value)) { + return JSON.stringify(value); + } + return value; +} interface QueryParametersDialogProps { queryParameters: QueryParameter[] | undefined; @@ -77,7 +96,11 @@ export const QueryParametersDialog = React.memo(function QueryParametersDialog( const { type, value } = queryParameter; function onValueChange(v: string | number) { - setCurrentQueryParameters(deepSet(currentQueryParameters, `${i}.value`, v)); + let finalValue: any = v; + if (type === 'ARRAY' && typeof v === 'string') { + finalValue = parseArrayValue(v); + } + setCurrentQueryParameters(deepSet(currentQueryParameters, `${i}.value`, finalValue)); } return ( @@ -112,11 +135,22 @@ export const QueryParametersDialog = React.memo(function QueryParametersDialog( fill arbitraryPrecision={type !== 'BIGINT'} /> - ) : ( + ) : type === 'ARRAY' ? ( + onValueChange(e.target.value)} + placeholder='[-25.7, null, 36.85]' + fill + /> + ) : ( onValueChange(e.target.value)} - placeholder={type === 'TIMESTAMP' ? '2022-01-01 00:00:00' : 'Parameter value'} + placeholder={ + type === 'TIMESTAMP' + ? '2022-01-01 00:00:00' + : 'Parameter value' + } fill /> )} From 6ed6170768b3bd4129aba4cdd081b719d34a7c04 Mon Sep 17 00:00:00 2001 From: Antoine Boyer Date: Wed, 22 Oct 2025 14:07:38 -0700 Subject: [PATCH 2/6] Update druid-query-toolkit to 1.2.1 --- web-console/package-lock.json | 15 ++++++++------- web-console/package.json | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/web-console/package-lock.json b/web-console/package-lock.json index 8c87c09706f5..daa9ca761f0f 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.2.0", + "druid-query-toolkit": "^1.2.1", "echarts": "^5.5.1", "file-saver": "^2.0.5", "hjson": "^3.2.2", @@ -7283,9 +7283,9 @@ } }, "node_modules/druid-query-toolkit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.2.0.tgz", - "integrity": "sha512-MMcr1012UZSbOG+O3bI1BxxGQOHM1sVwPWYGgbQlfnBCQovjcLDAxkzWUGY/nn1c3B+Yrblcp3oMRl/S0HpiDQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.2.1.tgz", + "integrity": "sha512-vg+r0J0cbK934QhqNaHs/Zs0nXYZSv//ZnLor71OCsP73ya60SBaN3nW3DuR+TxUGMIgZpSIgGQbG03eP7vfwA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.5.2" @@ -8864,6 +8864,7 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -23698,9 +23699,9 @@ } }, "druid-query-toolkit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.2.0.tgz", - "integrity": "sha512-MMcr1012UZSbOG+O3bI1BxxGQOHM1sVwPWYGgbQlfnBCQovjcLDAxkzWUGY/nn1c3B+Yrblcp3oMRl/S0HpiDQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-1.2.1.tgz", + "integrity": "sha512-vg+r0J0cbK934QhqNaHs/Zs0nXYZSv//ZnLor71OCsP73ya60SBaN3nW3DuR+TxUGMIgZpSIgGQbG03eP7vfwA==", "requires": { "tslib": "^2.5.2" } diff --git a/web-console/package.json b/web-console/package.json index e7152234610e..73c9d720cd19 100644 --- a/web-console/package.json +++ b/web-console/package.json @@ -72,7 +72,7 @@ "d3-shape": "^3.2.0", "d3-time-format": "^4.1.0", "date-fns": "^2.28.0", - "druid-query-toolkit": "^1.2.0", + "druid-query-toolkit": "^1.2.1", "echarts": "^5.5.1", "file-saver": "^2.0.5", "hjson": "^3.2.2", From f4dbcee159448ed1f54b9ba72aa872028d672bb6 Mon Sep 17 00:00:00 2001 From: Antoine Boyer Date: Fri, 24 Oct 2025 14:25:05 -0400 Subject: [PATCH 3/6] Update licenses --- licenses.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/licenses.yaml b/licenses.yaml index 4e5d201edb77..692fbbf6a75f 100644 --- a/licenses.yaml +++ b/licenses.yaml @@ -5470,7 +5470,7 @@ license_category: binary module: web-console license_name: MIT License copyright: Matt Zabriskie -version: 1.12.2 +version: 1.8.4 license_file_path: licenses/bin/axios.MIT --- @@ -5838,7 +5838,7 @@ license_category: binary module: web-console license_name: Apache License version 2.0 copyright: Imply Data -version: 1.2.0 +version: 1.2.1 --- From 318d51d65800c4b34cae72070e1562d7735ad45b Mon Sep 17 00:00:00 2001 From: Antoine Boyer Date: Fri, 24 Oct 2025 14:26:46 -0400 Subject: [PATCH 4/6] Update axios license --- licenses.yaml | 12 +++++++++++- licenses/bin/dayjs.MIT | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 licenses/bin/dayjs.MIT diff --git a/licenses.yaml b/licenses.yaml index 692fbbf6a75f..2c24535782f8 100644 --- a/licenses.yaml +++ b/licenses.yaml @@ -5470,7 +5470,7 @@ license_category: binary module: web-console license_name: MIT License copyright: Matt Zabriskie -version: 1.8.4 +version: 1.12.2 license_file_path: licenses/bin/axios.MIT --- @@ -5784,6 +5784,16 @@ license_file_path: licenses/bin/date-fns.MIT --- +name: "dayjs" +license_category: binary +module: web-console +license_name: MIT License +copyright: iamkun +version: 1.11.15 +license_file_path: licenses/bin/dayjs.MIT + +--- + name: "delayed-stream" license_category: binary module: web-console diff --git a/licenses/bin/dayjs.MIT b/licenses/bin/dayjs.MIT new file mode 100644 index 000000000000..caf9315493c6 --- /dev/null +++ b/licenses/bin/dayjs.MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018-present, iamkun + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 64236e3b789fc06b3b74a0801d6fbe923bfe10cc Mon Sep 17 00:00:00 2001 From: Antoine Boyer Date: Fri, 24 Oct 2025 20:16:12 -0400 Subject: [PATCH 5/6] prettify --- .../query-parameters-dialog.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx b/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx index 596f87e12216..fc61cbe8f099 100644 --- a/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx +++ b/web-console/src/views/workbench-view/query-parameters-dialog/query-parameters-dialog.tsx @@ -139,18 +139,14 @@ export const QueryParametersDialog = React.memo(function QueryParametersDialog( onValueChange(e.target.value)} - placeholder='[-25.7, null, 36.85]' + placeholder="[-25.7, null, 36.85]" fill /> - ) : ( + ) : ( onValueChange(e.target.value)} - placeholder={ - type === 'TIMESTAMP' - ? '2022-01-01 00:00:00' - : 'Parameter value' - } + placeholder={type === 'TIMESTAMP' ? '2022-01-01 00:00:00' : 'Parameter value'} fill /> )} From cce69d9fd2da9891fcb76d4b466d662fe750ec84 Mon Sep 17 00:00:00 2001 From: Antoine Boyer Date: Mon, 27 Oct 2025 10:58:13 -0700 Subject: [PATCH 6/6] update test snapshot --- .../query-parameters-dialog.spec.tsx.snap | 516 ++++++++++++++++++ 1 file changed, 516 insertions(+) diff --git a/web-console/src/views/workbench-view/query-parameters-dialog/__snapshots__/query-parameters-dialog.spec.tsx.snap b/web-console/src/views/workbench-view/query-parameters-dialog/__snapshots__/query-parameters-dialog.spec.tsx.snap index 576751c66f1b..84a8ef44991f 100644 --- a/web-console/src/views/workbench-view/query-parameters-dialog/__snapshots__/query-parameters-dialog.spec.tsx.snap +++ b/web-console/src/views/workbench-view/query-parameters-dialog/__snapshots__/query-parameters-dialog.spec.tsx.snap @@ -1,5 +1,373 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`QueryParametersDialog handles ARRAY type parameters correctly 1`] = ` + +
+

+ Druid SQL supports dynamic parameters using question mark + + ? + + syntax, where parameters are bound positionally to ? placeholders at execution time. +

+ + + + + + + + + + + } + defaultIsOpen={false} + disabled={false} + fill={false} + hasBackdrop={false} + hoverCloseDelay={300} + hoverOpenDelay={150} + inheritDarkTheme={true} + interactionKind="click" + matchTargetWidth={false} + minimal={true} + openOnTargetFocus={true} + position="bottom-left" + positioningStrategy="absolute" + shouldReturnFocusOnClose={false} + targetTagName="span" + transitionDuration={300} + usePortal={true} + > + + + + + + + + + + + + + + + + + } + defaultIsOpen={false} + disabled={false} + fill={false} + hasBackdrop={false} + hoverCloseDelay={300} + hoverOpenDelay={150} + inheritDarkTheme={true} + interactionKind="click" + matchTargetWidth={false} + minimal={true} + openOnTargetFocus={true} + position="bottom-left" + positioningStrategy="absolute" + shouldReturnFocusOnClose={false} + targetTagName="span" + transitionDuration={300} + usePortal={true} + > + + + + + + + + + + + + + + + + + } + defaultIsOpen={false} + disabled={false} + fill={false} + hasBackdrop={false} + hoverCloseDelay={300} + hoverOpenDelay={150} + inheritDarkTheme={true} + interactionKind="click" + matchTargetWidth={false} + minimal={true} + openOnTargetFocus={true} + position="bottom-left" + positioningStrategy="absolute" + shouldReturnFocusOnClose={false} + targetTagName="span" + transitionDuration={300} + usePortal={true} + > + + + + + + + +
+
+
+ + +
+
+
+`; + exports[`QueryParametersDialog matches snapshot 1`] = ` + } defaultIsOpen={false} @@ -177,6 +555,16 @@ exports[`QueryParametersDialog matches snapshot 1`] = ` shouldDismissPopover={true} text="FLOAT" /> + } defaultIsOpen={false} @@ -275,6 +663,16 @@ exports[`QueryParametersDialog matches snapshot 1`] = ` shouldDismissPopover={true} text="FLOAT" /> + } defaultIsOpen={false} @@ -373,6 +771,16 @@ exports[`QueryParametersDialog matches snapshot 1`] = ` shouldDismissPopover={true} text="FLOAT" /> + } defaultIsOpen={false} @@ -410,6 +818,114 @@ exports[`QueryParametersDialog matches snapshot 1`] = ` /> + + + + + + + + + + + } + defaultIsOpen={false} + disabled={false} + fill={false} + hasBackdrop={false} + hoverCloseDelay={300} + hoverOpenDelay={150} + inheritDarkTheme={true} + interactionKind="click" + matchTargetWidth={false} + minimal={true} + openOnTargetFocus={true} + position="bottom-left" + positioningStrategy="absolute" + shouldReturnFocusOnClose={false} + targetTagName="span" + transitionDuration={300} + usePortal={true} + > + + + + + +