Skip to content

Commit 6506da7

Browse files
committed
make extend of all the things in the view
1 parent 25f7cf3 commit 6506da7

File tree

2 files changed

+57
-33
lines changed

2 files changed

+57
-33
lines changed

packages/cubejs-schema-compiler/src/compiler/CubeSymbols.ts

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ interface CubeDefinition {
3535
includedMembers?: any[];
3636
}
3737

38+
interface CubeDefinitionExtended extends CubeDefinition {
39+
allDefinitions: (type: string) => Record<string, any>;
40+
rawFolders: () => any[];
41+
rawCubes: () => any[];
42+
}
43+
3844
interface SplitViews {
3945
[key: string]: any;
4046
}
@@ -102,7 +108,7 @@ export class CubeSymbols {
102108
}
103109
}
104110

105-
public getCubeDefinition(cubeName: string) {
111+
public getCubeDefinition(cubeName: string): CubeDefinitionExtended {
106112
if (!this.builtCubes[cubeName]) {
107113
const cubeDefinition = this.cubeDefinitions[cubeName];
108114
this.builtCubes[cubeName] = this.createCube(cubeDefinition);
@@ -111,7 +117,7 @@ export class CubeSymbols {
111117
return this.builtCubes[cubeName];
112118
}
113119

114-
public createCube(cubeDefinition: CubeDefinition) {
120+
public createCube(cubeDefinition: CubeDefinition): CubeDefinitionExtended {
115121
let preAggregations: any;
116122
let joins: any;
117123
let measures: any;
@@ -120,6 +126,7 @@ export class CubeSymbols {
120126
let hierarchies: any;
121127
let accessPolicy: any;
122128
let folders: any;
129+
let cubes: any;
123130

124131
const cubeObject = Object.assign({
125132
allDefinitions(type: string) {
@@ -149,6 +156,22 @@ export class CubeSymbols {
149156
return folders;
150157
},
151158

159+
// `Cubes` of a view are not a part of Cube Symbols,
160+
// but views can extend other views, so we need the ability to access parent view's cubes.
161+
rawCubes() {
162+
if (!cubes) {
163+
if (cubeDefinition.extends) {
164+
cubes = [
165+
...super.rawCubes(),
166+
...(cubeDefinition.cubes || [])
167+
];
168+
} else {
169+
cubes = [...(cubeDefinition.cubes || [])];
170+
}
171+
}
172+
return cubes;
173+
},
174+
152175
get preAggregations() {
153176
// For preAggregations order is important, and destructing parents cube pre-aggs first will lead to
154177
// unexpected results, so we can not use common approach with allDefinitions('preAggregations') here.
@@ -240,7 +263,7 @@ export class CubeSymbols {
240263
if (cubeDefinition.extends) {
241264
const superCube = this.resolveSymbolsCall(cubeDefinition.extends, (name: string) => this.cubeReferenceProxy(name));
242265
// eslint-disable-next-line no-underscore-dangle
243-
const parentCube = superCube.__cubeName ? this.getCubeDefinition(superCube.__cubeName) : superCube;
266+
const parentCube = superCube.__cubeName ? this.getCubeDefinition(superCube.__cubeName) : superCube as unknown as CubeDefinition;
244267
Object.setPrototypeOf(cubeObject, parentCube);
245268

246269
// We have 2 different properties that are mutually exclusive: `sqlTable` & `sql`
@@ -303,7 +326,7 @@ export class CubeSymbols {
303326
};
304327
}
305328

306-
private camelCaseTypes(obj: Object) {
329+
private camelCaseTypes(obj: Object | undefined) {
307330
if (!obj) {
308331
return;
309332
}
@@ -362,8 +385,9 @@ export class CubeSymbols {
362385
}
363386
}
364387

365-
protected prepareIncludes(cube: CubeDefinition, errorReporter: ErrorReporter, splitViews: SplitViews) {
366-
if (!cube.cubes) {
388+
protected prepareIncludes(cube: CubeDefinitionExtended, errorReporter: ErrorReporter, splitViews: SplitViews) {
389+
const includedCubes = cube.rawCubes();
390+
if (!includedCubes.length) {
367391
return;
368392
}
369393

@@ -378,32 +402,31 @@ export class CubeSymbols {
378402

379403
for (const type of types) {
380404
let cubeIncludes: any[] = [];
381-
if (cube.cubes) {
382-
// If the hierarchy is included all members from it should be included as well
383-
// Extend `includes` with members from hierarchies that should be auto-included
384-
const cubes = type === 'dimensions' ? cube.cubes.map((it) => {
385-
// TODO recheck `it.joinPath` typing
386-
const fullPath = this.evaluateReferences(null, it.joinPath as () => ToString, { collectJoinHints: true });
387-
const split = fullPath.split('.');
388-
const cubeRef = split[split.length - 1];
389-
390-
if (it.includes === '*') {
391-
return it;
392-
}
393405

394-
const currentCubeAutoIncludeMembers = Array.from(autoIncludeMembers)
395-
.filter((path) => path.startsWith(`${cubeRef}.`))
396-
.map((path) => path.split('.')[1])
397-
.filter(memberName => !it.includes.find((include) => (include.name || include) === memberName));
406+
// If the hierarchy is included all members from it should be included as well
407+
// Extend `includes` with members from hierarchies that should be auto-included
408+
const cubes = type === 'dimensions' ? includedCubes.map((it) => {
409+
// TODO recheck `it.joinPath` typing
410+
const fullPath = this.evaluateReferences(null, it.joinPath as () => ToString, { collectJoinHints: true });
411+
const split = fullPath.split('.');
412+
const cubeRef = split[split.length - 1];
398413

399-
return {
400-
...it,
401-
includes: (it.includes || []).concat(currentCubeAutoIncludeMembers),
402-
};
403-
}) : cube.cubes;
414+
if (it.includes === '*') {
415+
return it;
416+
}
404417

405-
cubeIncludes = this.membersFromCubes(cube, cubes, type, errorReporter, splitViews, memberSets) || [];
406-
}
418+
const currentCubeAutoIncludeMembers = Array.from(autoIncludeMembers)
419+
.filter((path) => path.startsWith(`${cubeRef}.`))
420+
.map((path) => path.split('.')[1])
421+
.filter(memberName => !it.includes.find((include) => (include.name || include) === memberName));
422+
423+
return {
424+
...it,
425+
includes: (it.includes || []).concat(currentCubeAutoIncludeMembers),
426+
};
427+
}) : includedCubes;
428+
429+
cubeIncludes = this.membersFromCubes(cube, cubes, type, errorReporter, splitViews, memberSets) || [];
407430

408431
if (type === 'hierarchies') {
409432
for (const member of cubeIncludes) {
@@ -424,15 +447,15 @@ export class CubeSymbols {
424447
const includeMembers = this.generateIncludeMembers(cubeIncludes, cube.name, type);
425448
this.applyIncludeMembers(includeMembers, cube, type, errorReporter);
426449

427-
cube.includedMembers = [...(cube.includedMembers || []), ...Array.from(new Set(cubeIncludes.map((it: any) => {
450+
cube.includedMembers = R.uniqWith(R.equals, [...(cube.includedMembers || []), ...Array.from(new Set(cubeIncludes.map((it: any) => {
428451
const split = it.member.split('.');
429452
const memberPath = this.pathFromArray([split[split.length - 2], split[split.length - 1]]);
430453
return {
431454
type,
432455
memberPath,
433456
name: it.name
434457
};
435-
})))];
458+
})))]);
436459
}
437460

438461
[...memberSets.allMembers].filter(it => !memberSets.resolvedMembers.has(it)).forEach(it => {
@@ -451,7 +474,7 @@ export class CubeSymbols {
451474
}
452475

453476
protected membersFromCubes(parentCube: CubeDefinition, cubes: any[], type: string, errorReporter: ErrorReporter, splitViews: SplitViews, memberSets: any) {
454-
return R.unnest(cubes.map(cubeInclude => {
477+
return R.uniqWith(R.equals, R.unnest(cubes.map(cubeInclude => {
455478
// TODO recheck `cubeInclude.joinPath` typing
456479
const fullPath = this.evaluateReferences(null, cubeInclude.joinPath as () => ToString, { collectJoinHints: true });
457480
const split = fullPath.split('.');
@@ -531,7 +554,7 @@ export class CubeSymbols {
531554
} else {
532555
return finalIncludes;
533556
}
534-
}));
557+
})));
535558
}
536559

537560
protected diffByMember(includes: any[], excludes: any[]) {

packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ const baseSchema = {
747747
extends: Joi.func(),
748748
allDefinitions: Joi.func(), // Helpers function for extending
749749
rawFolders: Joi.func(), // Helpers function for extending
750+
rawCubes: Joi.func(), // Helpers function for extending
750751
title: Joi.string(),
751752
sqlAlias: Joi.string(),
752753
dataSource: Joi.string(),

0 commit comments

Comments
 (0)