From 661b7a9f6839bb79a6236dcac0b79ce854c0929f Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Fri, 11 May 2018 10:55:35 -0700 Subject: [PATCH 1/2] Convert formatting to typescript --- ui/src/utils/{formatting.js => formatting.ts} | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) rename ui/src/utils/{formatting.js => formatting.ts} (73%) diff --git a/ui/src/utils/formatting.js b/ui/src/utils/formatting.ts similarity index 73% rename from ui/src/utils/formatting.js rename to ui/src/utils/formatting.ts index 881c1203ec..e685a21168 100644 --- a/ui/src/utils/formatting.js +++ b/ui/src/utils/formatting.ts @@ -1,8 +1,9 @@ -const KMB_LABELS = ['K', 'M', 'B', 'T', 'Q'] -const KMG2_BIG_LABELS = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] -const KMG2_SMALL_LABELS = ['m', 'u', 'n', 'p', 'f', 'a', 'z', 'y'] +import _ from 'lodash' +const KMB_LABELS: string[] = ['K', 'M', 'B', 'T', 'Q'] +const KMG2_BIG_LABELS: string[] = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] +const KMG2_SMALL_LABELS: string[] = ['m', 'u', 'n', 'p', 'f', 'a', 'z', 'y'] -const pow = (base, exp) => { +const pow = (base: number, exp: number): number => { if (exp < 0) { return 1.0 / Math.pow(base, -exp) } @@ -10,12 +11,12 @@ const pow = (base, exp) => { return Math.pow(base, exp) } -const round_ = (num, places) => { +const roundNum = (num, places): number => { const shift = Math.pow(10, places) return Math.round(num * shift) / shift } -const floatFormat = (x, optPrecision) => { +const floatFormat = (x: number, optPrecision: number): string => { // Avoid invalid precision values; [1, 21] is the valid range. const p = Math.min(Math.max(1, optPrecision || 2), 21) @@ -41,7 +42,12 @@ const floatFormat = (x, optPrecision) => { } // taken from https://github.com/danvk/dygraphs/blob/aaec6de56dba8ed712fd7b9d949de47b46a76ccd/src/dygraph-utils.js#L1103 -export const numberValueFormatter = (x, opts, prefix, suffix) => { +export const numberValueFormatter = ( + x: number, + opts: (name: string) => number, + prefix: string, + suffix: string +): string => { const sigFigs = opts('sigFigs') if (sigFigs !== null) { @@ -65,7 +71,7 @@ export const numberValueFormatter = (x, opts, prefix, suffix) => { ) { label = x.toExponential(digits) } else { - label = `${round_(x, digits)}` + label = `${roundNum(x, digits)}` } if (kmb || kmg2) { @@ -89,15 +95,17 @@ export const numberValueFormatter = (x, opts, prefix, suffix) => { let n = pow(k, kLabels.length) for (let j = kLabels.length - 1; j >= 0; j -= 1, n /= k) { if (absx >= n) { - label = round_(x / n, digits) + kLabels[j] + label = roundNum(x / n, digits) + kLabels[j] break } } if (kmg2) { - const xParts = String(x.toExponential()).split('e-') + const xParts = String(x.toExponential()) + .split('e-') + .map(Number) if (xParts.length === 2 && xParts[1] >= 3 && xParts[1] <= 24) { if (xParts[1] % 3 > 0) { - label = round_(xParts[0] / pow(10, xParts[1] % 3), digits) + label = roundNum(xParts[0] / pow(10, xParts[1] % 3), digits) } else { label = Number(xParts[0]).toFixed(2) } @@ -109,7 +117,7 @@ export const numberValueFormatter = (x, opts, prefix, suffix) => { return `${prefix}${label}${suffix}` } -export const formatBytes = bytes => { +export const formatBytes = (bytes: number) => { if (bytes === 0) { return '0 Bytes' } @@ -126,7 +134,7 @@ export const formatBytes = bytes => { return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` } -export const formatRPDuration = duration => { +export const formatRPDuration = (duration: string | null): string => { if (!duration) { return } @@ -137,13 +145,11 @@ export const formatRPDuration = duration => { let adjustedTime = duration const durationMatcher = /(?:(\d*)d)?(?:(\d*)h)?(?:(\d*)m)?(?:(\d*)s)?/ - const [ - _match, // eslint-disable-line no-unused-vars - days = 0, - hours = 0, - minutes = 0, - seconds = 0, - ] = duration.match(durationMatcher) + const result = duration.match(durationMatcher) + const days = _.get(result, 1, '0') + const hours = _.get(result, 2, '0') + const minutes = _.get(result, 3, '0') + const seconds = _.get(result, 4, '0') const hoursInDay = 24 if (days) { @@ -151,9 +157,9 @@ export const formatRPDuration = duration => { adjustedTime += +hours === 0 ? '' : `${hours}h` adjustedTime += +minutes === 0 ? '' : `${minutes}m` adjustedTime += +seconds === 0 ? '' : `${seconds}s` - } else if (hours > hoursInDay) { - const hoursRemainder = hours % hoursInDay - const daysQuotient = (hours - hoursRemainder) / hoursInDay + } else if (+hours > hoursInDay) { + const hoursRemainder = +hours % hoursInDay + const daysQuotient = (+hours - hoursRemainder) / hoursInDay adjustedTime = `${daysQuotient}d` adjustedTime += +hoursRemainder === 0 ? '' : `${hoursRemainder}h` adjustedTime += +minutes === 0 ? '' : `${minutes}m` From 9a16efbc699d8439fd4296934b9ad5fc375c6cdd Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Fri, 11 May 2018 11:54:56 -0700 Subject: [PATCH 2/2] Convert influxql.js to typescript --- .../shared/components/MeasurementListItem.tsx | 1 - ui/src/shared/components/TagList.tsx | 1 - ui/src/types/query.ts | 16 ++-- ui/src/utils/formatting.ts | 2 +- ui/src/utils/{influxql.js => influxql.ts} | 77 ++++++++++++------- 5 files changed, 59 insertions(+), 38 deletions(-) rename ui/src/utils/{influxql.js => influxql.ts} (63%) diff --git a/ui/src/shared/components/MeasurementListItem.tsx b/ui/src/shared/components/MeasurementListItem.tsx index a4dadcfd25..08544a50c8 100644 --- a/ui/src/shared/components/MeasurementListItem.tsx +++ b/ui/src/shared/components/MeasurementListItem.tsx @@ -3,7 +3,6 @@ import classnames from 'classnames' import React, {PureComponent, MouseEvent} from 'react' import TagList from 'src/shared/components/TagList' import {ErrorHandling} from 'src/shared/decorators/errors' - import {QueryConfig, Tag} from 'src/types' interface SourceLinks { diff --git a/ui/src/shared/components/TagList.tsx b/ui/src/shared/components/TagList.tsx index fb5255b035..c1ae5cb6c7 100644 --- a/ui/src/shared/components/TagList.tsx +++ b/ui/src/shared/components/TagList.tsx @@ -9,7 +9,6 @@ import {showTagKeys, showTagValues} from 'src/shared/apis/metaQuery' import showTagKeysParser from 'src/shared/parsing/showTagKeys' import showTagValuesParser from 'src/shared/parsing/showTagValues' import {ErrorHandling} from 'src/shared/decorators/errors' - import {QueryConfig, Tag} from 'src/types' const {shape} = PropTypes diff --git a/ui/src/types/query.ts b/ui/src/types/query.ts index 189d028913..27e54033be 100644 --- a/ui/src/types/query.ts +++ b/ui/src/types/query.ts @@ -1,18 +1,20 @@ export interface QueryConfig { id?: string - database: string - measurement: string - retentionPolicy: string - fields: Field[] + database?: string + measurement?: string + retentionPolicy?: string + fields?: Field[] tags: Tags - groupBy: GroupBy + groupBy?: GroupBy areTagsAccepted: boolean - rawText: string + rawText?: string range?: DurationRange | null sourceLink?: string fill?: string status?: Status - shifts: TimeShift[] + shifts?: TimeShift[] + lower?: string + upper?: string isQuerySupportedByExplorer?: boolean // doesn't come from server -- is set in CellEditorOverlay } diff --git a/ui/src/utils/formatting.ts b/ui/src/utils/formatting.ts index e685a21168..403232cd6d 100644 --- a/ui/src/utils/formatting.ts +++ b/ui/src/utils/formatting.ts @@ -152,7 +152,7 @@ export const formatRPDuration = (duration: string | null): string => { const seconds = _.get(result, 4, '0') const hoursInDay = 24 - if (days) { + if (+days) { adjustedTime = `${days}d` adjustedTime += +hours === 0 ? '' : `${hours}h` adjustedTime += +minutes === 0 ? '' : `${minutes}m` diff --git a/ui/src/utils/influxql.js b/ui/src/utils/influxql.ts similarity index 63% rename from ui/src/utils/influxql.js rename to ui/src/utils/influxql.ts index 61faa65be5..e36b11a9bf 100644 --- a/ui/src/utils/influxql.js +++ b/ui/src/utils/influxql.ts @@ -1,16 +1,22 @@ import _ from 'lodash' -import {TEMP_VAR_INTERVAL, AUTO_GROUP_BY} from 'shared/constants' -import {NULL_STRING} from 'shared/constants/queryFillOptions' +import {TEMP_VAR_INTERVAL, AUTO_GROUP_BY} from 'src/shared/constants' +import {NULL_STRING} from 'src/shared/constants/queryFillOptions' import { TYPE_QUERY_CONFIG, TYPE_SHIFTED, TYPE_IFQL, } from 'src/dashboards/constants' -import {shiftTimeRange} from 'shared/query/helpers' +import {shiftTimeRange} from 'src/shared/query/helpers' +import {QueryConfig, Field, GroupBy, TimeShift} from 'src/types' -/* eslint-disable quotes */ -export const quoteIfTimestamp = ({lower, upper}) => { +export const quoteIfTimestamp = ({ + lower, + upper, +}: { + lower: string + upper: string +}): {lower: string; upper: string} => { if (lower && lower.includes('Z') && !lower.includes("'")) { lower = `'${lower}'` } @@ -21,43 +27,53 @@ export const quoteIfTimestamp = ({lower, upper}) => { return {lower, upper} } -/* eslint-enable quotes */ -export default function buildInfluxQLQuery(timeRange, config, shift) { +export default function buildInfluxQLQuery( + timeRange, + config: QueryConfig, + shift: string = '' +): string { const {groupBy, fill = NULL_STRING, tags, areTagsAccepted} = config const {upper, lower} = quoteIfTimestamp(timeRange) - const select = _buildSelect(config, shift) + const select = buildSelect(config, shift) if (select === null) { return null } - const condition = _buildWhereClause({lower, upper, tags, areTagsAccepted}) - const dimensions = _buildGroupBy(groupBy) - const fillClause = groupBy.time ? _buildFill(fill) : '' + const condition = buildWhereClause({lower, upper, tags, areTagsAccepted}) + const dimensions = buildGroupBy(groupBy) + const fillClause = groupBy.time ? buildFill(fill) : '' return `${select}${condition}${dimensions}${fillClause}` } -function _buildSelect({fields, database, retentionPolicy, measurement}, shift) { - if (!database || !measurement || !fields || !fields.length) { +function buildSelect( + {fields, database, retentionPolicy, measurement}: QueryConfig, + shift: string | null = null +): string { + if (!database || !measurement || _.isEmpty(fields)) { return null } const rpSegment = retentionPolicy ? `"${retentionPolicy}"` : '' - const fieldsClause = _buildFields(fields, shift) + const fieldsClause = buildFields(fields, shift) const fullyQualifiedMeasurement = `"${database}".${rpSegment}."${measurement}"` const statement = `SELECT ${fieldsClause} FROM ${fullyQualifiedMeasurement}` return statement } // type arg will reason about new query types i.e. IFQL, GraphQL, or queryConfig -export const buildQuery = (type, timeRange, config, shift) => { +export const buildQuery = ( + type: string, + timeRange: object, + config: QueryConfig, + shift: TimeShift | null = null +): string => { switch (type) { case TYPE_QUERY_CONFIG: { return buildInfluxQLQuery(timeRange, config) } - case TYPE_SHIFTED: { const {quantity, unit} = shift return buildInfluxQLQuery( @@ -75,11 +91,11 @@ export const buildQuery = (type, timeRange, config, shift) => { return buildInfluxQLQuery(timeRange, config) } -export function buildSelectStatement(config) { - return _buildSelect(config) +export function buildSelectStatement(config: QueryConfig): string { + return buildSelect(config) } -function _buildFields(fieldFuncs, shift = '') { +function buildFields(fieldFuncs: Field[], shift = ''): string { if (!fieldFuncs) { return '' } @@ -103,7 +119,7 @@ function _buildFields(fieldFuncs, shift = '') { return `${f.value}` } case 'func': { - const args = _buildFields(f.args) + const args = buildFields(f.args) const alias = f.alias ? ` AS "${f.alias}${shift}"` : '' return `${f.value}(${args})${alias}` } @@ -112,7 +128,12 @@ function _buildFields(fieldFuncs, shift = '') { .join(', ') } -function _buildWhereClause({lower, upper, tags, areTagsAccepted}) { +function buildWhereClause({ + lower, + upper, + tags, + areTagsAccepted, +}: QueryConfig): string { const timeClauses = [] const timeClause = quoteIfTimestamp({lower, upper}) @@ -148,11 +169,11 @@ function _buildWhereClause({lower, upper, tags, areTagsAccepted}) { return ` WHERE ${subClauses.join(' AND ')}` } -function _buildGroupBy(groupBy) { - return `${_buildGroupByTime(groupBy)}${_buildGroupByTags(groupBy)}` +function buildGroupBy(groupBy: GroupBy): string { + return `${buildGroupByTime(groupBy)}${buildGroupByTags(groupBy)}` } -function _buildGroupByTime(groupBy) { +function buildGroupByTime(groupBy: GroupBy): string { if (!groupBy || !groupBy.time) { return '' } @@ -162,7 +183,7 @@ function _buildGroupByTime(groupBy) { })` } -function _buildGroupByTags(groupBy) { +function buildGroupByTags(groupBy: GroupBy): string { if (!groupBy || !groupBy.tags.length) { return '' } @@ -176,9 +197,9 @@ function _buildGroupByTags(groupBy) { return ` GROUP BY ${tags}` } -function _buildFill(fill) { +function buildFill(fill: string): string { return ` FILL(${fill})` } -export const buildRawText = (q, timeRange) => - q.rawText || buildInfluxQLQuery(timeRange, q) || '' +export const buildRawText = (config: QueryConfig, timeRange: object): string => + config.rawText || buildInfluxQLQuery(timeRange, config) || ''