@true-sight/model-schema 1.2.1 → 1.3.0
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.
- package/dist/dsl/compile/compile-explore.js +55 -0
- package/dist/dsl/errors/compile-errors.d.ts +3 -0
- package/dist/dsl/errors/compile-errors.js +8 -1
- package/dist/dsl/expr/define-always-filter.d.ts +7 -0
- package/dist/dsl/expr/define-always-filter.js +17 -0
- package/dist/dsl/expr/index.d.ts +1 -0
- package/dist/dsl/expr/index.js +3 -1
- package/dist/dsl/registry/explore-registry.d.ts +2 -1
- package/dist/dsl/types/join-scope.types.d.ts +9 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -1
- package/dist/types/manifest.types.d.ts +15 -0
- package/dist/validate/semantic-rules.js +17 -0
- package/manifest.schema.json +48 -0
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ require("reflect-metadata");
|
|
|
5
5
|
const manifest_expr_types_js_1 = require("../../types/manifest-expr.types.js");
|
|
6
6
|
const compile_errors_js_1 = require("../errors/compile-errors.js");
|
|
7
7
|
const field_js_1 = require("../expr/field.js");
|
|
8
|
+
const define_always_filter_js_1 = require("../expr/define-always-filter.js");
|
|
8
9
|
const explore_registry_js_1 = require("../registry/explore-registry.js");
|
|
9
10
|
const view_registry_js_1 = require("../registry/view-registry.js");
|
|
10
11
|
const compile_view_js_1 = require("./compile-view.js");
|
|
@@ -53,6 +54,7 @@ function compileExplore(ExploreClass) {
|
|
|
53
54
|
}
|
|
54
55
|
const views = [...viewClasses.values()].map((ViewClass) => (0, compile_view_js_1.compileView)(ViewClass));
|
|
55
56
|
const alwaysInclude = resolveAlwaysInclude(ExploreClass, exploreMeta.name, views, scopedViewNames);
|
|
57
|
+
const alwaysFilter = resolveAlwaysFilter(exploreMeta, exploreMeta.name, views, scopedViewNames);
|
|
56
58
|
return {
|
|
57
59
|
name: exploreMeta.name,
|
|
58
60
|
label: exploreMeta.label,
|
|
@@ -60,6 +62,7 @@ function compileExplore(ExploreClass) {
|
|
|
60
62
|
joins,
|
|
61
63
|
views,
|
|
62
64
|
...(alwaysInclude ? { alwaysInclude } : {}),
|
|
65
|
+
...(alwaysFilter ? { alwaysFilter } : {}),
|
|
63
66
|
};
|
|
64
67
|
}
|
|
65
68
|
function resolveAlwaysInclude(ExploreClass, exploreName, views, scopedViewNames) {
|
|
@@ -106,3 +109,55 @@ function resolveAlwaysInclude(ExploreClass, exploreName, views, scopedViewNames)
|
|
|
106
109
|
}
|
|
107
110
|
return names.length > 0 ? names : undefined;
|
|
108
111
|
}
|
|
112
|
+
function resolveAlwaysFilter(exploreMeta, exploreName, views, scopedViewNames) {
|
|
113
|
+
const callback = exploreMeta.alwaysFilter;
|
|
114
|
+
if (!callback) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const viewCtors = (0, define_always_filter_js_1.getAlwaysFilterViews)(callback);
|
|
118
|
+
if (!viewCtors) {
|
|
119
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, 'use defineAlwaysFilter');
|
|
120
|
+
}
|
|
121
|
+
const scope = (0, join_helpers_js_1.createJoinScope)(scopedViewNames);
|
|
122
|
+
const proxies = viewCtors.map((ViewClass) => {
|
|
123
|
+
const meta = (0, view_registry_js_1.getViewMeta)(ViewClass);
|
|
124
|
+
if (!meta) {
|
|
125
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, `unknown view '${ViewClass.name}'`);
|
|
126
|
+
}
|
|
127
|
+
const proxy = scope[meta.name];
|
|
128
|
+
if (!proxy) {
|
|
129
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, `view '${meta.name}' is not on this explore`);
|
|
130
|
+
}
|
|
131
|
+
return proxy;
|
|
132
|
+
});
|
|
133
|
+
const raw = callback(...proxies);
|
|
134
|
+
if (!Array.isArray(raw)) {
|
|
135
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, 'callback must return filter groups');
|
|
136
|
+
}
|
|
137
|
+
const dimensions = new Set();
|
|
138
|
+
for (const view of views) {
|
|
139
|
+
for (const dimension of view.dimensions) {
|
|
140
|
+
dimensions.add(`${view.name}.${dimension.name}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const groups = raw.map((group) => ({
|
|
144
|
+
type: group.type,
|
|
145
|
+
group: group.group.map((filter) => {
|
|
146
|
+
if (!(filter.dimension instanceof field_js_1.Field)) {
|
|
147
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, 'dimension must be a Field');
|
|
148
|
+
}
|
|
149
|
+
const ref = filter.dimension.ref;
|
|
150
|
+
if (!(0, manifest_expr_types_js_1.isRefString)(ref)) {
|
|
151
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, `invalid name "${String(ref)}"`);
|
|
152
|
+
}
|
|
153
|
+
if (!dimensions.has(ref)) {
|
|
154
|
+
throw new compile_errors_js_1.AlwaysFilterError(exploreName, `unknown dimension '${ref}'`);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
dimensionName: ref,
|
|
158
|
+
orStatements: filter.orStatements,
|
|
159
|
+
};
|
|
160
|
+
}),
|
|
161
|
+
}));
|
|
162
|
+
return groups.length > 0 ? groups : undefined;
|
|
163
|
+
}
|
|
@@ -13,3 +13,6 @@ export declare class DuplicateNameError extends Error {
|
|
|
13
13
|
export declare class AlwaysIncludeError extends Error {
|
|
14
14
|
constructor(exploreName: string, reason: string);
|
|
15
15
|
}
|
|
16
|
+
export declare class AlwaysFilterError extends Error {
|
|
17
|
+
constructor(exploreName: string, reason: string);
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AlwaysIncludeError = exports.DuplicateNameError = exports.JoinScopeError = exports.InvalidMeasureError = exports.MissingMetadataError = void 0;
|
|
3
|
+
exports.AlwaysFilterError = exports.AlwaysIncludeError = exports.DuplicateNameError = exports.JoinScopeError = exports.InvalidMeasureError = exports.MissingMetadataError = void 0;
|
|
4
4
|
class MissingMetadataError extends Error {
|
|
5
5
|
constructor(kind, className) {
|
|
6
6
|
super(`${kind} metadata missing on ${className}`);
|
|
@@ -38,3 +38,10 @@ class AlwaysIncludeError extends Error {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
exports.AlwaysIncludeError = AlwaysIncludeError;
|
|
41
|
+
class AlwaysFilterError extends Error {
|
|
42
|
+
constructor(exploreName, reason) {
|
|
43
|
+
super(`Always filter on explore '${exploreName}': ${reason}`);
|
|
44
|
+
this.name = 'AlwaysFilterError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.AlwaysFilterError = AlwaysFilterError;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AlwaysFilterCallback, AlwaysFilterDraftGroup } from '../types/join-scope.types.js';
|
|
2
|
+
import type { StrictViewProxy, ViewConstructor } from '../types/view-proxy.types.js';
|
|
3
|
+
export declare const ALWAYS_FILTER_VIEWS: unique symbol;
|
|
4
|
+
export declare function defineAlwaysFilter<const Vs extends readonly ViewConstructor[]>(views: Vs, fn: (...proxies: {
|
|
5
|
+
[I in keyof Vs]: Vs[I] extends ViewConstructor ? StrictViewProxy<Vs[I]> : never;
|
|
6
|
+
}) => AlwaysFilterDraftGroup[]): AlwaysFilterCallback;
|
|
7
|
+
export declare function getAlwaysFilterViews(callback: AlwaysFilterCallback): readonly ViewConstructor[] | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALWAYS_FILTER_VIEWS = void 0;
|
|
4
|
+
exports.defineAlwaysFilter = defineAlwaysFilter;
|
|
5
|
+
exports.getAlwaysFilterViews = getAlwaysFilterViews;
|
|
6
|
+
exports.ALWAYS_FILTER_VIEWS = Symbol.for('true-sight.alwaysFilterViews');
|
|
7
|
+
function defineAlwaysFilter(views, fn) {
|
|
8
|
+
const callback = fn;
|
|
9
|
+
Object.defineProperty(callback, exports.ALWAYS_FILTER_VIEWS, {
|
|
10
|
+
value: views,
|
|
11
|
+
enumerable: false,
|
|
12
|
+
});
|
|
13
|
+
return callback;
|
|
14
|
+
}
|
|
15
|
+
function getAlwaysFilterViews(callback) {
|
|
16
|
+
return callback[exports.ALWAYS_FILTER_VIEWS];
|
|
17
|
+
}
|
package/dist/dsl/expr/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Field, field } from './field.js';
|
|
2
2
|
export type { VisibleField, HiddenField } from './field.js';
|
|
3
3
|
export { defineAlwaysInclude } from './define-always-include.js';
|
|
4
|
+
export { defineAlwaysFilter } from './define-always-filter.js';
|
|
4
5
|
export { count, max, min, sum } from './aggregates.js';
|
|
5
6
|
export { raw } from './raw.js';
|
|
6
7
|
export { joinScope, isJoinScopeTagged } from './join-scope.js';
|
package/dist/dsl/expr/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isJoinScopeTagged = exports.joinScope = exports.raw = exports.sum = exports.min = exports.max = exports.count = exports.defineAlwaysInclude = exports.field = exports.Field = void 0;
|
|
3
|
+
exports.isJoinScopeTagged = exports.joinScope = exports.raw = exports.sum = exports.min = exports.max = exports.count = exports.defineAlwaysFilter = exports.defineAlwaysInclude = exports.field = exports.Field = void 0;
|
|
4
4
|
var field_js_1 = require("./field.js");
|
|
5
5
|
Object.defineProperty(exports, "Field", { enumerable: true, get: function () { return field_js_1.Field; } });
|
|
6
6
|
Object.defineProperty(exports, "field", { enumerable: true, get: function () { return field_js_1.field; } });
|
|
7
7
|
var define_always_include_js_1 = require("./define-always-include.js");
|
|
8
8
|
Object.defineProperty(exports, "defineAlwaysInclude", { enumerable: true, get: function () { return define_always_include_js_1.defineAlwaysInclude; } });
|
|
9
|
+
var define_always_filter_js_1 = require("./define-always-filter.js");
|
|
10
|
+
Object.defineProperty(exports, "defineAlwaysFilter", { enumerable: true, get: function () { return define_always_filter_js_1.defineAlwaysFilter; } });
|
|
9
11
|
var aggregates_js_1 = require("./aggregates.js");
|
|
10
12
|
Object.defineProperty(exports, "count", { enumerable: true, get: function () { return aggregates_js_1.count; } });
|
|
11
13
|
Object.defineProperty(exports, "max", { enumerable: true, get: function () { return aggregates_js_1.max; } });
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ManifestExpr } from '../../types/manifest-expr.types.js';
|
|
2
2
|
import type { JoinRelationship, JoinType } from '../../types/manifest.types.js';
|
|
3
|
-
import type { AlwaysIncludeCallback } from '../types/join-scope.types.js';
|
|
3
|
+
import type { AlwaysFilterCallback, AlwaysIncludeCallback } from '../types/join-scope.types.js';
|
|
4
4
|
export type ViewConstructor = new (...args: unknown[]) => object;
|
|
5
5
|
export type ExploreOptions = {
|
|
6
6
|
name: string;
|
|
7
7
|
label: string;
|
|
8
8
|
from: ViewConstructor;
|
|
9
|
+
alwaysFilter?: AlwaysFilterCallback;
|
|
9
10
|
};
|
|
10
11
|
export type JoinScope = Record<string, unknown>;
|
|
11
12
|
export type JoinOptions = {
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import type { ManifestExpr } from '../../types/manifest-expr.types.js';
|
|
2
|
+
import type { FilterStatement } from '../../types/manifest.types.js';
|
|
2
3
|
import type { Field } from '../expr/field.js';
|
|
3
4
|
import type { JoinScopeProxy } from './view-name-map.types.js';
|
|
4
5
|
export type JoinScopeCallback = (...proxies: JoinScopeProxy[]) => ManifestExpr;
|
|
5
6
|
export type AlwaysIncludeCallback = (...proxies: JoinScopeProxy[]) => Field<unknown>[];
|
|
7
|
+
export interface AlwaysFilterDraftGroup {
|
|
8
|
+
type: 'AND' | 'OR';
|
|
9
|
+
group: Array<{
|
|
10
|
+
dimension: Field<unknown, boolean>;
|
|
11
|
+
orStatements: FilterStatement[];
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export type AlwaysFilterCallback = (...proxies: JoinScopeProxy[]) => AlwaysFilterDraftGroup[];
|
|
6
15
|
export type JoinScopeSqlOn = (scope: Record<string, unknown>) => ManifestExpr;
|
|
7
16
|
export interface JoinScopeTagged {
|
|
8
17
|
readonly __joinScopeBrand: symbol;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export { SCHEMA_VERSION } from './constants.js';
|
|
2
2
|
export type { AggregateKind, AggregateExpr, ComparisonExpr, ComparisonKind, JoinOn, JoinPair, LogicExpr, LogicKind, ManifestExpr, ManifestExprObject, NotExpr, RawExpr, RefString, } from './types/manifest-expr.types.js';
|
|
3
3
|
export { isJoinPair, isManifestExprObject, isRefString, REF_STRING_PATTERN, } from './types/manifest-expr.types.js';
|
|
4
|
-
export type { AggregateType, DimensionDefinition, DimensionType, Explore as ManifestExplore, ExploreJoin, JoinRelationship, JoinType, MeasurementDefinition, Model as ManifestModel, ModelManifest, ViewDefinition, } from './types/manifest.types.js';
|
|
4
|
+
export type { AggregateType, DimensionDefinition, DimensionType, Explore as ManifestExplore, ExploreJoin, Filter, FilterGroup, FilterOperator, FilterStatement, FilterValue, JoinRelationship, JoinType, MeasurementDefinition, Model as ManifestModel, ModelManifest, ViewDefinition, } from './types/manifest.types.js';
|
|
5
5
|
export type { ManifestValidationError, ValidationResult, } from './validate/validation-result.js';
|
|
6
6
|
export { validateManifest } from './validate/validate-manifest.js';
|
|
7
|
-
export { Field, field, count, sum, min, max, raw, joinScope, isJoinScopeTagged, defineAlwaysInclude } from './dsl/expr/index.js';
|
|
7
|
+
export { Field, field, count, sum, min, max, raw, joinScope, isJoinScopeTagged, defineAlwaysInclude, defineAlwaysFilter } from './dsl/expr/index.js';
|
|
8
8
|
export type { VisibleField, HiddenField } from './dsl/expr/index.js';
|
|
9
|
-
export type { JoinScopeCallback, JoinScopeSqlOn, JoinScopeTagged, AlwaysIncludeCallback } from './dsl/types/join-scope.types.js';
|
|
9
|
+
export type { JoinScopeCallback, JoinScopeSqlOn, JoinScopeTagged, AlwaysIncludeCallback, AlwaysFilterCallback } from './dsl/types/join-scope.types.js';
|
|
10
10
|
export { View, Dimension, Measure, Explore, Join, Model, AlwaysInclude } from './dsl/decorators/index.js';
|
|
11
11
|
export type { ViewProxy, ViewConstructor, StrictViewProxy } from './dsl/types/view-proxy.types.js';
|
|
12
12
|
export type { ViewNameMap, ViewProxyByName, } from './dsl/types/view-name-map.types.js';
|
|
13
13
|
export { compileView, compileExplore, compileModel, compileModels } from './dsl/compile/index.js';
|
|
14
|
-
export { MissingMetadataError, InvalidMeasureError, JoinScopeError, DuplicateNameError, AlwaysIncludeError, } from './dsl/errors/compile-errors.js';
|
|
14
|
+
export { MissingMetadataError, InvalidMeasureError, JoinScopeError, DuplicateNameError, AlwaysIncludeError, AlwaysFilterError, } from './dsl/errors/compile-errors.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AlwaysIncludeError = exports.DuplicateNameError = exports.JoinScopeError = exports.InvalidMeasureError = exports.MissingMetadataError = exports.compileModels = exports.compileModel = exports.compileExplore = exports.compileView = exports.AlwaysInclude = exports.Model = exports.Join = exports.Explore = exports.Measure = exports.Dimension = exports.View = exports.defineAlwaysInclude = exports.isJoinScopeTagged = exports.joinScope = exports.raw = exports.max = exports.min = exports.sum = exports.count = exports.field = exports.Field = exports.validateManifest = exports.REF_STRING_PATTERN = exports.isRefString = exports.isManifestExprObject = exports.isJoinPair = exports.SCHEMA_VERSION = void 0;
|
|
3
|
+
exports.AlwaysFilterError = exports.AlwaysIncludeError = exports.DuplicateNameError = exports.JoinScopeError = exports.InvalidMeasureError = exports.MissingMetadataError = exports.compileModels = exports.compileModel = exports.compileExplore = exports.compileView = exports.AlwaysInclude = exports.Model = exports.Join = exports.Explore = exports.Measure = exports.Dimension = exports.View = exports.defineAlwaysFilter = exports.defineAlwaysInclude = exports.isJoinScopeTagged = exports.joinScope = exports.raw = exports.max = exports.min = exports.sum = exports.count = exports.field = exports.Field = exports.validateManifest = exports.REF_STRING_PATTERN = exports.isRefString = exports.isManifestExprObject = exports.isJoinPair = exports.SCHEMA_VERSION = void 0;
|
|
4
4
|
var constants_js_1 = require("./constants.js");
|
|
5
5
|
Object.defineProperty(exports, "SCHEMA_VERSION", { enumerable: true, get: function () { return constants_js_1.SCHEMA_VERSION; } });
|
|
6
6
|
var manifest_expr_types_js_1 = require("./types/manifest-expr.types.js");
|
|
@@ -21,6 +21,7 @@ Object.defineProperty(exports, "raw", { enumerable: true, get: function () { ret
|
|
|
21
21
|
Object.defineProperty(exports, "joinScope", { enumerable: true, get: function () { return index_js_1.joinScope; } });
|
|
22
22
|
Object.defineProperty(exports, "isJoinScopeTagged", { enumerable: true, get: function () { return index_js_1.isJoinScopeTagged; } });
|
|
23
23
|
Object.defineProperty(exports, "defineAlwaysInclude", { enumerable: true, get: function () { return index_js_1.defineAlwaysInclude; } });
|
|
24
|
+
Object.defineProperty(exports, "defineAlwaysFilter", { enumerable: true, get: function () { return index_js_1.defineAlwaysFilter; } });
|
|
24
25
|
var index_js_2 = require("./dsl/decorators/index.js");
|
|
25
26
|
Object.defineProperty(exports, "View", { enumerable: true, get: function () { return index_js_2.View; } });
|
|
26
27
|
Object.defineProperty(exports, "Dimension", { enumerable: true, get: function () { return index_js_2.Dimension; } });
|
|
@@ -40,3 +41,4 @@ Object.defineProperty(exports, "InvalidMeasureError", { enumerable: true, get: f
|
|
|
40
41
|
Object.defineProperty(exports, "JoinScopeError", { enumerable: true, get: function () { return compile_errors_js_1.JoinScopeError; } });
|
|
41
42
|
Object.defineProperty(exports, "DuplicateNameError", { enumerable: true, get: function () { return compile_errors_js_1.DuplicateNameError; } });
|
|
42
43
|
Object.defineProperty(exports, "AlwaysIncludeError", { enumerable: true, get: function () { return compile_errors_js_1.AlwaysIncludeError; } });
|
|
44
|
+
Object.defineProperty(exports, "AlwaysFilterError", { enumerable: true, get: function () { return compile_errors_js_1.AlwaysFilterError; } });
|
|
@@ -35,6 +35,20 @@ export interface ViewDefinition {
|
|
|
35
35
|
dimensions: DimensionDefinition[];
|
|
36
36
|
measurements: MeasurementDefinition[];
|
|
37
37
|
}
|
|
38
|
+
export type FilterOperator = 'eq' | 'neq' | 'contains' | 'not_contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_null' | 'is_not_null';
|
|
39
|
+
export type FilterValue = string | number | boolean;
|
|
40
|
+
export interface FilterStatement {
|
|
41
|
+
operator: FilterOperator;
|
|
42
|
+
values: FilterValue[];
|
|
43
|
+
}
|
|
44
|
+
export interface Filter {
|
|
45
|
+
dimensionName: string;
|
|
46
|
+
orStatements: FilterStatement[];
|
|
47
|
+
}
|
|
48
|
+
export interface FilterGroup {
|
|
49
|
+
type: 'AND' | 'OR';
|
|
50
|
+
group: Filter[];
|
|
51
|
+
}
|
|
38
52
|
export interface Explore {
|
|
39
53
|
name: string;
|
|
40
54
|
label: string;
|
|
@@ -42,6 +56,7 @@ export interface Explore {
|
|
|
42
56
|
joins: ExploreJoin[];
|
|
43
57
|
views: ViewDefinition[];
|
|
44
58
|
alwaysInclude?: string[];
|
|
59
|
+
alwaysFilter?: FilterGroup[];
|
|
45
60
|
}
|
|
46
61
|
export interface Model {
|
|
47
62
|
name: string;
|
|
@@ -76,6 +76,23 @@ function collectSemanticErrors(manifest) {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
|
+
const qualifiedDimensions = new Set();
|
|
80
|
+
for (const view of explore.views) {
|
|
81
|
+
for (const dimension of view.dimensions) {
|
|
82
|
+
qualifiedDimensions.add(`${view.name}.${dimension.name}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
(explore.alwaysFilter ?? []).forEach((filterGroup, groupIndex) => {
|
|
86
|
+
filterGroup.group.forEach((filter, filterIndex) => {
|
|
87
|
+
const path = `${explorePath}.alwaysFilter[${groupIndex}].group[${filterIndex}].dimensionName`;
|
|
88
|
+
if (!qualifiedDimensions.has(filter.dimensionName)) {
|
|
89
|
+
errors.push({
|
|
90
|
+
path,
|
|
91
|
+
message: `alwaysFilter dimensionName "${filter.dimensionName}" is not a dimension on this explore`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
79
96
|
explore.joins.forEach((join, joinIndex) => {
|
|
80
97
|
if (!viewNames.has(join.fromView)) {
|
|
81
98
|
errors.push({
|
package/manifest.schema.json
CHANGED
|
@@ -173,6 +173,50 @@
|
|
|
173
173
|
"relationship": { "$ref": "#/definitions/JoinRelationship" }
|
|
174
174
|
}
|
|
175
175
|
},
|
|
176
|
+
"FilterOperator": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"enum": [
|
|
179
|
+
"eq", "neq", "contains", "not_contains",
|
|
180
|
+
"gt", "gte", "lt", "lte",
|
|
181
|
+
"is_null", "is_not_null"
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
"FilterStatement": {
|
|
185
|
+
"type": "object",
|
|
186
|
+
"required": ["operator", "values"],
|
|
187
|
+
"additionalProperties": false,
|
|
188
|
+
"properties": {
|
|
189
|
+
"operator": { "$ref": "#/definitions/FilterOperator" },
|
|
190
|
+
"values": {
|
|
191
|
+
"type": "array",
|
|
192
|
+
"items": { "type": ["string", "number", "boolean"] }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"Filter": {
|
|
197
|
+
"type": "object",
|
|
198
|
+
"required": ["dimensionName", "orStatements"],
|
|
199
|
+
"additionalProperties": false,
|
|
200
|
+
"properties": {
|
|
201
|
+
"dimensionName": { "$ref": "#/definitions/RefString" },
|
|
202
|
+
"orStatements": {
|
|
203
|
+
"type": "array",
|
|
204
|
+
"items": { "$ref": "#/definitions/FilterStatement" }
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"FilterGroup": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"required": ["type", "group"],
|
|
211
|
+
"additionalProperties": false,
|
|
212
|
+
"properties": {
|
|
213
|
+
"type": { "type": "string", "enum": ["AND", "OR"] },
|
|
214
|
+
"group": {
|
|
215
|
+
"type": "array",
|
|
216
|
+
"items": { "$ref": "#/definitions/Filter" }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
},
|
|
176
220
|
"Explore": {
|
|
177
221
|
"type": "object",
|
|
178
222
|
"required": ["name", "label", "from", "joins", "views"],
|
|
@@ -192,6 +236,10 @@
|
|
|
192
236
|
"alwaysInclude": {
|
|
193
237
|
"type": "array",
|
|
194
238
|
"items": { "$ref": "#/definitions/RefString" }
|
|
239
|
+
},
|
|
240
|
+
"alwaysFilter": {
|
|
241
|
+
"type": "array",
|
|
242
|
+
"items": { "$ref": "#/definitions/FilterGroup" }
|
|
195
243
|
}
|
|
196
244
|
}
|
|
197
245
|
},
|