Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,9 @@ export class CubeEvaluator extends CubeSymbols {
}

private prepareHierarchies(cube: any, errorReporter: ErrorReporter): void {
if (Object.keys(cube.hierarchies).length) {
// Hierarchies from views are not fully populated at this moment and are processed later,
// so we should not pollute the cube hierarchies definition here.
if (!cube.isView && Object.keys(cube.hierarchies).length) {
cube.evaluatedHierarchies = Object.entries(cube.hierarchies).map(([name, hierarchy]) => ({
name,
...(typeof hierarchy === 'object' ? hierarchy : {}),
Expand Down Expand Up @@ -306,6 +308,8 @@ export class CubeEvaluator extends CubeSymbols {
throw new UserError(`Hierarchy '${it.name}' not found in cube '${cubeName}'`);
}
return {
// Title might be overridden in the view
title: cube.hierarchies?.[it.name]?.override?.title || it.title,
...it,
name,
levels
Expand Down
90 changes: 48 additions & 42 deletions packages/cubejs-schema-compiler/src/compiler/CubeSymbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

public cubeList: any[];

private evaluateViews: boolean;
private readonly evaluateViews: boolean;

private resolveSymbolsCallContext: any;

Expand Down Expand Up @@ -147,7 +147,7 @@
}
return preAggregations;
},
set preAggregations(v) {
set preAggregations(_v) {
// Dont allow to modify
},

Expand All @@ -157,7 +157,7 @@
}
return joins;
},
set joins(v) {
set joins(_v) {
// Dont allow to modify
},

Expand All @@ -167,7 +167,7 @@
}
return measures;
},
set measures(v) {
set measures(_v) {
// Dont allow to modify
},

Expand All @@ -177,7 +177,7 @@
}
return dimensions;
},
set dimensions(v) {
set dimensions(_v) {
// Dont allow to modify
},

Expand All @@ -187,7 +187,7 @@
}
return segments;
},
set segments(v) {
set segments(_v) {
// Dont allow to modify
},

Expand All @@ -197,7 +197,7 @@
}
return hierarchies;
},
set hierarchies(v) {
set hierarchies(_v) {
// Dont allow to modify
},

Expand All @@ -213,7 +213,7 @@
return undefined;
}
},
set accessPolicy(v) {
set accessPolicy(_v) {
// Dont allow to modify
}
},
Expand Down Expand Up @@ -275,13 +275,14 @@
this.prepareIncludes(cube, errorReporter, splitViews);
}

return Object.assign(
{ cubeName: () => cube.name, cubeObj: () => cube },
cube.measures || {},
cube.dimensions || {},
cube.segments || {},
cube.preAggregations || {}
);
return {
cubeName: () => cube.name,
cubeObj: () => cube,
...cube.measures || {},
...cube.dimensions || {},
...cube.segments || {},
...cube.preAggregations || {}
};
}

private camelCaseTypes(obj: Object) {
Expand Down Expand Up @@ -425,7 +426,7 @@
for (const [memberName, memberDefinition] of includeMembers) {
if (cube[type]?.[memberName]) {
errorReporter.error(`Included member '${memberName}' conflicts with existing member of '${cube.name}'. Please consider excluding this member or assigning it an alias.`);
} else if (type !== 'hierarchies') {
} else {
cube[type][memberName] = memberDefinition;
}
}
Expand All @@ -439,28 +440,36 @@
const cubeReference = split[split.length - 1];
const cubeName = cubeInclude.alias || cubeReference;

let includes;
let includes: any[];
const fullMemberName = (memberName: string) => (cubeInclude.prefix ? `${cubeName}_${memberName}` : memberName);

if (cubeInclude.includes === '*') {
const membersObj = this.symbols[cubeReference]?.cubeObj()?.[type] || {};
includes = Object.keys(membersObj).map(memberName => ({ member: `${fullPath}.${memberName}`, name: fullMemberName(memberName) }));
} else {
includes = cubeInclude.includes.map((include: any) => {
const member = include.alias || include;
const member = include.alias || include.name || include;

if (member.includes('.')) {
errorReporter.error(`Paths aren't allowed in cube includes but '${member}' provided as include member`);
}

const name = fullMemberName(include.alias || member);
const name = fullMemberName(member);
memberSets.allMembers.add(name);

const includedMemberName = include.name || include;

const resolvedMember = this.getResolvedMember(type, cubeReference, includedMemberName) ? {
member: `${fullPath}.${includedMemberName}`,
name,
...(include.title || include.description || include.format || include.meta) ? {
override: {
title: include.title,
description: include.description,
format: include.format,
meta: include.meta,
}
} : {}
} : undefined;

if (resolvedMember) {
Expand Down Expand Up @@ -537,10 +546,10 @@
sql,
type: CubeSymbols.toMemberDataType(resolvedMember.type),
aggType: resolvedMember.type,
meta: resolvedMember.meta,
title: resolvedMember.title,
description: resolvedMember.description,
format: resolvedMember.format,
meta: memberRef.override?.meta || resolvedMember.meta,
title: memberRef.override?.title || resolvedMember.title,
description: memberRef.override?.description || resolvedMember.description,
format: memberRef.override?.format || resolvedMember.format,
...(resolvedMember.multiStage && { multiStage: resolvedMember.multiStage }),
...(resolvedMember.timeShift && { timeShift: resolvedMember.timeShift }),
...(resolvedMember.orderBy && { orderBy: resolvedMember.orderBy }),
Expand All @@ -549,24 +558,24 @@
memberDefinition = {
sql,
type: resolvedMember.type,
meta: resolvedMember.meta,
title: resolvedMember.title,
description: resolvedMember.description,
format: resolvedMember.format,
meta: memberRef.override?.meta || resolvedMember.meta,
title: memberRef.override?.title || resolvedMember.title,
description: memberRef.override?.description || resolvedMember.description,
format: memberRef.override?.format || resolvedMember.format,
...(resolvedMember.granularities ? { granularities: resolvedMember.granularities } : {}),
...(resolvedMember.multiStage && { multiStage: resolvedMember.multiStage }),
};
} else if (type === 'segments') {
memberDefinition = {
sql,
meta: resolvedMember.meta,
title: resolvedMember.title,
description: resolvedMember.description,
meta: memberRef.override?.meta || resolvedMember.meta,
description: memberRef.override?.description || resolvedMember.description,
title: memberRef.override?.title || resolvedMember.title,
aliases: resolvedMember.aliases,
};
} else if (type === 'hierarchies') {
memberDefinition = {
title: resolvedMember.title,
title: memberRef.override?.title || resolvedMember.title,
levels: resolvedMember.levels,
};
} else {
Expand All @@ -578,7 +587,7 @@

/**
* This method is mainly used for evaluating RLS conditions and filters.
* It allows referencing security_context (lowecase) in dynamic conditions or filter values.
* It allows referencing security_context (lowercase) in dynamic conditions or filter values.
*
* It currently does not support async calls because inner resolveSymbol and
* resolveSymbolsCall are sync. Async support may be added later with deeper
Expand All @@ -587,7 +596,7 @@
protected evaluateContextFunction(cube: any, contextFn: any, context: any = {}) {
const cubeEvaluator = this;

const res = cubeEvaluator.resolveSymbolsCall(contextFn, (name: string) => {
return cubeEvaluator.resolveSymbolsCall(contextFn, (name: string) => {

Check warning on line 599 in packages/cubejs-schema-compiler/src/compiler/CubeSymbols.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L599 was not covered by tests
const resolvedSymbol = this.resolveSymbol(cube, name);
if (resolvedSymbol) {
return resolvedSymbol;
Expand All @@ -600,8 +609,6 @@
securityContext: context.securityContext,
}
});

return res;
}

protected evaluateReferences<T extends ToString | Array<ToString>>(
Expand Down Expand Up @@ -757,15 +764,14 @@
}

protected depsContextSymbols() {
return Object.assign({
return {

Check warning on line 767 in packages/cubejs-schema-compiler/src/compiler/CubeSymbols.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L767 was not covered by tests
filterParams: this.filtersProxyDep(),
filterGroup: this.filterGroupFunctionDep(),
securityContext: CubeSymbols.contextSymbolsProxyFrom({}, (param) => param),
sqlUtils: {
convertTz: (f) => f

},
});
};
}

protected filtersProxyDep() {
Expand Down Expand Up @@ -810,7 +816,7 @@

if (CONTEXT_SYMBOLS[name]) {
// always resolves if contextSymbols aren't passed for transpile step
const symbol = contextSymbols && contextSymbols[CONTEXT_SYMBOLS[name]] || {};
const symbol = contextSymbols?.[CONTEXT_SYMBOLS[name]] || {};
// eslint-disable-next-line no-underscore-dangle
symbol._objectWithResolvedProperties = true;
return symbol;
Expand Down Expand Up @@ -842,12 +848,12 @@
const parentIndex = currResolveIndexFn();
cube = this.cubeDependenciesProxy(parentIndex, newCubeName);
return cube;
} else if (this.symbols[cubeName] && this.symbols[cubeName][name] && this.symbols[cubeName][name].type === 'time') {
} else if (this.symbols[cubeName]?.[name] && this.symbols[cubeName][name].type === 'time') {
const parentIndex = currResolveIndexFn();
return this.timeDimDependenciesProxy(parentIndex);
}
}
return cube || (this.symbols[cubeName] && this.symbols[cubeName][name]);
return cube || this.symbols[cubeName]?.[name];
}

protected cubeReferenceProxy(cubeName, joinHints?: any[], refProperty?: any) {
Expand Down Expand Up @@ -937,7 +943,7 @@
return { interval: `1 ${granName}` };
}

return cube && cube[dimName] && cube[dimName][gr] && cube[dimName][gr][granName];
return cube?.[dimName]?.[gr]?.[granName];
}

protected cubeDependenciesProxy(parentIndex, cubeName) {
Expand Down
22 changes: 14 additions & 8 deletions packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ const GranularityInterval = Joi.string().pattern(/^\d+\s+(second|minute|hour|day
// Do not allow negative intervals for granularities, while offsets could be negative
const GranularityOffset = Joi.string().pattern(/^-?(\d+\s+)(second|minute|hour|day|week|month|quarter|year)s?(\s-?\d+\s+(second|minute|hour|day|week|month|quarter|year)s?){0,7}$/, 'granularity offset');

const formatSchema = Joi.alternatives([
Joi.string().valid('imageUrl', 'link', 'currency', 'percent', 'number', 'id'),
Joi.object().keys({
type: Joi.string().valid('link'),
label: Joi.string().required()
})
]);

const BaseDimensionWithoutSubQuery = {
aliases: Joi.array().items(Joi.string()),
type: Joi.any().valid('string', 'number', 'boolean', 'time', 'geo').required(),
Expand All @@ -122,13 +130,7 @@ const BaseDimensionWithoutSubQuery = {
description: Joi.string(),
suggestFilterValues: Joi.boolean().strict(),
enableSuggestions: Joi.boolean().strict(),
format: Joi.alternatives([
Joi.string().valid('imageUrl', 'link', 'currency', 'percent', 'number', 'id'),
Joi.object().keys({
type: Joi.string().valid('link'),
label: Joi.string().required()
})
]),
format: formatSchema,
meta: Joi.any(),
granularities: Joi.when('type', {
is: 'time',
Expand Down Expand Up @@ -796,7 +798,11 @@ const viewSchema = inherit(baseSchema, {
Joi.string().required(),
Joi.object().keys({
name: identifier.required(),
alias: identifier
alias: identifier,
title: Joi.string(),
description: Joi.string(),
format: formatSchema,
meta: Joi.any(),
})
]))
]).required(),
Expand Down
Loading
Loading