Skip to content

Commit 5f55675

Browse files
Request constraints (#1248)
* New: Metadata driven request constraints * Update: Remove active state on column config filter
1 parent cde8614 commit 5f55675

File tree

58 files changed

+980
-362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+980
-362
lines changed

packages/dashboards/addon/templates/dashboards/dashboard/widgets/widget.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@
128128
@openFilters={{route-action "openFilters"}}
129129
@onAddColumn={{update-report-action "ADD_COLUMN_WITH_PARAMS"}}
130130
@onRemoveColumn={{update-report-action "REMOVE_COLUMN_FRAGMENT"}}
131-
@onToggleFilter={{update-report-action "TOGGLE_FILTER"}}
131+
@onAddFilter={{update-report-action "ADD_FILTER"}}
132132
@onRenameColumn={{update-report-action "RENAME_COLUMN_FRAGMENT"}}
133133
@onReorderColumn={{update-report-action "REORDER_COLUMN_FRAGMENT"}}
134134
@onUpdateColumnParam={{update-report-action "UPDATE_COLUMN_FRAGMENT_WITH_PARAMS"}}

packages/dashboards/tests/acceptance/dashboards-test.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { setupApplicationTest } from 'ember-qunit';
66
import { setupMirage } from 'ember-cli-mirage/test-support';
77
import { Response } from 'ember-cli-mirage';
88
import { selectChoose } from 'ember-power-select/test-support';
9-
import { clickItem, clickItemFilter } from 'navi-reports/test-support/report-builder';
9+
import { clickItem } from 'navi-reports/test-support/report-builder';
1010
import $ from 'jquery';
1111

1212
let confirm;
@@ -388,7 +388,6 @@ module('Acceptance | Dashboards', function (hooks) {
388388
await click('.add-widget__new-btn');
389389

390390
// Fill out request
391-
await clickItemFilter('dimension', 'Date Time');
392391
await selectChoose('.filter-builder__operator-trigger', 'In The Past');
393392
await clickItem('dimension', 'Date Time');
394393
await selectChoose('.navi-column-config-item__parameter-trigger', 'Day');
@@ -422,7 +421,6 @@ module('Acceptance | Dashboards', function (hooks) {
422421
await click('.add-widget__new-btn');
423422

424423
// Fill out request
425-
await clickItemFilter('dimension', 'Date Time');
426424
await selectChoose('.filter-builder__operator-trigger', 'In The Past');
427425
await clickItem('dimension', 'Date Time');
428426
await selectChoose('.navi-column-config-item__parameter-trigger', 'Day');
@@ -510,7 +508,6 @@ module('Acceptance | Dashboards', function (hooks) {
510508
await visit('/dashboards/1/widgets/new');
511509

512510
// Build Request
513-
await clickItemFilter('dimension', 'Date Time');
514511
await selectChoose('.filter-builder__operator-trigger', 'In The Past');
515512
await clickItem('dimension', 'Date Time');
516513
await selectChoose('.navi-column-config-item__parameter-trigger', 'Day');
@@ -697,7 +694,6 @@ module('Acceptance | Dashboards', function (hooks) {
697694
await click('.add-widget__new-btn');
698695

699696
// Fill out request
700-
await clickItemFilter('dimension', 'Date Time');
701697
await selectChoose('.filter-builder__operator-trigger', 'In The Past');
702698
await clickItem('dimension', 'Date Time');
703699
await selectChoose('.navi-column-config-item__parameter-trigger', 'Day');

packages/dashboards/tests/acceptance/mutli-datasource-dashboards-test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { visit, click, findAll, currentURL } from '@ember/test-helpers';
33
import { setupApplicationTest, test } from 'ember-qunit';
44
import { setupMirage } from 'ember-cli-mirage/test-support';
55
import { selectChoose } from 'ember-power-select/test-support';
6-
import { clickItem, clickItemFilter } from 'navi-reports/test-support/report-builder';
6+
import { clickItem } from 'navi-reports/test-support/report-builder';
77

88
module('Acceptance | Multi datasource Dashboard', function (hooks) {
99
setupApplicationTest(hooks);
@@ -65,7 +65,6 @@ module('Acceptance | Multi datasource Dashboard', function (hooks) {
6565
await selectChoose('.navi-table-select__trigger', 'Inventory');
6666
await clickItem('dimension', 'Date Time');
6767
await selectChoose('.navi-column-config-item__parameter-trigger', 'Day');
68-
await clickItemFilter('dimension', 'Date Time');
6968
await selectChoose('.filter-builder__operator-trigger', 'Current');
7069
await clickItem('dimension', 'Container');
7170
await clickItem('metric', 'Used Amount');

packages/data/addon/mirage/routes/bard-meta.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export default function () {
6363
if (table.name === 'tableB') {
6464
timeGrains.shift();
6565
}
66+
if (table.name === 'tableC') {
67+
timeGrains.pop();
68+
}
6669

6770
return Object.assign({}, table, { timeGrains });
6871
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2021, Yahoo Holdings Inc.
3+
* Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms.
4+
*
5+
* A collection of function parameters that has a one to many relationship to columns
6+
*/
7+
import EmberObject from '@ember/object';
8+
import { RequestV2 } from 'navi-data/adapters/facts/interface';
9+
import { matches } from 'lodash-es';
10+
11+
type ConstrainableProperties = 'filters' | 'columns';
12+
13+
type ExistenceConstraintForType<Type extends ConstrainableProperties> = {
14+
property: Type;
15+
matches: Pick<RequestV2[Type][number], 'type' | 'field'>;
16+
};
17+
type ExistenceConstraint = ExistenceConstraintForType<'filters'> | ExistenceConstraintForType<'columns'>;
18+
19+
export interface RequestConstraintMetadataPayload {
20+
id: string;
21+
name: string;
22+
description?: string;
23+
type: 'existence';
24+
constraint: ExistenceConstraint;
25+
source: string;
26+
}
27+
export type RequestConstraintMetadata = RequestConstraintMetadataPayload;
28+
29+
export default class RequestConstraintMetadataModel
30+
extends EmberObject
31+
implements RequestConstraintMetadataPayload, RequestConstraintMetadata {
32+
id!: string;
33+
name!: string;
34+
description?: string | undefined;
35+
type!: 'existence';
36+
constraint!: ExistenceConstraint;
37+
source!: string;
38+
39+
isSatisfied(request: RequestV2): boolean {
40+
const { property, matches: partialProperties } = this.constraint;
41+
return request[property].some(matches(partialProperties));
42+
}
43+
}
44+
45+
declare module './registry' {
46+
export default interface MetadataModelRegistry {
47+
requestConstraint: RequestConstraintMetadataModel;
48+
}
49+
}

packages/data/addon/models/metadata/table.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import DimensionMetadataModel from './dimension';
99
import TimeDimensionMetadataModel from './time-dimension';
1010
import CARDINALITY_SIZES from '../../utils/enums/cardinality-sizes';
1111
import NaviMetadataService from 'navi-data/services/navi-metadata';
12+
import RequestConstraintMetadataModel from './request-constraint';
1213

1314
// Shape passed to model constructor
1415
export interface TableMetadataPayload {
@@ -21,6 +22,7 @@ export interface TableMetadataPayload {
2122
metricIds: string[];
2223
dimensionIds: string[];
2324
timeDimensionIds: string[];
25+
requestConstraintIds: string[];
2426
source: string;
2527
tags?: string[];
2628
}
@@ -35,6 +37,7 @@ export interface TableMetadata {
3537
metrics: MetricMetadataModel[];
3638
dimensions: DimensionMetadataModel[];
3739
timeDimensions: TimeDimensionMetadataModel[];
40+
requestConstraints: RequestConstraintMetadataModel[];
3841
source: string;
3942
tags: string[];
4043
}
@@ -98,6 +101,11 @@ export default class TableMetadataModel extends EmberObject implements TableMeta
98101
*/
99102
timeDimensionIds!: string[];
100103

104+
/**
105+
* @property {string[]} requestConstraintIds - array of request constraint ids
106+
*/
107+
requestConstraintIds!: string[];
108+
101109
/**
102110
* @param {Metric[]} metrics
103111
*/
@@ -121,6 +129,12 @@ export default class TableMetadataModel extends EmberObject implements TableMeta
121129
.filter(isPresent);
122130
}
123131

132+
get requestConstraints(): RequestConstraintMetadataModel[] {
133+
return this.requestConstraintIds
134+
.map((id) => this.naviMetadata.getById('requestConstraint', id, this.source))
135+
.filter(isPresent);
136+
}
137+
124138
/**
125139
* @param {string[]} tags
126140
*/

packages/data/addon/serializers/metadata/bard.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import ColumnFunctionMetadataModel, { ColumnFunctionMetadataPayload } from 'navi
88
import MetricMetadataModel, { MetricMetadataPayload } from 'navi-data/models/metadata/metric';
99
import DimensionMetadataModel, { DimensionMetadataPayload } from 'navi-data/models/metadata/dimension';
1010
import TimeDimensionMetadataModel, { TimeDimensionMetadataPayload } from 'navi-data/models/metadata/time-dimension';
11+
import RequestConstraintMetadataModel, {
12+
RequestConstraintMetadataPayload,
13+
} from 'navi-data/models/metadata/request-constraint';
1114
import NaviMetadataSerializer, { MetadataModelMap, EverythingMetadataPayload } from './base';
1215
import { assert } from '@ember/debug';
1316
import { isNone } from '@ember/utils';
@@ -117,6 +120,7 @@ export default class BardMetadataSerializer extends NaviMetadataSerializer {
117120
const metrics: { [k: string]: MetricMetadataModel } = {};
118121
const dimensions: { [k: string]: DimensionMetadataModel } = {};
119122
const timeDimensions: { [k: string]: TimeDimensionMetadataModel } = {};
123+
const requestConstraints: { [k: string]: RequestConstraintMetadataModel } = {};
120124
const convertedToColumnFunctions: { [k: string]: ColumnFunctionMetadataModel } = {};
121125
const tablePayloads: BardTableMetadataPayload[] = rawTables.map((table: RawTablePayload) => {
122126
// Reduce all columns regardless of timegrain into one object
@@ -191,6 +195,15 @@ export default class BardMetadataSerializer extends NaviMetadataSerializer {
191195
allTableColumns.timeDimensions[dateTime.id] = dateTime;
192196
allTableColumns.tableTimeDimensionIds.add(dateTime.id);
193197

198+
const requiredDateTimeFilter = this.createRequiredDateTimeFilterConstraint(table, dataSourceName);
199+
requestConstraints[requiredDateTimeFilter.id] = requiredDateTimeFilter;
200+
const constraints = [requiredDateTimeFilter.id];
201+
if (!timeGrainInfo.hasAllGrain) {
202+
const requiredDateTimeColumn = this.createRequiredDateTimeColumnConstraint(table, dataSourceName);
203+
requestConstraints[requiredDateTimeColumn.id] = requiredDateTimeColumn;
204+
constraints.push(requiredDateTimeColumn.id);
205+
}
206+
194207
return {
195208
id: table.name,
196209
name: table.longName,
@@ -204,6 +217,7 @@ export default class BardMetadataSerializer extends NaviMetadataSerializer {
204217
metricIds: [...allTableColumns.tableMetricIds],
205218
dimensionIds: [...allTableColumns.tableDimensionIds],
206219
timeDimensionIds: [...allTableColumns.tableTimeDimensionIds],
220+
requestConstraintIds: [...constraints],
207221
};
208222
});
209223

@@ -215,6 +229,7 @@ export default class BardMetadataSerializer extends NaviMetadataSerializer {
215229
metrics: Object.values(metrics),
216230
timeDimensions: Object.values(timeDimensions),
217231
columnFunctions: [...columnFunctions, ...Object.values(convertedToColumnFunctions)],
232+
requestConstraints: Object.values(requestConstraints),
218233
};
219234
}
220235

@@ -306,6 +321,60 @@ export default class BardMetadataSerializer extends NaviMetadataSerializer {
306321
return this.timeDimensionFactory.create(payload);
307322
}
308323

324+
/**
325+
* Constructs a request constraint that requires a date time column
326+
* @param table - the table to create a dateTime for
327+
* @param dataSourceName - data source name
328+
*/
329+
private createRequiredDateTimeColumnConstraint(
330+
table: RawTablePayload,
331+
dataSourceName: string
332+
): RequestConstraintMetadataModel {
333+
const id = `${table.name}.dateTime`;
334+
const payload: RequestConstraintMetadataPayload = {
335+
id: `${this.namespace}:requestConstraint(columns=${id})`,
336+
name: 'Date Time Column',
337+
description: `The request has a Date Time column.`,
338+
source: dataSourceName,
339+
type: 'existence',
340+
constraint: {
341+
property: 'columns',
342+
matches: {
343+
type: 'timeDimension',
344+
field: id,
345+
},
346+
},
347+
};
348+
return this.requestConstraintFactory.create(payload);
349+
}
350+
351+
/**
352+
* Constructs a request constraint that requires a date time filter
353+
* @param table - the table to create a dateTime for
354+
* @param dataSourceName - data source name
355+
*/
356+
private createRequiredDateTimeFilterConstraint(
357+
table: RawTablePayload,
358+
dataSourceName: string
359+
): RequestConstraintMetadataModel {
360+
const id = `${table.name}.dateTime`;
361+
const payload: RequestConstraintMetadataPayload = {
362+
id: `${this.namespace}:requestConstraint(filters=${id})`,
363+
name: 'Date Time Filter',
364+
description: 'The request has a Date Time filter that specifies an interval.',
365+
source: dataSourceName,
366+
type: 'existence',
367+
constraint: {
368+
property: 'filters',
369+
matches: {
370+
type: 'timeDimension',
371+
field: id,
372+
},
373+
},
374+
};
375+
return this.requestConstraintFactory.create(payload);
376+
}
377+
309378
/**
310379
* Normalize raw bard time grains
311380
*/
@@ -505,7 +574,7 @@ export default class BardMetadataSerializer extends NaviMetadataSerializer {
505574
}
506575

507576
/**
508-
* @param metricFunctions - raw metric functions
577+
* @param columnFunctions - raw column functions
509578
* @param dataSourceName - data source name
510579
*/
511580
private normalizeColumnFunctions(

packages/data/addon/serializers/metadata/base.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import MetricMetadataModel from 'navi-data/models/metadata/metric';
88
import DimensionMetadataModel from 'navi-data/models/metadata/dimension';
99
import TimeDimensionMetadataModel from 'navi-data/models/metadata/time-dimension';
1010
import ColumnFunctionMetadataModel from 'navi-data/models/metadata/column-function';
11+
import RequestConstraintMetadataModel from 'navi-data/models/metadata/request-constraint';
1112
import { getOwner } from '@ember/application';
1213

1314
export interface EverythingMetadataPayload {
@@ -16,11 +17,13 @@ export interface EverythingMetadataPayload {
1617
dimensions: DimensionMetadataModel[];
1718
timeDimensions: TimeDimensionMetadataModel[];
1819
columnFunctions?: ColumnFunctionMetadataModel[];
20+
requestConstraints: RequestConstraintMetadataModel[];
1921
}
2022

2123
export interface MetadataModelMap {
2224
everything: EverythingMetadataPayload;
2325
table: TableMetadataModel[];
26+
requestConstraint: RequestConstraintMetadataModel[];
2427
metric: MetricMetadataModel[];
2528
dimension: DimensionMetadataModel[];
2629
timeDimension: TimeDimensionMetadataModel[];
@@ -33,6 +36,7 @@ export default abstract class NaviMetadataSerializer extends EmberObject {
3336
protected metricFactory = getOwner(this).factoryFor('model:metadata/metric');
3437
protected dimensionFactory = getOwner(this).factoryFor('model:metadata/dimension');
3538
protected timeDimensionFactory = getOwner(this).factoryFor('model:metadata/time-dimension');
39+
protected requestConstraintFactory = getOwner(this).factoryFor('model:metadata/request-constraint');
3640
protected tableFactory = getOwner(this).factoryFor('model:metadata/table');
3741
protected columnFunctionFactory = getOwner(this).factoryFor('model:metadata/column-function');
3842

packages/data/addon/serializers/metadata/elide.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export default class ElideMetadataSerializer extends NaviMetadataSerializer {
102102
metricIds: [],
103103
dimensionIds: [],
104104
timeDimensionIds: [],
105+
requestConstraintIds: [],
105106
source,
106107
};
107108

@@ -133,6 +134,7 @@ export default class ElideMetadataSerializer extends NaviMetadataSerializer {
133134
dimensions,
134135
timeDimensions,
135136
columnFunctions,
137+
requestConstraints: [],
136138
};
137139
}
138140

packages/data/addon/services/navi-metadata.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ export default class NaviMetadataService extends Service {
5656
*/
5757
private loadEverythingMetadataIntoKeg(payload: EverythingMetadataPayload, dataSourceName: string) {
5858
this.loadMetadataForType('table', payload.tables, dataSourceName);
59+
this.loadMetadataForType('metric', payload.metrics, dataSourceName);
5960
this.loadMetadataForType('dimension', payload.dimensions, dataSourceName);
6061
this.loadMetadataForType('timeDimension', payload.timeDimensions, dataSourceName);
6162
this.loadMetadataForType('columnFunction', payload.columnFunctions || [], dataSourceName);
62-
this.loadMetadataForType('metric', payload.metrics, dataSourceName);
63+
this.loadMetadataForType('requestConstraint', payload.requestConstraints, dataSourceName);
6364
this.loadedDataSources.add(dataSourceName);
6465
}
6566

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from 'navi-data/models/metadata/request-constraint';

packages/data/tests/unit/adapters/metadata/bard-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ module('Unit | Adapter | metadata/bard', function (hooks) {
4747
{ dimensions: 31, grains: 7, metrics: 42, name: 'tableA' },
4848
{ dimensions: 31, grains: 6, metrics: 42, name: 'tableB' },
4949
{ dimensions: 31, grains: 7, metrics: 42, name: 'protected' },
50-
{ dimensions: 31, grains: 7, metrics: 33, name: 'tableC' },
50+
{ dimensions: 31, grains: 6, metrics: 33, name: 'tableC' },
5151
],
5252
'`fetchEverything` correctly requested all datasource metadata'
5353
);

packages/data/tests/unit/models/metadata/bard/table-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module('Unit | Model | metadata/bard/table', function (hooks) {
2020
dimensionIds: ['age'],
2121
timeDimensionIds: ['orderDate'],
2222
timeGrainIds: ['day', 'month', 'week'],
23+
requestConstraintIds: [],
2324
hasAllGrain: false,
2425
source: 'bardOne',
2526
tags: ['DISPLAY'],

0 commit comments

Comments
 (0)