Skip to content

Commit 427e846

Browse files
committed
feat(cubesql): Support filtering date within one granularity unit
1 parent 6017a4b commit 427e846

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed

rust/cubesql/cubesql/src/compile/mod.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11084,4 +11084,91 @@ ORDER BY \"COUNT(count)\" DESC"
1108411084
}
1108511085
)
1108611086
}
11087+
11088+
#[tokio::test]
11089+
async fn test_quicksight_date_trunc_equals() {
11090+
init_logger();
11091+
11092+
let base_date = "2022-08-27 19:43:09";
11093+
let granularities = vec![
11094+
(
11095+
"second",
11096+
"2022-08-27T19:43:09.000Z",
11097+
"2022-08-27T19:43:09.999Z",
11098+
),
11099+
(
11100+
"minute",
11101+
"2022-08-27T19:43:00.000Z",
11102+
"2022-08-27T19:43:59.999Z",
11103+
),
11104+
(
11105+
"hour",
11106+
"2022-08-27T19:00:00.000Z",
11107+
"2022-08-27T19:59:59.999Z",
11108+
),
11109+
(
11110+
"day",
11111+
"2022-08-27T00:00:00.000Z",
11112+
"2022-08-27T23:59:59.999Z",
11113+
),
11114+
(
11115+
"week",
11116+
"2022-08-22T00:00:00.000Z",
11117+
"2022-08-28T23:59:59.999Z",
11118+
),
11119+
(
11120+
"month",
11121+
"2022-08-01T00:00:00.000Z",
11122+
"2022-08-31T23:59:59.999Z",
11123+
),
11124+
(
11125+
"quarter",
11126+
"2022-07-01T00:00:00.000Z",
11127+
"2022-09-30T23:59:59.999Z",
11128+
),
11129+
(
11130+
"year",
11131+
"2022-01-01T00:00:00.000Z",
11132+
"2022-12-31T23:59:59.999Z",
11133+
),
11134+
];
11135+
11136+
for (granularity, date_min, date_max) in granularities {
11137+
let sql = format!(
11138+
r#"
11139+
SELECT date_trunc('{}', "order_date") AS "uuid.order_date_tg", COUNT(*) AS "count"
11140+
FROM "public"."KibanaSampleDataEcommerce"
11141+
WHERE date_trunc('{}', "order_date") = date_trunc('{}', TO_TIMESTAMP('{}', 'yyyy-MM-dd HH24:mi:ss'))
11142+
GROUP BY date_trunc('{}', "order_date")
11143+
ORDER BY date_trunc('{}', "order_date") DESC NULLS LAST
11144+
LIMIT 2500;
11145+
"#,
11146+
granularity, granularity, granularity, base_date, granularity, granularity,
11147+
);
11148+
let logical_plan = convert_select_to_query_plan(sql, DatabaseProtocol::PostgreSQL)
11149+
.await
11150+
.as_logical_plan();
11151+
11152+
assert_eq!(
11153+
logical_plan.find_cube_scan().request,
11154+
V1LoadRequestQuery {
11155+
measures: Some(vec!["KibanaSampleDataEcommerce.count".to_string(),]),
11156+
dimensions: Some(vec![]),
11157+
segments: Some(vec![]),
11158+
time_dimensions: Some(vec![V1LoadRequestQueryTimeDimension {
11159+
dimension: "KibanaSampleDataEcommerce.order_date".to_string(),
11160+
granularity: Some(granularity.to_string()),
11161+
date_range: Some(json!(vec![date_min.to_string(), date_max.to_string()]))
11162+
}]),
11163+
order: Some(vec![vec![
11164+
"KibanaSampleDataEcommerce.order_date".to_string(),
11165+
"desc".to_string()
11166+
]]),
11167+
limit: Some(2500),
11168+
offset: None,
11169+
filters: None,
11170+
}
11171+
)
11172+
}
11173+
}
1108711174
}

rust/cubesql/cubesql/src/compile/rewrite/rules/filters.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,52 @@ impl RewriteRules for FilterRules {
543543
"?members",
544544
),
545545
),
546+
transforming_rewrite(
547+
"filter-replacer-date-trunc-equals",
548+
filter_replacer(
549+
binary_expr(
550+
fun_expr(
551+
"DateTrunc",
552+
vec![literal_expr("?granularity"), column_expr("?column")],
553+
),
554+
"=",
555+
fun_expr(
556+
"DateTrunc",
557+
vec![literal_expr("?granularity"), literal_expr("?date")],
558+
),
559+
),
560+
"?alias_to_cube",
561+
"?members",
562+
),
563+
filter_replacer(
564+
binary_expr(
565+
binary_expr(
566+
column_expr("?column"),
567+
">=",
568+
fun_expr(
569+
"DateTrunc",
570+
vec![literal_expr("?granularity"), literal_expr("?date")],
571+
),
572+
),
573+
"AND",
574+
binary_expr(
575+
column_expr("?column"),
576+
"<",
577+
binary_expr(
578+
fun_expr(
579+
"DateTrunc",
580+
vec![literal_expr("?granularity"), literal_expr("?date")],
581+
),
582+
"+",
583+
literal_expr("?interval"),
584+
),
585+
),
586+
),
587+
"?alias_to_cube",
588+
"?members",
589+
),
590+
self.transform_date_trunc_equals("?granularity", "?interval"),
591+
),
546592
// TODO define zero
547593
rewrite(
548594
"filter-str-pos-to-like",
@@ -1691,6 +1737,43 @@ impl FilterRules {
16911737
}
16921738
}
16931739

1740+
fn transform_date_trunc_equals(
1741+
&self,
1742+
granularity_var: &'static str,
1743+
interval_var: &'static str,
1744+
) -> impl Fn(&mut EGraph<LogicalPlanLanguage, LogicalPlanAnalysis>, &mut Subst) -> bool {
1745+
let granularity_var = var!(granularity_var);
1746+
let interval_var = var!(interval_var);
1747+
move |egraph, subst| {
1748+
for granularity in var_iter!(egraph[subst[granularity_var]], LiteralExprValue) {
1749+
if let ScalarValue::Utf8(Some(granularity)) = granularity {
1750+
let interval = match granularity.as_str() {
1751+
"second" => ScalarValue::IntervalDayTime(Some(1000)),
1752+
"minute" => ScalarValue::IntervalDayTime(Some(60000)),
1753+
"hour" => ScalarValue::IntervalDayTime(Some(3600000)),
1754+
"day" => ScalarValue::IntervalDayTime(Some(4294967296)),
1755+
"week" => ScalarValue::IntervalDayTime(Some(30064771072)),
1756+
"month" => ScalarValue::IntervalYearMonth(Some(1)),
1757+
"quarter" => ScalarValue::IntervalYearMonth(Some(3)),
1758+
"year" => ScalarValue::IntervalYearMonth(Some(12)),
1759+
_ => continue,
1760+
};
1761+
1762+
subst.insert(
1763+
interval_var,
1764+
egraph.add(LogicalPlanLanguage::LiteralExprValue(LiteralExprValue(
1765+
interval,
1766+
))),
1767+
);
1768+
1769+
return true;
1770+
}
1771+
}
1772+
1773+
false
1774+
}
1775+
}
1776+
16941777
fn merge_date_range(
16951778
&self,
16961779
date_range_start_var: &'static str,

0 commit comments

Comments
 (0)