Skip to content

Commit d5172f9

Browse files
authored
chore(schema-compiler): More defined types (cube-js#9785)
* add @types/node-dijkstra * some ramda fixes * more types in base member classes * more types * more types and EvaluatedCube type!! * more types * more types in CubeSymbols * more types in CubeSymbols * fix types in QueryOrchestrator * more types in CubeSymbols & Evaluator * fix types in ScaffoldingSchema * move JoinGraph to ts * more types in BaseQuery * fix * fix
1 parent 0523f7a commit d5172f9

File tree

17 files changed

+761
-424
lines changed

17 files changed

+761
-424
lines changed

packages/cubejs-query-orchestrator/src/orchestrator/QueryOrchestrator.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import R from 'ramda';
33
import { getEnv } from '@cubejs-backend/shared';
44
import { CubeStoreDriver } from '@cubejs-backend/cubestore-driver';
55

6-
import { QueryCache, QueryBody, TempTable } from './QueryCache';
6+
import { QueryCache, QueryBody, TempTable, PreAggTableToTempTable } from './QueryCache';
77
import { PreAggregations, PreAggregationDescription, getLastUpdatedAtTimestamp } from './PreAggregations';
88
import { DriverFactory, DriverFactoryByDataSource } from './DriverFactory';
99
import { LocalQueueEventsBus } from './LocalQueueEventsBus';
@@ -224,28 +224,18 @@ export class QueryOrchestrator {
224224
};
225225
}
226226

227-
const usedPreAggregations = R.pipe(
227+
const usedPreAggregations = R.pipe<
228+
PreAggTableToTempTable[],
229+
Record<string, TempTable>,
230+
Record<string, unknown>
231+
>(
228232
R.fromPairs,
229-
R.map((pa: TempTable) => ({
233+
R.mapObjIndexed((pa: TempTable) => ({
230234
targetTableName: pa.targetTableName,
231235
refreshKeyValues: pa.refreshKeyValues,
232236
lastUpdatedAt: pa.lastUpdatedAt,
233237
})),
234-
)(
235-
preAggregationsTablesToTempTables as unknown as [
236-
number, // TODO: we actually have a string here
237-
{
238-
buildRangeEnd: string,
239-
lastUpdatedAt: number,
240-
queryKey: unknown,
241-
refreshKeyValues: [{
242-
'refresh_key': string,
243-
}][],
244-
targetTableName: string,
245-
type: string,
246-
},
247-
][]
248-
);
238+
)(preAggregationsTablesToTempTables);
249239

250240
if (this.rollupOnlyMode && Object.keys(usedPreAggregations).length === 0) {
251241
throw new Error(

packages/cubejs-schema-compiler/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"@types/inflection": "^1.5.28",
6969
"@types/jest": "^29",
7070
"@types/node": "^20",
71+
"@types/node-dijkstra": "^2.5.6",
7172
"@types/ramda": "^0.27.34",
7273
"@types/sqlstring": "^2.3.0",
7374
"@types/syntax-error": "^1.4.1",

packages/cubejs-schema-compiler/src/adapter/BaseDimension.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ export class BaseDimension {
142142
if (this.expression) {
143143
return `expr:${this.expressionName}`;
144144
}
145-
return this.query.cubeEvaluator.pathFromArray(this.path() as string[]);
145+
146+
const path = this.path();
147+
if (path === null) {
148+
// Sanity check, this should not actually happen because we checked this.expression earlier
149+
throw new Error('Unexpected null path');
150+
}
151+
return this.query.cubeEvaluator.pathFromArray(path);
146152
}
147153
}

packages/cubejs-schema-compiler/src/adapter/BaseFilter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import inlection from 'inflection';
22
import moment from 'moment-timezone';
3-
import { contains, join, map } from 'ramda';
3+
import { includes, join, map } from 'ramda';
44
import { FROM_PARTITION_RANGE, TO_PARTITION_RANGE } from '@cubejs-backend/shared';
55

66
import { BaseDimension } from './BaseDimension';
@@ -134,7 +134,7 @@ export class BaseFilter extends BaseDimension {
134134
}
135135

136136
public isDateOperator(): boolean {
137-
return contains(this.camelizeOperator, DATE_OPERATORS);
137+
return includes(this.camelizeOperator, DATE_OPERATORS);
138138
}
139139

140140
public valuesArray() {

packages/cubejs-schema-compiler/src/adapter/BaseMeasure.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,32 +206,32 @@ export class BaseMeasure {
206206
return this.measureDefinition();
207207
}
208208

209-
public aliasName() {
209+
public aliasName(): string {
210210
return this.query.escapeColumnName(this.unescapedAliasName());
211211
}
212212

213-
public unescapedAliasName() {
213+
public unescapedAliasName(): string {
214214
if (this.expression) {
215215
return this.query.aliasName(this.expressionName);
216216
}
217217
return this.query.aliasName(this.measure);
218218
}
219219

220-
public isCumulative() {
220+
public isCumulative(): boolean {
221221
if (this.expression) { // TODO
222222
return false;
223223
}
224224
return BaseMeasure.isCumulative(this.measureDefinition());
225225
}
226226

227-
public isMultiStage() {
227+
public isMultiStage(): boolean {
228228
if (this.expression) { // TODO
229229
return false;
230230
}
231231
return this.definition().multiStage;
232232
}
233233

234-
public isAdditive() {
234+
public isAdditive(): boolean {
235235
if (this.expression) { // TODO
236236
return false;
237237
}
@@ -243,7 +243,7 @@ export class BaseMeasure {
243243
definition.type === 'min' || definition.type === 'max';
244244
}
245245

246-
public static isCumulative(definition) {
246+
public static isCumulative(definition): boolean {
247247
return definition.type === 'runningTotal' || !!definition.rollingWindow;
248248
}
249249

@@ -294,7 +294,7 @@ export class BaseMeasure {
294294
return this.query.minGranularity(granularityA, granularityB);
295295
}
296296

297-
public granularityFromInterval(interval: string) {
297+
public granularityFromInterval(interval: string): string | undefined {
298298
if (!interval) {
299299
return undefined;
300300
}
@@ -312,25 +312,31 @@ export class BaseMeasure {
312312
return undefined;
313313
}
314314

315-
public shouldUngroupForCumulative() {
315+
public shouldUngroupForCumulative(): boolean {
316316
return this.measureDefinition().rollingWindow && !this.isAdditive();
317317
}
318318

319319
public sqlDefinition() {
320320
return this.measureDefinition().sql;
321321
}
322322

323-
public path() {
323+
public path(): string[] | null {
324324
if (this.expression) {
325325
return null;
326326
}
327327
return this.query.cubeEvaluator.parsePath('measures', this.measure);
328328
}
329329

330-
public expressionPath() {
330+
public expressionPath(): string {
331331
if (this.expression) {
332332
return `expr:${this.expression.expressionName}`;
333333
}
334-
return this.query.cubeEvaluator.pathFromArray(this.path() as string[]);
334+
335+
const path = this.path();
336+
if (path === null) {
337+
// Sanity check, this should not actually happen because we checked this.expression earlier
338+
throw new Error('Unexpected null path');
339+
}
340+
return this.query.cubeEvaluator.pathFromArray(path);
335341
}
336342
}

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ export class BaseQuery {
130130
/** @type {import('./BaseTimeDimension').BaseTimeDimension[]} */
131131
timeDimensions;
132132

133+
/**
134+
* @type {import('../compiler/JoinGraph').FinishedJoinTree}
135+
*/
136+
join;
137+
133138
/**
134139
* BaseQuery class constructor.
135140
* @param {Compilers|*} compilers
@@ -2166,6 +2171,12 @@ export class BaseQuery {
21662171
));
21672172
}
21682173

2174+
/**
2175+
*
2176+
* @param {string} cube
2177+
* @param {boolean} [isLeftJoinCondition]
2178+
* @returns {[string, string, string?]}
2179+
*/
21692180
rewriteInlineCubeSql(cube, isLeftJoinCondition) {
21702181
const sql = this.cubeSql(cube);
21712182
const cubeAlias = this.cubeAlias(cube);
@@ -2188,9 +2199,14 @@ export class BaseQuery {
21882199
}
21892200
}
21902201

2202+
/**
2203+
* @param {import('../compiler/JoinGraph').FinishedJoinTree} join
2204+
* @param {Array<string>} subQueryDimensions
2205+
* @returns {string}
2206+
*/
21912207
joinQuery(join, subQueryDimensions) {
21922208
const subQueryDimensionsByCube = R.groupBy(d => this.cubeEvaluator.cubeNameFromPath(d), subQueryDimensions);
2193-
const joins = join.joins.map(
2209+
const joins = join.joins.flatMap(
21942210
j => {
21952211
const [cubeSql, cubeAlias, conditions] = this.rewriteInlineCubeSql(j.originalTo, true);
21962212
return [{
@@ -2200,7 +2216,7 @@ export class BaseQuery {
22002216
// TODO handle the case when sub query referenced by a foreign cube on other side of a join
22012217
}].concat((subQueryDimensionsByCube[j.originalTo] || []).map(d => this.subQueryJoin(d)));
22022218
}
2203-
).reduce((a, b) => a.concat(b), []);
2219+
);
22042220

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

@@ -2212,6 +2228,10 @@ export class BaseQuery {
22122228
]);
22132229
}
22142230

2231+
/**
2232+
* @param {JoinChain} toJoin
2233+
* @returns {string}
2234+
*/
22152235
joinSql(toJoin) {
22162236
const [root, ...rest] = toJoin;
22172237
const joins = rest.map(
@@ -2273,6 +2293,11 @@ export class BaseQuery {
22732293
return this.filtersWithoutSubQueriesValue;
22742294
}
22752295

2296+
/**
2297+
*
2298+
* @param {string} dimension
2299+
* @returns {{ prefix: string, subQuery: this, cubeName: string }}
2300+
*/
22762301
subQueryDescription(dimension) {
22772302
const symbol = this.cubeEvaluator.dimensionByPath(dimension);
22782303
const [cubeName, name] = this.cubeEvaluator.parsePath('dimensions', dimension);
@@ -2317,6 +2342,12 @@ export class BaseQuery {
23172342
return { prefix, subQuery, cubeName };
23182343
}
23192344

2345+
/**
2346+
*
2347+
* @param {string} cubeName
2348+
* @param {string} name
2349+
* @returns {string}
2350+
*/
23202351
subQueryName(cubeName, name) {
23212352
return `${cubeName}_${name}_subquery`;
23222353
}
@@ -2520,6 +2551,9 @@ export class BaseQuery {
25202551
);
25212552
}
25222553

2554+
/**
2555+
* @param {string} cube
2556+
*/
25232557
cubeSql(cube) {
25242558
const foundPreAggregation = this.preAggregations.findPreAggregationToUseForCube(cube);
25252559
if (foundPreAggregation &&
@@ -2630,6 +2664,13 @@ export class BaseQuery {
26302664
];
26312665
}
26322666

2667+
/**
2668+
* @template T
2669+
* @param {boolean} excludeTimeDimensions
2670+
* @param {(t: () => void) => T} fn
2671+
* @param {string | Array<string>} methodName
2672+
* @returns {T}
2673+
*/
26332674
collectFromMembers(excludeTimeDimensions, fn, methodName) {
26342675
const membersToCollectFrom = this.allMembersConcat(excludeTimeDimensions)
26352676
.concat(this.join ? this.join.joins.map(j => ({
@@ -2656,6 +2697,14 @@ export class BaseQuery {
26562697
.concat(excludeTimeDimensions ? [] : this.timeDimensions);
26572698
}
26582699

2700+
/**
2701+
* @template T
2702+
* @param {Array<unknown>} membersToCollectFrom
2703+
* @param {(t: () => void) => T} fn
2704+
* @param {string | Array<string>} methodName
2705+
* @param {unknown} [cache]
2706+
* @returns {T}
2707+
*/
26592708
collectFrom(membersToCollectFrom, fn, methodName, cache) {
26602709
const methodCacheKey = Array.isArray(methodName) ? methodName : [methodName];
26612710
return R.pipe(
@@ -2677,6 +2726,11 @@ export class BaseQuery {
26772726
);
26782727
}
26792728

2729+
/**
2730+
*
2731+
* @param {() => void} fn
2732+
* @returns {Array<string>}
2733+
*/
26802734
collectSubQueryDimensionsFor(fn) {
26812735
const context = { subQueryDimensions: [] };
26822736
this.evaluateSymbolSqlWithContext(
@@ -3239,6 +3293,11 @@ export class BaseQuery {
32393293
return strings.join(' || ');
32403294
}
32413295

3296+
/**
3297+
*
3298+
* @param {string} cubeName
3299+
* @returns {Array<string>}
3300+
*/
32423301
primaryKeyNames(cubeName) {
32433302
const primaryKeys = this.cubeEvaluator.primaryKeys[cubeName];
32443303
if (!primaryKeys || !primaryKeys.length) {
@@ -3374,6 +3433,12 @@ export class BaseQuery {
33743433
)(context.leafMeasures);
33753434
}
33763435

3436+
/**
3437+
* @template T
3438+
* @param {() => T} fn
3439+
* @param {unknown} context
3440+
* @returns {T}
3441+
*/
33773442
evaluateSymbolSqlWithContext(fn, context) {
33783443
const oldContext = this.evaluateSymbolContext;
33793444
this.evaluateSymbolContext = oldContext ? Object.assign({}, oldContext, context) : context;
@@ -3596,6 +3661,11 @@ export class BaseQuery {
35963661
.map(s => `(${s})`).join(' AND ');
35973662
}
35983663

3664+
/**
3665+
* @param {string} primaryKeyName
3666+
* @param {string} cubeName
3667+
* @returns {unknown}
3668+
*/
35993669
primaryKeySql(primaryKeyName, cubeName) {
36003670
const primaryKeyDimension = this.cubeEvaluator.dimensionByPath([cubeName, primaryKeyName]);
36013671
return this.evaluateSymbolSql(
@@ -3745,7 +3815,7 @@ export class BaseQuery {
37453815
/**
37463816
*
37473817
* @param options
3748-
* @returns {BaseQuery}
3818+
* @returns {this}
37493819
*/
37503820
newSubQuery(options) {
37513821
const QueryClass = this.constructor;

packages/cubejs-schema-compiler/src/adapter/BaseSegment.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,23 @@ export class BaseSegment {
8181
return this.segmentDefinition().sql;
8282
}
8383

84-
public path() {
84+
public path(): string[] | null {
8585
if (this.expression) {
8686
return null;
8787
}
8888
return this.query.cubeEvaluator.parsePath('segments', this.segment);
8989
}
9090

91-
public expressionPath() {
91+
public expressionPath(): string {
9292
if (this.expression) {
9393
return `expr:${this.expression.expressionName}`;
9494
}
95-
return this.query.cubeEvaluator.pathFromArray(this.path() as string[]);
95+
96+
const path = this.path();
97+
if (path === null) {
98+
// Sanity check, this should not actually happen because we checked this.expression earlier
99+
throw new Error('Unexpected null path');
100+
}
101+
return this.query.cubeEvaluator.pathFromArray(path);
96102
}
97103
}

0 commit comments

Comments
 (0)