mirror of https://github.com/apache/druid.git
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
This commit is contained in:
parent
ca5afd29b8
commit
df01335789
|
@ -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`] = `
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Reference in New Issue