Skip to content
Merged
44 changes: 18 additions & 26 deletions packages/cubejs-backend-native/src/node_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::stream::OnDrainHandler;
use crate::tokio_runtime_node;
use crate::transport::NodeBridgeTransport;
use crate::utils::batch_to_rows;
use cubenativeutils::wrappers::neon::context::ContextHolder;
use cubenativeutils::wrappers::neon::context::neon_run_with_guarded_lifetime;
use cubenativeutils::wrappers::neon::inner_types::NeonInnerTypes;
use cubenativeutils::wrappers::neon::object::NeonObject;
use cubenativeutils::wrappers::object_handle::NativeObjectHandle;
Expand Down Expand Up @@ -462,37 +462,29 @@ pub fn setup_logger(mut cx: FunctionContext) -> JsResult<JsUndefined> {
//============ sql planner ===================

fn build_sql_and_params(cx: FunctionContext) -> JsResult<JsValue> {
//IMPORTANT It seems to be safe here, because context lifetime is bound to function, but this
//context should be used only inside function
let mut cx = extend_function_context_lifetime(cx);
let options = cx.argument::<JsValue>(0)?;

let neon_context_holder = ContextHolder::new(cx);

let options = NativeObjectHandle::<NeonInnerTypes<'static, FunctionContext<'static>>>::new(
NeonObject::new(neon_context_holder.clone(), options),
);

let context_holder =
NativeContextHolder::<NeonInnerTypes<'static, FunctionContext<'static>>>::new(
neon_run_with_guarded_lifetime(cx, |neon_context_holder| {
let options =
NativeObjectHandle::<NeonInnerTypes<FunctionContext<'static>>>::new(NeonObject::new(
neon_context_holder.clone(),
neon_context_holder
.with_context(|cx| cx.argument::<JsValue>(0))
.unwrap()?,
));

let context_holder = NativeContextHolder::<NeonInnerTypes<FunctionContext<'static>>>::new(
neon_context_holder,
);

let base_query_options = Rc::new(NativeBaseQueryOptions::from_native(options).unwrap());
let base_query_options = Rc::new(NativeBaseQueryOptions::from_native(options).unwrap());

let base_query = BaseQuery::try_new(context_holder.clone(), base_query_options).unwrap();
let base_query = BaseQuery::try_new(context_holder.clone(), base_query_options).unwrap();

//arg_clrep.into_js(&mut cx)
let res = base_query.build_sql_and_params().unwrap();

let result: NeonObject<'static, FunctionContext<'static>> = res.into_object();
let result = result.into_object();

Ok(result)
}
let res = base_query.build_sql_and_params();

fn extend_function_context_lifetime<'a>(cx: FunctionContext<'a>) -> FunctionContext<'static> {
unsafe { std::mem::transmute::<FunctionContext<'a>, FunctionContext<'static>>(cx) }
let result: NeonObject<FunctionContext<'static>> = res.into_object();
let result = result.into_object();
Ok(result)
})
}

fn debug_js_to_clrepr_to_js(mut cx: FunctionContext) -> JsResult<JsValue> {
Expand Down
20 changes: 19 additions & 1 deletion packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,17 @@ export class BaseQuery {
ungrouped: this.options.ungrouped

};
const res = nativeBuildSqlAndParams(queryParams);
const buildResult = nativeBuildSqlAndParams(queryParams);

if (buildResult.error) {
if (buildResult.error.cause && buildResult.error.cause === 'User') {
throw new UserError(buildResult.error.message);
} else {
throw new Error(buildResult.error.message);
}
}

const res = buildResult.result;
// FIXME
res[1] = [...res[1]];
return res;
Expand Down Expand Up @@ -3332,6 +3342,7 @@ export class BaseQuery {
sort: '{{ expr }} {% if asc %}ASC{% else %}DESC{% endif %} NULLS {% if nulls_first %}FIRST{% else %}LAST{% endif %}',
order_by: '{% if index %} {{ index }} {% else %} {{ expr }} {% endif %} {% if asc %}ASC{% else %}DESC{% endif %}{% if nulls_first %} NULLS FIRST{% endif %}',
cast: 'CAST({{ expr }} AS {{ data_type }})',
cast_to_string: 'CAST({{ expr }} AS TEXT)',
window_function: '{{ fun_call }} OVER ({% if partition_by_concat %}PARTITION BY {{ partition_by_concat }}{% if order_by_concat or window_frame %} {% endif %}{% endif %}{% if order_by_concat %}ORDER BY {{ order_by_concat }}{% if window_frame %} {% endif %}{% endif %}{% if window_frame %}{{ window_frame }}{% endif %})',
window_frame_bounds: '{{ frame_type }} BETWEEN {{ frame_start }} AND {{ frame_end }}',
in_list: '{{ expr }} {% if negated %}NOT {% endif %}IN ({{ in_exprs_concat }})',
Expand All @@ -3348,6 +3359,7 @@ export class BaseQuery {
like: '{{ expr }} {% if negated %}NOT {% endif %}LIKE {{ pattern }}',
ilike: '{{ expr }} {% if negated %}NOT {% endif %}ILIKE {{ pattern }}',
like_escape: '{{ like_expr }} ESCAPE {{ escape_char }}',
concat_strings: '{{ strings | join(\' || \' ) }}',
},
filters: {
equals: '{{ column }} = {{ value }}{{ is_null_check }}',
Expand Down Expand Up @@ -3803,6 +3815,12 @@ export class BaseQuery {
return this.contextSymbolsProxy(this.contextSymbols.securityContext);
}

sqlUtilsForRust() {
return {
convertTz: this.convertTz.bind(this)
};
}

contextSymbolsProxy(symbols) {
return BaseQuery.contextSymbolsProxyFrom(symbols, this.paramAllocator.allocateParam.bind(this.paramAllocator));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,11 @@ export class CubeSymbols {
return Object.assign({
filterParams: this.filtersProxyDep(),
filterGroup: this.filterGroupFunctionDep(),
securityContext: BaseQuery.contextSymbolsProxyFrom({}, (param) => param)
securityContext: BaseQuery.contextSymbolsProxyFrom({}, (param) => param),
sqlUtils: {
convertTz: (f) => f

},
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ describe('SQL Generation', () => {
}
});

it('having filter with operator OR 1', async () => {
it('having filter with operator OR', async () => {
await compiler.compile();

const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
Expand Down Expand Up @@ -648,7 +648,7 @@ describe('SQL Generation', () => {
});
});

it('where filter with operators OR & AND 1', async () => {
it('where filter with operators OR & AND', async () => {
await compiler.compile();

const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -945,8 +945,6 @@ describe('SQL Generation', () => {
timezone: 'America/Los_Angeles'
});

console.log(query.buildSqlAndParams());

expect(query.buildSqlAndParams()[0]).toMatch(/HLL_COUNT\.MERGE/);
expect(query.buildSqlAndParams()[0]).toMatch(/HLL_COUNT\.INIT/);
});
Expand All @@ -971,7 +969,7 @@ describe('SQL Generation', () => {

console.log(query.buildSqlAndParams());

expect(query.buildSqlAndParams()[0]).toMatch(/OFFSET (\d) LIMIT (\d)/);
expect(query.buildSqlAndParams()[0]).toMatch(/OFFSET (\d)\s+LIMIT (\d)/);
});

it('calculated join', async () => {
Expand Down Expand Up @@ -2535,6 +2533,9 @@ describe('SQL Generation', () => {

const sqlBuild = query.buildSqlAndParams();

console.log(sqlBuild[0]);
console.log(sqlBuild[1]);

expect(sqlBuild[0].includes('America/Los_Angeles')).toEqual(true);
expect(sqlBuild[1][0]).toEqual(granularityTest.from);
expect(sqlBuild[1][1]).toEqual(granularityTest.to);
Expand Down
2 changes: 1 addition & 1 deletion rust/cubenativeutils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod wrappers;
pub use cubesql::CubeError;
pub use cubesql::{CubeError, CubeErrorCauseType};
30 changes: 16 additions & 14 deletions rust/cubenativeutils/src/wrappers/context.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use super::{inner_types::InnerTypes, object_handle::NativeObjectHandle};
use cubesql::CubeError;

pub trait NativeContext<IT: InnerTypes>: Clone {
fn boolean(&self, v: bool) -> IT::Boolean;
fn string(&self, v: String) -> IT::String;
fn number(&self, v: f64) -> IT::Number;
fn undefined(&self) -> NativeObjectHandle<IT>;
fn empty_array(&self) -> IT::Array;
fn empty_struct(&self) -> IT::Struct;
fn to_string_fn(&self, result: String) -> IT::Function;
fn boolean(&self, v: bool) -> Result<IT::Boolean, CubeError>;
fn string(&self, v: String) -> Result<IT::String, CubeError>;
fn number(&self, v: f64) -> Result<IT::Number, CubeError>;
fn undefined(&self) -> Result<NativeObjectHandle<IT>, CubeError>;
fn empty_array(&self) -> Result<IT::Array, CubeError>;
fn empty_struct(&self) -> Result<IT::Struct, CubeError>;
//fn boxed<T: 'static>(&self, value: T) -> impl NativeBox<IT, T>;
fn to_string_fn(&self, result: String) -> Result<IT::Function, CubeError>;
}

#[derive(Clone)]
Expand All @@ -22,26 +24,26 @@ impl<IT: InnerTypes> NativeContextHolder<IT> {
pub fn context(&self) -> &impl NativeContext<IT> {
&self.context
}
pub fn boolean(&self, v: bool) -> IT::Boolean {
pub fn boolean(&self, v: bool) -> Result<IT::Boolean, CubeError> {
self.context.boolean(v)
}
pub fn string(&self, v: String) -> IT::String {
pub fn string(&self, v: String) -> Result<IT::String, CubeError> {
self.context.string(v)
}
pub fn number(&self, v: f64) -> IT::Number {
pub fn number(&self, v: f64) -> Result<IT::Number, CubeError> {
self.context.number(v)
}
pub fn undefined(&self) -> NativeObjectHandle<IT> {
pub fn undefined(&self) -> Result<NativeObjectHandle<IT>, CubeError> {
self.context.undefined()
}
pub fn empty_array(&self) -> IT::Array {
pub fn empty_array(&self) -> Result<IT::Array, CubeError> {
self.context.empty_array()
}
pub fn empty_struct(&self) -> IT::Struct {
pub fn empty_struct(&self) -> Result<IT::Struct, CubeError> {
self.context.empty_struct()
}
#[allow(dead_code)]
pub fn to_string_fn(&self, result: String) -> IT::Function {
pub fn to_string_fn(&self, result: String) -> Result<IT::Function, CubeError> {
self.context.to_string_fn(result)
}
}
Loading
Loading