@lightdash/common 0.1397.2 → 0.1399.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
- import { type CompiledExploreJoin, type CompiledTable, type Explore, type ExploreError, type InlineError } from './explore';
2
- import { type CompiledDimension, type CompiledMetric, type Dimension, type Field, type FieldType } from './field';
1
+ import { type CompiledExploreJoin, type Explore, type ExploreError, type InlineError } from './explore';
2
+ import { DimensionType, type CompiledDimension, type CompiledMetric, type Dimension, type Field, type FieldType } from './field';
3
3
  import type { KnexPaginatedData } from './knex-paginate';
4
4
  import { type ChartSummary } from './savedCharts';
5
5
  import { type TableBase } from './table';
@@ -70,7 +70,14 @@ export type ApiMetricsCatalog = {
70
70
  status: 'ok';
71
71
  results: KnexPaginatedData<ApiMetricsCatalogResults>;
72
72
  };
73
- export type MetricWithAssociatedTimeDimension = CompiledMetric & Pick<CompiledTable, 'defaultTimeDimension'>;
73
+ export type MetricWithAssociatedTimeDimension = CompiledMetric & {
74
+ timeDimension: (CompiledMetric['defaultTimeDimension'] & {
75
+ table: string;
76
+ }) | undefined;
77
+ availableTimeDimensions?: (CompiledDimension & {
78
+ type: DimensionType.DATE | DimensionType.TIMESTAMP;
79
+ })[];
80
+ };
74
81
  export type ApiGetMetricPeek = {
75
82
  status: 'ok';
76
83
  results: MetricWithAssociatedTimeDimension;
@@ -1,3 +1,4 @@
1
+ import { type MetricWithAssociatedTimeDimension } from './catalog';
1
2
  import type { ItemsMap } from './field';
2
3
  import type { ResultRow } from './results';
3
4
  export declare enum MetricExplorerComparison {
@@ -13,6 +14,7 @@ export type MetricExplorerComparisonType = {
13
14
  type: MetricExplorerComparison.PREVIOUS_PERIOD;
14
15
  } | {
15
16
  type: MetricExplorerComparison.DIFFERENT_METRIC;
17
+ metricTable: string;
16
18
  metricName: string;
17
19
  };
18
20
  export type MetricExploreDataPoint = {
@@ -21,6 +23,7 @@ export type MetricExploreDataPoint = {
21
23
  compareMetric: unknown;
22
24
  };
23
25
  export type MetricsExplorerQueryResults = {
26
+ metric: MetricWithAssociatedTimeDimension;
24
27
  rows: ResultRow[];
25
28
  comparisonRows: ResultRow[] | undefined;
26
29
  fields: ItemsMap;
@@ -1,10 +1,12 @@
1
1
  import type { MetricWithAssociatedTimeDimension } from '../types/catalog';
2
2
  import { ConditionalOperator } from '../types/conditionalRule';
3
+ import { type CompiledTable } from '../types/explore';
3
4
  import type { Dimension } from '../types/field';
5
+ import { DimensionType, type CompiledDimension, type CompiledMetric } from '../types/field';
4
6
  import { type DateFilterSettings, type FieldTarget, type FilterRule } from '../types/filter';
5
- import type { MetricExploreDataPoint, MetricExplorerDateRange } from '../types/metricsExplorer';
7
+ import { type MetricExploreDataPoint, type MetricExplorerComparisonType, type MetricExplorerDateRange } from '../types/metricsExplorer';
6
8
  import type { ResultRow } from '../types/results';
7
- import { TimeFrames } from '../types/timeFrames';
9
+ import { TimeFrames, type DefaultTimeDimension } from '../types/timeFrames';
8
10
  type DateFilter = FilterRule<ConditionalOperator, FieldTarget, unknown, DateFilterSettings>;
9
11
  type ImpelemntedTimeframe = TimeFrames.DAY | TimeFrames.WEEK | TimeFrames.MONTH | TimeFrames.YEAR;
10
12
  export declare const getFieldIdForDateDimension: (fieldId: string, timeframe: TimeFrames) => string;
@@ -13,7 +15,7 @@ export declare const oneYearForward: (date: Date) => Date;
13
15
  export declare const getGrainForDateRange: (dateRange: [Date, Date]) => ImpelemntedTimeframe;
14
16
  export declare const getMetricExplorerDateRangeFilters: (exploreName: string, dimensionName: string, dateRange: MetricExplorerDateRange) => DateFilter[];
15
17
  export declare const getMetricExplorerDataPoints: (dimension: Dimension, metric: MetricWithAssociatedTimeDimension, metricRows: ResultRow[]) => Array<MetricExploreDataPoint>;
16
- export declare const getMetricExplorerDataPointsWithCompare: (dimension: Dimension, metric: MetricWithAssociatedTimeDimension, metricRows: ResultRow[], compareMetricRows: ResultRow[], offsetFunction?: (date: Date) => Date) => Array<MetricExploreDataPoint>;
18
+ export declare const getMetricExplorerDataPointsWithCompare: (dimension: Dimension, metric: MetricWithAssociatedTimeDimension, metricRows: ResultRow[], compareMetricRows: ResultRow[], comparison: MetricExplorerComparisonType) => Array<MetricExploreDataPoint>;
17
19
  /**
18
20
  * Get the date range for a given time interval, based on the current date and the time interval
19
21
  * Time grain Year: -> past 5 years (i.e. 5 completed years + this uncompleted year)
@@ -24,4 +26,17 @@ export declare const getMetricExplorerDataPointsWithCompare: (dimension: Dimensi
24
26
  * @returns The date range
25
27
  */
26
28
  export declare const getDefaultDateRangeFromInterval: (timeInterval: TimeFrames) => MetricExplorerDateRange;
29
+ /**
30
+ * Default time interval to use when no time interval is provided.
31
+ * For example, when there is no default time dimension defined for a metric or table.
32
+ */
33
+ export declare const DEFAULT_METRICS_EXPLORER_TIME_INTERVAL = TimeFrames.MONTH;
34
+ export type TimeDimensionConfig = DefaultTimeDimension & {
35
+ table: string;
36
+ };
37
+ export declare const getFirstAvailableTimeDimension: (metric: MetricWithAssociatedTimeDimension) => TimeDimensionConfig | undefined;
38
+ export declare const getDefaultTimeDimension: (metric: CompiledMetric, table?: CompiledTable) => DefaultTimeDimension | undefined;
39
+ export declare const getAvailableTimeDimensionsFromTables: (tables: Record<string, CompiledTable>) => (CompiledDimension & {
40
+ type: DimensionType.DATE | DimensionType.TIMESTAMP;
41
+ })[];
27
42
  export {};
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDefaultDateRangeFromInterval = exports.getMetricExplorerDataPointsWithCompare = exports.getMetricExplorerDataPoints = exports.getMetricExplorerDateRangeFilters = exports.getGrainForDateRange = exports.oneYearForward = exports.oneYearBack = exports.getFieldIdForDateDimension = void 0;
3
+ exports.getAvailableTimeDimensionsFromTables = exports.getDefaultTimeDimension = exports.getFirstAvailableTimeDimension = exports.DEFAULT_METRICS_EXPLORER_TIME_INTERVAL = exports.getDefaultDateRangeFromInterval = exports.getMetricExplorerDataPointsWithCompare = exports.getMetricExplorerDataPoints = exports.getMetricExplorerDateRangeFilters = exports.getGrainForDateRange = exports.oneYearForward = exports.oneYearBack = exports.getFieldIdForDateDimension = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
6
6
  const lodash_1 = require("lodash");
7
7
  const uuid_1 = require("uuid");
8
8
  const conditionalRule_1 = require("../types/conditionalRule");
9
+ const field_1 = require("../types/field");
10
+ const metricsExplorer_1 = require("../types/metricsExplorer");
9
11
  const timeFrames_1 = require("../types/timeFrames");
10
12
  const assertUnreachable_1 = tslib_1.__importDefault(require("./assertUnreachable"));
11
13
  const item_1 = require("./item");
@@ -105,22 +107,33 @@ const getMetricExplorerDataPoints = (dimension, metric, metricRows) => {
105
107
  }));
106
108
  };
107
109
  exports.getMetricExplorerDataPoints = getMetricExplorerDataPoints;
108
- const getMetricExplorerDataPointsWithCompare = (dimension, metric, metricRows, compareMetricRows, offsetFunction = exports.oneYearForward) => {
110
+ const getMetricExplorerDataPointsWithCompare = (dimension, metric, metricRows, compareMetricRows, comparison) => {
111
+ if (comparison.type === metricsExplorer_1.MetricExplorerComparison.NONE) {
112
+ throw new Error('Comparison type is required');
113
+ }
109
114
  const dimensionId = (0, item_1.getItemId)(dimension);
110
115
  const metricId = (0, item_1.getItemId)(metric);
111
116
  const mapDateField = (row) => new Date(String(row[dimensionId].value.raw)).toString();
112
117
  const groupByMetricRows = (0, lodash_1.groupBy)(metricRows, (row) => mapDateField(row));
113
118
  const groupByCompareMetricRows = (0, lodash_1.groupBy)(compareMetricRows, (row) => mapDateField(row));
114
- const offsetGroupByCompareMetricRows = (0, lodash_1.mapKeys)(groupByCompareMetricRows, (_, date) => offsetFunction(new Date(date)).toString());
119
+ const offsetGroupByCompareMetricRows = (0, lodash_1.mapKeys)(groupByCompareMetricRows, (_, date) => comparison.type === metricsExplorer_1.MetricExplorerComparison.PREVIOUS_PERIOD
120
+ ? (0, exports.oneYearForward)(new Date(date)).toString()
121
+ : date);
115
122
  const dates = new Set([
116
123
  ...Object.keys(groupByMetricRows),
117
124
  ...Object.keys(offsetGroupByCompareMetricRows),
118
125
  ]);
126
+ const compareMetricId = comparison.type === metricsExplorer_1.MetricExplorerComparison.PREVIOUS_PERIOD
127
+ ? metricId
128
+ : (0, item_1.getItemId)({
129
+ table: comparison.metricTable,
130
+ name: comparison.metricName,
131
+ });
119
132
  return Array.from(dates).map((date) => ({
120
133
  date: new Date(date),
121
134
  metric: groupByMetricRows[date]?.[0]?.[metricId]?.value.raw ?? null,
122
- compareMetric: offsetGroupByCompareMetricRows[date]?.[0]?.[metricId]?.value.raw ??
123
- null,
135
+ compareMetric: offsetGroupByCompareMetricRows[date]?.[0]?.[compareMetricId]?.value
136
+ .raw ?? null,
124
137
  }));
125
138
  };
126
139
  exports.getMetricExplorerDataPointsWithCompare = getMetricExplorerDataPointsWithCompare;
@@ -161,3 +174,50 @@ const getDefaultDateRangeFromInterval = (timeInterval) => {
161
174
  }
162
175
  };
163
176
  exports.getDefaultDateRangeFromInterval = getDefaultDateRangeFromInterval;
177
+ /**
178
+ * Default time interval to use when no time interval is provided.
179
+ * For example, when there is no default time dimension defined for a metric or table.
180
+ */
181
+ exports.DEFAULT_METRICS_EXPLORER_TIME_INTERVAL = timeFrames_1.TimeFrames.MONTH;
182
+ const getFirstAvailableTimeDimension = (metric) => {
183
+ if (metric.availableTimeDimensions &&
184
+ metric.availableTimeDimensions.length > 0) {
185
+ return {
186
+ table: metric.availableTimeDimensions[0].table,
187
+ field: metric.availableTimeDimensions[0].name,
188
+ interval: exports.DEFAULT_METRICS_EXPLORER_TIME_INTERVAL,
189
+ };
190
+ }
191
+ return undefined;
192
+ };
193
+ exports.getFirstAvailableTimeDimension = getFirstAvailableTimeDimension;
194
+ const getDefaultTimeDimension = (metric, table) => {
195
+ // Priority 1: Use metric-level default time dimension if defined in yml
196
+ if (metric.defaultTimeDimension) {
197
+ return metric.defaultTimeDimension;
198
+ }
199
+ // Priority 2: Use model-level default time dimension if defined in yml
200
+ if (table?.defaultTimeDimension) {
201
+ return table.defaultTimeDimension;
202
+ }
203
+ // Priority 3: Use the only time dimension if there's exactly one
204
+ if (table?.dimensions) {
205
+ const timeDimensions = Object.values(table.dimensions).filter((dim) => (dim.type === field_1.DimensionType.DATE ||
206
+ dim.type === field_1.DimensionType.TIMESTAMP) &&
207
+ !!dim.isIntervalBase &&
208
+ !dim.hidden);
209
+ if (timeDimensions.length === 1) {
210
+ return {
211
+ field: timeDimensions[0].name,
212
+ interval: exports.DEFAULT_METRICS_EXPLORER_TIME_INTERVAL,
213
+ };
214
+ }
215
+ }
216
+ return undefined;
217
+ };
218
+ exports.getDefaultTimeDimension = getDefaultTimeDimension;
219
+ const getAvailableTimeDimensionsFromTables = (tables) => Object.values(tables).flatMap((table) => Object.values(table.dimensions).filter((dim) => (dim.type === field_1.DimensionType.DATE ||
220
+ dim.type === field_1.DimensionType.TIMESTAMP) &&
221
+ !!dim.isIntervalBase &&
222
+ !dim.hidden));
223
+ exports.getAvailableTimeDimensionsFromTables = getAvailableTimeDimensionsFromTables;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/common",
3
- "version": "0.1397.2",
3
+ "version": "0.1399.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [