diff --git a/packages/core/src/query/flux.ts b/packages/core/src/query/flux.ts index 841dc84f5..ac5dca3fd 100644 --- a/packages/core/src/query/flux.ts +++ b/packages/core/src/query/flux.ts @@ -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). @@ -243,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 diff --git a/packages/core/test/unit/query/flux.test.ts b/packages/core/test/unit/query/flux.test.ts index 851819efc..cf42ddebe 100644 --- a/packages/core/test/unit/query/flux.test.ts +++ b/packages/core/test/unit/query/flux.test.ts @@ -148,6 +148,11 @@ describe('Flux Tagged Template', () => { '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', () => { try { flux`${undefined}` @@ -156,6 +161,19 @@ describe('Flux Tagged Template', () => { // ok expected, undefined is not supported } }) + it('fails on empty toString', () => { + try { + const x = { + toString(): string { + return '' + }, + } + flux`${x}` + expect.fail() + } catch (_e) { + // ok expected, undefined is not supported + } + }) it('fails on wrong usage of template', () => { try { flux((['1', '2'] as any) as TemplateStringsArray) @@ -166,17 +184,21 @@ describe('Flux Tagged Template', () => { }) it('processes a simple nested flux template', () => { - // nested flux templates 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 simple nested flux template', () => { - // nested flux templates + 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")' + ) + }) })