@cubejs-client/core 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ResultSet.d.ts","sourceRoot":"","sources":["../../src/ResultSet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ResultSet.d.ts","sourceRoot":"","sources":["../../src/ResultSet.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EAAE,eAAe,EAC5B,UAAU,EACV,QAAQ,EACR,KAAK,EACL,gBAAgB,EAAE,SAAS,EAC3B,gBAAgB,EAChB,MAAM,EACN,iBAAiB,EACjB,WAAW,EACX,aAAa,EACd,MAAM,SAAS,CAAC;AA6BjB,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAIhD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAE/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IAExD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAsB;IAExD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAK;IAE7B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA0B;WAEnD,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM;WAI7C,mBAAmB,CAAC,EAAE,EAAE,aAAa;IAInD;;;;;;;;;;;;;OAaG;WACW,WAAW,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC;gBAI3G,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,gBAAqB;IA2BxG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0DG;IACI,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,IAAI;IAmG7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACI,MAAM,CAAC,UAAU,GAAG,GAAG,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,EAAE;IAShF,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,gBAAgB;WAaV,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,eAAe;IAkE/F,oBAAoB,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,eAAe;IAIhE,UAAU,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;IAmD9G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACI,KAAK,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,QAAQ,EAAE;IA4FnD,OAAO,CAAC,WAAW;IAiBnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgFG;IACI,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,aAAa,EAAE;IAiC7D;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACI,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAoBjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6FG;IACI,YAAY,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE;IAwHtD,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,aAAa;IAIlD,UAAU,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,aAAa,EAAE;IAI7D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACI,WAAW,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,EAAE;IA+C3D,KAAK,IAAI,KAAK;IAQd,UAAU,IAAI,UAAU;IAI/B;;OAEG;IACI,SAAS,IAAI,MAAM,GAAG,IAAI,GAAG,SAAS;IAItC,OAAO,IAAI,CAAC,EAAE;IAQd,UAAU,IAAI,gBAAgB;IAQrC,OAAO,CAAC,mCAAmC;IA8B3C;;;;;;;OAOG;IACI,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE;IAWpC;;OAEG;IACI,SAAS,IAAI,gBAAgB;CAKrC"}
@@ -152,7 +152,7 @@ export default class ResultSet {
152
152
  normalizedPivotConfig?.x.forEach((member, currentIndex) => values.push([member, xValues[currentIndex]]));
153
153
  normalizedPivotConfig?.y.forEach((member, currentIndex) => values.push([member, yValues[currentIndex]]));
154
154
  const { filters: parentFilters = [], segments = [] } = this.query();
155
- const { measures } = this.loadResponses[0].annotation;
155
+ const { measures, timeDimensions: timeDimensionsAnnotation } = this.loadResponses[0].annotation;
156
156
  let [, measureName] = values.find(([member]) => member === 'measures') || [];
157
157
  if (measureName === undefined) {
158
158
  [measureName] = Object.keys(measures);
@@ -172,7 +172,8 @@ export default class ResultSet {
172
172
  .forEach(([member, value]) => {
173
173
  const [cubeName, dimension, granularity] = member.split('.');
174
174
  if (granularity !== undefined) {
175
- const range = dayRange(value, value).snapTo(granularity);
175
+ // dayRange.snapTo now handles both predefined and custom granularities
176
+ const range = dayRange(value, value, timeDimensionsAnnotation).snapTo(granularity);
176
177
  const originalTimeDimension = query.timeDimensions?.find((td) => td.dimension);
177
178
  let dateRange = [
178
179
  range.start,
@@ -357,7 +358,7 @@ export default class ResultSet {
357
358
  timeDimension.dateRange.find(d => d.match(DateRegex)) :
358
359
  !['hour', 'minute', 'second'].includes(timeDimension.granularity);
359
360
  const [start, end] = dateRange;
360
- const range = dayRange(start, end);
361
+ const range = dayRange(start, end, annotations);
361
362
  if (isPredefinedGranularity(timeDimension.granularity)) {
362
363
  return TIME_SERIES[timeDimension.granularity](padToDay ? range.snapTo('d') : range);
363
364
  }
@@ -25,7 +25,6 @@ export declare const TIME_SERIES: Record<string, (range: DayRange) => string[]>;
25
25
  export declare const isPredefinedGranularity: (granularity: TimeDimensionGranularity) => boolean;
26
26
  export declare const DateRegex: RegExp;
27
27
  export declare const LocalDateRegex: RegExp;
28
- export declare const dayRange: (from: any, to: any) => DayRange;
29
28
  /**
30
29
  * Parse PostgreSQL-like interval string into object
31
30
  * E.g. '2 years 15 months 100 weeks 99 hours 15 seconds'
@@ -55,6 +54,9 @@ export declare function addInterval(date: dayjs.Dayjs, interval: ParsedInterval)
55
54
  * @returns {dayjs}
56
55
  */
57
56
  export declare function subtractInterval(date: dayjs.Dayjs, interval: ParsedInterval): dayjs.Dayjs;
57
+ export declare const dayRange: (from: any, to: any, annotations?: Record<string, {
58
+ granularity?: Granularity;
59
+ }>) => DayRange;
58
60
  /**
59
61
  * Returns the time series points for the custom interval
60
62
  * TODO: It's almost a copy/paste of timeSeriesFromCustomInterval from
@@ -1 +1 @@
1
- {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/time.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAGjC,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;IAClC,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC;IACjC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAC5C,QAAQ,GACN,QAAQ,GACR,MAAM,GACN,KAAK,GACL,MAAM,GACN,OAAO,GACP,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,kCAAkC,GAAG,MAAM,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,eAAe,EAU1C,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAIzC,eAAO,MAAM,aAAa,YAAa,GAAG,EAAE,KAAG,MAAM,KAAuD,CAAC;AAE7G,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,EAAE,CAWrE,CAAC;AAEF,eAAO,MAAM,uBAAuB,gBAAiB,wBAAwB,KAAG,OAAqC,CAAC;AAEtH,eAAO,MAAM,SAAS,QAAyB,CAAC;AAChD,eAAO,MAAM,cAAc,QAAkD,CAAC;AAE9E,eAAO,MAAM,QAAQ,SAAU,GAAG,MAAM,GAAG,KAAG,QAiB5C,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,cAAc,CAczE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,GAAG,KAAK,CAAC,KAAK,CAQpF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,GAAG,KAAK,CAAC,KAAK,CAQzF;AA4CD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,SAAU,MAAM,MAAM,MAAM,eAAe,WAAW,KAAG,MAAM,EAkBvG,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,aAAc,MAAM,KAAG,MAkB1D,CAAC;AAIF,eAAO,MAAM,0BAA0B,OAAQ,MAAM,MAAM,MAAM,KAAG,MAWnE,CAAC;AAEF,eAAO,MAAM,cAAc,YAAa,MAAM,KAAG,MA4DhD,CAAC"}
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/time.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAGjC,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;IAClC,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC;IACjC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAC5C,QAAQ,GACN,QAAQ,GACR,MAAM,GACN,KAAK,GACL,MAAM,GACN,OAAO,GACP,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,kCAAkC,GAAG,MAAM,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,eAAe,EAU1C,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAIzC,eAAO,MAAM,aAAa,YAAa,GAAG,EAAE,KAAG,MAAM,KAAuD,CAAC;AAE7G,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,EAAE,CAWrE,CAAC;AAEF,eAAO,MAAM,uBAAuB,gBAAiB,wBAAwB,KAAG,OAAqC,CAAC;AAEtH,eAAO,MAAM,SAAS,QAAyB,CAAC;AAChD,eAAO,MAAM,cAAc,QAAkD,CAAC;AAE9E;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,cAAc,CAczE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,GAAG,KAAK,CAAC,KAAK,CAQpF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,GAAG,KAAK,CAAC,KAAK,CAQzF;AA4CD,eAAO,MAAM,QAAQ,SAAU,GAAG,MAAM,GAAG,gBAAgB,OAAO,MAAM,EAAE;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC,KAAG,QA8DzG,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,SAAU,MAAM,MAAM,MAAM,eAAe,WAAW,KAAG,MAAM,EAkBvG,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,aAAc,MAAM,KAAG,MAkB1D,CAAC;AAIF,eAAO,MAAM,0BAA0B,OAAQ,MAAM,MAAM,MAAM,KAAG,MAWnE,CAAC;AAEF,eAAO,MAAM,cAAc,YAAa,MAAM,KAAG,MA4DhD,CAAC"}
package/dist/src/time.js CHANGED
@@ -34,21 +34,6 @@ export const TIME_SERIES = {
34
34
  export const isPredefinedGranularity = (granularity) => !!TIME_SERIES[granularity];
35
35
  export const DateRegex = /^\d\d\d\d-\d\d-\d\d$/;
36
36
  export const LocalDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z?$/;
37
- export const dayRange = (from, to) => ({
38
- by: (value) => {
39
- const results = [];
40
- let start = internalDayjs(from);
41
- const end = internalDayjs(to);
42
- while (start.startOf(value).isBefore(end) || start.isSame(end)) {
43
- results.push(start);
44
- start = start.add(1, value);
45
- }
46
- return results;
47
- },
48
- snapTo: (value) => dayRange(internalDayjs(from).startOf(value), internalDayjs(to).endOf(value)),
49
- start: internalDayjs(from),
50
- end: internalDayjs(to),
51
- });
52
37
  /**
53
38
  * Parse PostgreSQL-like interval string into object
54
39
  * E.g. '2 years 15 months 100 weeks 99 hours 15 seconds'
@@ -135,6 +120,60 @@ function alignToOrigin(startDate, interval, origin) {
135
120
  }
136
121
  return alignedDate;
137
122
  }
123
+ export const dayRange = (from, to, annotations) => ({
124
+ by: (value) => {
125
+ const results = [];
126
+ let start = internalDayjs(from);
127
+ const end = internalDayjs(to);
128
+ while (start.startOf(value).isBefore(end) || start.isSame(end)) {
129
+ results.push(start);
130
+ start = start.add(1, value);
131
+ }
132
+ return results;
133
+ },
134
+ snapTo: (value) => {
135
+ // Check if this is a custom granularity
136
+ if (!isPredefinedGranularity(value) && annotations) {
137
+ // Try to find the custom granularity metadata
138
+ // The annotation key might be in format "Cube.dimension.granularity"
139
+ // So we need to search through all annotations
140
+ let customGranularity;
141
+ for (const key of Object.keys(annotations)) {
142
+ if (key.endsWith(`.${value}`) && annotations[key].granularity) {
143
+ customGranularity = annotations[key].granularity;
144
+ break;
145
+ }
146
+ }
147
+ if (customGranularity?.interval) {
148
+ // For custom granularities, calculate the range for the bucket
149
+ const intervalParsed = parseSqlInterval(customGranularity.interval);
150
+ let intervalStart = internalDayjs(from);
151
+ // origin and offset are mutually exclusive
152
+ // If either is specified, align to it
153
+ if (customGranularity.origin || customGranularity.offset) {
154
+ let origin;
155
+ if (customGranularity.origin) {
156
+ // Absolute origin time
157
+ origin = internalDayjs(customGranularity.origin);
158
+ }
159
+ else {
160
+ // offset is relative to start of year
161
+ origin = addInterval(internalDayjs().startOf('year'), parseSqlInterval(customGranularity.offset));
162
+ }
163
+ // Align the value to the origin to find the actual bucket start
164
+ intervalStart = alignToOrigin(intervalStart, intervalParsed, origin);
165
+ }
166
+ // End is start + interval - 1 millisecond (to stay within the bucket)
167
+ const intervalEnd = addInterval(intervalStart, intervalParsed).subtract(1, 'millisecond');
168
+ return dayRange(intervalStart, intervalEnd, annotations);
169
+ }
170
+ }
171
+ // Default behavior for predefined granularities
172
+ return dayRange(internalDayjs(from).startOf(value), internalDayjs(to).endOf(value), annotations);
173
+ },
174
+ start: internalDayjs(from),
175
+ end: internalDayjs(to),
176
+ });
138
177
  /**
139
178
  * Returns the time series points for the custom interval
140
179
  * TODO: It's almost a copy/paste of timeSeriesFromCustomInterval from
@@ -370,4 +370,230 @@ describe('drill down query', () => {
370
370
  timezone: 'UTC',
371
371
  });
372
372
  });
373
+ it('handles custom granularity with interval and origin', () => {
374
+ const EVALUATION_PERIOD = 5;
375
+ const LAST_EVALUATED_AT = '2020-08-01T00:00:00.000';
376
+ const customGranularityResponse = {
377
+ queryType: 'regularQuery',
378
+ results: [
379
+ {
380
+ query: {
381
+ measures: ['Transactions.count'],
382
+ timeDimensions: [
383
+ {
384
+ dimension: 'Transactions.createdAt',
385
+ granularity: 'alerting_monitor',
386
+ dateRange: ['2020-08-01T00:00:00.000', '2020-08-01T01:00:00.000'],
387
+ },
388
+ ],
389
+ filters: [],
390
+ timezone: 'UTC',
391
+ order: [],
392
+ dimensions: [],
393
+ },
394
+ data: [
395
+ {
396
+ 'Transactions.createdAt.alerting_monitor': '2020-08-01T00:00:00.000',
397
+ 'Transactions.createdAt': '2020-08-01T00:00:00.000',
398
+ 'Transactions.count': 10,
399
+ },
400
+ {
401
+ 'Transactions.createdAt.alerting_monitor': '2020-08-01T00:05:00.000',
402
+ 'Transactions.createdAt': '2020-08-01T00:05:00.000',
403
+ 'Transactions.count': 15,
404
+ },
405
+ {
406
+ 'Transactions.createdAt.alerting_monitor': '2020-08-01T00:10:00.000',
407
+ 'Transactions.createdAt': '2020-08-01T00:10:00.000',
408
+ 'Transactions.count': 8,
409
+ },
410
+ ],
411
+ annotation: {
412
+ measures: {
413
+ 'Transactions.count': {
414
+ title: 'Transactions Count',
415
+ shortTitle: 'Count',
416
+ type: 'number',
417
+ drillMembers: ['Transactions.id', 'Transactions.createdAt'],
418
+ drillMembersGrouped: {
419
+ measures: [],
420
+ dimensions: ['Transactions.id', 'Transactions.createdAt'],
421
+ },
422
+ },
423
+ },
424
+ dimensions: {},
425
+ segments: {},
426
+ timeDimensions: {
427
+ 'Transactions.createdAt.alerting_monitor': {
428
+ title: 'Transaction created at',
429
+ shortTitle: 'Created at',
430
+ type: 'time',
431
+ granularity: {
432
+ name: 'alerting_monitor',
433
+ title: 'Alerting Monitor',
434
+ interval: `${EVALUATION_PERIOD} minutes`,
435
+ origin: LAST_EVALUATED_AT,
436
+ },
437
+ },
438
+ 'Transactions.createdAt': {
439
+ title: 'Transaction created at',
440
+ shortTitle: 'Created at',
441
+ type: 'time',
442
+ },
443
+ },
444
+ },
445
+ },
446
+ ],
447
+ pivotQuery: {
448
+ measures: ['Transactions.count'],
449
+ timeDimensions: [
450
+ {
451
+ dimension: 'Transactions.createdAt',
452
+ granularity: 'alerting_monitor',
453
+ dateRange: ['2020-08-01T00:00:00.000', '2020-08-01T01:00:00.000'],
454
+ },
455
+ ],
456
+ filters: [],
457
+ timezone: 'UTC',
458
+ order: [],
459
+ dimensions: [],
460
+ },
461
+ };
462
+ const resultSet = new ResultSet(customGranularityResponse);
463
+ // Test drilling down on the second data point (00:05:00)
464
+ expect(resultSet.drillDown({ xValues: ['2020-08-01T00:05:00.000'] })).toEqual({
465
+ measures: [],
466
+ segments: [],
467
+ dimensions: ['Transactions.id', 'Transactions.createdAt'],
468
+ filters: [
469
+ {
470
+ member: 'Transactions.count',
471
+ operator: 'measureFilter',
472
+ },
473
+ ],
474
+ timeDimensions: [
475
+ {
476
+ dimension: 'Transactions.createdAt',
477
+ // Should create a date range for the 5-minute interval starting at 00:05:00
478
+ dateRange: ['2020-08-01T00:05:00.000', '2020-08-01T00:09:59.999'],
479
+ },
480
+ ],
481
+ timezone: 'UTC',
482
+ });
483
+ });
484
+ it('handles custom granularity with non-aligned origin', () => {
485
+ const EVALUATION_PERIOD = 5;
486
+ const NON_ALIGNED_ORIGIN = '2020-08-01T00:02:00.000'; // Origin at 00:02 instead of 00:00
487
+ const customGranularityResponse = {
488
+ queryType: 'regularQuery',
489
+ results: [
490
+ {
491
+ query: {
492
+ measures: ['Transactions.count'],
493
+ timeDimensions: [
494
+ {
495
+ dimension: 'Transactions.createdAt',
496
+ granularity: 'alerting_monitor',
497
+ dateRange: ['2020-08-01T00:00:00.000', '2020-08-01T01:00:00.000'],
498
+ },
499
+ ],
500
+ filters: [],
501
+ timezone: 'UTC',
502
+ order: [],
503
+ dimensions: [],
504
+ },
505
+ data: [
506
+ {
507
+ // First bucket starts at 00:02:00 (origin)
508
+ 'Transactions.createdAt.alerting_monitor': '2020-08-01T00:02:00.000',
509
+ 'Transactions.createdAt': '2020-08-01T00:02:00.000',
510
+ 'Transactions.count': 10,
511
+ },
512
+ {
513
+ // Second bucket starts at 00:07:00 (origin + 5 minutes)
514
+ 'Transactions.createdAt.alerting_monitor': '2020-08-01T00:07:00.000',
515
+ 'Transactions.createdAt': '2020-08-01T00:07:00.000',
516
+ 'Transactions.count': 15,
517
+ },
518
+ {
519
+ // Third bucket starts at 00:12:00 (origin + 10 minutes)
520
+ 'Transactions.createdAt.alerting_monitor': '2020-08-01T00:12:00.000',
521
+ 'Transactions.createdAt': '2020-08-01T00:12:00.000',
522
+ 'Transactions.count': 8,
523
+ },
524
+ ],
525
+ annotation: {
526
+ measures: {
527
+ 'Transactions.count': {
528
+ title: 'Transactions Count',
529
+ shortTitle: 'Count',
530
+ type: 'number',
531
+ drillMembers: ['Transactions.id', 'Transactions.createdAt'],
532
+ drillMembersGrouped: {
533
+ measures: [],
534
+ dimensions: ['Transactions.id', 'Transactions.createdAt'],
535
+ },
536
+ },
537
+ },
538
+ dimensions: {},
539
+ segments: {},
540
+ timeDimensions: {
541
+ 'Transactions.createdAt.alerting_monitor': {
542
+ title: 'Transaction created at',
543
+ shortTitle: 'Created at',
544
+ type: 'time',
545
+ granularity: {
546
+ name: 'alerting_monitor',
547
+ title: 'Alerting Monitor',
548
+ interval: `${EVALUATION_PERIOD} minutes`,
549
+ origin: NON_ALIGNED_ORIGIN,
550
+ },
551
+ },
552
+ 'Transactions.createdAt': {
553
+ title: 'Transaction created at',
554
+ shortTitle: 'Created at',
555
+ type: 'time',
556
+ },
557
+ },
558
+ },
559
+ },
560
+ ],
561
+ pivotQuery: {
562
+ measures: ['Transactions.count'],
563
+ timeDimensions: [
564
+ {
565
+ dimension: 'Transactions.createdAt',
566
+ granularity: 'alerting_monitor',
567
+ dateRange: ['2020-08-01T00:00:00.000', '2020-08-01T01:00:00.000'],
568
+ },
569
+ ],
570
+ filters: [],
571
+ timezone: 'UTC',
572
+ order: [],
573
+ dimensions: [],
574
+ },
575
+ };
576
+ const resultSet = new ResultSet(customGranularityResponse);
577
+ // Test drilling down on the second data point (00:07:00)
578
+ // Since origin is 00:02:00, the bucket is 00:07:00 - 00:11:59
579
+ expect(resultSet.drillDown({ xValues: ['2020-08-01T00:07:00.000'] })).toEqual({
580
+ measures: [],
581
+ segments: [],
582
+ dimensions: ['Transactions.id', 'Transactions.createdAt'],
583
+ filters: [
584
+ {
585
+ member: 'Transactions.count',
586
+ operator: 'measureFilter',
587
+ },
588
+ ],
589
+ timeDimensions: [
590
+ {
591
+ dimension: 'Transactions.createdAt',
592
+ // Should align to origin: bucket starts at 00:07:00 (origin + 5min)
593
+ dateRange: ['2020-08-01T00:07:00.000', '2020-08-01T00:11:59.999'],
594
+ },
595
+ ],
596
+ timezone: 'UTC',
597
+ });
598
+ });
373
599
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubejs-client/core",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "engines": {},
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "license": "MIT",
40
40
  "devDependencies": {
41
- "@cubejs-backend/linter": "1.5.0",
41
+ "@cubejs-backend/linter": "1.5.2",
42
42
  "@types/jest": "^29",
43
43
  "@types/moment-range": "^4.0.0",
44
44
  "@types/ramda": "^0.27.34",
@@ -50,5 +50,5 @@
50
50
  "eslintConfig": {
51
51
  "extends": "../cubejs-linter"
52
52
  },
53
- "gitHead": "e4d767eee86887aab47bfcb6448d9db2bf0851cc"
53
+ "gitHead": "1e757cdc3ef005d24388d0f6e9be3d708595cb1d"
54
54
  }