Skip to content

Commit 54880a4

Browse files
committed
feat(tesseract): Allow named calendar timeshifts for common intervals
1 parent 849591f commit 54880a4

File tree

3 files changed

+30
-13
lines changed

3 files changed

+30
-13
lines changed

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -626,15 +626,26 @@ const MeasuresSchema = Joi.object().pattern(identifierRegex, Joi.alternatives().
626626
]
627627
));
628628

629-
const CalendarTimeShiftItem = Joi.object({
630-
name: identifier,
631-
interval: regexTimeInterval,
632-
type: Joi.string().valid('next', 'prior'),
633-
sql: Joi.func().required(),
634-
})
635-
.or('name', 'interval')
636-
.with('interval', 'type')
637-
.with('type', 'interval');
629+
const CalendarTimeShiftItem = Joi.alternatives().try(
630+
Joi.object({
631+
name: identifier.required(),
632+
interval: regexTimeInterval.required(),
633+
type: Joi.string().valid('next', 'prior').required(),
634+
sql: Joi.forbidden()
635+
}),
636+
Joi.object({
637+
name: identifier.required(),
638+
sql: Joi.func().required(),
639+
interval: Joi.forbidden(),
640+
type: Joi.forbidden()
641+
}),
642+
Joi.object({
643+
interval: regexTimeInterval.required(),
644+
type: Joi.string().valid('next', 'prior').required(),
645+
sql: Joi.func().required(),
646+
name: Joi.forbidden()
647+
})
648+
);
638649

639650
const DimensionsSchema = Joi.object().pattern(identifierRegex, Joi.alternatives().try(
640651
inherit(BaseDimensionWithoutSubQuery, {

rust/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/builder.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ impl PhysicalPlanBuilderContext {
3838

3939
for (key, shift) in self.time_shifts.dimensions_shifts.iter() {
4040
if let Ok(dimension) = shift.dimension.as_dimension() {
41+
// 1. Shift might be referenced by name or by interval
42+
// 2. Shift body might be defined in calendar dimension as:
43+
// * sql reference
44+
// * interval + type
45+
4146
if let Some(dim_shift_name) = &shift.name {
4247
if let Some((dim_key, cts)) =
4348
dimension.calendar_time_shift_for_named_interval(dim_shift_name)
4449
{
4550
calendar_time_shifts.insert(dim_key.clone(), cts.clone());
46-
continue;
4751
} else if let Some(_calendar_pk) = dimension.time_shift_pk_full_name() {
4852
return Err(CubeError::internal(format!(
4953
"Time shift with name {} not found for dimension {}",
@@ -56,16 +60,15 @@ impl PhysicalPlanBuilderContext {
5660
dimension.calendar_time_shift_for_interval(dim_shift_interval)
5761
{
5862
calendar_time_shifts.insert(dim_key.clone(), cts.clone());
59-
continue;
6063
} else if let Some(calendar_pk) = dimension.time_shift_pk_full_name() {
6164
let mut shift = shift.clone();
6265
shift.interval = Some(dim_shift_interval.inverse());
6366
time_shifts.insert(calendar_pk, shift.clone());
64-
continue;
6567
}
6668
}
69+
} else {
70+
time_shifts.insert(key.clone(), shift.clone());
6771
}
68-
time_shifts.insert(key.clone(), shift.clone());
6972
}
7073

7174
let common_time_shifts = TimeShiftState {

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_nodes/calendar_time_shift.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ impl SqlNode for CalendarTimeShiftSqlNode {
5454
query_tools.clone(),
5555
templates,
5656
)?
57+
} else if let Some (interval) = &shift.interval {
58+
let res = templates.add_timestamp_interval(input, interval.inverse().to_sql())?;
59+
format!("({})", res)
5760
} else {
5861
input
5962
}

0 commit comments

Comments
 (0)