This is an automated email from the ASF dual-hosted git repository.

vogievetsky pushed a commit to branch 29.0.1
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/29.0.1 by this push:
     new dd3aff5f61a Web console: support for the export execution state 
(#15969) (#16058)
dd3aff5f61a is described below

commit dd3aff5f61af523eb05e75ec67d19b1592c2417f
Author: Karan Kumar <karankumar1...@gmail.com>
AuthorDate: Sat Mar 9 03:14:16 2024 +0530

    Web console: support for the export execution state (#15969) (#16058)
    
    * init
    
    * add CSV keyword
    
    Co-authored-by: Vadim Ogievetsky <va...@ogievetsky.com>
---
 web-console/lib/keywords.js                        |  1 +
 .../src/druid-models/execution/execution.ts        |  2 +-
 .../workbench-query/workbench-query.spec.ts        | 94 ----------------------
 .../workbench-query/workbench-query.ts             | 33 ++------
 .../views/workbench-view/query-tab/query-tab.scss  | 20 +++++
 .../views/workbench-view/query-tab/query-tab.tsx   | 28 ++++---
 6 files changed, 47 insertions(+), 131 deletions(-)

diff --git a/web-console/lib/keywords.js b/web-console/lib/keywords.js
index 62dec991f86..bf7b9a03910 100644
--- a/web-console/lib/keywords.js
+++ b/web-console/lib/keywords.js
@@ -108,6 +108,7 @@ exports.SQL_EXPRESSION_PARTS = [
   'YEAR',
   'TIMESTAMP',
   'INTERVAL',
+  'CSV',
 ];
 
 exports.SQL_CONSTANTS = ['NULL', 'FALSE', 'TRUE'];
diff --git a/web-console/src/druid-models/execution/execution.ts 
b/web-console/src/druid-models/execution/execution.ts
index baf07b0c143..6fd5e3f8230 100644
--- a/web-console/src/druid-models/execution/execution.ts
+++ b/web-console/src/druid-models/execution/execution.ts
@@ -574,7 +574,7 @@ export class Execution {
     return this.destination?.numTotalRows;
   }
 
-  public isSuccessfulInsert(): boolean {
+  public isSuccessfulIngest(): boolean {
     return Boolean(this.status === 'SUCCESS' && this.getIngestDatasource());
   }
 
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 ec057b3efc7..02bb3e399b0 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
@@ -455,100 +455,6 @@ describe('WorkbenchQuery', () => {
     });
   });
 
-  describe('#getIngestDatasource', () => {
-    it('works with INSERT', () => {
-      const sql = sane`
-        -- Some comment
-        INSERT INTO trips2
-        SELECT
-          TIME_PARSE(pickup_datetime) AS __time,
-          *
-        FROM TABLE(
-          EXTERN(
-            '{"type": "local", ...}',
-            '{"type":"csv", ...}'
-          )
-        ) EXTEND (cab_type, VARCHAR)
-        CLUSTERED BY trip_id
-      `;
-
-      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
-      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
-      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
-    });
-
-    it('works with INSERT (unparsable)', () => {
-      const sql = sane`
-        -- Some comment
-        INSERT into trips2
-        SELECT
-          TIME_PARSE(pickup_datetime) AS __time,
-          *
-        FROM TABLE(
-      `;
-
-      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
-      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
-      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
-    });
-
-    it('works with INSERT (unparsable with paren)', () => {
-      const sql = sane`
-        -- Some comment
-        INSERT into trips2
-        (SELECT TIME_PARSE(pickup_datetime) AS __time,
-      `;
-
-      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
-      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
-      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
-    });
-
-    it('works with REPLACE', () => {
-      const sql = sane`
-        REPLACE INTO trips2 OVERWRITE ALL
-        SELECT
-          TIME_PARSE(pickup_datetime) AS __time,
-          *
-        FROM TABLE(
-          EXTERN(
-            '{"type": "local", ...}',
-            '{"type":"csv", ...}'
-          )
-        ) EXTEND (cab_type, VARCHAR)
-        CLUSTERED BY trip_id
-      `;
-
-      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
-      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
-      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
-    });
-
-    it('works with REPLACE (unparsable)', () => {
-      const sql = sane`
-        REPLACE INTO trips2 OVERWRITE ALL
-        WITH kttm_data AS (SELECT *
-      `;
-
-      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
-      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
-      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
-    });
-
-    it('works with REPLACE (unparsable with comment at start)', () => {
-      const sql = sane`
-        -- Hello world SELECT
-
-        REPLACE INTO trips2 OVERWRITE ALL
-        WITH kttm_data AS (SELECT *
-      `;
-
-      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
-      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
-      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
-    });
-  });
-
   describe('#getIssue', () => {
     it('works', () => {
       expect(
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 f027efdc0a5..27cf6a0109d 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.ts
@@ -158,7 +158,7 @@ export class WorkbenchQuery {
       .changeQueryString(queryString)
       .changeQueryContext(cleanContext);
 
-    if (noSqlOuterLimit && !retQuery.getIngestDatasource()) {
+    if (noSqlOuterLimit && !retQuery.isIngestQuery()) {
       retQuery = retQuery.changeUnlimited(true);
     }
 
@@ -221,23 +221,6 @@ export class WorkbenchQuery {
     return /EXTERN\s*\(|(?:INSERT|REPLACE)\s+INTO/im.test(queryString);
   }
 
-  static getIngestDatasourceFromQueryFragment(queryFragment: string): string | 
undefined {
-    // Assuming the queryFragment is no parsable find the prefix that look 
like:
-    // REPLACE<space>INTO<space><whatever><space>SELECT<space or EOF>
-    const matchInsertReplaceIndex = 
queryFragment.match(/(?:INSERT|REPLACE)\s+INTO/i)?.index;
-    if (typeof matchInsertReplaceIndex !== 'number') return;
-
-    const queryStartingWithInsertOrReplace = 
queryFragment.substring(matchInsertReplaceIndex);
-
-    const matchEnd = 
queryStartingWithInsertOrReplace.match(/\(|\b(?:SELECT|WITH)\b|$/i);
-    const fragmentQuery = SqlQuery.maybeParse(
-      queryStartingWithInsertOrReplace.substring(0, matchEnd?.index) + ' 
SELECT * FROM t',
-    );
-    if (!fragmentQuery) return;
-
-    return fragmentQuery.getIngestTable()?.getName();
-  }
-
   public readonly queryString: string;
   public readonly queryContext: QueryContext;
   public readonly queryParameters?: QueryParameter[];
@@ -409,21 +392,17 @@ export class WorkbenchQuery {
     }
   }
 
-  public getIngestDatasource(): string | undefined {
-    if (this.getEffectiveEngine() !== 'sql-msq-task') return;
+  public isIngestQuery(): boolean {
+    if (this.getEffectiveEngine() !== 'sql-msq-task') return false;
 
     const { queryString, parsedQuery } = this;
     if (parsedQuery) {
-      return parsedQuery.getIngestTable()?.getName();
+      return Boolean(parsedQuery.getIngestTable());
     }
 
-    if (this.isJsonLike()) return;
-
-    return WorkbenchQuery.getIngestDatasourceFromQueryFragment(queryString);
-  }
+    if (this.isJsonLike()) return false;
 
-  public isIngestQuery(): boolean {
-    return Boolean(this.getIngestDatasource());
+    return /(?:INSERT|REPLACE)\s+INTO/i.test(queryString);
   }
 
   public toggleUnlimited(): WorkbenchQuery {
diff --git a/web-console/src/views/workbench-view/query-tab/query-tab.scss 
b/web-console/src/views/workbench-view/query-tab/query-tab.scss
index eee0375e0ea..4c143194a87 100644
--- a/web-console/src/views/workbench-view/query-tab/query-tab.scss
+++ b/web-console/src/views/workbench-view/query-tab/query-tab.scss
@@ -124,5 +124,25 @@ $vertical-gap: 6px;
         right: 0;
       }
     }
+
+    .generic-status-container {
+      position: relative;
+
+      .generic-status-container-info {
+        position: absolute;
+        top: 5px;
+        left: 5px;
+        right: 5px;
+        height: 30px;
+      }
+
+      .execution-stages-pane {
+        position: absolute;
+        top: 40px;
+        bottom: 0;
+        left: 0;
+        right: 0;
+      }
+    }
   }
 }
diff --git a/web-console/src/views/workbench-view/query-tab/query-tab.tsx 
b/web-console/src/views/workbench-view/query-tab/query-tab.tsx
index 8c7db042736..bd3a7dc769c 100644
--- a/web-console/src/views/workbench-view/query-tab/query-tab.tsx
+++ b/web-console/src/views/workbench-view/query-tab/query-tab.tsx
@@ -286,11 +286,11 @@ export const QueryTab = React.memo(function 
QueryTab(props: QueryTabProps) {
     useCallback(state => state.increment, []),
   );
   useEffect(() => {
-    if (execution?.isSuccessfulInsert()) {
+    if (execution?.isSuccessfulIngest()) {
       incrementMetadataVersion();
     }
     // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [Boolean(execution?.isSuccessfulInsert())]);
+  }, [Boolean(execution?.isSuccessfulIngest())]);
 
   function moveToPosition(position: RowColumn) {
     const currentQueryInput = queryInputRef.current;
@@ -434,12 +434,6 @@ export const QueryTab = React.memo(function 
QueryTab(props: QueryTabProps) {
                 queryResult={execution.result}
                 onQueryAction={handleQueryAction}
               />
-            ) : execution.isSuccessfulInsert() ? (
-              <IngestSuccessPane
-                execution={execution}
-                onDetails={onDetails}
-                onQueryTab={onQueryTab}
-              />
             ) : execution.error ? (
               <div className="error-container">
                 <ExecutionErrorPane execution={execution} />
@@ -452,8 +446,24 @@ export const QueryTab = React.memo(function 
QueryTab(props: QueryTabProps) {
                   />
                 )}
               </div>
+            ) : execution.isSuccessfulIngest() ? (
+              <IngestSuccessPane
+                execution={execution}
+                onDetails={onDetails}
+                onQueryTab={onQueryTab}
+              />
             ) : (
-              <div>Unknown query execution state</div>
+              <div className="generic-status-container">
+                <div className="generic-status-container-info">
+                  {`Execution completed with status: ${execution.status}`}
+                </div>
+                <ExecutionStagesPane
+                  execution={execution}
+                  onErrorClick={() => onDetails(statsTaskId!, 'error')}
+                  onWarningClick={() => onDetails(statsTaskId!, 'warnings')}
+                  goToTask={goToTask}
+                />
+              </div>
             ))}
           {executionState.error && (
             <QueryErrorPane


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@druid.apache.org
For additional commands, e-mail: commits-h...@druid.apache.org

Reply via email to