Merge pull request #3430 from influxdata/bf-typescript-conversions

Start converting utils to typescript
pull/10616/head
Brandon Farmer 2018-05-14 10:00:31 -07:00 committed by GitHub
commit 7a9fa74ed2
5 changed files with 88 additions and 61 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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,23 +145,21 @@ 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<string, string>(result, 1, '0')
const hours = _.get<string, string>(result, 2, '0')
const minutes = _.get<string, string>(result, 3, '0')
const seconds = _.get<string, string>(result, 4, '0')
const hoursInDay = 24
if (days) {
if (+days) {
adjustedTime = `${days}d`
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`

View File

@ -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) || ''