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
1 change: 0 additions & 1 deletion packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3665,7 +3665,6 @@ export class BaseQuery {
* @param {import('./Granularity').Granularity} granularity
* @return {string}
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
dimensionTimeGroupedColumn(dimension, granularity) {
let dtDate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ describe('SQL Generation', () => {
granularity: 'week'
}
},
countRollingThreeDaysToDate: {
type: 'count',
rollingWindow: {
type: 'to_date',
granularity: 'three_days'
}
},
revenue_qtd: {
type: 'sum',
sql: 'amount',
Expand Down Expand Up @@ -1210,6 +1217,149 @@ SELECT 1 AS revenue, cast('2024-01-01' AS timestamp) as time UNION ALL
}
]));

if (getEnv('nativeSqlPlanner')) {
it('custom granularity rolling window to_date with one time dimension with regular granularity', async () => runQueryTest({
measures: [
'visitors.countRollingThreeDaysToDate'
],
timeDimensions: [
{
dimension: 'visitors.created_at',
granularity: 'day',
dateRange: ['2017-01-01', '2017-01-10']
}
],
order: [{
id: 'visitors.created_at'
}],
timezone: 'America/Los_Angeles'
}, [
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-01T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '1',
visitors__created_at_day: '2017-01-02T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '1',
visitors__created_at_day: '2017-01-03T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '1',
visitors__created_at_day: '2017-01-04T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '2',
visitors__created_at_day: '2017-01-05T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '4',
visitors__created_at_day: '2017-01-06T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-07T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-08T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-09T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-10T00:00:00.000Z',
},
]));
} else {
it.skip('NO_BASE_QUERY_SUPPORT: custom granularity rolling window to_date with one time dimension with regular granularity', () => {
// Skipping because it works only in Tesseract
});
}

if (getEnv('nativeSqlPlanner')) {
it('custom granularity rolling window to_date with two time dimension granularities one custom one regular', async () => runQueryTest({
measures: [
'visitors.countRollingThreeDaysToDate'
],
timeDimensions: [
{
dimension: 'visitors.created_at',
granularity: 'three_days',
dateRange: ['2017-01-01', '2017-01-10']
},
{
dimension: 'visitors.created_at',
granularity: 'day',
dateRange: ['2017-01-01', '2017-01-10']
}
],
order: [{
id: 'visitors.created_at'
}],
timezone: 'America/Los_Angeles'
}, [
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-01T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-01T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '1',
visitors__created_at_day: '2017-01-02T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-01T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '1',
visitors__created_at_day: '2017-01-03T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-01T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '1',
visitors__created_at_day: '2017-01-04T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-04T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '2',
visitors__created_at_day: '2017-01-05T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-04T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: '4',
visitors__created_at_day: '2017-01-06T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-04T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-07T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-07T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-08T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-07T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-09T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-07T00:00:00.000Z',
},
{
visitors__count_rolling_three_days_to_date: null,
visitors__created_at_day: '2017-01-10T00:00:00.000Z',
visitors__created_at_three_days: '2017-01-10T00:00:00.000Z',
},
]));
} else {
it.skip('NO_BASE_QUERY_SUPPORT: custom granularity rolling window to_date with two time dimension granularities one custom one regular', () => {
// Skipping because it works only in Tesseract
});
}

it('rolling window with same td with and without granularity', async () => runQueryTest({
measures: [
'visitors.countRollingWeekToDate'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::logical_plan::*;
use crate::planner::query_properties::OrderByItem;
use crate::planner::sql_evaluator::MemberSymbol;
use crate::planner::Granularity;
use std::rc::Rc;

pub struct MultiStageRegularRollingWindow {
Expand All @@ -24,14 +25,17 @@ impl PrettyPrint for MultiStageRegularRollingWindow {
}

pub struct MultiStageToDateRollingWindow {
pub granularity: String,
pub granularity_obj: Rc<Granularity>,
}

impl PrettyPrint for MultiStageToDateRollingWindow {
fn pretty_print(&self, result: &mut PrettyPrintResult, state: &PrettyPrintState) {
result.println("ToDate Rolling Window", state);
let state = state.new_level();
result.println(&format!("granularity: {}", self.granularity), &state);
result.println(
&format!("granularity: {}", self.granularity_obj.granularity()),
&state,
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,7 @@ impl PhysicalPlanBuilder {
MultiStageRollingWindowType::ToDate(to_date_rolling_window) => {
JoinCondition::new_to_date_rolling_join(
root_alias.clone(),
to_date_rolling_window.granularity.clone(),
to_date_rolling_window.granularity_obj.clone(),
Expr::Reference(QualifiedColumnName::new(
Some(measure_input_alias.clone()),
base_time_dimension_alias,
Expand Down Expand Up @@ -1092,7 +1092,7 @@ impl PhysicalPlanBuilder {
let mut render_references = HashMap::new();
let mut select_builder = SelectBuilder::new(from.clone());

//We insert render reference for main time dimension (with the some granularity as in time series to avoid unnecessary date_tranc)
//We insert render reference for main time dimension (with some granularity as in time series to avoid unnecessary date_tranc)
render_references.insert(
time_dimension.full_name(),
QualifiedColumnName::new(Some(root_alias.clone()), format!("date_from")),
Expand Down
10 changes: 5 additions & 5 deletions rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{Expr, SingleAliasedSource};
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::{BaseJoinCondition, VisitorContext};
use crate::planner::{BaseJoinCondition, Granularity, VisitorContext};
use cubenativeutils::CubeError;
use lazy_static::lazy_static;

Expand Down Expand Up @@ -118,15 +118,15 @@ impl RollingTotalJoinCondition {
}
pub struct ToDateRollingWindowJoinCondition {
time_series_source: String,
granularity: String,
granularity: Rc<Granularity>,
time_dimension: Expr,
_query_tools: Rc<QueryTools>,
}

impl ToDateRollingWindowJoinCondition {
pub fn new(
time_series_source: String,
granularity: String,
granularity: Rc<Granularity>,
time_dimension: Expr,
query_tools: Rc<QueryTools>,
) -> Self {
Expand All @@ -151,7 +151,7 @@ impl ToDateRollingWindowJoinCondition {
templates.column_reference(&Some(self.time_series_source.clone()), "date_from")?;
let date_from = templates.rolling_window_expr_timestamp_cast(&date_from)?;
let date_to = templates.rolling_window_expr_timestamp_cast(&date_to)?;
let grouped_from = templates.time_grouped_column(self.granularity.clone(), date_from)?;
let grouped_from = self.granularity.apply_to_input_sql(templates, date_from)?;
let result = format!("{date_column} >= {grouped_from} and {date_column} <= {date_to}");
Ok(result)
}
Expand Down Expand Up @@ -243,7 +243,7 @@ impl JoinCondition {

pub fn new_to_date_rolling_join(
time_series_source: String,
granularity: String,
granularity: Rc<Granularity>,
time_dimension: Expr,
query_tools: Rc<QueryTools>,
) -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::MemberSymbol;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::sql_templates::TemplateProjectionColumn;
use crate::planner::QueryDateTimeHelper;
use crate::planner::{evaluate_with_context, FiltersContext, VisitorContext};
use crate::planner::{Granularity, GranularityHelper, QueryDateTimeHelper};
use cubenativeutils::CubeError;
use std::rc::Rc;

Expand Down Expand Up @@ -188,13 +188,47 @@ impl BaseFilter {
filters_context,
&member_type,
)?,
FilterOperator::ToDateRollingWindowDateRange => self
.to_date_rolling_window_date_range(
FilterOperator::ToDateRollingWindowDateRange => {
let query_granularity = if self.values.len() >= 3 {
if let Some(granularity) = &self.values[2] {
granularity
} else {
return Err(CubeError::user(
"Granularity required for to_date rolling window".to_string(),
));
}
} else {
return Err(CubeError::user(
"Granularity required for to_date rolling window".to_string(),
));
};
let evaluator_compiler_cell = self.query_tools.evaluator_compiler().clone();
let mut evaluator_compiler = evaluator_compiler_cell.borrow_mut();

let Some(granularity_obj) = GranularityHelper::make_granularity_obj(
self.query_tools.cube_evaluator().clone(),
&mut evaluator_compiler,
self.query_tools.timezone().clone(),
&symbol.cube_name(),
&symbol.name(),
Some(query_granularity.clone()),
)?
else {
return Err(CubeError::internal(format!(
"Rolling window granularity '{}' is not found in time dimension '{}'",
query_granularity,
symbol.name()
)));
};

self.to_date_rolling_window_date_range(
&member_sql,
plan_templates,
filters_context,
&member_type,
)?,
granularity_obj,
)?
}
FilterOperator::In => {
self.in_where(&member_sql, plan_templates, filters_context, &member_type)?
}
Expand Down Expand Up @@ -539,22 +573,11 @@ impl BaseFilter {
plan_templates: &PlanSqlTemplates,
_filters_context: &FiltersContext,
_member_type: &Option<String>,
granularity_obj: Granularity,
) -> Result<String, CubeError> {
let (from, to) = self.date_range_from_time_series(plan_templates)?;

let from = if self.values.len() >= 3 {
if let Some(granularity) = &self.values[2] {
plan_templates.time_grouped_column(granularity.clone(), from)?
} else {
return Err(CubeError::user(format!(
"Granularity required for to_date rolling window"
)));
}
} else {
return Err(CubeError::user(format!(
"Granularity required for to_date rolling window"
)));
};
let from = granularity_obj.apply_to_input_sql(plan_templates, from.clone())?;

let date_field = plan_templates.convert_tz(member_sql.to_string())?;
plan_templates.time_range_filter(date_field, from, to)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::logical_plan::*;
use crate::planner::planners::{multi_stage::RollingWindowType, QueryPlanner, SimpleQueryPlanner};
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::MemberSymbol;
use crate::planner::{BaseDimension, BaseMeasure, BaseMember, BaseMemberHelper, BaseTimeDimension};
use crate::planner::{
BaseDimension, BaseMeasure, BaseMember, BaseMemberHelper, BaseTimeDimension, GranularityHelper,
};
use crate::planner::{OrderByItem, QueryProperties};

use cubenativeutils::CubeError;
Expand Down Expand Up @@ -126,8 +128,30 @@ impl MultiStageMemberQueryPlanner {
})
}
RollingWindowType::ToDate(to_date_rolling_window) => {
let time_dimension = &rolling_window_desc.time_dimension;
let query_granularity = to_date_rolling_window.granularity.clone();

let evaluator_compiler_cell = self.query_tools.evaluator_compiler().clone();
let mut evaluator_compiler = evaluator_compiler_cell.borrow_mut();

let Some(granularity_obj) = GranularityHelper::make_granularity_obj(
self.query_tools.cube_evaluator().clone(),
&mut evaluator_compiler,
self.query_tools.timezone().clone(),
time_dimension.cube_name(),
time_dimension.name(),
Some(query_granularity.clone()),
)?
else {
return Err(CubeError::internal(format!(
"Rolling window granularity '{}' is not found in time dimension '{}'",
query_granularity,
time_dimension.name()
)));
};

MultiStageRollingWindowType::ToDate(MultiStageToDateRollingWindow {
granularity: to_date_rolling_window.granularity.clone(),
granularity_obj: Rc::new(granularity_obj),
})
}
RollingWindowType::RunningTotal => MultiStageRollingWindowType::RunningTotal,
Expand Down
Loading
Loading