Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import R from 'ramda';
import { getEnv } from '@cubejs-backend/shared';
import { CubeStoreDriver } from '@cubejs-backend/cubestore-driver';

import { QueryCache, QueryBody, TempTable } from './QueryCache';
import { QueryCache, QueryBody, TempTable, PreAggTableToTempTable } from './QueryCache';
import { PreAggregations, PreAggregationDescription, getLastUpdatedAtTimestamp } from './PreAggregations';
import { DriverFactory, DriverFactoryByDataSource } from './DriverFactory';
import { LocalQueueEventsBus } from './LocalQueueEventsBus';
Expand Down Expand Up @@ -224,28 +224,18 @@ export class QueryOrchestrator {
};
}

const usedPreAggregations = R.pipe(
const usedPreAggregations = R.pipe<
PreAggTableToTempTable[],
Record<string, TempTable>,
Record<string, unknown>
>(
R.fromPairs,
R.map((pa: TempTable) => ({
R.mapObjIndexed((pa: TempTable) => ({
targetTableName: pa.targetTableName,
refreshKeyValues: pa.refreshKeyValues,
lastUpdatedAt: pa.lastUpdatedAt,
})),
)(
preAggregationsTablesToTempTables as unknown as [
number, // TODO: we actually have a string here
{
buildRangeEnd: string,
lastUpdatedAt: number,
queryKey: unknown,
refreshKeyValues: [{
'refresh_key': string,
}][],
targetTableName: string,
type: string,
},
][]
);
)(preAggregationsTablesToTempTables);

if (this.rollupOnlyMode && Object.keys(usedPreAggregations).length === 0) {
throw new Error(
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-schema-compiler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@types/inflection": "^1.5.28",
"@types/jest": "^29",
"@types/node": "^20",
"@types/node-dijkstra": "^2.5.6",
"@types/ramda": "^0.27.34",
"@types/sqlstring": "^2.3.0",
"@types/syntax-error": "^1.4.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ export class BaseDimension {
if (this.expression) {
return `expr:${this.expressionName}`;
}
return this.query.cubeEvaluator.pathFromArray(this.path() as string[]);

const path = this.path();
if (path === null) {
// Sanity check, this should not actually happen because we checked this.expression earlier
throw new Error('Unexpected null path');
}
return this.query.cubeEvaluator.pathFromArray(path);
}
}
4 changes: 2 additions & 2 deletions packages/cubejs-schema-compiler/src/adapter/BaseFilter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import inlection from 'inflection';
import moment from 'moment-timezone';
import { contains, join, map } from 'ramda';
import { includes, join, map } from 'ramda';
import { FROM_PARTITION_RANGE, TO_PARTITION_RANGE } from '@cubejs-backend/shared';

import { BaseDimension } from './BaseDimension';
Expand Down Expand Up @@ -134,7 +134,7 @@ export class BaseFilter extends BaseDimension {
}

public isDateOperator(): boolean {
return contains(this.camelizeOperator, DATE_OPERATORS);
return includes(this.camelizeOperator, DATE_OPERATORS);
}

public valuesArray() {
Expand Down
28 changes: 17 additions & 11 deletions packages/cubejs-schema-compiler/src/adapter/BaseMeasure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,32 +206,32 @@ export class BaseMeasure {
return this.measureDefinition();
}

public aliasName() {
public aliasName(): string {
return this.query.escapeColumnName(this.unescapedAliasName());
}

public unescapedAliasName() {
public unescapedAliasName(): string {
if (this.expression) {
return this.query.aliasName(this.expressionName);
}
return this.query.aliasName(this.measure);
}

public isCumulative() {
public isCumulative(): boolean {
if (this.expression) { // TODO
return false;
}
return BaseMeasure.isCumulative(this.measureDefinition());
}

public isMultiStage() {
public isMultiStage(): boolean {
if (this.expression) { // TODO
return false;
}
return this.definition().multiStage;
}

public isAdditive() {
public isAdditive(): boolean {
if (this.expression) { // TODO
return false;
}
Expand All @@ -243,7 +243,7 @@ export class BaseMeasure {
definition.type === 'min' || definition.type === 'max';
}

public static isCumulative(definition) {
public static isCumulative(definition): boolean {
return definition.type === 'runningTotal' || !!definition.rollingWindow;
}

Expand Down Expand Up @@ -294,7 +294,7 @@ export class BaseMeasure {
return this.query.minGranularity(granularityA, granularityB);
}

public granularityFromInterval(interval: string) {
public granularityFromInterval(interval: string): string | undefined {
if (!interval) {
return undefined;
}
Expand All @@ -312,25 +312,31 @@ export class BaseMeasure {
return undefined;
}

public shouldUngroupForCumulative() {
public shouldUngroupForCumulative(): boolean {
return this.measureDefinition().rollingWindow && !this.isAdditive();
}

public sqlDefinition() {
return this.measureDefinition().sql;
}

public path() {
public path(): string[] | null {
if (this.expression) {
return null;
}
return this.query.cubeEvaluator.parsePath('measures', this.measure);
}

public expressionPath() {
public expressionPath(): string {
if (this.expression) {
return `expr:${this.expression.expressionName}`;
}
return this.query.cubeEvaluator.pathFromArray(this.path() as string[]);

const path = this.path();
if (path === null) {
// Sanity check, this should not actually happen because we checked this.expression earlier
throw new Error('Unexpected null path');
}
return this.query.cubeEvaluator.pathFromArray(path);
}
}
76 changes: 73 additions & 3 deletions packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ export class BaseQuery {
/** @type {import('./BaseTimeDimension').BaseTimeDimension[]} */
timeDimensions;

/**
* @type {import('../compiler/JoinGraph').FinishedJoinTree}
*/
join;

/**
* BaseQuery class constructor.
* @param {Compilers|*} compilers
Expand Down Expand Up @@ -2166,6 +2171,12 @@ export class BaseQuery {
));
}

/**
*
* @param {string} cube
* @param {boolean} [isLeftJoinCondition]
* @returns {[string, string, string?]}
*/
rewriteInlineCubeSql(cube, isLeftJoinCondition) {
const sql = this.cubeSql(cube);
const cubeAlias = this.cubeAlias(cube);
Expand All @@ -2188,9 +2199,14 @@ export class BaseQuery {
}
}

/**
* @param {import('../compiler/JoinGraph').FinishedJoinTree} join
* @param {Array<string>} subQueryDimensions
* @returns {string}
*/
joinQuery(join, subQueryDimensions) {
const subQueryDimensionsByCube = R.groupBy(d => this.cubeEvaluator.cubeNameFromPath(d), subQueryDimensions);
const joins = join.joins.map(
const joins = join.joins.flatMap(
j => {
const [cubeSql, cubeAlias, conditions] = this.rewriteInlineCubeSql(j.originalTo, true);
return [{
Expand All @@ -2200,7 +2216,7 @@ export class BaseQuery {
// TODO handle the case when sub query referenced by a foreign cube on other side of a join
}].concat((subQueryDimensionsByCube[j.originalTo] || []).map(d => this.subQueryJoin(d)));
}
).reduce((a, b) => a.concat(b), []);
);

const [cubeSql, cubeAlias] = this.rewriteInlineCubeSql(join.root);

Expand All @@ -2212,6 +2228,10 @@ export class BaseQuery {
]);
}

/**
* @param {JoinChain} toJoin
* @returns {string}
*/
joinSql(toJoin) {
const [root, ...rest] = toJoin;
const joins = rest.map(
Expand Down Expand Up @@ -2273,6 +2293,11 @@ export class BaseQuery {
return this.filtersWithoutSubQueriesValue;
}

/**
*
* @param {string} dimension
* @returns {{ prefix: string, subQuery: this, cubeName: string }}
*/
subQueryDescription(dimension) {
const symbol = this.cubeEvaluator.dimensionByPath(dimension);
const [cubeName, name] = this.cubeEvaluator.parsePath('dimensions', dimension);
Expand Down Expand Up @@ -2317,6 +2342,12 @@ export class BaseQuery {
return { prefix, subQuery, cubeName };
}

/**
*
* @param {string} cubeName
* @param {string} name
* @returns {string}
*/
subQueryName(cubeName, name) {
return `${cubeName}_${name}_subquery`;
}
Expand Down Expand Up @@ -2520,6 +2551,9 @@ export class BaseQuery {
);
}

/**
* @param {string} cube
*/
cubeSql(cube) {
const foundPreAggregation = this.preAggregations.findPreAggregationToUseForCube(cube);
if (foundPreAggregation &&
Expand Down Expand Up @@ -2630,6 +2664,13 @@ export class BaseQuery {
];
}

/**
* @template T
* @param {boolean} excludeTimeDimensions
* @param {(t: () => void) => T} fn
* @param {string | Array<string>} methodName
* @returns {T}
*/
collectFromMembers(excludeTimeDimensions, fn, methodName) {
const membersToCollectFrom = this.allMembersConcat(excludeTimeDimensions)
.concat(this.join ? this.join.joins.map(j => ({
Expand All @@ -2656,6 +2697,14 @@ export class BaseQuery {
.concat(excludeTimeDimensions ? [] : this.timeDimensions);
}

/**
* @template T
* @param {Array<unknown>} membersToCollectFrom
* @param {(t: () => void) => T} fn
* @param {string | Array<string>} methodName
* @param {unknown} [cache]
* @returns {T}
*/
collectFrom(membersToCollectFrom, fn, methodName, cache) {
const methodCacheKey = Array.isArray(methodName) ? methodName : [methodName];
return R.pipe(
Expand All @@ -2677,6 +2726,11 @@ export class BaseQuery {
);
}

/**
*
* @param {() => void} fn
* @returns {Array<string>}
*/
collectSubQueryDimensionsFor(fn) {
const context = { subQueryDimensions: [] };
this.evaluateSymbolSqlWithContext(
Expand Down Expand Up @@ -3239,6 +3293,11 @@ export class BaseQuery {
return strings.join(' || ');
}

/**
*
* @param {string} cubeName
* @returns {Array<string>}
*/
primaryKeyNames(cubeName) {
const primaryKeys = this.cubeEvaluator.primaryKeys[cubeName];
if (!primaryKeys || !primaryKeys.length) {
Expand Down Expand Up @@ -3374,6 +3433,12 @@ export class BaseQuery {
)(context.leafMeasures);
}

/**
* @template T
* @param {() => T} fn
* @param {unknown} context
* @returns {T}
*/
evaluateSymbolSqlWithContext(fn, context) {
const oldContext = this.evaluateSymbolContext;
this.evaluateSymbolContext = oldContext ? Object.assign({}, oldContext, context) : context;
Expand Down Expand Up @@ -3596,6 +3661,11 @@ export class BaseQuery {
.map(s => `(${s})`).join(' AND ');
}

/**
* @param {string} primaryKeyName
* @param {string} cubeName
* @returns {unknown}
*/
primaryKeySql(primaryKeyName, cubeName) {
const primaryKeyDimension = this.cubeEvaluator.dimensionByPath([cubeName, primaryKeyName]);
return this.evaluateSymbolSql(
Expand Down Expand Up @@ -3745,7 +3815,7 @@ export class BaseQuery {
/**
*
* @param options
* @returns {BaseQuery}
* @returns {this}
*/
newSubQuery(options) {
const QueryClass = this.constructor;
Expand Down
12 changes: 9 additions & 3 deletions packages/cubejs-schema-compiler/src/adapter/BaseSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,23 @@ export class BaseSegment {
return this.segmentDefinition().sql;
}

public path() {
public path(): string[] | null {
if (this.expression) {
return null;
}
return this.query.cubeEvaluator.parsePath('segments', this.segment);
}

public expressionPath() {
public expressionPath(): string {
if (this.expression) {
return `expr:${this.expression.expressionName}`;
}
return this.query.cubeEvaluator.pathFromArray(this.path() as string[]);

const path = this.path();
if (path === null) {
// Sanity check, this should not actually happen because we checked this.expression earlier
throw new Error('Unexpected null path');
}
return this.query.cubeEvaluator.pathFromArray(path);
}
}
Loading
Loading