Skip to content
Merged
188 changes: 8 additions & 180 deletions packages/cubejs-backend-native/src/bridge_test_exports.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
//! Test endpoints for the Tesseract bridge layer.
//!
//! These functions are exported on the native module under names prefixed with
//! `__testBridge` (e.g. `__testBridgeCompileMemberSql`). They drive real V8
//! `__testBridge` (e.g. `__testBridgeParseArgsNames`). They drive real V8
//! through the production bridge code so
//! that bridge logic can be regression-tested at the unit level rather than
//! only via end-to-end JS planner tests.
//!
//! Stub implementations for trait dependencies (e.g. `BaseTools`) live in this
//! module; they should fail loudly when an unsupported code path is exercised.

use cubenativeutils::wrappers::bridge_meta::{BridgeFieldKind, BridgeFieldMeta};
use cubenativeutils::wrappers::neon::neon_guarded_funcion_call;
Expand Down Expand Up @@ -49,7 +46,6 @@ use cubesqlplanner::cube_bridge::{
},
join_definition::{join_definition_bridge_fields_meta, JoinDefinition, NativeJoinDefinition},
join_graph::{join_graph_bridge_fields_meta, JoinGraph, NativeJoinGraph},
join_hints::JoinHintItem,
join_item::{join_item_bridge_fields_meta, JoinItem, NativeJoinItem},
join_item_definition::{
join_item_definition_bridge_fields_meta, JoinItemDefinition, NativeJoinItemDefinition,
Expand All @@ -66,9 +62,6 @@ use cubesqlplanner::cube_bridge::{
NativeMemberExpressionDefinition,
},
member_order_by::{member_order_by_bridge_fields_meta, MemberOrderBy, NativeMemberOrderBy},
member_sql::{
FilterGroupItem, FilterParamsItem, MemberSql, NativeMemberSql, SqlTemplate, SqlTemplateArgs,
},
multi_stage_filter::{
multi_stage_filter_references_bridge_fields_meta, NativeMultiStageFilterReferences,
},
Expand All @@ -79,21 +72,16 @@ use cubesqlplanner::cube_bridge::{
pre_aggregation_description_bridge_fields_meta, NativePreAggregationDescription,
PreAggregationDescription,
},
pre_aggregation_obj::{
pre_aggregation_obj_bridge_fields_meta, NativePreAggregationObj, PreAggregationObj,
},
pre_aggregation_obj::{pre_aggregation_obj_bridge_fields_meta, NativePreAggregationObj},
pre_aggregation_time_dimension::{
pre_aggregation_time_dimension_bridge_fields_meta, NativePreAggregationTimeDimension,
PreAggregationTimeDimension,
},
security_context::{
security_context_bridge_fields_meta, NativeSecurityContext, SecurityContext,
},
security_context::{security_context_bridge_fields_meta, NativeSecurityContext},
segment_definition::{
segment_definition_bridge_fields_meta, NativeSegmentDefinition, SegmentDefinition,
},
sql_templates_render::SqlTemplatesRender,
sql_utils::{sql_utils_bridge_fields_meta, NativeSqlUtils, SqlUtils},
sql_utils::{sql_utils_bridge_fields_meta, NativeSqlUtils},
struct_with_sql_member::{
struct_with_sql_member_bridge_fields_meta, NativeStructWithSqlMember, StructWithSqlMember,
},
Expand All @@ -105,9 +93,7 @@ use cubesqlplanner::cube_bridge::{
},
};
use neon::prelude::*;
use std::any::Any;
use std::collections::HashSet;
use std::rc::Rc;

enum InvokeStatus {
Ok,
Expand Down Expand Up @@ -169,167 +155,6 @@ impl InvokeResult {
}
}

struct StubBaseTools;

fn stub_err(method: &str) -> CubeError {
CubeError::internal(format!(
"StubBaseTools::{} called from bridge test harness — \
this test path requires a real BaseTools implementation",
method
))
}

impl BaseTools for StubBaseTools {
fn as_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
fn driver_tools(&self, _external: bool) -> Result<Rc<dyn DriverTools>, CubeError> {
Err(stub_err("driver_tools"))
}
fn sql_templates(&self) -> Result<Rc<dyn SqlTemplatesRender>, CubeError> {
Err(stub_err("sql_templates"))
}
fn sql_utils_for_rust(&self) -> Result<Rc<dyn SqlUtils>, CubeError> {
Err(stub_err("sql_utils_for_rust"))
}
fn get_allocated_params(&self) -> Result<Vec<String>, CubeError> {
Err(stub_err("get_allocated_params"))
}
fn all_cube_members(&self, _path: String) -> Result<Vec<String>, CubeError> {
Err(stub_err("all_cube_members"))
}
fn interval_and_minimal_time_unit(&self, _interval: String) -> Result<Vec<String>, CubeError> {
Err(stub_err("interval_and_minimal_time_unit"))
}
fn get_pre_aggregation_by_name(
&self,
_cube_name: String,
_name: String,
) -> Result<Rc<dyn PreAggregationObj>, CubeError> {
Err(stub_err("get_pre_aggregation_by_name"))
}
fn pre_aggregation_table_name(
&self,
_cube_name: String,
_name: String,
) -> Result<String, CubeError> {
Err(stub_err("pre_aggregation_table_name"))
}
fn join_tree_for_hints(
&self,
_hints: Vec<JoinHintItem>,
) -> Result<Rc<dyn JoinDefinition>, CubeError> {
Err(stub_err("join_tree_for_hints"))
}
}

fn handles_to_array<IT: InnerTypes>(
items: Vec<NativeObjectHandle<IT>>,
context: NativeContextHolder<IT>,
) -> Result<NativeObjectHandle<IT>, CubeError> {
let arr = context.empty_array()?;
for (i, item) in items.into_iter().enumerate() {
arr.set(i as u32, item)?;
}
Ok(NativeObjectHandle::new(arr.into_object()))
}

fn template_to_native<IT: InnerTypes>(
template: &SqlTemplate,
context: NativeContextHolder<IT>,
) -> Result<NativeObjectHandle<IT>, CubeError> {
match template {
SqlTemplate::String(s) => s.to_native(context),
SqlTemplate::StringVec(strings) => strings.to_native(context),
}
}

fn filter_params_to_native<IT: InnerTypes>(
items: &[FilterParamsItem],
context: NativeContextHolder<IT>,
) -> Result<NativeObjectHandle<IT>, CubeError> {
let serialized = items
.iter()
.map(|itm| itm.to_native(context.clone()))
.collect::<Result<Vec<_>, _>>()?;
handles_to_array(serialized, context)
}

fn filter_group_to_native<IT: InnerTypes>(
group: &FilterGroupItem,
context: NativeContextHolder<IT>,
) -> Result<NativeObjectHandle<IT>, CubeError> {
let result = context.empty_struct()?;
result.set_field(
"filter_params",
filter_params_to_native(&group.filter_params, context.clone())?,
)?;
Ok(NativeObjectHandle::new(result.into_object()))
}

fn args_to_native<IT: InnerTypes>(
args: &SqlTemplateArgs,
context: NativeContextHolder<IT>,
) -> Result<NativeObjectHandle<IT>, CubeError> {
let result = context.empty_struct()?;
result.set_field(
"symbol_paths",
args.symbol_paths.to_native(context.clone())?,
)?;
result.set_field(
"filter_params",
filter_params_to_native(&args.filter_params, context.clone())?,
)?;
let groups = args
.filter_groups
.iter()
.map(|g| filter_group_to_native(g, context.clone()))
.collect::<Result<Vec<_>, _>>()?;
result.set_field("filter_groups", handles_to_array(groups, context.clone())?)?;
let security_context = context.empty_struct()?;
security_context.set_field(
"values",
args.security_context.values.to_native(context.clone())?,
)?;
result.set_field(
"security_context",
NativeObjectHandle::new(security_context.into_object()),
)?;
Ok(NativeObjectHandle::new(result.into_object()))
}

fn compile_member_sql_inner<IT: InnerTypes>(
context_holder: NativeContextHolder<IT>,
js_fn: NativeObjectHandle<IT>,
security_context_obj: NativeObjectHandle<IT>,
) -> Result<NativeObjectHandle<IT>, CubeError> {
let member_sql = NativeMemberSql::try_new(js_fn)?;
let security_context: Rc<dyn SecurityContext> =
Rc::new(NativeSecurityContext::try_new(security_context_obj)?);
let base_tools: Rc<dyn BaseTools> = Rc::new(StubBaseTools);

let (template, args) = member_sql.compile_template_sql(base_tools, security_context)?;

let result = context_holder.empty_struct()?;
result.set_field(
"template",
template_to_native(&template, context_holder.clone())?,
)?;
result.set_field("args", args_to_native(&args, context_holder.clone())?)?;
Ok(NativeObjectHandle::new(result.into_object()))
}

fn compile_member_sql(cx: FunctionContext) -> JsResult<JsValue> {
neon_guarded_funcion_call(
cx,
|context_holder: NativeContextHolder<_>,
js_fn: NativeObjectHandle<_>,
security_context_obj: NativeObjectHandle<_>| {
compile_member_sql_inner(context_holder, js_fn, security_context_obj)
},
)
}

fn parse_args_names_inner<IT: InnerTypes>(
context_holder: NativeContextHolder<IT>,
js_fn: NativeObjectHandle<IT>,
Expand Down Expand Up @@ -824,6 +649,10 @@ fn invoke_base_tools<IT: InnerTypes>(b: &NativeBaseTools<IT>) -> InvokeResult {
b.pre_aggregation_table_name("Orders".to_string(), "main".to_string()),
);
r.record("join_tree_for_hints", b.join_tree_for_hints(vec![]));
r.skip(
"compile_member_sql",
"Rc<dyn MemberSql> argument has no auto-default in Rust",
);
r
}

Expand Down Expand Up @@ -969,7 +798,6 @@ fn rust_box_unwrap(cx: FunctionContext) -> JsResult<JsValue> {
}

pub fn register_module(cx: &mut ModuleContext) -> NeonResult<()> {
cx.export_function("__testBridgeCompileMemberSql", compile_member_sql)?;
cx.export_function("__testBridgeParseArgsNames", parse_args_names)?;
cx.export_function(
"__testBridgeInvokeFilterParamsCallback",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ export const baseToolsFixture = (): unknown => ({
getPreAggregationByName: () => preAggregationObjFixture(),
preAggregationTableName: () => 'pre_aggr_table',
joinTreeForHints: () => joinDefinitionFixture(),
compileMemberSql: () => ({
template: '',
symbolPaths: [],
filterParams: [],
filterGroups: [],
securityContextValues: [],
}),
});

export const baseQueryOptionsFixture = (): unknown => ({
Expand Down
87 changes: 0 additions & 87 deletions packages/cubejs-backend-native/test/bridge/filter-group.test.ts

This file was deleted.

Loading
Loading