diff --git a/tsp-typescript-client/fixtures/tsp-client/fetch-generic-xy-0.json b/tsp-typescript-client/fixtures/tsp-client/fetch-generic-xy-0.json index 1345492..e0fa467 100644 --- a/tsp-typescript-client/fixtures/tsp-client/fetch-generic-xy-0.json +++ b/tsp-typescript-client/fixtures/tsp-client/fetch-generic-xy-0.json @@ -6,26 +6,26 @@ "seriesId": 3, "seriesName": "15652", "xValues": [ - [ - 0, - 604229397 - ], - [ - 604229398, - 1208458795 - ], - [ - 1208458796, - 1812688193 - ], - [ - 1812688194, - 2416917590 - ], - [ - 2416917591, - 3021146988 - ] + { + "start": 0, + "end": 604229397 + }, + { + "start": 604229398, + "end": 1208458795 + }, + { + "start": 1208458796, + "end": 1812688193 + }, + { + "start": 1812688194, + "end": 2416917590 + }, + { + "start": 2416917591, + "end": 3021146988 + } ], "yValues": [ 3.0, @@ -61,26 +61,26 @@ "seriesId": 4, "seriesName": "15653", "xValues": [ - [ - 0, - 604229397 - ], - [ - 604229398, - 1208458795 - ], - [ - 1208458796, - 1812688193 - ], - [ - 1812688194, - 2416917590 - ], - [ - 2416917591, - 3021146988 - ] + { + "start": 0, + "end": 604229397 + }, + { + "start": 604229398, + "end": 1208458795 + }, + { + "start": 1208458796, + "end": 1812688193 + }, + { + "start": 1812688194, + "end": 2416917590 + }, + { + "start": 2416917591, + "end": 3021146988 + } ], "yValues": [ 3.0, @@ -116,26 +116,26 @@ "seriesId": 2, "seriesName": "15646", "xValues": [ - [ - 0, - 604229397 - ], - [ - 604229398, - 1208458795 - ], - [ - 1208458796, - 1812688193 - ], - [ - 1812688194, - 2416917590 - ], - [ - 2416917591, - 3021146988 - ] + { + "start": 0, + "end": 604229397 + }, + { + "start": 604229398, + "end": 1208458795 + }, + { + "start": 1208458796, + "end": 1812688193 + }, + { + "start": 1812688194, + "end": 2416917590 + }, + { + "start": 2416917591, + "end": 3021146988 + } ], "yValues": [ 3.0, @@ -171,26 +171,26 @@ "seriesId": 1, "seriesName": "15647", "xValues": [ - [ - 0, - 604229397 - ], - [ - 604229398, - 1208458795 - ], - [ - 1208458796, - 1812688193 - ], - [ - 1812688194, - 2416917590 - ], - [ - 2416917591, - 3021146988 - ] + { + "start": 0, + "end": 604229397 + }, + { + "start": 604229398, + "end": 1208458795 + }, + { + "start": 1208458796, + "end": 1812688193 + }, + { + "start": 1812688194, + "end": 2416917590 + }, + { + "start": 2416917591, + "end": 3021146988 + } ], "yValues": [ 3.0, diff --git a/tsp-typescript-client/src/models/sampling.ts b/tsp-typescript-client/src/models/sampling.ts index 8946ca2..a2b5634 100644 --- a/tsp-typescript-client/src/models/sampling.ts +++ b/tsp-typescript-client/src/models/sampling.ts @@ -1,14 +1,25 @@ -import { toBigInt } from '../protocol/serialization'; +import { createNormalizer, toBigInt } from '../protocol/serialization'; -export type StartEndRange = [bigint, bigint]; +export const StartEndRange = createNormalizer({ + start: BigInt, + end: BigInt, +}); + +/** + * Represents a closed interval {start, end} as an object. + */ +export interface StartEndRange { + /** + * Start time of the range + */ + start: bigint; + + /** + * End time of the range + */ + end: bigint; +} -export const StartEndRange = (v: unknown): StartEndRange => { - if (!Array.isArray(v) || v.length !== 2) { - throw new Error('StartEndRange: expected [start,end]'); - } - const [s, e] = v; - return [toBigInt(s as any), toBigInt(e as any)]; -}; /** * Represent sampling on a list of timestamps. @@ -30,8 +41,21 @@ export type RangeSampling = StartEndRange[]; */ export type Sampling = TimestampSampling | CategorySampling | RangeSampling; -export const isRangeSampling = (s: Sampling): s is [bigint, bigint][] => - Array.isArray(s) && Array.isArray(s[0]); +export const isRangeSampling = (s: Sampling): s is StartEndRange[] => { + if (!Array.isArray(s)) { + return false; + } + if (s.length === 0) { + return true; + } + const firstElement = s[0]; + return ( + typeof firstElement === 'object' && + firstElement !== null && + 'start' in firstElement && + 'end' in firstElement + ); +}; export const isTimestampSampling = (s: Sampling): s is bigint[] => Array.isArray(s) && typeof s[0] === 'bigint'; @@ -57,9 +81,9 @@ export const Sampling = (v: unknown): Sampling => { return arr.map(toBigInt) as bigint[]; } - // ranges → array of [bigint, bigint] - if (Array.isArray(first) && first.length === 2) { - return (v as unknown[]).map(StartEndRange); + // Range sampling (array of {start, end} objects) + if (typeof first === 'object' && first !== null && 'start' in first && 'end' in first) { + return v.map(StartEndRange); } // Category sampling → strings; leave as-is diff --git a/tsp-typescript-client/src/protocol/tsp-client.test.ts b/tsp-typescript-client/src/protocol/tsp-client.test.ts index 098cc67..daa9430 100644 --- a/tsp-typescript-client/src/protocol/tsp-client.test.ts +++ b/tsp-typescript-client/src/protocol/tsp-client.test.ts @@ -7,6 +7,7 @@ import { DataType } from '../models/data-type'; import { ConfigurationParameterDescriptor } from '../models/configuration-source'; import { QueryHelper } from '../models/query/query-helper'; import { isAxisDomainCategorical, isAxisDomainRange } from '../models/axis-domain'; +import { StartEndRange } from '../models/sampling'; describe('HttpTspClient Deserialization', () => { @@ -372,12 +373,16 @@ describe('HttpTspClient Deserialization', () => { expect(serie.xValues).toHaveLength(5); expect(serie.yValues).toHaveLength(5); for (const xValue of serie.xValues) { - if (Array.isArray(xValue) && xValue.length === 2) { - const [start, end] = xValue; - expect(typeof start).toBe('bigint'); - expect(typeof end).toBe('bigint'); + if ( + typeof xValue === 'object' && + xValue !== null && + !Array.isArray(xValue) + ) { + const rangeObject = xValue as StartEndRange; + expect(typeof rangeObject.start).toBe('bigint'); + expect(typeof rangeObject.end).toBe('bigint'); } else { - fail('xValues is not RangeSampling ([start,end] tuple)'); + throw new Error('xValue is not a valid StartEndRange object ({start, end})'); } }