Skip to content

Commit 698a5f8

Browse files
committed
in work
1 parent f62b46b commit 698a5f8

File tree

22 files changed

+765
-145
lines changed

22 files changed

+765
-145
lines changed

packages/cubejs-backend-shared/src/time.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export const timeSeries = (granularity: string, dateRange: QueryDateRange, optio
179179
// moment.range works with strings
180180
const range = moment.range(<any>dateRange[0], <any>dateRange[1]);
181181

182+
console.log("!!!! timeSeries:", TIME_SERIES[granularity](range, options.timestampPrecision));
182183
return TIME_SERIES[granularity](range, options.timestampPrecision);
183184
};
184185

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import cronParser from 'cron-parser';
1111

1212
import moment from 'moment-timezone';
1313
import inflection from 'inflection';
14-
import { FROM_PARTITION_RANGE, inDbTimeZone, MAX_SOURCE_ROW_LIMIT, QueryAlias, getEnv } from '@cubejs-backend/shared';
14+
import { FROM_PARTITION_RANGE, inDbTimeZone, MAX_SOURCE_ROW_LIMIT, QueryAlias, getEnv, timeSeries } from '@cubejs-backend/shared';
1515

1616
import {
1717
buildSqlAndParams as nativeBuildSqlAndParams,
@@ -576,6 +576,29 @@ export class BaseQuery {
576576
return false;
577577
}
578578

579+
buildSqlAndParamsTest(exportAnnotatedSql) {
580+
if (!this.options.preAggregationQuery && !this.options.disableExternalPreAggregations && this.externalQueryClass) {
581+
if (this.externalPreAggregationQuery()) { // TODO performance
582+
return this.externalQuery().buildSqlAndParams(exportAnnotatedSql);
583+
}
584+
}
585+
const js_res = this.compilers.compiler.withQuery(
586+
this,
587+
() => this.cacheValue(
588+
['buildSqlAndParams', exportAnnotatedSql],
589+
() => this.paramAllocator.buildSqlAndParams(
590+
this.buildParamAnnotatedSql(),
591+
exportAnnotatedSql,
592+
this.shouldReuseParams
593+
),
594+
{ cache: this.queryCache }
595+
)
596+
);
597+
const rust = this.buildSqlAndParamsRust(exportAnnotatedSql);
598+
console.log('js result: ', js_res[0]);
599+
console.log('rust result: ', rust[0]);
600+
return js_res;
601+
}
579602
/**
580603
* Returns an array of SQL query strings for the query.
581604
* @param {boolean} [exportAnnotatedSql] - returns annotated sql with not rendered params if true
@@ -628,6 +651,10 @@ export class BaseQuery {
628651
return res;
629652
}
630653

654+
//FIXME helper for native generator, maybe should be moved entire to rust
655+
generateTimeSeries(granularity, dateRange) {
656+
return timeSeries(granularity, dateRange);
657+
}
631658
get shouldReuseParams() {
632659
return false;
633660
}
@@ -1381,6 +1408,7 @@ export class BaseQuery {
13811408
) || undefined
13821409
);
13831410
const baseQueryAlias = this.cubeAlias('base');
1411+
console.log("!!! date join contdition: ", dateJoinCondition);
13841412
const dateJoinConditionSql =
13851413
dateJoinCondition.map(
13861414
([d, f]) => f(
@@ -1392,6 +1420,8 @@ export class BaseQuery {
13921420
)
13931421
).join(' AND ');
13941422

1423+
console.log("!!! date join contdition sql: ", dateJoinConditionSql);
1424+
13951425
return this.overTimeSeriesSelect(
13961426
cumulativeMeasures,
13971427
dateSeriesSql,
@@ -3231,7 +3261,16 @@ export class BaseQuery {
32313261
'{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}',
32323262
group_by_exprs: '{{ group_by | map(attribute=\'index\') | join(\', \') }}',
32333263
join: '{{ join_type }} JOIN {{ source }} ON {{ condition }}',
3234-
cte: '{{ alias }} AS ({{ query | indent(2, true) }})'
3264+
cte: '{{ alias }} AS ({{ query | indent(2, true) }})',
3265+
time_seria_select: 'SELECT date_from::timestamp AS "date_from",\n' +
3266+
'date_to::timestamp AS "date_to" \n' +
3267+
'FROM(\n' +
3268+
' VALUES ' +
3269+
'{% for time_item in seria %}' +
3270+
'(\'{{ time_item | join(\'\\\', \\\'\') }}\')' +
3271+
'{% if not loop.last %}, {% endif %}' +
3272+
'{% endfor %}' +
3273+
') AS dates (date_from, date_to)'
32353274
},
32363275
expressions: {
32373276
column_reference: '{% if table_name %}{{ table_name }}.{% endif %}{{ name }}',

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ describe('SQL Generation', () => {
538538
});
539539
`);
540540

541-
it('simple join 1', async () => {
541+
it('simple join', async () => {
542542
await compiler.compile();
543543

544544
console.log(joinGraph.buildJoin(['visitor_checkins', 'visitors']));
@@ -704,7 +704,7 @@ describe('SQL Generation', () => {
704704
});
705705
});
706706

707-
it('rolling', async () => runQueryTest({
707+
it('rolling 1', async () => runQueryTest({
708708
measures: [
709709
'visitors.revenueRolling'
710710
],
@@ -730,7 +730,7 @@ describe('SQL Generation', () => {
730730
{ visitors__created_at_day: '2017-01-10T00:00:00.000Z', visitors__revenue_rolling: null }
731731
]));
732732

733-
it('rolling multiplied', async () => runQueryTest({
733+
it('rolling multiplied 1', async () => runQueryTest({
734734
measures: [
735735
'visitors.revenueRolling',
736736
'visitor_checkins.visitor_checkins_count'
@@ -916,6 +916,7 @@ describe('SQL Generation', () => {
916916
{ visitors__created_at_day: '2017-01-10T00:00:00.000Z', visitors__running_revenue_per_count: '300' }
917917
]));
918918

919+
919920
it('hll rolling (BigQuery)', async () => {
920921
await compiler.compile();
921922

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,9 @@ pub trait BaseTools {
3838
fn filter_group_function(&self) -> Result<Rc<dyn FilterGroup>, CubeError>;
3939
fn timestamp_precision(&self) -> Result<u32, CubeError>;
4040
fn in_db_time_zone(&self, date: String) -> Result<String, CubeError>;
41+
fn generate_time_series(
42+
&self,
43+
granularity: String,
44+
date_range: Vec<String>,
45+
) -> Result<Vec<Vec<String>>, CubeError>;
4146
}

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_definition.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ pub struct TimeShiftReference {
2121
pub time_dimension: String,
2222
}
2323

24+
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
25+
pub struct RollingWindow {
26+
trailing: Option<String>,
27+
leading: Option<String>,
28+
offset: Option<String>,
29+
}
30+
2431
#[derive(Serialize, Deserialize, Debug)]
2532
pub struct MeasureDefinitionStatic {
2633
#[serde(rename = "type")]
@@ -37,6 +44,8 @@ pub struct MeasureDefinitionStatic {
3744
pub group_by_references: Option<Vec<String>>,
3845
#[serde(rename = "timeShiftReferences")]
3946
pub time_shift_references: Option<Vec<TimeShiftReference>>,
47+
#[serde(rename = "rollingWindow")]
48+
pub rolling_window: Option<RollingWindow>,
4049
}
4150

4251
#[nativebridge::native_bridge(MeasureDefinitionStatic)]

rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,80 @@
1-
use super::{Schema, SingleAliasedSource};
1+
use super::{time_seria, Schema, SingleAliasedSource};
22
use crate::planner::sql_templates::PlanSqlTemplates;
33
use crate::planner::{BaseJoinCondition, BaseMember, VisitorContext};
44
use cubenativeutils::CubeError;
55

66
use std::rc::Rc;
77

8+
pub struct RollingWindowJoinCondition {
9+
tailing_interval: Option<String>,
10+
leading_interval: Option<String>,
11+
offset: String,
12+
is_from_start_to_end: bool,
13+
time_dimension: Vec<Rc<BaseMember>>,
14+
}
15+
16+
impl RollingWindowJoinCondition {
17+
pub fn new(
18+
trailing_interval: Option<String>,
19+
leading_interval: Option<String>,
20+
offset: String,
21+
is_from_start_to_end: bool,
22+
dimensions: Vec<Rc<BaseMember>>,
23+
) -> Self {
24+
Self {
25+
tailing_interval,
26+
leading_interval,
27+
offset,
28+
is_from_start_to_end,
29+
time_dimension,
30+
}
31+
}
32+
33+
pub fn to_sql(
34+
&self,
35+
templates: &PlanSqlTemplates,
36+
context: Rc<VisitorContext>,
37+
schema: Rc<Schema>,
38+
) -> Result<String, CubeError> {
39+
let result = if self.dimensions.is_empty() {
40+
format!("1 = 1")
41+
} else {
42+
let conditions = vec![];
43+
self.dimensions
44+
.iter()
45+
.map(|dim| -> Result<String, CubeError> {
46+
if let Some(trailing_interval) = self.trailing_interval {
47+
if tailing_interval == "unbounded" {
48+
let seria_column = "date_from",
49+
}
50+
}
51+
52+
53+
})
54+
.collect::<Result<Vec<_>, _>>()?
55+
.join(" AND ")
56+
};
57+
Ok(result)
58+
}
59+
60+
fn resolve_member_alias(
61+
&self,
62+
templates: &PlanSqlTemplates,
63+
context: Rc<VisitorContext>,
64+
source: &String,
65+
dimension: &Rc<dyn BaseMember>,
66+
schema: Rc<Schema>,
67+
) -> Result<String, CubeError> {
68+
let schema = schema.extract_source_schema(source);
69+
let source = Some(source.clone());
70+
if let Some(column) = schema.find_column_for_member(&dimension.full_name(), &source) {
71+
templates.column_reference(&source, &column.alias.clone())
72+
} else {
73+
dimension.to_sql(context.clone(), schema.clone())
74+
}
75+
}
76+
}
77+
878
pub struct DimensionJoinCondition {
979
left_source: String,
1080
right_source: String,

rust/cubesqlplanner/cubesqlplanner/src/plan/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod order;
88
pub mod query_plan;
99
pub mod schema;
1010
pub mod select;
11+
pub mod time_seria;
1112
pub mod union;
1213

1314
pub use builder::{JoinBuilder, SelectBuilder};
@@ -20,4 +21,6 @@ pub use order::OrderBy;
2021
pub use query_plan::QueryPlan;
2122
pub use schema::{Schema, SchemaColumn, SchemaCube};
2223
pub use select::{AliasedExpr, Select};
24+
pub use time_seria::TimeSeria;
2325
pub use union::Union;
26+
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
use super::{Schema, Select, Union};
1+
use super::{Schema, Select, TimeSeria, Union};
22
use crate::planner::sql_templates::PlanSqlTemplates;
33
use cubenativeutils::CubeError;
44
use std::rc::Rc;
55

66
pub enum QueryPlan {
77
Select(Rc<Select>),
88
Union(Rc<Union>),
9+
TimeSeria(Rc<TimeSeria>),
910
}
1011

1112
impl QueryPlan {
1213
pub fn make_schema(&self, self_alias: Option<String>) -> Schema {
1314
match self {
1415
QueryPlan::Select(select) => select.make_schema(self_alias),
1516
QueryPlan::Union(union) => union.make_schema(self_alias),
17+
QueryPlan::TimeSeria(seria) => seria.make_schema(self_alias),
1618
}
1719
}
1820
pub fn to_sql(&self, templates: &PlanSqlTemplates) -> Result<String, CubeError> {
1921
match self {
2022
QueryPlan::Select(s) => s.to_sql(templates),
2123
QueryPlan::Union(u) => u.to_sql(templates),
24+
QueryPlan::TimeSeria(seria) => seria.to_sql(templates),
2225
}
2326
}
2427
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use super::{Schema, SchemaColumn, Select, Union};
2+
use crate::planner::sql_templates::PlanSqlTemplates;
3+
use cubenativeutils::CubeError;
4+
use std::rc::Rc;
5+
6+
pub struct TimeSeria {
7+
pub time_dimension_name: String,
8+
pub from_date: Option<String>,
9+
pub to_date: Option<String>,
10+
pub seria: Vec<Vec<String>>,
11+
}
12+
13+
impl TimeSeria {
14+
pub fn make_schema(&self, self_alias: Option<String>) -> Schema {
15+
let column = SchemaColumn::new(
16+
self_alias,
17+
format!("from_date"),
18+
self.time_dimension_name.clone(),
19+
);
20+
Schema::new(vec![column], vec![])
21+
}
22+
23+
pub fn to_sql(&self, templates: &PlanSqlTemplates) -> Result<String, CubeError> {
24+
templates.time_seria_select(
25+
self.from_date.clone(),
26+
self.to_date.clone(),
27+
self.seria.clone(),
28+
)
29+
}
30+
}

rust/cubesqlplanner/cubesqlplanner/src/planner/base_measure.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use super::query_tools::QueryTools;
22
use super::sql_evaluator::{EvaluationNode, MemberSymbol, MemberSymbolType};
33
use super::{evaluate_with_context, BaseMember, VisitorContext};
4-
use crate::cube_bridge::measure_definition::{MeasureDefinition, TimeShiftReference};
4+
use crate::cube_bridge::measure_definition::{
5+
MeasureDefinition, RollingWindow, TimeShiftReference,
6+
};
57
use crate::plan::Schema;
68
use cubenativeutils::CubeError;
79
use lazy_static::lazy_static;
@@ -195,6 +197,14 @@ impl BaseMeasure {
195197
self.definition.static_data().multi_stage.unwrap_or(false)
196198
}
197199

200+
pub fn rolling_window(&self) -> &Option<RollingWindow> {
201+
&self.definition.static_data().rolling_window
202+
}
203+
204+
pub fn is_rolling_window(&self) -> bool {
205+
self.rolling_window().is_some()
206+
}
207+
198208
//FIXME dublicate with symbol
199209
pub fn measure_type(&self) -> &String {
200210
&self.definition.static_data().measure_type

rust/cubesqlplanner/cubesqlplanner/src/planner/planners/multi_stage/applied_state.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::planner::base_measure::MeasureTimeShift;
1+
use crate::planner::planners::multi_stage::MultiStageTimeShift;
22
use crate::planner::BaseDimension;
33
use itertools::Itertools;
44
use std::cmp::PartialEq;
@@ -43,7 +43,7 @@ impl MultiStageAppliedState {
4343
.collect_vec();
4444
}
4545

46-
pub fn add_time_shifts(&mut self, time_shifts: Vec<MeasureTimeShift>) {
46+
pub fn add_time_shifts(&mut self, time_shifts: Vec<MultiStageTimeShift>) {
4747
for ts in time_shifts.into_iter() {
4848
self.time_shifts
4949
.insert(ts.time_dimension.clone(), ts.interval.clone());

0 commit comments

Comments
 (0)