@lightdash/common 0.1396.3 → 0.1397.1

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.
@@ -56,7 +56,7 @@ export type CatalogTable = Pick<TableBase, 'name' | 'label' | 'groupLabel' | 'de
56
56
  icon: CatalogItemIcon | null;
57
57
  };
58
58
  export type CatalogItem = CatalogField | CatalogTable;
59
- export type CatalogMetricsTreeNode = Pick<CatalogField, 'name' | 'tableName'>;
59
+ export type CatalogMetricsTreeNode = Pick<CatalogField, 'catalogSearchUuid' | 'name' | 'tableName'>;
60
60
  export type CatalogMetricsTreeEdge = {
61
61
  source: CatalogMetricsTreeNode;
62
62
  target: CatalogMetricsTreeNode;
@@ -82,8 +82,8 @@ export type ApiGetMetricsTree = {
82
82
  };
83
83
  };
84
84
  export type ApiMetricsTreeEdgePayload = {
85
- sourceMetricId: string;
86
- targetMetricId: string;
85
+ sourceCatalogSearchUuid: string;
86
+ targetCatalogSearchUuid: string;
87
87
  };
88
88
  export type CatalogMetadata = {
89
89
  name: string;
@@ -5,7 +5,8 @@ export declare enum MetricExplorerComparison {
5
5
  PREVIOUS_PERIOD = "previous_period",
6
6
  DIFFERENT_METRIC = "different_metric"
7
7
  }
8
- export type MetricExplorerDateRange = [Date | null, Date | null];
8
+ export type MetricExplorerPartialDateRange = [Date | null, Date | null];
9
+ export type MetricExplorerDateRange = [Date, Date];
9
10
  export type MetricExplorerComparisonType = {
10
11
  type: MetricExplorerComparison.NONE;
11
12
  } | {
@@ -14,6 +15,11 @@ export type MetricExplorerComparisonType = {
14
15
  type: MetricExplorerComparison.DIFFERENT_METRIC;
15
16
  metricName: string;
16
17
  };
18
+ export type MetricExploreDataPoint = {
19
+ date: Date;
20
+ metric: unknown;
21
+ compareMetric: unknown;
22
+ };
17
23
  export type MetricsExplorerQueryResults = {
18
24
  rows: ResultRow[];
19
25
  comparisonRows: ResultRow[] | undefined;
@@ -1,4 +1 @@
1
- import type { CatalogMetricsTreeNode } from '../types/catalog';
2
1
  export declare const MAX_METRICS_TREE_NODE_COUNT = 30;
3
- export declare function getMetricsTreeNodeId(field: CatalogMetricsTreeNode): string;
4
- export declare function parseMetricsTreeNodeId(id: string): CatalogMetricsTreeNode;
@@ -1,19 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseMetricsTreeNodeId = exports.getMetricsTreeNodeId = exports.MAX_METRICS_TREE_NODE_COUNT = void 0;
3
+ exports.MAX_METRICS_TREE_NODE_COUNT = void 0;
4
4
  exports.MAX_METRICS_TREE_NODE_COUNT = 30;
5
- function getMetricsTreeNodeId(field) {
6
- return `${field.tableName}::${field.name}`;
7
- }
8
- exports.getMetricsTreeNodeId = getMetricsTreeNodeId;
9
- function parseMetricsTreeNodeId(id) {
10
- const [tableName, name] = id.split('::');
11
- if (!tableName || !name) {
12
- throw new Error('Invalid metrics tree node id');
13
- }
14
- return {
15
- name,
16
- tableName,
17
- };
18
- }
19
- exports.parseMetricsTreeNodeId = parseMetricsTreeNodeId;
@@ -1,10 +1,27 @@
1
+ import type { MetricWithAssociatedTimeDimension } from '../types/catalog';
1
2
  import { ConditionalOperator } from '../types/conditionalRule';
3
+ import type { Dimension } from '../types/field';
2
4
  import { type DateFilterSettings, type FieldTarget, type FilterRule } from '../types/filter';
3
- import type { MetricExplorerDateRange } from '../types/metricsExplorer';
5
+ import type { MetricExploreDataPoint, MetricExplorerDateRange } from '../types/metricsExplorer';
6
+ import type { ResultRow } from '../types/results';
4
7
  import { TimeFrames } from '../types/timeFrames';
5
8
  type DateFilter = FilterRule<ConditionalOperator, FieldTarget, unknown, DateFilterSettings>;
9
+ type ImpelemntedTimeframe = TimeFrames.DAY | TimeFrames.WEEK | TimeFrames.MONTH | TimeFrames.YEAR;
6
10
  export declare const getFieldIdForDateDimension: (fieldId: string, timeframe: TimeFrames) => string;
7
- export declare const getMetricExplorerDefaultGrainFilters: (exploreName: string, dimensionName: string, timeInterval: TimeFrames | undefined) => DateFilter[];
8
- export declare const getMetricExplorerDimensionPreviousFilters: (exploreName: string, dimensionName: string, timeInterval: TimeFrames | undefined) => DateFilter[];
9
- export declare const getMetricExplorerDateRangeFilters: (exploreName: string, dimensionName: string, [startDate, endDate]: MetricExplorerDateRange) => DateFilter[];
11
+ export declare const oneYearBack: (date: Date) => Date;
12
+ export declare const oneYearForward: (date: Date) => Date;
13
+ export declare const getGrainForDateRange: (dateRange: [Date, Date]) => ImpelemntedTimeframe;
14
+ export declare const getMetricExplorerDateRangeFilters: (exploreName: string, dimensionName: string, dateRange: MetricExplorerDateRange) => DateFilter[];
15
+ 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>;
17
+ /**
18
+ * Get the date range for a given time interval, based on the current date and the time interval
19
+ * Time grain Year: -> past 5 years (i.e. 5 completed years + this uncompleted year)
20
+ * Time grain Month -> past 12 months (i.e. 12 completed months + this uncompleted month)
21
+ * Time grain Week -> past 12 weeks (i.e. 12 completed weeks + this uncompleted week)
22
+ * Time grain Day -> past 30 days (i.e. 30 completed days + this uncompleted day)
23
+ * @param timeInterval - The time interval
24
+ * @returns The date range
25
+ */
26
+ export declare const getDefaultDateRangeFromInterval: (timeInterval: TimeFrames) => MetricExplorerDateRange;
10
27
  export {};
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMetricExplorerDateRangeFilters = exports.getMetricExplorerDimensionPreviousFilters = exports.getMetricExplorerDefaultGrainFilters = exports.getFieldIdForDateDimension = void 0;
3
+ 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
+ const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
6
+ const lodash_1 = require("lodash");
5
7
  const uuid_1 = require("uuid");
6
8
  const conditionalRule_1 = require("../types/conditionalRule");
7
- const filter_1 = require("../types/filter");
8
9
  const timeFrames_1 = require("../types/timeFrames");
9
10
  const assertUnreachable_1 = tslib_1.__importDefault(require("./assertUnreachable"));
10
11
  const item_1 = require("./item");
@@ -48,241 +49,37 @@ const getFieldIdForDateDimension = (fieldId, timeframe) => {
48
49
  }
49
50
  };
50
51
  exports.getFieldIdForDateDimension = getFieldIdForDateDimension;
51
- // Time grain Year: -> past 5 years (i.e. 5 completed years + this uncompleted year)
52
- // Time grain Month -> past 12 months (i.e. 12 completed months + this uncompleted month)
53
- // Time grain Week -> past 12 weeks (i.e. 12 completed weeks + this uncompleted week)
54
- // Time grain Day -> past 30 days (i.e. 30 completed days + this uncompleted day)
55
- const getMetricExplorerDefaultGrainFilters = (exploreName, dimensionName, timeInterval) => {
56
- const fieldWithGrain = timeInterval
57
- ? (0, exports.getFieldIdForDateDimension)(dimensionName, timeInterval)
58
- : dimensionName;
59
- const targetFieldId = (0, item_1.getItemId)({
60
- table: exploreName,
61
- name: fieldWithGrain,
62
- });
63
- if (!timeInterval) {
64
- throw new Error('Time interval is required to get relevant filter');
65
- }
66
- switch (timeInterval) {
67
- case timeFrames_1.TimeFrames.DAY:
68
- return [
69
- {
70
- id: (0, uuid_1.v4)(),
71
- target: { fieldId: targetFieldId },
72
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
73
- values: [29],
74
- settings: {
75
- unitOfTime: filter_1.UnitOfTime.days,
76
- completed: true,
77
- },
78
- },
79
- {
80
- id: (0, uuid_1.v4)(),
81
- target: { fieldId: targetFieldId },
82
- operator: conditionalRule_1.ConditionalOperator.IN_THE_CURRENT,
83
- values: [],
84
- settings: { unitOfTime: filter_1.UnitOfTime.days },
85
- },
86
- ];
87
- case timeFrames_1.TimeFrames.WEEK:
88
- return [
89
- {
90
- id: (0, uuid_1.v4)(),
91
- target: { fieldId: targetFieldId },
92
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
93
- values: [11],
94
- settings: {
95
- unitOfTime: filter_1.UnitOfTime.weeks,
96
- completed: true,
97
- },
98
- },
99
- {
100
- id: (0, uuid_1.v4)(),
101
- target: { fieldId: targetFieldId },
102
- operator: conditionalRule_1.ConditionalOperator.IN_THE_CURRENT,
103
- values: [],
104
- settings: { unitOfTime: filter_1.UnitOfTime.weeks },
105
- },
106
- ];
107
- case timeFrames_1.TimeFrames.MONTH:
108
- return [
109
- {
110
- id: (0, uuid_1.v4)(),
111
- target: { fieldId: targetFieldId },
112
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
113
- values: [11],
114
- settings: {
115
- unitOfTime: filter_1.UnitOfTime.months,
116
- completed: true,
117
- },
118
- },
119
- {
120
- id: (0, uuid_1.v4)(),
121
- target: { fieldId: targetFieldId },
122
- operator: conditionalRule_1.ConditionalOperator.IN_THE_CURRENT,
123
- values: [],
124
- settings: { unitOfTime: filter_1.UnitOfTime.months },
125
- },
126
- ];
127
- case timeFrames_1.TimeFrames.YEAR:
128
- return [
129
- {
130
- id: (0, uuid_1.v4)(),
131
- target: { fieldId: targetFieldId },
132
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
133
- values: [4],
134
- settings: { unitOfTime: filter_1.UnitOfTime.years, completed: true },
135
- },
136
- {
137
- id: (0, uuid_1.v4)(),
138
- target: { fieldId: targetFieldId },
139
- operator: conditionalRule_1.ConditionalOperator.IN_THE_CURRENT,
140
- values: [],
141
- settings: { unitOfTime: filter_1.UnitOfTime.years },
142
- },
143
- ];
144
- default:
145
- return assertUnimplementedTimeframe(timeInterval);
146
- }
147
- };
148
- exports.getMetricExplorerDefaultGrainFilters = getMetricExplorerDefaultGrainFilters;
149
- // Time grain Year: -> 10 years ago - 5 years ago
150
- // Time grain Month -> 24 months ago - 12 months ago
151
- // Time grain Week -> 24 weeks ago - 12 weeks ago
152
- // Time grain Day -> 60 days ago - 30 days ago
153
- const getMetricExplorerDimensionPreviousFilters = (exploreName, dimensionName, timeInterval) => {
154
- const targetFieldId = (0, item_1.getItemId)({
155
- table: exploreName,
156
- name: dimensionName,
157
- });
158
- if (!timeInterval) {
159
- throw new Error('Time interval is required to get relevant filter');
160
- }
161
- switch (timeInterval) {
162
- case timeFrames_1.TimeFrames.DAY:
163
- // 60 days ago - 30 days ago
164
- return [
165
- {
166
- id: (0, uuid_1.v4)(),
167
- target: { fieldId: targetFieldId },
168
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
169
- values: [60],
170
- settings: {
171
- unitOfTime: filter_1.UnitOfTime.days,
172
- completed: true,
173
- },
174
- },
175
- {
176
- id: (0, uuid_1.v4)(),
177
- target: { fieldId: targetFieldId },
178
- operator: conditionalRule_1.ConditionalOperator.NOT_IN_THE_PAST,
179
- values: [30],
180
- settings: {
181
- unitOfTime: filter_1.UnitOfTime.days,
182
- completed: true,
183
- },
184
- },
185
- ];
186
- case timeFrames_1.TimeFrames.WEEK:
187
- // 24 weeks ago - 12 weeks ago
188
- return [
189
- {
190
- id: (0, uuid_1.v4)(),
191
- target: { fieldId: targetFieldId },
192
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
193
- values: [24],
194
- settings: {
195
- unitOfTime: filter_1.UnitOfTime.weeks,
196
- completed: true,
197
- },
198
- },
199
- {
200
- id: (0, uuid_1.v4)(),
201
- target: { fieldId: targetFieldId },
202
- operator: conditionalRule_1.ConditionalOperator.NOT_IN_THE_PAST,
203
- values: [12],
204
- settings: {
205
- unitOfTime: filter_1.UnitOfTime.weeks,
206
- completed: true,
207
- },
208
- },
209
- ];
210
- case timeFrames_1.TimeFrames.MONTH:
211
- // 24 months ago - 12 months ago
212
- return [
213
- {
214
- id: (0, uuid_1.v4)(),
215
- target: { fieldId: targetFieldId },
216
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
217
- values: [24],
218
- settings: {
219
- unitOfTime: filter_1.UnitOfTime.months,
220
- completed: true,
221
- },
222
- },
223
- {
224
- id: (0, uuid_1.v4)(),
225
- target: { fieldId: targetFieldId },
226
- operator: conditionalRule_1.ConditionalOperator.NOT_IN_THE_PAST,
227
- values: [12],
228
- settings: {
229
- unitOfTime: filter_1.UnitOfTime.months,
230
- completed: true,
231
- },
232
- },
233
- ];
234
- case timeFrames_1.TimeFrames.YEAR:
235
- // 10 years ago - 5 years ago
236
- return [
237
- {
238
- id: (0, uuid_1.v4)(),
239
- target: { fieldId: targetFieldId },
240
- operator: conditionalRule_1.ConditionalOperator.IN_THE_PAST,
241
- values: [10],
242
- settings: {
243
- unitOfTime: filter_1.UnitOfTime.years,
244
- completed: true,
245
- },
246
- },
247
- {
248
- id: (0, uuid_1.v4)(),
249
- target: { fieldId: targetFieldId },
250
- operator: conditionalRule_1.ConditionalOperator.NOT_IN_THE_PAST,
251
- values: [5],
252
- settings: {
253
- unitOfTime: filter_1.UnitOfTime.years,
254
- completed: true,
255
- },
256
- },
257
- ];
258
- default:
259
- return assertUnimplementedTimeframe(timeInterval);
260
- }
261
- };
262
- exports.getMetricExplorerDimensionPreviousFilters = getMetricExplorerDimensionPreviousFilters;
263
- // Time grain Year: -> past 5 years (i.e. 5 completed years + this uncompleted year)
264
- // Time grain Month -> past 12 months (i.e. 12 completed months + this uncompleted month)
265
- // Time grain Week -> past 12 weeks (i.e. 12 completed weeks + this uncompleted week)
266
- // Time grain Day -> past 30 days (i.e. 30 completed days + this uncompleted day)
52
+ const oneYearBack = (date) => (0, dayjs_1.default)(date)
53
+ .set('year', (0, dayjs_1.default)(date).get('year') - 1)
54
+ .toDate();
55
+ exports.oneYearBack = oneYearBack;
56
+ const oneYearForward = (date) => (0, dayjs_1.default)(date)
57
+ .set('year', (0, dayjs_1.default)(date).get('year') + 1)
58
+ .toDate();
59
+ exports.oneYearForward = oneYearForward;
60
+ // TODO: refine the time grain for each time frame
61
+ // Time grain Year: -> past 5 years (i.e. 5 completed years + this uncompleted year)
62
+ // Time grain Month -> past 12 months (i.e. 12 completed months + this uncompleted month)
63
+ // Time grain Week -> past 12 weeks (i.e. 12 completed weeks + this uncompleted week)
64
+ // Time grain Day -> past 30 days (i.e. 30 completed days + this uncompleted day)
65
+ // above sample is taken from the spec but the implementation is different for practical reasons for visualization
267
66
  const getGrainForDateRange = (dateRange) => {
268
67
  const diff = dateRange[1].getTime() - dateRange[0].getTime();
269
68
  const days = diff / (1000 * 60 * 60 * 24);
270
- if (days <= 31) {
69
+ if (days <= 31 * 3) {
271
70
  return timeFrames_1.TimeFrames.DAY;
272
71
  }
273
72
  if (days <= 7 * 12) {
274
73
  return timeFrames_1.TimeFrames.WEEK;
275
74
  }
276
- if (days <= 366) {
75
+ if (days <= 31 * 12) {
277
76
  return timeFrames_1.TimeFrames.MONTH;
278
77
  }
279
78
  return timeFrames_1.TimeFrames.YEAR;
280
79
  };
281
- const getMetricExplorerDateRangeFilters = (exploreName, dimensionName, [startDate, endDate]) => {
282
- if (!startDate || !endDate) {
283
- return [];
284
- }
285
- const defaultGrain = getGrainForDateRange([startDate, endDate]);
80
+ exports.getGrainForDateRange = getGrainForDateRange;
81
+ const getMetricExplorerDateRangeFilters = (exploreName, dimensionName, dateRange) => {
82
+ const defaultGrain = (0, exports.getGrainForDateRange)(dateRange);
286
83
  const targetFieldId = (0, item_1.getItemId)({
287
84
  table: exploreName,
288
85
  name: (0, exports.getFieldIdForDateDimension)(dimensionName, defaultGrain),
@@ -292,8 +89,75 @@ const getMetricExplorerDateRangeFilters = (exploreName, dimensionName, [startDat
292
89
  id: (0, uuid_1.v4)(),
293
90
  target: { fieldId: targetFieldId },
294
91
  operator: conditionalRule_1.ConditionalOperator.IN_BETWEEN,
295
- values: [startDate, endDate],
92
+ values: dateRange,
296
93
  },
297
94
  ];
298
95
  };
299
96
  exports.getMetricExplorerDateRangeFilters = getMetricExplorerDateRangeFilters;
97
+ const getMetricExplorerDataPoints = (dimension, metric, metricRows) => {
98
+ const dimensionId = (0, item_1.getItemId)(dimension);
99
+ const metricId = (0, item_1.getItemId)(metric);
100
+ const groupByMetricRows = (0, lodash_1.groupBy)(metricRows, (row) => new Date(String(row[dimensionId].value.raw)).toString());
101
+ return Object.keys(groupByMetricRows).map((date) => ({
102
+ date: new Date(date),
103
+ metric: groupByMetricRows[date]?.[0]?.[metricId]?.value.raw ?? null,
104
+ compareMetric: null,
105
+ }));
106
+ };
107
+ exports.getMetricExplorerDataPoints = getMetricExplorerDataPoints;
108
+ const getMetricExplorerDataPointsWithCompare = (dimension, metric, metricRows, compareMetricRows, offsetFunction = exports.oneYearForward) => {
109
+ const dimensionId = (0, item_1.getItemId)(dimension);
110
+ const metricId = (0, item_1.getItemId)(metric);
111
+ const mapDateField = (row) => new Date(String(row[dimensionId].value.raw)).toString();
112
+ const groupByMetricRows = (0, lodash_1.groupBy)(metricRows, (row) => mapDateField(row));
113
+ const groupByCompareMetricRows = (0, lodash_1.groupBy)(compareMetricRows, (row) => mapDateField(row));
114
+ const offsetGroupByCompareMetricRows = (0, lodash_1.mapKeys)(groupByCompareMetricRows, (_, date) => offsetFunction(new Date(date)).toString());
115
+ const dates = new Set([
116
+ ...Object.keys(groupByMetricRows),
117
+ ...Object.keys(offsetGroupByCompareMetricRows),
118
+ ]);
119
+ return Array.from(dates).map((date) => ({
120
+ date: new Date(date),
121
+ metric: groupByMetricRows[date]?.[0]?.[metricId]?.value.raw ?? null,
122
+ compareMetric: offsetGroupByCompareMetricRows[date]?.[0]?.[metricId]?.value.raw ??
123
+ null,
124
+ }));
125
+ };
126
+ exports.getMetricExplorerDataPointsWithCompare = getMetricExplorerDataPointsWithCompare;
127
+ /**
128
+ * Get the date range for a given time interval, based on the current date and the time interval
129
+ * Time grain Year: -> past 5 years (i.e. 5 completed years + this uncompleted year)
130
+ * Time grain Month -> past 12 months (i.e. 12 completed months + this uncompleted month)
131
+ * Time grain Week -> past 12 weeks (i.e. 12 completed weeks + this uncompleted week)
132
+ * Time grain Day -> past 30 days (i.e. 30 completed days + this uncompleted day)
133
+ * @param timeInterval - The time interval
134
+ * @returns The date range
135
+ */
136
+ const getDefaultDateRangeFromInterval = (timeInterval) => {
137
+ const now = (0, dayjs_1.default)();
138
+ switch (timeInterval) {
139
+ case timeFrames_1.TimeFrames.DAY:
140
+ return [
141
+ now.subtract(29, 'day').startOf('day').toDate(),
142
+ now.toDate(),
143
+ ];
144
+ case timeFrames_1.TimeFrames.WEEK:
145
+ return [
146
+ now.subtract(11, 'week').startOf('week').toDate(),
147
+ now.toDate(),
148
+ ];
149
+ case timeFrames_1.TimeFrames.MONTH:
150
+ return [
151
+ now.subtract(11, 'month').startOf('month').toDate(),
152
+ now.toDate(),
153
+ ];
154
+ case timeFrames_1.TimeFrames.YEAR:
155
+ return [
156
+ now.subtract(4, 'year').startOf('year').toDate(),
157
+ now.toDate(),
158
+ ];
159
+ default:
160
+ return assertUnimplementedTimeframe(timeInterval);
161
+ }
162
+ };
163
+ exports.getDefaultDateRangeFromInterval = getDefaultDateRangeFromInterval;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/common",
3
- "version": "0.1396.3",
3
+ "version": "0.1397.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [