Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a18f779
chore(tesseract): Symbols refactoring
waralexrom Nov 13, 2025
d784e30
in work
waralexrom Nov 13, 2025
49b4a79
in work
waralexrom Nov 13, 2025
6771878
in work
waralexrom Nov 13, 2025
896b3f3
member_sql mock
waralexrom Nov 13, 2025
7a09141
in work
waralexrom Nov 13, 2025
94faed9
dimension mock
waralexrom Nov 13, 2025
b692926
measure mock
waralexrom Nov 13, 2025
55df9ec
cube mock
waralexrom Nov 13, 2025
cd5d631
member expression mock
waralexrom Nov 13, 2025
faa76ae
join mock
waralexrom Nov 13, 2025
cd4e55b
schema mock
waralexrom Nov 13, 2025
91d4125
in work
waralexrom Nov 13, 2025
7cfacde
segment definition
waralexrom Nov 13, 2025
e663d9a
in work
waralexrom Nov 13, 2025
3a50ee0
evaluator mock
waralexrom Nov 13, 2025
70728cb
in work
waralexrom Nov 13, 2025
ce463e3
compiler tests in work
waralexrom Nov 13, 2025
2aafc36
compiler tests in work
waralexrom Nov 13, 2025
c8721c2
compiler tests in work
waralexrom Nov 13, 2025
f757159
compiler tests in work
waralexrom Nov 13, 2025
f332a72
compiler tests in work
waralexrom Nov 13, 2025
f140d84
view mock
waralexrom Nov 13, 2025
49b4e9b
view symbol compilation
waralexrom Nov 13, 2025
e01da5a
proxy symbol compilation
waralexrom Nov 13, 2025
37e36ea
granularity mock
waralexrom Nov 13, 2025
6a96c77
templates mock
waralexrom Nov 13, 2025
765a5a3
driver tools mock
waralexrom Nov 13, 2025
fc241b6
base tools mock
waralexrom Nov 13, 2025
36c5fe0
in work
waralexrom Nov 13, 2025
c5f0558
fix warnings
waralexrom Nov 14, 2025
d6b7d93
basic evaluation test
waralexrom Nov 14, 2025
bc2cef1
basic evaluation test
waralexrom Nov 14, 2025
07082f3
in work
waralexrom Nov 14, 2025
fcfeb26
simple measures tests
waralexrom Nov 14, 2025
3b26349
count measure test
waralexrom Nov 14, 2025
babc23f
composite symbols test
waralexrom Nov 14, 2025
98e66ea
in work
waralexrom Nov 14, 2025
480f9cd
fmt
waralexrom Nov 14, 2025
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
11 changes: 0 additions & 11 deletions rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use super::base_query_options::FilterItem;
use super::driver_tools::{DriverTools, NativeDriverTools};
use super::filter_group::{FilterGroup, NativeFilterGroup};
use super::filter_params::{FilterParams, NativeFilterParams};
use super::join_definition::{JoinDefinition, NativeJoinDefinition};
use super::pre_aggregation_obj::{NativePreAggregationObj, PreAggregationObj};
use super::security_context::{NativeSecurityContext, SecurityContext};
Expand All @@ -23,14 +20,6 @@ pub trait BaseTools {
fn sql_templates(&self) -> Result<Rc<dyn SqlTemplatesRender>, CubeError>;
fn security_context_for_rust(&self) -> Result<Rc<dyn SecurityContext>, CubeError>;
fn sql_utils_for_rust(&self) -> Result<Rc<dyn SqlUtils>, CubeError>;
fn filters_proxy_for_rust(
&self,
used_filters: Option<Vec<FilterItem>>,
) -> Result<Rc<dyn FilterParams>, CubeError>;
fn filter_group_function_for_rust(
&self,
used_filters: Option<Vec<FilterItem>>,
) -> Result<Rc<dyn FilterGroup>, CubeError>;
fn generate_time_series(
&self,
granularity: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub struct DimensionDefinitionStatic {
#[serde(rename = "propagateFiltersToSubQuery")]
pub propagate_filters_to_sub_query: Option<bool>,
pub values: Option<Vec<String>>,
#[serde(rename = "primaryKey")]
pub primary_key: Option<bool>,
}

#[nativebridge::native_bridge(DimensionDefinitionStatic)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ pub struct CallDep {

#[nativebridge::native_bridge(CubeEvaluatorStatic)]
pub trait CubeEvaluator {
#[nbridge(field)]
fn primary_keys(&self) -> Result<HashMap<String, String>, CubeError>;
fn parse_path(&self, path_type: String, path: String) -> Result<Vec<String>, CubeError>;
fn measure_by_path(&self, measure_path: String)
-> Result<Rc<dyn MeasureDefinition>, CubeError>;
Expand All @@ -51,11 +49,6 @@ pub trait CubeEvaluator {
fn is_dimension(&self, path: Vec<String>) -> Result<bool, CubeError>;
fn is_segment(&self, path: Vec<String>) -> Result<bool, CubeError>;
fn cube_exists(&self, name: String) -> Result<bool, CubeError>;
fn resolve_symbols_call_deps(
&self,
cube_name: String,
sql: Rc<dyn MemberSql>,
) -> Result<Vec<CallDep>, CubeError>;
fn resolve_granularity(
&self,
path: Vec<String>,
Expand Down
11 changes: 6 additions & 5 deletions rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use super::{
security_context::{NativeSecurityContext, SecurityContext},
sql_utils::NativeSqlUtils,
};
use crate::cube_bridge::sql_utils::SqlUtils;
use crate::planner::sql_evaluator::SqlCallArg;
use crate::utils::UniqueVector;
use crate::{cube_bridge::base_tools::BaseTools, planner::sql_evaluator::SqlCallArg};
use cubenativeutils::wrappers::object::{NativeFunction, NativeStruct, NativeType};
use cubenativeutils::wrappers::serializer::{NativeDeserialize, NativeSerialize};
use cubenativeutils::wrappers::NativeContextHolderRef;
Expand Down Expand Up @@ -300,7 +301,7 @@ pub trait MemberSql {
fn as_any(self: Rc<Self>) -> Rc<dyn Any>;
fn compile_template_sql(
&self,
base_tools: Rc<dyn BaseTools>,
sql_utils: Rc<dyn SqlUtils>,
security_context: Rc<dyn SecurityContext>,
) -> Result<(SqlTemplate, SqlTemplateArgs), CubeError>;
}
Expand Down Expand Up @@ -633,7 +634,7 @@ impl<IT: InnerTypes> MemberSql for NativeMemberSql<IT> {

fn compile_template_sql(
&self,
base_tools: Rc<dyn BaseTools>,
sql_utils: Rc<dyn SqlUtils>,
security_context: Rc<dyn SecurityContext>,
) -> Result<(SqlTemplate, SqlTemplateArgs), CubeError> {
let state = ProxyState::new();
Expand Down Expand Up @@ -666,8 +667,8 @@ impl<IT: InnerTypes> MemberSql for NativeMemberSql<IT> {
context_obj,
)?
} else if arg == "SQL_UTILS" {
base_tools
.sql_utils_for_rust()?
sql_utils
.clone()
.as_any()
.downcast::<NativeSqlUtils<IT>>()
.unwrap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ use cubenativeutils::wrappers::inner_types::InnerTypes;
use cubenativeutils::wrappers::serializer::NativeDeserialize;
use cubenativeutils::wrappers::NativeObjectHandle;
use cubenativeutils::CubeError;
use std::fmt;
use std::rc::Rc;

#[derive(Clone)]
pub enum StringOrSql {
String(String),
MemberSql(Rc<dyn StructWithSqlMember>),
}

impl fmt::Debug for StringOrSql {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StringOrSql::String(s) => write!(f, "String({:?})", s),
StringOrSql::MemberSql(_) => write!(f, "MemberSql(<trait object>)"),
}
}
}

impl<IT: InnerTypes> NativeDeserialize<IT> for StringOrSql {
fn from_native(native_object: NativeObjectHandle<IT>) -> Result<Self, CubeError> {
match String::from_native(native_object.clone()) {
Expand Down
4 changes: 4 additions & 0 deletions rust/cubesqlplanner/cubesqlplanner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ pub mod logical_plan;
pub mod physical_plan_builder;
pub mod plan;
pub mod planner;
#[cfg(test)]
pub(crate) mod test_fixtures;
#[cfg(test)]
mod tests;
pub(crate) mod utils;
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl QueryTools {
};
let evaluator_compiler = Rc::new(RefCell::new(Compiler::new(
cube_evaluator.clone(),
base_tools.clone(),
base_tools.sql_utils_for_rust()?,
security_context.clone(),
timezone.clone(),
)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ use super::{
CubeNameSymbolFactory, CubeTableSymbolFactory, DimensionSymbolFactory, MeasureSymbolFactory,
SqlCall, SymbolFactory, TraversalVisitor,
};
use crate::cube_bridge::base_tools::BaseTools;
use crate::cube_bridge::evaluator::CubeEvaluator;
use crate::cube_bridge::join_hints::JoinHintItem;
use crate::cube_bridge::member_sql::MemberSql;
use crate::cube_bridge::security_context::SecurityContext;
use crate::cube_bridge::sql_utils::SqlUtils;
use crate::planner::sql_evaluator::sql_call_builder::SqlCallBuilder;
use chrono_tz::Tz;
use cubenativeutils::CubeError;
use std::collections::HashMap;
use std::rc::Rc;
pub struct Compiler {
cube_evaluator: Rc<dyn CubeEvaluator>,
base_tools: Rc<dyn BaseTools>,
sql_utils: Rc<dyn SqlUtils>,
security_context: Rc<dyn SecurityContext>,
timezone: Tz,
/* (type, name) */
Expand All @@ -26,14 +26,14 @@ pub struct Compiler {
impl Compiler {
pub fn new(
cube_evaluator: Rc<dyn CubeEvaluator>,
base_tools: Rc<dyn BaseTools>,
sql_utils: Rc<dyn SqlUtils>,
security_context: Rc<dyn SecurityContext>,
timezone: Tz,
) -> Self {
Self {
cube_evaluator,
security_context,
base_tools,
sql_utils,
timezone,
members: HashMap::new(),
}
Expand All @@ -56,10 +56,6 @@ impl Compiler {
}
}

pub fn base_tools(&self) -> Rc<dyn BaseTools> {
self.base_tools.clone()
}

pub fn add_measure_evaluator(
&mut self,
measure: String,
Expand Down Expand Up @@ -136,6 +132,7 @@ impl Compiler {
let call_builder = SqlCallBuilder::new(
self,
self.cube_evaluator.clone(),
self.sql_utils.clone(),
self.security_context.clone(),
);
let sql_call = call_builder.build(&cube_name, member_sql.clone())?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::{SqlCall, SqlCallDependency, SqlCallFilterGroupItem, SqlCallFilterPar
use crate::cube_bridge::evaluator::CubeEvaluator;
use crate::cube_bridge::member_sql::*;
use crate::cube_bridge::security_context::SecurityContext;
use crate::cube_bridge::sql_utils::SqlUtils;
use crate::planner::sql_evaluator::TimeDimensionSymbol;
use crate::planner::GranularityHelper;
use cubenativeutils::CubeError;
Expand All @@ -12,18 +13,21 @@ use std::rc::Rc;
pub struct SqlCallBuilder<'a> {
compiler: &'a mut Compiler,
cube_evaluator: Rc<dyn CubeEvaluator>,
sql_utils: Rc<dyn SqlUtils>,
security_context: Rc<dyn SecurityContext>,
}

impl<'a> SqlCallBuilder<'a> {
pub fn new(
compiler: &'a mut Compiler,
cube_evaluator: Rc<dyn CubeEvaluator>,
sql_utils: Rc<dyn SqlUtils>,
security_context: Rc<dyn SecurityContext>,
) -> Self {
Self {
compiler,
cube_evaluator,
sql_utils,
security_context,
}
}
Expand All @@ -34,7 +38,7 @@ impl<'a> SqlCallBuilder<'a> {
member_sql: Rc<dyn MemberSql>,
) -> Result<SqlCall, CubeError> {
let (template, template_args) = member_sql
.compile_template_sql(self.compiler.base_tools(), self.security_context.clone())?;
.compile_template_sql(self.sql_utils.clone(), self.security_context.clone())?;

let deps = template_args
.symbol_paths
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/// Macro to implement static_data() helper method for mock bridge types
///
/// This macro generates a helper method that returns an owned StaticData struct.
/// The helper is used by the trait's static_data() method which applies Box::leak.
///
/// # Usage
/// ```ignore
/// impl_static_data!(
/// MockDimensionDefinition, // The mock type
/// DimensionDefinitionStatic, // The static data type
/// dimension_type, // Fields to include
/// owned_by_cube,
/// multi_stage
/// );
/// ```
///
/// # Generated Code
/// ```ignore
/// impl MockDimensionDefinition {
/// pub fn static_data(&self) -> DimensionDefinitionStatic {
/// DimensionDefinitionStatic {
/// dimension_type: self.dimension_type.clone(),
/// owned_by_cube: self.owned_by_cube.clone(),
/// multi_stage: self.multi_stage.clone(),
/// }
/// }
/// }
/// ```
#[macro_export]
macro_rules! impl_static_data {
// Pattern: impl_static_data!(MockType, StaticType, field1, field2, ...)
($mock_type:ty, $static_type:path, $($field:ident),* $(,)?) => {
// Helper method that returns owned StaticData
impl $mock_type {
pub fn static_data(&self) -> $static_type {
$static_type {
$($field: self.$field.clone()),*
}
}
}
};
}

/// Macro to implement the trait's static_data() method using Box::leak
///
/// This macro should be used INSIDE the trait implementation block to generate
/// the static_data() method that returns &'static references.
///
/// # Memory Leak Explanation
/// This macro uses `Box::leak(Box::new(...))` to convert owned values into static
/// references. This intentionally leaks memory, which is acceptable because:
/// - Mock objects are only used in tests with short lifetimes
/// - Tests typically create a small number of mock objects
/// - The leaked memory is minimal and reclaimed when the test process exits
/// - This approach significantly simplifies test code by avoiding complex lifetime management
///
/// # Usage
/// ```ignore
/// impl DimensionDefinition for MockDimensionDefinition {
/// impl_static_data_method!(DimensionDefinitionStatic);
///
/// fn sql(&self) -> Result<Option<Rc<dyn MemberSql>>, CubeError> {
/// // ... other trait methods
/// }
/// }
/// ```
///
/// # Generated Code
/// ```ignore
/// fn static_data(&self) -> &DimensionDefinitionStatic {
/// // Intentional memory leak - acceptable for test mocks
/// // The Box::leak pattern converts the owned value to a static reference
/// Box::leak(Box::new(Self::static_data(self)))
/// }
/// ```
#[macro_export]
macro_rules! impl_static_data_method {
($static_type:path) => {
fn static_data(&self) -> &$static_type {
// Intentional memory leak for test mocks - see macro documentation
// This converts the owned StaticData from the helper method into a &'static reference
// required by the trait. The leak is acceptable because:
// 1. Test mocks have short lifetimes (duration of test)
// 2. Small number of instances created
// 3. Memory reclaimed when test process exits
Box::leak(Box::new(Self::static_data(self)))
}
};
}

#[cfg(test)]
mod tests {
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct TestStatic {
pub name: String,
pub value: Option<i32>,
}

pub trait TestTrait {
fn static_data(&self) -> &TestStatic;
}

#[derive(TypedBuilder)]
pub struct MockTest {
#[builder(default = "test".to_string())]
name: String,
#[builder(default)]
value: Option<i32>,
}

impl_static_data!(MockTest, TestStatic, name, value);

impl TestTrait for MockTest {
impl_static_data_method!(TestStatic);
}

#[test]
fn test_static_data_helper_method() {
let mock = MockTest::builder()
.name("hello".to_string())
.value(Some(42))
.build();

let static_data = mock.static_data();
assert_eq!(static_data.name, "hello");
assert_eq!(static_data.value, Some(42));
}

#[test]
fn test_static_data_trait_method() {
let mock = MockTest::builder()
.name("world".to_string())
.value(Some(123))
.build();

// Call trait method
let static_data: &TestStatic = TestTrait::static_data(&mock);
assert_eq!(static_data.name, "world");
assert_eq!(static_data.value, Some(123));
}

#[test]
fn test_static_data_macro_with_defaults() {
let mock = MockTest::builder().build();

let static_data = mock.static_data();
assert_eq!(static_data.name, "test");
assert_eq!(static_data.value, None);
}
}
Loading
Loading