Skip to content

Commit 9b5dd5b

Browse files
committed
case expression
1 parent f22e543 commit 9b5dd5b

File tree

17 files changed

+409
-129
lines changed

17 files changed

+409
-129
lines changed

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -678,10 +678,7 @@ const CaseSchema = Joi.object().keys({
678678
}).required();
679679

680680
const SwitchCaseSchema = Joi.object().keys({
681-
switch: Joi.alternatives([
682-
Joi.string(),
683-
Joi.func()
684-
]).required(),
681+
switch: Joi.func().required(),
685682
when: Joi.array().items(Joi.object().keys({
686683
value: Joi.string().required(),
687684
sql: Joi.func().required()

packages/cubejs-schema-compiler/test/integration/postgres/calc-groups.test.ts

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,23 @@ cubes:
5151
- EUR
5252
- GBP
5353
54-
- name: test
54+
- name: strategy
55+
type: switch
56+
values:
57+
- A
58+
- B
59+
60+
- name: currency_full_name
5561
type: string
5662
case:
57-
switch: "{CUBE}.currency"
63+
switch: "{CUBE.currency}"
5864
when:
5965
- value: USD
60-
sql: "'111'"
66+
sql: "'dollars'"
6167
- value: EUR
62-
sql: "'333'"
68+
sql: "'euros'"
6369
else:
64-
sql: "'def'"
65-
66-
- name: strategy
67-
type: switch
68-
values:
69-
- A
70-
- B
70+
sql: "'unknown'"
7171
7272
measures:
7373
- name: count
@@ -460,13 +460,14 @@ views:
460460
],
461461
{ joinGraph, cubeEvaluator, compiler }));
462462

463-
it('measure switch', async () => dbRunner.runQueryTest({
464-
dimensions: ['orders.currency', 'orders.test'],
463+
it('dimension switch expression simple', async () => dbRunner.runQueryTest({
464+
dimensions: ['orders.currency', 'orders.currency_full_name'],
465465
measures: ['orders.revenue'],
466466
timeDimensions: [
467467
{
468468
dimension: 'orders.date',
469-
granularity: 'year'
469+
granularity: 'year',
470+
dateRange: ['2024-01-01', '2026-01-01']
470471
}
471472
],
472473
timezone: 'UTC',
@@ -477,27 +478,43 @@ views:
477478
},
478479
],
479480
}, [
480-
{
481-
orders__date_year: '2022-01-01T00:00:00.000Z',
482-
orders__strategy: 'B',
483-
orders__revenue: '5',
484-
},
485-
{
486-
orders__date_year: '2023-01-01T00:00:00.000Z',
487-
orders__strategy: 'B',
488-
orders__revenue: '15',
489-
},
490-
{
491-
orders__date_year: '2024-01-01T00:00:00.000Z',
492-
orders__strategy: 'B',
493-
orders__revenue: '30',
494-
},
495-
{
496-
orders__date_year: '2025-01-01T00:00:00.000Z',
497-
orders__strategy: 'B',
498-
orders__revenue: '5',
499-
}
500-
],
481+
{
482+
orders__currency: 'EUR',
483+
orders__currency_full_name: 'euros',
484+
orders__date_year: '2024-01-01T00:00:00.000Z',
485+
orders__revenue: '30'
486+
},
487+
{
488+
orders__currency: 'GBP',
489+
orders__currency_full_name: 'unknown',
490+
orders__date_year: '2024-01-01T00:00:00.000Z',
491+
orders__revenue: '30'
492+
},
493+
{
494+
orders__currency: 'USD',
495+
orders__currency_full_name: 'dollars',
496+
orders__date_year: '2024-01-01T00:00:00.000Z',
497+
orders__revenue: '30'
498+
},
499+
{
500+
orders__currency: 'EUR',
501+
orders__currency_full_name: 'euros',
502+
orders__date_year: '2025-01-01T00:00:00.000Z',
503+
orders__revenue: '5'
504+
},
505+
{
506+
orders__currency: 'GBP',
507+
orders__currency_full_name: 'unknown',
508+
orders__date_year: '2025-01-01T00:00:00.000Z',
509+
orders__revenue: '5'
510+
},
511+
{
512+
orders__currency: 'USD',
513+
orders__currency_full_name: 'dollars',
514+
orders__date_year: '2025-01-01T00:00:00.000Z',
515+
orders__revenue: '5'
516+
}
517+
],
501518
{ joinGraph, cubeEvaluator, compiler }));
502519
} else {
503520
// This test is working only in tesseract

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/case_else_item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::case_label::CaseLabel;
1+
use super::string_or_sql::StringOrSql;
22
use cubenativeutils::wrappers::serializer::{
33
NativeDeserialize, NativeDeserializer, NativeSerialize,
44
};
@@ -11,5 +11,5 @@ use std::rc::Rc;
1111
#[nativebridge::native_bridge]
1212
pub trait CaseElseItem {
1313
#[nbridge(field)]
14-
fn label(&self) -> Result<CaseLabel, CubeError>;
14+
fn label(&self) -> Result<StringOrSql, CubeError>;
1515
}

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/case_item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::case_label::CaseLabel;
1+
use super::string_or_sql::StringOrSql;
22
use super::member_sql::{MemberSql, NativeMemberSql};
33
use cubenativeutils::wrappers::serializer::{
44
NativeDeserialize, NativeDeserializer, NativeSerialize,
@@ -14,5 +14,5 @@ pub trait CaseItem {
1414
#[nbridge(field)]
1515
fn sql(&self) -> Result<Rc<dyn MemberSql>, CubeError>;
1616
#[nbridge(field)]
17-
fn label(&self) -> Result<CaseLabel, CubeError>;
17+
fn label(&self) -> Result<StringOrSql, CubeError>;
1818
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::cube_bridge::member_sql::{MemberSql, NativeMemberSql};
2+
3+
use super::case_switch_else_item::{CaseSwitchElseItem, NativeCaseSwitchElseItem};
4+
use super::case_switch_item::{CaseSwitchItem, NativeCaseSwitchItem};
5+
use super::string_or_sql::StringOrSql;
6+
use cubenativeutils::wrappers::serializer::{
7+
NativeDeserialize, NativeDeserializer, NativeSerialize,
8+
};
9+
use cubenativeutils::wrappers::NativeArray;
10+
use cubenativeutils::wrappers::NativeContextHolder;
11+
use cubenativeutils::wrappers::NativeObjectHandle;
12+
use cubenativeutils::CubeError;
13+
use std::any::Any;
14+
use std::rc::Rc;
15+
16+
#[nativebridge::native_bridge]
17+
pub trait CaseSwitchDefinition {
18+
#[nbridge(field)]
19+
fn switch(&self) -> Result<Rc<dyn MemberSql>, CubeError>;
20+
#[nbridge(field, vec)]
21+
fn when(&self) -> Result<Vec<Rc<dyn CaseSwitchItem>>, CubeError>;
22+
#[nbridge(field, rename = "else")]
23+
fn else_sql(&self) -> Result<Rc<dyn CaseSwitchElseItem>, CubeError>;
24+
}

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/case_switch_else_item.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::cube_bridge::member_sql::{MemberSql, NativeMemberSql};
22

3-
use super::case_label::CaseLabel;
43
use cubenativeutils::wrappers::serializer::{
54
NativeDeserialize, NativeDeserializer, NativeSerialize,
65
};
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
use super::case_label::CaseLabel;
21
use super::member_sql::{MemberSql, NativeMemberSql};
32
use cubenativeutils::wrappers::serializer::{
43
NativeDeserialize, NativeDeserializer, NativeSerialize,
54
};
65
use cubenativeutils::wrappers::NativeContextHolder;
76
use cubenativeutils::wrappers::NativeObjectHandle;
87
use cubenativeutils::CubeError;
8+
use serde::{Deserialize, Serialize};
99
use std::any::Any;
1010
use std::rc::Rc;
1111

12-
#[nativebridge::native_bridge]
12+
#[derive(Serialize, Deserialize, Debug)]
13+
pub struct CaseSwitchItemStatic {
14+
pub value: String,
15+
}
16+
17+
#[nativebridge::native_bridge(CaseSwitchItemStatic)]
1318
pub trait CaseSwitchItem {
14-
#[nbridge(field)]
15-
fn value(&self) -> Result<String, CubeError>;
1619
#[nbridge(field)]
1720
fn sql(&self) -> Result<Rc<dyn MemberSql>, CubeError>;
1821
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use crate::cube_bridge::case_definition::{CaseDefinition, NativeCaseDefinition};
2+
use crate::cube_bridge::case_switch_definition::{
3+
CaseSwitchDefinition, NativeCaseSwitchDefinition,
4+
};
5+
6+
use super::struct_with_sql_member::{NativeStructWithSqlMember, StructWithSqlMember};
7+
use cubenativeutils::wrappers::inner_types::InnerTypes;
8+
use cubenativeutils::wrappers::serializer::NativeDeserialize;
9+
use cubenativeutils::wrappers::NativeObjectHandle;
10+
use cubenativeutils::CubeError;
11+
use std::rc::Rc;
12+
13+
pub enum CaseVariant {
14+
Case(Rc<dyn CaseDefinition>),
15+
CaseSwitch(Rc<dyn CaseSwitchDefinition>),
16+
}
17+
18+
impl<IT: InnerTypes> NativeDeserialize<IT> for CaseVariant {
19+
fn from_native(native_object: NativeObjectHandle<IT>) -> Result<Self, CubeError> {
20+
match NativeCaseSwitchDefinition::from_native(native_object.clone()) {
21+
Ok(case) => Ok(Self::CaseSwitch(Rc::new(case))),
22+
Err(_) => match NativeCaseDefinition::from_native(native_object) {
23+
Ok(case) => Ok(Self::Case(Rc::new(case))),
24+
Err(_) => Err(CubeError::user(format!("Case or Case Switch expected"))),
25+
},
26+
}
27+
}
28+
}

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/dimension_definition.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::case_definition::{CaseDefinition, NativeCaseDefinition};
1+
use super::case_variant::CaseVariant;
22
use super::geo_item::{GeoItem, NativeGeoItem};
33
use super::member_sql::{MemberSql, NativeMemberSql};
44
use crate::cube_bridge::timeshift_definition::{NativeTimeShiftDefinition, TimeShiftDefinition};
@@ -34,7 +34,7 @@ pub trait DimensionDefinition {
3434
fn sql(&self) -> Result<Option<Rc<dyn MemberSql>>, CubeError>;
3535

3636
#[nbridge(field, optional)]
37-
fn case(&self) -> Result<Option<Rc<dyn CaseDefinition>>, CubeError>;
37+
fn case(&self) -> Result<Option<CaseVariant>, CubeError>;
3838

3939
#[nbridge(field, optional)]
4040
fn latitude(&self) -> Result<Option<Rc<dyn GeoItem>>, CubeError>;

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ pub mod base_tools;
33
pub mod case_definition;
44
pub mod case_else_item;
55
pub mod case_item;
6-
pub mod case_label;
6+
pub mod case_switch_definition;
77
pub mod case_switch_else_item;
88
pub mod case_switch_item;
9+
pub mod case_variant;
910
pub mod cube_definition;
1011
pub mod dimension_definition;
1112
pub mod driver_tools;
@@ -31,5 +32,6 @@ pub mod security_context;
3132
pub mod segment_definition;
3233
pub mod sql_templates_render;
3334
pub mod sql_utils;
35+
pub mod string_or_sql;
3436
pub mod struct_with_sql_member;
3537
pub mod timeshift_definition;

0 commit comments

Comments
 (0)