Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
06392cc
feat(tesseract): Switch dimensions and case measures
waralexrom Sep 4, 2025
1d8adb0
in work
waralexrom Sep 4, 2025
ce13c9e
case expression
waralexrom Sep 5, 2025
0f4f0c9
measure switch
waralexrom Sep 5, 2025
4d5cf6b
lint
waralexrom Sep 5, 2025
40cb7fd
optimization
waralexrom Sep 5, 2025
b00147f
fix
waralexrom Sep 5, 2025
628fcf4
fix
waralexrom Sep 8, 2025
11d516d
in work
waralexrom Sep 8, 2025
507f024
almost work
waralexrom Sep 8, 2025
1d0f710
in work
waralexrom Sep 9, 2025
209378a
fix
waralexrom Sep 10, 2025
ed22c12
fix
waralexrom Sep 10, 2025
b2693c6
in work
waralexrom Sep 10, 2025
b7b3d5a
in work
waralexrom Sep 10, 2025
a6aa0f8
in work
waralexrom Sep 10, 2025
7811491
builder for logical plan nodes
waralexrom Sep 11, 2025
9badb62
in work
waralexrom Sep 12, 2025
c866f63
render references refactor
waralexrom Sep 12, 2025
bb0b3d0
in work
waralexrom Sep 12, 2025
ad30cdb
in work
waralexrom Sep 12, 2025
14d790b
recursive static filter
waralexrom Sep 12, 2025
652a4e0
fix
waralexrom Sep 12, 2025
e57ffd0
in work
waralexrom Sep 13, 2025
3a83fb9
in work
waralexrom Sep 13, 2025
d2f054f
in work
waralexrom Sep 14, 2025
6cfbba6
in work
waralexrom Sep 14, 2025
f773fca
in work
waralexrom Sep 14, 2025
8ce7e23
in work
waralexrom Sep 14, 2025
a75f192
in work
waralexrom Sep 15, 2025
e756dea
in work
waralexrom Sep 16, 2025
526d5f9
lint
waralexrom Sep 16, 2025
fe8aed2
lint
waralexrom Sep 16, 2025
d16eb5a
fix
waralexrom Sep 16, 2025
2d7f20a
tests
waralexrom Sep 16, 2025
639264a
tests
waralexrom Sep 16, 2025
30662f4
tests
waralexrom Sep 16, 2025
206e813
tests
waralexrom Sep 16, 2025
9f7b54e
tests
waralexrom Sep 17, 2025
d502b99
fixes
waralexrom Sep 17, 2025
b196a32
fix
waralexrom Sep 17, 2025
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
21 changes: 21 additions & 0 deletions packages/cubejs-backend-native/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3232,6 +3232,9 @@ export class BaseQuery {
}
if (symbol.case) {
return this.renderDimensionCase(symbol, cubeName);
} else if (symbol.type === 'switch') {
// Dimension of type switch is not supported in BaseQuery, return an empty string to make dependency resolution work.
return '';
} else if (symbol.type === 'geo') {
return this.concatStringsSql([
this.autoPrefixAndEvaluateSql(cubeName, symbol.latitude.sql, isMemberExpr),
Expand Down Expand Up @@ -4210,7 +4213,17 @@ export class BaseQuery {
time_series_get_range: 'SELECT {{ max_expr }} as {{ quoted_max_name }},\n' +
'{{ min_expr }} as {{ quoted_min_name }}\n' +
'FROM {{ from_prepared }}\n' +
'{% if filter %}WHERE {{ filter }}{% endif %}'
'{% if filter %}WHERE {{ filter }}{% endif %}',
calc_groups_join: '{% if original_sql %}{{ original_sql }}\n{% endif %}' +
'{% for group in groups %}' +
'{% if original_sql or not loop.first %}CROSS JOIN\n{% endif %}' +
'(\n' +
'{% for value in group.values %}' +
'SELECT {{ value }} as {{ group.name }}' +
'{% if not loop.last %} UNION ALL\n{% endif %}' +
'{% endfor %}' +
') AS {{ group.alias }}\n' +
'{% endfor %}'
},
expressions: {
column_reference: '{% if table_name %}{{ table_name }}.{% endif %}{{ name }}',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,9 @@ export class CubeEvaluator extends CubeSymbols {
let aliasMember;

const member = members[memberName];
if (member.type === 'switch' || member.multiStage) {
ownedByCube = false;
}
if (member.sql && !member.subQuery) {
const funcArgs = this.funcArguments(member.sql);
const { cubeReferencesUsed, evaluatedSql, pathReferencesUsed } = this.collectUsedCubeReferences(cube.name, member.sql);
Expand Down
128 changes: 81 additions & 47 deletions packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ const BaseDimensionWithoutSubQuery = {
enableSuggestions: Joi.boolean().strict(),
format: formatSchema,
meta: Joi.any(),
values: Joi.when('type', {
is: 'switch',
then: Joi.array().items(Joi.string()),
otherwise: Joi.forbidden()
}),
granularities: Joi.when('type', {
is: 'time',
then: Joi.object().pattern(identifierRegex,
Expand Down Expand Up @@ -583,13 +588,50 @@ const timeShiftItemOptional = Joi.object({
.xor('name', 'interval')
.and('interval', 'type');

const CaseSchema = Joi.object().keys({
when: Joi.array().items(Joi.object().keys({
sql: Joi.func().required(),
label: Joi.alternatives([
Joi.string(),
Joi.object().keys({
sql: Joi.func().required()
})
])
})),
else: Joi.object().keys({
label: Joi.alternatives([
Joi.string(),
Joi.object().keys({
sql: Joi.func().required()
})
])
})
}).required();

const SwitchCaseSchema = Joi.object().keys({
switch: Joi.func().required(),
when: Joi.array().items(Joi.object().keys({
value: Joi.string().required(),
sql: Joi.func().required()
})),
else: Joi.object().keys({
sql: Joi.func().required()
})
}).required();

const CaseVariants = Joi.alternatives().try(
CaseSchema,
SwitchCaseSchema
);

const MeasuresSchema = Joi.object().pattern(identifierRegex, Joi.alternatives().conditional(Joi.ref('.multiStage'), [
{
is: true,
then: inherit(BaseMeasure, {
multiStage: Joi.boolean().strict(),
type: multiStageMeasureType.required(),
sql: Joi.func(), // TODO .required(),
case: CaseVariants,
groupBy: Joi.func(),
reduceBy: Joi.func(),
addGroupBy: Joi.func(),
Expand Down Expand Up @@ -647,53 +689,45 @@ const CalendarTimeShiftItem = Joi.alternatives().try(
})
);

const DimensionsSchema = Joi.object().pattern(identifierRegex, Joi.alternatives().try(
inherit(BaseDimensionWithoutSubQuery, {
case: Joi.object().keys({
when: Joi.array().items(Joi.object().keys({
sql: Joi.func().required(),
label: Joi.alternatives([
Joi.string(),
Joi.object().keys({
sql: Joi.func().required()
})
])
})),
else: Joi.object().keys({
label: Joi.alternatives([
Joi.string(),
Joi.object().keys({
sql: Joi.func().required()
})
])
})
}).required()
}),
inherit(BaseDimensionWithoutSubQuery, {
latitude: Joi.object().keys({
sql: Joi.func().required()
}).required(),
longitude: Joi.object().keys({
sql: Joi.func().required()
}).required()
}),
inherit(BaseDimension, {
sql: Joi.func().required(),
}),
inherit(BaseDimension, {
multiStage: Joi.boolean().valid(true),
type: Joi.any().valid('number').required(),
sql: Joi.func().required(),
addGroupBy: Joi.func(),
}),
// TODO should be valid only for calendar cubes, but this requires significant refactoring
// of all schemas. Left for the future when we'll switch to zod.
inherit(BaseDimensionWithoutSubQuery, {
type: Joi.any().valid('time').required(),
sql: Joi.func().required(),
timeShift: Joi.array().items(CalendarTimeShiftItem),
})
));
const SwitchDimension = Joi.object({
type: Joi.string().valid('switch').required(),
values: Joi.array().items(Joi.string()).min(1).required()
});

const DimensionsSchema = Joi.object().pattern(identifierRegex, Joi.alternatives().conditional(Joi.ref('.type'), {
is: 'switch',
then: SwitchDimension,
otherwise: Joi.alternatives().try(
inherit(BaseDimensionWithoutSubQuery, {
case: CaseVariants.required(),
multiStage: Joi.boolean().strict(),
}),
inherit(BaseDimensionWithoutSubQuery, {
latitude: Joi.object().keys({
sql: Joi.func().required()
}).required(),
longitude: Joi.object().keys({
sql: Joi.func().required()
}).required()
}),
inherit(BaseDimension, {
sql: Joi.func().required(),
}),
inherit(BaseDimension, {
multiStage: Joi.boolean().valid(true),
type: Joi.any().valid('number').required(),
sql: Joi.func().required(),
addGroupBy: Joi.func(),
}),
// TODO should be valid only for calendar cubes, but this requires significant refactoring
// of all schemas. Left for the future when we'll switch to zod.
inherit(BaseDimensionWithoutSubQuery, {
type: Joi.any().valid('time').required(),
sql: Joi.func().required(),
timeShift: Joi.array().items(CalendarTimeShiftItem),
})
)
}));

const SegmentsSchema = Joi.object().pattern(identifierRegex, Joi.object().keys({
aliases: Joi.array().items(Joi.string()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const transpiledFieldsPatterns: Array<RegExp> = [
/^measures\.[_a-zA-Z][_a-zA-Z0-9]*\.(orderBy|order_by)\.[0-9]+\.sql$/,
/^measures\.[_a-zA-Z][_a-zA-Z0-9]*\.(timeShift|time_shift)\.[0-9]+\.(timeDimension|time_dimension)$/,
/^measures\.[_a-zA-Z][_a-zA-Z0-9]*\.(reduceBy|reduce_by|groupBy|group_by|addGroupBy|add_group_by)$/,
/^(measures|dimensions)\.[_a-zA-Z][_a-zA-Z0-9]*\.case\.switch$/,
/^dimensions\.[_a-zA-Z][_a-zA-Z0-9]*\.(reduceBy|reduce_by|groupBy|group_by|addGroupBy|add_group_by)$/,
/^(preAggregations|pre_aggregations)\.[_a-zA-Z][_a-zA-Z0-9]*\.indexes\.[_a-zA-Z][_a-zA-Z0-9]*\.columns$/,
/^(preAggregations|pre_aggregations)\.[_a-zA-Z][_a-zA-Z0-9]*\.(timeDimensionReference|timeDimension|time_dimension|segments|dimensions|measures|rollups|segmentReferences|dimensionReferences|measureReferences|rollupReferences)$/,
Expand Down
Loading
Loading