Skip to content

Commit 4b6cb93

Browse files
committed
chore(tesseract): Fix issue with FILTER_PARAMS and issue with multi-stage behavior of not multi-stage members
1 parent 0dbf3bb commit 4b6cb93

File tree

17 files changed

+326
-23
lines changed

17 files changed

+326
-23
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,7 @@ export class BaseQuery {
17631763
'collectSubQueryDimensionsFor'
17641764
)
17651765
), inlineWhereConditions);
1766+
17661767
return `SELECT ${this.selectAllDimensionsAndMeasures(measures)} FROM ${
17671768
query
17681769
} ${this.baseWhere(filters.concat(inlineWhereConditions))}` +
@@ -3909,6 +3910,23 @@ export class BaseQuery {
39093910
);
39103911
}
39113912

3913+
filtersProxyForRust(usedFilters) {
3914+
const filters = this.extractFiltersAsTree(usedFilters || []);
3915+
const allFilters = filters.map(this.initFilter.bind(this));
3916+
return BaseQuery.filterProxyFromAllFilters(
3917+
allFilters,
3918+
this.cubeEvaluator,
3919+
this.paramAllocator.allocateParam.bind(this.paramAllocator),
3920+
this.newGroupFilter.bind(this),
3921+
);
3922+
}
3923+
3924+
filterGroupFunctionForRust(usedFilters) {
3925+
const filters = this.extractFiltersAsTree(usedFilters || []);
3926+
const allFilters = filters.map(this.initFilter.bind(this));
3927+
return this.filterGroupFunctionImpl(allFilters);
3928+
}
3929+
39123930
static renderFilterParams(filter, filterParamArgs, allocateParam, newGroupFilter, aliases) {
39133931
if (!filter) {
39143932
return BaseFilter.ALWAYS_TRUE;
@@ -3954,6 +3972,10 @@ export class BaseQuery {
39543972

39553973
filterGroupFunction() {
39563974
const { allFilters } = this;
3975+
return this.filterGroupFunctionImpl(allFilters);
3976+
}
3977+
3978+
filterGroupFunctionImpl(allFilters) {
39573979
const allocateParam = this.paramAllocator.allocateParam.bind(this.paramAllocator);
39583980
const newGroupFilter = this.newGroupFilter.bind(this);
39593981
return (...filterParamArgs) => {

packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getEnv } from '@cubejs-backend/shared';
12
import { UserError } from '../../../src/compiler/UserError';
23
import { PostgresQuery } from '../../../src/adapter/PostgresQuery';
34
import { BigqueryQuery } from '../../../src/adapter/BigqueryQuery';
@@ -547,6 +548,84 @@ describe('SQL Generation', () => {
547548
},
548549
}
549550
});
551+
552+
cube('rollingWindowDates', {
553+
sql: \`
554+
SELECT cast('2024-01-13' AS timestamp) as time UNION ALL
555+
SELECT cast('2024-02-13' AS timestamp) as time UNION ALL
556+
SELECT cast('2024-03-13' AS timestamp) as time UNION ALL
557+
SELECT cast('2024-04-13' AS timestamp) as time UNION ALL
558+
SELECT cast('2024-05-13' AS timestamp) as time UNION ALL
559+
SELECT cast('2024-06-13' AS timestamp) as time UNION ALL
560+
SELECT cast('2024-07-13' AS timestamp) as time UNION ALL
561+
SELECT cast('2024-08-13' AS timestamp) as time UNION ALL
562+
SELECT cast('2024-09-13' AS timestamp) as time UNION ALL
563+
SELECT cast('2024-10-13' AS timestamp) as time UNION ALL
564+
SELECT cast('2024-11-13' AS timestamp) as time UNION ALL
565+
SELECT cast('2024-12-13' AS timestamp) as time
566+
\`,
567+
568+
dimensions: {
569+
time: {
570+
type: 'time',
571+
sql: 'time',
572+
primaryKey: true
573+
}
574+
}
575+
});
576+
577+
cube('rollingWindowTest', {
578+
sql: \`
579+
SELECT 1 AS revenue, cast('2024-01-01' AS timestamp) as time UNION ALL
580+
SELECT 1 AS revenue, cast('2024-02-01' AS timestamp) as time UNION ALL
581+
SELECT 1 AS revenue, cast('2024-03-01' AS timestamp) as time UNION ALL
582+
SELECT 1 AS revenue, cast('2024-04-01' AS timestamp) as time UNION ALL
583+
SELECT 1 AS revenue, cast('2024-05-01' AS timestamp) as time UNION ALL
584+
SELECT 1 AS revenue, cast('2024-06-01' AS timestamp) as time UNION ALL
585+
SELECT 1 AS revenue, cast('2024-07-01' AS timestamp) as time UNION ALL
586+
SELECT 1 AS revenue, cast('2024-08-01' AS timestamp) as time UNION ALL
587+
SELECT 1 AS revenue, cast('2024-09-01' AS timestamp) as time UNION ALL
588+
SELECT 1 AS revenue, cast('2024-10-01' AS timestamp) as time UNION ALL
589+
SELECT 1 AS revenue, cast('2024-11-01' AS timestamp) as time UNION ALL
590+
SELECT 1 AS revenue, cast('2024-12-01' AS timestamp) as time
591+
\`,
592+
593+
dimensions: {
594+
time: {
595+
type: 'time',
596+
sql: 'time',
597+
primaryKey: true
598+
}
599+
},
600+
measures: {
601+
revenue: {
602+
sql: 'revenue',
603+
type: 'sum',
604+
filters: [{
605+
sql: \`\${rollingWindowDates.time} <= current_date\`
606+
}]
607+
},
608+
revenue_ytd: {
609+
sql: \`\${CUBE.revenue}\`,
610+
type: 'sum',
611+
rolling_window: {
612+
type: 'to_date',
613+
granularity: 'year'
614+
}
615+
},
616+
revenue_ms: {
617+
sql: \`\${CUBE.revenue}\`,
618+
type: 'sum',
619+
multi_stage: true,
620+
},
621+
},
622+
joins: {
623+
rollingWindowDates: {
624+
relationship: 'manyToOne',
625+
sql: \`\${CUBE}.time = date_trunc('month', \${rollingWindowDates.time})\`
626+
}
627+
}
628+
});
550629
`);
551630

552631
it('simple join', async () => {
@@ -993,7 +1072,7 @@ describe('SQL Generation', () => {
9931072
});
9941073
});
9951074

996-
it('filter join', async () => {
1075+
it('filter join 1', async () => {
9971076
await compiler.compile();
9981077

9991078
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
@@ -1613,7 +1692,7 @@ describe('SQL Generation', () => {
16131692
});
16141693
});
16151694

1616-
it('security context', async () => {
1695+
it('security context 1', async () => {
16171696
await compiler.compile();
16181697

16191698
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
@@ -2975,6 +3054,37 @@ describe('SQL Generation', () => {
29753054
}]
29763055
));
29773056

3057+
if (getEnv('nativeSqlPlanner')) {
3058+
it('nested aggregations with filtered measures and rolling windows', async () => runQueryTest(
3059+
{
3060+
measures: ['rollingWindowTest.revenue_ms'],
3061+
},
3062+
[{
3063+
rolling_window_test__revenue_ms: '12'
3064+
}]
3065+
));
3066+
}
3067+
3068+
it('multiplied sum and count no dimensions through view', async () => runQueryTest(
3069+
{
3070+
measures: ['visitors_visitors_checkins_view.revenue', 'visitors_visitors_checkins_view.visitor_checkins_count'],
3071+
},
3072+
[{
3073+
visitors_visitors_checkins_view__revenue: '2000',
3074+
visitors_visitors_checkins_view__visitor_checkins_count: '6'
3075+
}]
3076+
));
3077+
3078+
it('multiplied sum no dimensions through view', async () => runQueryTest(
3079+
{
3080+
measures: ['visitors_visitors_checkins_view.revenue', 'visitors_visitors_checkins_view.id_sum'],
3081+
},
3082+
[{
3083+
visitors_visitors_checkins_view__revenue: '2000',
3084+
visitors_visitors_checkins_view__id_sum: '21'
3085+
}]
3086+
));
3087+
29783088
// Subquery aggregation for multiplied measure (and any `keysSelect` for that matter)
29793089
// should pick up all dimensions, even through member expressions
29803090
it('multiplied sum with dimension member expressions', async () => runQueryTest(

rust/cubenativeutils/src/wrappers/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub trait NativeContext<IT: InnerTypes>: Clone {
66
fn string(&self, v: String) -> Result<IT::String, CubeError>;
77
fn number(&self, v: f64) -> Result<IT::Number, CubeError>;
88
fn undefined(&self) -> Result<NativeObjectHandle<IT>, CubeError>;
9+
fn null(&self) -> Result<NativeObjectHandle<IT>, CubeError>;
910
fn empty_array(&self) -> Result<IT::Array, CubeError>;
1011
fn empty_struct(&self) -> Result<IT::Struct, CubeError>;
1112
//fn boxed<T: 'static>(&self, value: T) -> impl NativeBox<IT, T>;
@@ -36,6 +37,9 @@ impl<IT: InnerTypes> NativeContextHolder<IT> {
3637
pub fn undefined(&self) -> Result<NativeObjectHandle<IT>, CubeError> {
3738
self.context.undefined()
3839
}
40+
pub fn null(&self) -> Result<NativeObjectHandle<IT>, CubeError> {
41+
self.context.null()
42+
}
3943
pub fn empty_array(&self) -> Result<IT::Array, CubeError> {
4044
self.context.empty_array()
4145
}

rust/cubenativeutils/src/wrappers/neon/context.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ impl<C: Context<'static> + 'static> NativeContext<NeonInnerTypes<C>> for Context
144144
)))
145145
}
146146

147+
fn null(&self) -> Result<NativeObjectHandle<NeonInnerTypes<C>>, CubeError> {
148+
Ok(NativeObjectHandle::new(NeonObject::new(
149+
self.clone(),
150+
self.with_context(|cx| cx.null().upcast())?,
151+
)))
152+
}
153+
147154
fn empty_array(&self) -> Result<NeonArray<C>, CubeError> {
148155
let obj = NeonObject::new(
149156
self.clone(),

rust/cubenativeutils/src/wrappers/serializer/serializer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl<IT: InnerTypes> ser::Serializer for NativeSerdeSerializer<IT> {
138138
}
139139

140140
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
141-
Ok(self.context.undefined()?)
141+
Ok(self.context.null()?)
142142
}
143143

144144
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub struct TimeDimension {
2323
pub struct FilterItem {
2424
pub or: Option<Vec<FilterItem>>,
2525
pub and: Option<Vec<FilterItem>>,
26-
member: Option<String>,
26+
pub member: Option<String>,
2727
pub dimension: Option<String>,
2828
pub operator: Option<String>,
2929
pub values: Option<Vec<Option<String>>>,

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::base_query_options::FilterItem;
12
use super::filter_group::{FilterGroup, NativeFilterGroup};
23
use super::filter_params::{FilterParams, NativeFilterParams};
34
use super::member_sql::{MemberSql, NativeMemberSql};
@@ -36,8 +37,11 @@ pub trait BaseTools {
3637
) -> Result<Vec<CallDep>, CubeError>;
3738
fn security_context_for_rust(&self) -> Result<Rc<dyn SecurityContext>, CubeError>;
3839
fn sql_utils_for_rust(&self) -> Result<Rc<dyn SqlUtils>, CubeError>;
39-
fn filters_proxy(&self) -> Result<Rc<dyn FilterParams>, CubeError>;
40-
fn filter_group_function(&self) -> Result<Rc<dyn FilterGroup>, CubeError>;
40+
fn filters_proxy_for_rust(
41+
&self,
42+
used_filters: Option<Vec<FilterItem>>,
43+
) -> Result<Rc<dyn FilterParams>, CubeError>;
44+
fn filter_group_function_for_rust(&self, used_filters: Option<Vec<FilterItem>>) -> Result<Rc<dyn FilterGroup>, CubeError>;
4145
fn timestamp_precision(&self) -> Result<u32, CubeError>;
4246
fn in_db_time_zone(&self, date: String) -> Result<String, CubeError>;
4347
fn generate_time_series(

rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,11 @@ impl SelectBuilder {
193193
Select {
194194
projection_columns: self.projection_columns,
195195
from: self.from,
196-
filter: self.filter,
196+
filter: self.filter.clone(),
197197
group_by: self.group_by,
198198
having: self.having,
199199
order_by: self.order_by,
200-
context: Rc::new(VisitorContext::new(&nodes_factory)),
200+
context: Rc::new(VisitorContext::new(&nodes_factory, self.filter)),
201201
ctes: self.ctes,
202202
is_distinct: self.is_distinct,
203203
limit: self.limit,

rust/cubesqlplanner/cubesqlplanner/src/planner/filter/compiler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl<'a> FilterCompiler<'a> {
129129
} else {
130130
Err(CubeError::user(format!(
131131
"Member and operator attributes is required for filter"
132-
))) //TODO pring condition
132+
))) //TODO print condition
133133
}
134134
}
135135
}

rust/cubesqlplanner/cubesqlplanner/src/planner/filter/filter_operator.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,31 @@ impl FromStr for FilterOperator {
5353
}
5454
}
5555
}
56+
57+
impl ToString for FilterOperator {
58+
fn to_string(&self) -> String {
59+
let str = match self {
60+
FilterOperator::Equal => "equals",
61+
FilterOperator::NotEqual => "notEquals",
62+
FilterOperator::InDateRange => "inDateRange",
63+
FilterOperator::RegularRollingWindowDateRange => "inDateRange",
64+
FilterOperator::ToDateRollingWindowDateRange => "inDateRange",
65+
FilterOperator::In => "in",
66+
FilterOperator::NotIn => "notIn",
67+
FilterOperator::Set => "set",
68+
FilterOperator::NotSet => "notSet",
69+
FilterOperator::Gt => "gt",
70+
FilterOperator::Gte => "gte",
71+
FilterOperator::Lt => "lt",
72+
FilterOperator::Lte => "lte",
73+
FilterOperator::Contains => "contains",
74+
FilterOperator::NotContains => "notContains",
75+
FilterOperator::StartsWith => "startsWith",
76+
FilterOperator::NotStartsWith => "notStartsWith",
77+
FilterOperator::NotEndsWith => "notEndsWith",
78+
FilterOperator::EndsWith => "endsWith",
79+
FilterOperator::MeasureFilter => "measureFilter",
80+
};
81+
str.to_string()
82+
}
83+
}

0 commit comments

Comments
 (0)