Skip to content

Commit

Permalink
Merge pull request #252 from influxdata/251/flux_expression
Browse files Browse the repository at this point in the history
fix(core): repair nesting of flux expressions
  • Loading branch information
sranka authored Sep 9, 2020
2 parents 22a2fdd + c0e7b53 commit 299d33e
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 54 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
1. [#237](https://github.com/influxdata/influxdb-client-js/pull/237): Fixed line splitter of query results that might have produced wrong results for query responses with quoted data.
1. [#242](https://github.com/influxdata/influxdb-client-js/pull/242): Repair escaping of backslash in line protocol string field.
1. [#246](https://github.com/influxdata/influxdb-client-js/pull/246): Throw error on attempt to write points using a closed WriteApi instance.
1. [#252](https://github.com/influxdata/influxdb-client-js/pull/252): Repair nesting of flux expressions.

## 1.6.0 [2020-08-14]

Expand Down
22 changes: 18 additions & 4 deletions packages/core/src/query/flux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ class FluxParameter implements FluxParameterLike, ParameterizedQuery {
}
}

/**
* Checks if the supplied object is FluxParameterLike
* @param value - any value
* @returns true if it is
*/
function isFluxParameterLike(value: any): boolean {
return typeof value === 'object' && typeof value[FLUX_VALUE] === 'function'
}

/**
* Escapes content of the supplied string so it can be wrapped into double qoutes
* to become a [flux string literal](https://docs.influxdata.com/flux/v0.65/language/lexical-elements/#string-literals).
Expand Down Expand Up @@ -222,7 +231,9 @@ export function flux(
strings: TemplateStringsArray,
...values: any
): ParameterizedQuery {
if (strings.length == 1 && (!values || values.length === 0)) return strings[0] // the simplest case
if (strings.length == 1 && (!values || values.length === 0)) {
return fluxExpression(strings[0]) // the simplest case
}
const parts = new Array<string>(strings.length + values.length)
let partIndex = 0
for (let i = 0; i < strings.length; i++) {
Expand All @@ -241,9 +252,12 @@ export function flux(
} else {
sanitized = toFluxValue(val)
if (sanitized === '') {
throw new Error(
`Unsupported parameter literal '${val}' at index: ${i}, type: ${typeof val}`
)
// do not allow to insert empty strings, unless it is FluxParameterLike
if (!isFluxParameterLike(val)) {
throw new Error(
`Unsupported parameter literal '${val}' at index: ${i}, type: ${typeof val}`
)
}
}
}
parts[partIndex++] = sanitized
Expand Down
116 changes: 66 additions & 50 deletions packages/core/test/unit/query/flux.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,7 @@ describe('Flux Values', () => {
const subject = fluxInteger(123)
expect(subject.toString()).equals('123')
expect((subject as any)[FLUX_VALUE]()).equals('123')
try {
fluxInteger('123a')
expect.fail()
} catch (_e) {
// OK, this must happen
}
expect(() => fluxInteger('123a')).to.throw()
})
it('creates fluxBool', () => {
expect(fluxBool('true').toString()).equals('true')
Expand All @@ -49,18 +44,8 @@ describe('Flux Values', () => {
const subject = fluxFloat(123.456)
expect(subject.toString()).equals('123.456')
expect((subject as any)[FLUX_VALUE]()).equals('123.456')
try {
fluxFloat('123..')
expect.fail()
} catch (_e) {
// OK, this must happen
}
try {
fluxFloat('123.a')
expect.fail()
} catch (_e) {
// OK, this must happen
}
expect(() => fluxFloat('123..')).to.throw()
expect(() => fluxFloat('123.a')).to.throw()
})
it('creates fluxDuration', () => {
const subject = fluxDuration('1ms')
Expand Down Expand Up @@ -127,37 +112,68 @@ describe('Flux Values', () => {
})

describe('Flux Tagged Template', () => {
expect(
flux`from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")`.toString(),
'from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")'
)
expect(
flux`from(bucket:"my-bucket") |> range(start: ${0}) |> filter(fn: (r) => r._measurement == ${'temperature'})`.toString(),
'from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")'
)
expect(
flux`from(bucket:"my-bucket") |> range(start: ${0}) |> filter(fn: (r) => r._measurement == "${'temperature'}")`.toString(),
'from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")'
)

try {
flux`${undefined}`
expect.fail()
} catch (_e) {
// ok expected, undefined is not supported
}

try {
flux((['1', '2'] as any) as TemplateStringsArray)
expect.fail()
} catch (_e) {
// ok expected, too few arguments supplied to a tagged template
}
it('creates a string from a simple string', () => {
expect(
flux`from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")`.toString()
).equals(
'from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")'
)
})
it('interpolates a number', () => {
expect(
flux`from(bucket:"my-bucket") |> range(start: ${0}) |> filter(fn: (r) => r._measurement == ${'temperature'})`.toString()
).equals(
'from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")'
)
})
it('interpolates a string', () => {
expect(
flux`from(bucket:${'my-bucket'}) |> range(start: 0) |> filter(fn: (r) => r._measurement == ${'temperature'})`.toString()
).equals(
'from(bucket:"my-bucket") |> range(start: 0) |> filter(fn: (r) => r._measurement == "temperature")'
)
})
it('interpolates a wrapped string', () => {
expect(flux`from(bucket:"${'my-bucket'}")`.toString()).equals(
'from(bucket:"my-bucket")'
)
})
it('fails on undefined', () => {
expect(() => flux`${undefined}`).to.throw()
})
it('converts object with empty toString to ""', () => {
const x = {
toString(): string {
return ''
},
}
expect(flux`${x}`.toString()).equals('""')
})
it('fails on wrong usage of template', () => {
try {
flux((['1', '2'] as any) as TemplateStringsArray)
expect.fail()
} catch (_e) {
// ok expected, too few arguments supplied to a tagged template
}
})

// nested flux templates
const flux1 = flux`from(bucket:"my-bucket")`
expect(
flux`${flux1} |> range(start: ${0})")`.toString(),
'from(bucket:"my-bucket") |> range(start: 0)")'
)
it('processes a simple nested flux template', () => {
const flux1 = flux`from(bucket:"my-bucket")`
expect(flux`${flux1} |> range(start: ${0})")`.toString()).equals(
'from(bucket:"my-bucket") |> range(start: 0)")'
)
})
it('processes a parameterized nested flux template', () => {
const flux1 = flux`from(bucket:${'my-bucket'})`
expect(flux`${flux1} |> range(start: ${0})")`.toString()).equals(
'from(bucket:"my-bucket") |> range(start: 0)")'
)
})
it('processes an empty nested flux template', () => {
const empty = flux``
expect(flux`from(bucket:"my-bucket")${empty}`.toString()).equals(
'from(bucket:"my-bucket")'
)
})
})

0 comments on commit 299d33e

Please sign in to comment.