You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by fj...@apache.org on 2019/06/07 15:32:15 UTC

[incubator-druid] branch master updated: Web console: prevent the time parse view from going into a bad state (#7846)

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

fjy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git


The following commit(s) were added to refs/heads/master by this push:
     new df01335  Web console: prevent the time parse view from going into a bad state (#7846)
df01335 is described below

commit df01335789f6e4f89d70b7b33dc373b8afc99c2e
Author: Vadim Ogievetsky <va...@gmail.com>
AuthorDate: Fri Jun 7 08:32:10 2019 -0700

    Web console: prevent the time parse view from going into a bad state (#7846)
    
    * prevent the time parse view from going into a bad state
    
    * add test
---
 .../__snapshots__/table-cell.spec.tsx.snap         |  8 +++
 .../src/components/table-cell/table-cell.spec.tsx  | 11 ++++
 .../src/components/table-cell/table-cell.tsx       |  6 ++-
 web-console/src/utils/sampler.ts                   | 59 +++++++++++++++++++++-
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap b/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
index 48d579d..d1cf2ff 100644
--- a/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
+++ b/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
@@ -43,6 +43,14 @@ exports[`table cell matches snapshot null 1`] = `
 </span>
 `;
 
+exports[`table cell matches snapshot null timestamp 1`] = `
+<span
+  class="table-cell unparseable"
+>
+  unparseable timestamp
+</span>
+`;
+
 exports[`table cell matches snapshot simple 1`] = `Hello World`;
 
 exports[`table cell matches snapshot truncate 1`] = `
diff --git a/web-console/src/components/table-cell/table-cell.spec.tsx b/web-console/src/components/table-cell/table-cell.spec.tsx
index 821119a..1401a74 100644
--- a/web-console/src/components/table-cell/table-cell.spec.tsx
+++ b/web-console/src/components/table-cell/table-cell.spec.tsx
@@ -33,6 +33,17 @@ describe('table cell', () => {
     expect(container.firstChild).toMatchSnapshot();
   });
 
+  it('matches snapshot null timestamp', () => {
+    const tableCell = <TableCell
+      value={null}
+      unparseable={false}
+      timestamp
+    />;
+
+    const { container } = render(tableCell);
+    expect(container.firstChild).toMatchSnapshot();
+  });
+
   it('matches snapshot simple', () => {
     const tableCell = <TableCell
       value="Hello World"
diff --git a/web-console/src/components/table-cell/table-cell.tsx b/web-console/src/components/table-cell/table-cell.tsx
index 6970b1d..9801dfb 100644
--- a/web-console/src/components/table-cell/table-cell.tsx
+++ b/web-console/src/components/table-cell/table-cell.tsx
@@ -89,7 +89,11 @@ export class TableCell extends React.PureComponent<NullTableCellProps, {}> {
         return TableCell.possiblyTruncate(String(value));
       }
     } else {
-      return <span className="table-cell null">null</span>;
+      if (timestamp) {
+        return <span className="table-cell unparseable">unparseable timestamp</span>;
+      } else {
+        return <span className="table-cell null">null</span>;
+      }
     }
   }
 }
diff --git a/web-console/src/utils/sampler.ts b/web-console/src/utils/sampler.ts
index 4a3f7fc..cff22b9 100644
--- a/web-console/src/utils/sampler.ts
+++ b/web-console/src/utils/sampler.ts
@@ -24,7 +24,7 @@ import {
   DimensionsSpec,
   getEmptyTimestampSpec, getSpecType,
   IngestionSpec,
-  IoConfig, MetricSpec,
+  IoConfig, isColumnTimestampSpec, MetricSpec,
   Parser,
   ParseSpec,
   Transform, TransformSpec
@@ -209,7 +209,42 @@ export async function sampleForTimestamp(spec: IngestionSpec, sampleStrategy: Sa
   const ioConfig: IoConfig = makeSamplerIoConfig(deepGet(spec, 'ioConfig'), samplerType, sampleStrategy);
   const parser: Parser = deepGet(spec, 'dataSchema.parser') || {};
   const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || {};
+  const timestampSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec.timestampSpec') || getEmptyTimestampSpec();
+  const columnTimestampSpec = isColumnTimestampSpec(timestampSpec);
 
+  // First do a query with a static timestamp spec
+  const sampleSpecColumns: SampleSpec = {
+    type: samplerType,
+    spec: {
+      type: samplerType,
+      ioConfig: deepSet(ioConfig, 'type', samplerType),
+      dataSchema: {
+        dataSource: 'sample',
+        parser: {
+          type: parser.type,
+          parseSpec: (
+            parser.parseSpec ?
+              Object.assign({}, parseSpec, {
+                dimensionsSpec: {},
+                timestampSpec: columnTimestampSpec ? getEmptyTimestampSpec() : timestampSpec
+              }) :
+              undefined
+          ) as any
+        }
+      }
+    },
+    samplerConfig: Object.assign({}, BASE_SAMPLER_CONFIG, {
+      cacheKey
+    })
+  };
+
+  const sampleColumns = await postToSampler(sampleSpecColumns, 'timestamp-columns');
+
+  // If we are not parsing a column then there is nothing left to do
+  if (!columnTimestampSpec) return sampleColumns;
+
+  // If we are trying to parts a column then get a bit fancy:
+  // Query the same sample again (same cache key)
   const sampleSpec: SampleSpec = {
     type: samplerType,
     spec: {
@@ -230,7 +265,27 @@ export async function sampleForTimestamp(spec: IngestionSpec, sampleStrategy: Sa
     })
   };
 
-  return postToSampler(sampleSpec, 'timestamp');
+  const sampleTime = await postToSampler(sampleSpec, 'timestamp-time');
+
+  if (
+    sampleTime.cacheKey !== sampleColumns.cacheKey ||
+    sampleTime.data.length !== sampleColumns.data.length
+  ) {
+    // If the two responses did not come from the same cache (or for some reason have different lengths) then
+    // just return the one with the parsed time column.
+    return sampleTime;
+  }
+
+  const sampleTimeData = sampleTime.data;
+  return Object.assign({}, sampleColumns, {
+    data: sampleColumns.data.map((d, i) => {
+      // Merge the column sample with the time column sample
+      if (!d.parsed) return d;
+      const timeDatumParsed = sampleTimeData[i].parsed;
+      d.parsed.__time = timeDatumParsed ? timeDatumParsed.__time : null;
+      return d;
+    })
+  });
 }
 
 export async function sampleForTransform(spec: IngestionSpec, sampleStrategy: SampleStrategy, cacheKey: string | undefined): Promise<SampleResponse> {


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