diff --git a/packages/cubejs-backend-native/src/node_export.rs b/packages/cubejs-backend-native/src/node_export.rs index 5d4eb733206c6..802076279c47d 100644 --- a/packages/cubejs-backend-native/src/node_export.rs +++ b/packages/cubejs-backend-native/src/node_export.rs @@ -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; @@ -462,37 +462,29 @@ pub fn setup_logger(mut cx: FunctionContext) -> JsResult { //============ sql planner =================== fn build_sql_and_params(cx: FunctionContext) -> JsResult { - //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::(0)?; - - let neon_context_holder = ContextHolder::new(cx); - - let options = NativeObjectHandle::>>::new( - NeonObject::new(neon_context_holder.clone(), options), - ); - - let context_holder = - NativeContextHolder::>>::new( + neon_run_with_guarded_lifetime(cx, |neon_context_holder| { + let options = + NativeObjectHandle::>>::new(NeonObject::new( + neon_context_holder.clone(), + neon_context_holder + .with_context(|cx| cx.argument::(0)) + .unwrap()?, + )); + + let context_holder = NativeContextHolder::>>::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<'static>>(cx) } + let result: NeonObject> = res.into_object(); + let result = result.into_object(); + Ok(result) + }) } fn debug_js_to_clrepr_to_js(mut cx: FunctionContext) -> JsResult { diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js index d7863713f6b2a..f452d904655ed 100644 --- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js +++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js @@ -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; @@ -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 }})', @@ -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 }}', @@ -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)); } diff --git a/packages/cubejs-schema-compiler/src/compiler/CubeSymbols.js b/packages/cubejs-schema-compiler/src/compiler/CubeSymbols.js index e8c59a8fb2972..0efdc4dcf45a2 100644 --- a/packages/cubejs-schema-compiler/src/compiler/CubeSymbols.js +++ b/packages/cubejs-schema-compiler/src/compiler/CubeSymbols.js @@ -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 + + }, }); } diff --git a/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation-logic.test.ts b/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation-logic.test.ts index c902b7d1faf37..e8d6d6e4b2aac 100644 --- a/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation-logic.test.ts +++ b/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation-logic.test.ts @@ -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 }, { @@ -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 }, { diff --git a/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts b/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts index 03740b7088b68..86184d058e311 100644 --- a/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts +++ b/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts @@ -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/); }); @@ -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 () => { @@ -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); diff --git a/rust/cubenativeutils/src/lib.rs b/rust/cubenativeutils/src/lib.rs index cc20b75017d02..0e6c3b186707d 100644 --- a/rust/cubenativeutils/src/lib.rs +++ b/rust/cubenativeutils/src/lib.rs @@ -1,2 +1,2 @@ pub mod wrappers; -pub use cubesql::CubeError; +pub use cubesql::{CubeError, CubeErrorCauseType}; diff --git a/rust/cubenativeutils/src/wrappers/context.rs b/rust/cubenativeutils/src/wrappers/context.rs index 98bb3ba6f7eb9..9695b30717ec3 100644 --- a/rust/cubenativeutils/src/wrappers/context.rs +++ b/rust/cubenativeutils/src/wrappers/context.rs @@ -1,13 +1,15 @@ use super::{inner_types::InnerTypes, object_handle::NativeObjectHandle}; +use cubesql::CubeError; pub trait NativeContext: 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; - 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; + fn string(&self, v: String) -> Result; + fn number(&self, v: f64) -> Result; + fn undefined(&self) -> Result, CubeError>; + fn empty_array(&self) -> Result; + fn empty_struct(&self) -> Result; + //fn boxed(&self, value: T) -> impl NativeBox; + fn to_string_fn(&self, result: String) -> Result; } #[derive(Clone)] @@ -22,26 +24,26 @@ impl NativeContextHolder { pub fn context(&self) -> &impl NativeContext { &self.context } - pub fn boolean(&self, v: bool) -> IT::Boolean { + pub fn boolean(&self, v: bool) -> Result { self.context.boolean(v) } - pub fn string(&self, v: String) -> IT::String { + pub fn string(&self, v: String) -> Result { self.context.string(v) } - pub fn number(&self, v: f64) -> IT::Number { + pub fn number(&self, v: f64) -> Result { self.context.number(v) } - pub fn undefined(&self) -> NativeObjectHandle { + pub fn undefined(&self) -> Result, CubeError> { self.context.undefined() } - pub fn empty_array(&self) -> IT::Array { + pub fn empty_array(&self) -> Result { self.context.empty_array() } - pub fn empty_struct(&self) -> IT::Struct { + pub fn empty_struct(&self) -> Result { 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 { self.context.to_string_fn(result) } } diff --git a/rust/cubenativeutils/src/wrappers/neon/context.rs b/rust/cubenativeutils/src/wrappers/neon/context.rs index 96950e5e3aedb..cc5139110f393 100644 --- a/rust/cubenativeutils/src/wrappers/neon/context.rs +++ b/rust/cubenativeutils/src/wrappers/neon/context.rs @@ -1,4 +1,3 @@ -//use super::object::NeonObject; use super::{ inner_types::NeonInnerTypes, object::{ @@ -12,21 +11,31 @@ use crate::wrappers::{ use cubesql::CubeError; use neon::prelude::*; use std::{ - cell::{RefCell, RefMut}, + cell::RefCell, marker::PhantomData, + panic::{catch_unwind, resume_unwind, AssertUnwindSafe}, rc::{Rc, Weak}, }; -pub struct ContextWrapper<'cx, C: Context<'cx>> { + +pub trait NoenContextLifetimeExpand<'cx> { + type ExpandedResult: Context<'static>; + fn expand_lifetime(self) -> Self::ExpandedResult; +} + +impl<'cx> NoenContextLifetimeExpand<'cx> for FunctionContext<'cx> { + type ExpandedResult = FunctionContext<'static>; + fn expand_lifetime(self) -> Self::ExpandedResult { + unsafe { std::mem::transmute::, FunctionContext<'static>>(self) } + } +} + +pub struct ContextWrapper> { cx: C, - lifetime: PhantomData<&'cx ()>, } -impl<'cx, C: Context<'cx>> ContextWrapper<'cx, C> { +impl> ContextWrapper { pub fn new(cx: C) -> Rc> { - Rc::new(RefCell::new(Self { - cx, - lifetime: Default::default(), - })) + Rc::new(RefCell::new(Self { cx })) } pub fn with_context(&mut self, f: F) -> T @@ -41,129 +50,129 @@ impl<'cx, C: Context<'cx>> ContextWrapper<'cx, C> { } } -pub struct ContextHolder<'cx, C: Context<'cx>> { - context: Rc>>, +pub struct NeonContextGuard<'cx, C: Context<'cx> + NoenContextLifetimeExpand<'cx>> { + context: Rc>>, + lifetime: PhantomData<&'cx ()>, } -impl<'cx, C: Context<'cx> + 'cx> ContextHolder<'cx, C> { - pub fn new(cx: C) -> Self { +impl<'cx, C: Context<'cx> + NoenContextLifetimeExpand<'cx> + 'cx> NeonContextGuard<'cx, C> { + fn new(cx: C) -> Self { Self { - context: ContextWrapper::new(cx), + context: ContextWrapper::new(cx.expand_lifetime()), + lifetime: PhantomData::default(), } } - pub fn borrow_mut(&self) -> RefMut> { - self.context.borrow_mut() + fn context_holder(&self) -> ContextHolder { + ContextHolder::new(Rc::downgrade(&self.context)) } - pub fn with_context(&self, f: F) -> T - where - F: FnOnce(&mut C) -> T, - { - let mut context = self.context.borrow_mut(); - context.with_context(f) + fn unwrap(self) { + if Rc::strong_count(&self.context) > 0 { + match Rc::try_unwrap(self.context) { + Ok(_) => {} + Err(_) => panic!("Guarded context have more then one reference"), + } + } + } +} + +pub fn neon_run_with_guarded_lifetime<'cx, C, T, F>(cx: C, func: F) -> T +where + C: Context<'cx> + NoenContextLifetimeExpand<'cx> + 'cx, + F: FnOnce(ContextHolder) -> T, +{ + let guard = NeonContextGuard::new(cx); + let context_holder = guard.context_holder(); + let res = catch_unwind(AssertUnwindSafe(|| func(context_holder))); + guard.unwrap(); + + match res { + Ok(res) => res, + Err(e) => resume_unwind(e), } +} + +pub struct ContextHolder> { + context: Weak>>, +} - /* pub fn as_native_context_holder(&self) -> NativeContextHolder { - NativeContextHolder::new(Box::new(self.clone())) - } */ +impl> ContextHolder { + fn new(context: Weak>>) -> Self { + Self { context } + } - pub fn weak(&self) -> WeakContextHolder<'cx, C> { - WeakContextHolder { - context: Rc::downgrade(&self.context), + pub fn with_context(&self, f: F) -> Result + where + F: FnOnce(&mut C) -> T, + { + if let Some(context) = self.context.upgrade() { + let mut cx = context.borrow_mut(); + let res = cx.with_context(f); + Ok(res) + } else { + Err(CubeError::internal(format!( + "Call to neon context outside of its lifetime" + ))) } } } -impl<'cx, C: Context<'cx> + 'cx> NativeContext> for ContextHolder<'cx, C> { - fn boolean(&self, v: bool) -> NeonBoolean<'cx, C> { - let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.boolean(v).upcast())); - obj.into_boolean().unwrap() +impl + 'static> NativeContext> for ContextHolder { + fn boolean(&self, v: bool) -> Result, CubeError> { + let obj = NeonObject::new( + self.clone(), + self.with_context(|cx| cx.boolean(v).upcast())?, + ); + obj.into_boolean() } - fn string(&self, v: String) -> NeonString<'cx, C> { - let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.string(v).upcast())); - obj.into_string().unwrap() + fn string(&self, v: String) -> Result, CubeError> { + let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.string(v).upcast())?); + obj.into_string() } - fn number(&self, v: f64) -> NeonNumber<'cx, C> { - let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.number(v).upcast())); - obj.into_number().unwrap() + fn number(&self, v: f64) -> Result, CubeError> { + let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.number(v).upcast())?); + obj.into_number() } - fn undefined(&self) -> NativeObjectHandle> { - NativeObjectHandle::new(NeonObject::new( + fn undefined(&self) -> Result>, CubeError> { + Ok(NativeObjectHandle::new(NeonObject::new( self.clone(), - self.with_context(|cx| cx.undefined().upcast()), - )) + self.with_context(|cx| cx.undefined().upcast())?, + ))) } - fn empty_array(&self) -> NeonArray<'cx, C> { + fn empty_array(&self) -> Result, CubeError> { let obj = NeonObject::new( self.clone(), - self.with_context(|cx| cx.empty_array().upcast()), + self.with_context(|cx| cx.empty_array().upcast())?, ); - obj.into_array().unwrap() + obj.into_array() } - fn empty_struct(&self) -> NeonStruct<'cx, C> { + fn empty_struct(&self) -> Result, CubeError> { let obj = NeonObject::new( self.clone(), - self.with_context(|cx| cx.empty_object().upcast()), + self.with_context(|cx| cx.empty_object().upcast())?, ); - obj.into_struct().unwrap() + obj.into_struct() } - fn to_string_fn(&self, result: String) -> NeonFunction<'cx, C> { + fn to_string_fn(&self, result: String) -> Result, CubeError> { let obj = NeonObject::new( self.clone(), self.with_context(|cx| { JsFunction::new(cx, move |mut c| Ok(c.string(result.clone()))) .unwrap() .upcast() - }), + })?, ); - obj.into_function().unwrap() - } -} - -impl<'cx, C: Context<'cx>> Clone for ContextHolder<'cx, C> { - fn clone(&self) -> Self { - Self { - context: self.context.clone(), - } - } -} - -pub struct WeakContextHolder<'cx, C: Context<'cx>> { - context: Weak>>, -} - -impl<'cx, C: Context<'cx>> WeakContextHolder<'cx, C> { - pub fn try_upgrade<'a>(&'a self) -> Result, CubeError> - where - 'a: 'cx, - { - if let Some(context) = self.context.upgrade() { - Ok(ContextHolder { context }) - } else { - Err(CubeError::internal(format!("Neon context is not alive"))) - } - } - pub fn with_context(&self, f: F) -> Result - where - F: FnOnce(&mut C) -> T, - { - if let Some(context) = self.context.upgrade() { - let mut cx = context.borrow_mut(); - let res = cx.with_context(f); - Ok(res) - } else { - Err(CubeError::internal(format!("Neon context is not alive"))) - } + obj.into_function() } } -impl<'cx, C: Context<'cx>> Clone for WeakContextHolder<'cx, C> { +impl> Clone for ContextHolder { fn clone(&self) -> Self { Self { context: self.context.clone(), diff --git a/rust/cubenativeutils/src/wrappers/neon/inner_types.rs b/rust/cubenativeutils/src/wrappers/neon/inner_types.rs index 8bf32d0be843e..5da5dca397de4 100644 --- a/rust/cubenativeutils/src/wrappers/neon/inner_types.rs +++ b/rust/cubenativeutils/src/wrappers/neon/inner_types.rs @@ -9,25 +9,25 @@ use crate::wrappers::inner_types::InnerTypes; use neon::prelude::*; use std::marker::PhantomData; -pub struct NeonInnerTypes<'cx: 'static, C: Context<'cx>> { - lifetime: PhantomData<&'cx ContextHolder<'cx, C>>, +pub struct NeonInnerTypes> { + marker: PhantomData>, } -impl<'cx, C: Context<'cx>> Clone for NeonInnerTypes<'cx, C> { +impl> Clone for NeonInnerTypes { fn clone(&self) -> Self { Self { - lifetime: Default::default(), + marker: Default::default(), } } } -impl<'cx: 'static, C: Context<'cx>> InnerTypes for NeonInnerTypes<'cx, C> { - type Object = NeonObject<'cx, C>; - type Context = ContextHolder<'cx, C>; - type Array = NeonArray<'cx, C>; - type Struct = NeonStruct<'cx, C>; - type String = NeonString<'cx, C>; - type Boolean = NeonBoolean<'cx, C>; - type Function = NeonFunction<'cx, C>; - type Number = NeonNumber<'cx, C>; +impl + 'static> InnerTypes for NeonInnerTypes { + type Object = NeonObject; + type Context = ContextHolder; + type Array = NeonArray; + type Struct = NeonStruct; + type String = NeonString; + type Boolean = NeonBoolean; + type Function = NeonFunction; + type Number = NeonNumber; } diff --git a/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs b/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs index 26e58fc21f982..54d1a7de02285 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs @@ -1,75 +1,103 @@ -use super::NeonObject; +use super::{NeonObject, NeonTypeHandle}; use crate::wrappers::neon::inner_types::NeonInnerTypes; +use std::marker::PhantomData; -use crate::wrappers::object::{NativeBoolean, NativeNumber, NativeString, NativeType}; +use crate::wrappers::object::{NativeBoolean, NativeBox, NativeNumber, NativeString, NativeType}; use cubesql::CubeError; use neon::prelude::*; +use std::ops::Deref; -pub struct NeonString<'cx: 'static, C: Context<'cx>> { - object: NeonObject<'cx, C>, +pub struct NeonString> { + object: NeonTypeHandle, } -impl<'cx, C: Context<'cx>> NeonString<'cx, C> { - pub fn new(object: NeonObject<'cx, C>) -> Self { +impl> NeonString { + pub fn new(object: NeonTypeHandle) -> Self { Self { object } } } -impl<'cx, C: Context<'cx> + 'cx> NativeType> for NeonString<'cx, C> { - fn into_object(self) -> NeonObject<'cx, C> { - self.object +impl + 'static> NativeType> for NeonString { + fn into_object(self) -> NeonObject { + self.object.upcast() } } -impl<'cx, C: Context<'cx> + 'cx> NativeString> for NeonString<'cx, C> { +impl + 'static> NativeString> for NeonString { fn value(&self) -> Result { self.object - .map_downcast_neon_object::(|cx, object| Ok(object.value(cx))) + .map_neon_object::<_, _>(|cx, object| Ok(object.value(cx)))? } } -pub struct NeonNumber<'cx: 'static, C: Context<'cx>> { - object: NeonObject<'cx, C>, +pub struct NeonNumber> { + object: NeonTypeHandle, } -impl<'cx, C: Context<'cx>> NeonNumber<'cx, C> { - pub fn new(object: NeonObject<'cx, C>) -> Self { +impl> NeonNumber { + pub fn new(object: NeonTypeHandle) -> Self { Self { object } } } -impl<'cx, C: Context<'cx> + 'cx> NativeType> for NeonNumber<'cx, C> { - fn into_object(self) -> NeonObject<'cx, C> { - self.object +impl + 'static> NativeType> for NeonNumber { + fn into_object(self) -> NeonObject { + self.object.upcast() } } -impl<'cx, C: Context<'cx> + 'cx> NativeNumber> for NeonNumber<'cx, C> { +impl + 'static> NativeNumber> for NeonNumber { fn value(&self) -> Result { self.object - .map_downcast_neon_object::(|cx, object| Ok(object.value(cx))) + .map_neon_object::<_, _>(|cx, object| Ok(object.value(cx)))? } } -pub struct NeonBoolean<'cx: 'static, C: Context<'cx>> { - object: NeonObject<'cx, C>, +pub struct NeonBoolean> { + object: NeonTypeHandle, } -impl<'cx, C: Context<'cx>> NeonBoolean<'cx, C> { - pub fn new(object: NeonObject<'cx, C>) -> Self { +impl> NeonBoolean { + pub fn new(object: NeonTypeHandle) -> Self { Self { object } } } -impl<'cx, C: Context<'cx> + 'cx> NativeType> for NeonBoolean<'cx, C> { - fn into_object(self) -> NeonObject<'cx, C> { - self.object +impl + 'static> NativeType> for NeonBoolean { + fn into_object(self) -> NeonObject { + self.object.upcast() } } -impl<'cx, C: Context<'cx> + 'cx> NativeBoolean> for NeonBoolean<'cx, C> { +impl + 'static> NativeBoolean> for NeonBoolean { fn value(&self) -> Result { self.object - .map_downcast_neon_object::(|cx, object| Ok(object.value(cx))) + .map_neon_object::<_, _>(|cx, object| Ok(object.value(cx)))? + } +} + +pub struct NeonBox, T: 'static> { + object: NeonTypeHandle>, + _marker: PhantomData, +} + +impl, T: 'static> NeonBox { + pub fn new(object: NeonTypeHandle>) -> Self { + Self { + object, + _marker: PhantomData::default(), + } + } +} + +impl + 'static, T: 'static> NativeType> for NeonBox { + fn into_object(self) -> NeonObject { + self.object.upcast() + } +} + +impl + 'static, T: 'static> NativeBox, T> for NeonBox { + fn deref_value(&self) -> &T { + self.object.get_object_ref().deref() } } diff --git a/rust/cubenativeutils/src/wrappers/neon/object/mod.rs b/rust/cubenativeutils/src/wrappers/neon/object/mod.rs index 40763a228b97d..54b28d10684b5 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/mod.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/mod.rs @@ -14,37 +14,46 @@ use crate::wrappers::{neon::context::ContextHolder, object::NativeObject}; use cubesql::CubeError; use neon::prelude::*; -pub struct NeonObject<'cx: 'static, C: Context<'cx>> { - context: ContextHolder<'cx, C>, - object: Handle<'cx, JsValue>, +pub struct NeonTypeHandle, V: Value + 'static> { + context: ContextHolder, + object: Handle<'static, V>, } -impl<'cx: 'static, C: Context<'cx> + 'cx> NeonObject<'cx, C> { - pub fn new(context: ContextHolder<'cx, C>, object: Handle<'cx, JsValue>) -> Self { +impl + 'static, V: Value + 'static> NeonTypeHandle { + pub fn new(context: ContextHolder, object: Handle<'static, V>) -> Self { Self { context, object } } - pub fn get_object(&self) -> Handle<'cx, JsValue> { + fn get_context(&self) -> ContextHolder { + self.context.clone() + } + + pub fn get_object(&self) -> Handle<'static, V> { self.object.clone() } - pub fn get_object_ref(&self) -> &Handle<'cx, JsValue> { + pub fn get_object_ref(&self) -> &Handle<'static, V> { &self.object } - pub fn into_object(self) -> Handle<'cx, JsValue> { + pub fn into_object(self) -> Handle<'static, V> { self.object } - pub fn map_neon_object(&self, f: F) -> T + pub fn upcast(&self) -> NeonObject { + NeonObject::new(self.context.clone(), self.object.upcast()) + } + + pub fn map_neon_object(&self, f: F) -> Result where - F: FnOnce(&mut C, &Handle<'cx, JsValue>) -> T, + F: FnOnce(&mut C, &Handle<'static, V>) -> T, { self.context.with_context(|cx| f(cx, &self.object)) } + pub fn map_downcast_neon_object(&self, f: F) -> Result where - F: FnOnce(&mut C, &Handle<'cx, JT>) -> Result, + F: FnOnce(&mut C, &Handle<'static, JT>) -> Result, { self.context.with_context(|cx| { let obj = self @@ -52,80 +61,111 @@ impl<'cx: 'static, C: Context<'cx> + 'cx> NeonObject<'cx, C> { .downcast::(cx) .map_err(|_| CubeError::internal("Downcast error".to_string()))?; f(cx, &obj) - }) + })? + } + + pub fn is_a(&self) -> Result { + self.context.with_context(|cx| self.object.is_a::(cx)) + } +} + +impl, V: Value + 'static> Clone for NeonTypeHandle { + fn clone(&self) -> Self { + Self { + context: self.context.clone(), + object: self.object.clone(), + } + } +} + +pub struct NeonObject> { + context: ContextHolder, + object: Handle<'static, JsValue>, +} + +impl + 'static> NeonObject { + pub fn new(context: ContextHolder, object: Handle<'static, JsValue>) -> Self { + Self { context, object } + } + + pub fn get_object(&self) -> Handle<'static, JsValue> { + self.object.clone() + } + + pub fn get_object_ref(&self) -> &Handle<'static, JsValue> { + &self.object + } + + pub fn into_object(self) -> Handle<'static, JsValue> { + self.object } - pub fn is_a(&self) -> bool { + pub fn is_a(&self) -> Result { self.context.with_context(|cx| self.object.is_a::(cx)) } + + pub fn downcast(&self) -> Result, CubeError> { + let obj = self.context.with_context(|cx| { + self.object + .downcast::(cx) + .map_err(|_| CubeError::internal("Downcast error".to_string())) + })??; + Ok(NeonTypeHandle::new(self.context.clone(), obj)) + } + + pub fn downcast_with_err_msg( + &self, + msg: &str, + ) -> Result, CubeError> { + let obj = self.context.with_context(|cx| { + self.object + .downcast::(cx) + .map_err(|_| CubeError::internal(msg.to_string())) + })??; + Ok(NeonTypeHandle::new(self.context.clone(), obj)) + } } -impl<'cx: 'static, C: Context<'cx> + 'cx> NativeObject> - for NeonObject<'cx, C> -{ - fn get_context(&self) -> ContextHolder<'cx, C> { +impl + 'static> NativeObject> for NeonObject { + fn get_context(&self) -> ContextHolder { self.context.clone() } - fn into_struct(self) -> Result, CubeError> { - if !self.is_a::() { - return Err(CubeError::internal(format!( - "NeonObject is not the JsObject" - ))); - } - Ok(NeonStruct::new(self)) + fn into_struct(self) -> Result, CubeError> { + let obj = self.downcast_with_err_msg::("NeonObject is not the JsObject")?; + Ok(NeonStruct::new(obj)) } - fn into_function(self) -> Result, CubeError> { - if !self.is_a::() { - return Err(CubeError::internal(format!( - "NeonObject is not the JsFunction" - ))); - } - Ok(NeonFunction::new(self)) + fn into_function(self) -> Result, CubeError> { + let obj = self.downcast_with_err_msg::("NeonObject is not the JsArray")?; + Ok(NeonFunction::new(obj)) } - fn into_array(self) -> Result, CubeError> { - if !self.is_a::() { - return Err(CubeError::internal(format!( - "NeonObject is not the JsArray" - ))); - } - Ok(NeonArray::new(self)) + fn into_array(self) -> Result, CubeError> { + let obj = self.downcast_with_err_msg::("NeonObject is not the JsArray")?; + Ok(NeonArray::new(obj)) } - fn into_string(self) -> Result, CubeError> { - if !self.is_a::() { - return Err(CubeError::internal(format!( - "NeonObject is not the JsString" - ))); - } - Ok(NeonString::new(self)) + fn into_string(self) -> Result, CubeError> { + let obj = self.downcast_with_err_msg::("NeonObject is not the JsString")?; + Ok(NeonString::new(obj)) } - fn into_number(self) -> Result, CubeError> { - if !self.is_a::() { - return Err(CubeError::internal(format!( - "NeonObject is not the JsNumber" - ))); - } - Ok(NeonNumber::new(self)) + fn into_number(self) -> Result, CubeError> { + let obj = self.downcast_with_err_msg::("NeonObject is not the JsNumber")?; + Ok(NeonNumber::new(obj)) } - fn into_boolean(self) -> Result, CubeError> { - if !self.is_a::() { - return Err(CubeError::internal(format!( - "NeonObject is not the JsBoolean" - ))); - } - Ok(NeonBoolean::::new(self)) + fn into_boolean(self) -> Result, CubeError> { + let obj = self.downcast_with_err_msg::("NeonObject is not the JsBoolean")?; + Ok(NeonBoolean::new(obj)) } - fn is_null(&self) -> bool { + fn is_null(&self) -> Result { self.is_a::() } - fn is_undefined(&self) -> bool { + fn is_undefined(&self) -> Result { self.is_a::() } } -impl<'cx: 'static, C: Context<'cx>> Clone for NeonObject<'cx, C> { +impl> Clone for NeonObject { fn clone(&self) -> Self { Self { context: self.context.clone(), diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs index dc06714227c61..08dea2a0c1ee0 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs @@ -1,46 +1,40 @@ -use super::NeonObject; +use super::{NeonObject, NeonTypeHandle}; use crate::wrappers::{ neon::inner_types::NeonInnerTypes, - object::{NativeArray, NativeObject, NativeType}, + object::{NativeArray, NativeType}, object_handle::NativeObjectHandle, }; use cubesql::CubeError; use neon::prelude::*; #[derive(Clone)] -pub struct NeonArray<'cx: 'static, C: Context<'cx>> { - object: NeonObject<'cx, C>, +pub struct NeonArray> { + object: NeonTypeHandle, } -/* impl> InnerTyped for NeonArray { - type Inner = NeonObject; -} */ - -impl<'cx, C: Context<'cx> + 'cx> NeonArray<'cx, C> { - pub fn new(object: NeonObject<'cx, C>) -> Self { +impl + 'static> NeonArray { + pub fn new(object: NeonTypeHandle) -> Self { Self { object } } } -impl<'cx, C: Context<'cx> + 'cx> NativeType> for NeonArray<'cx, C> { - fn into_object(self) -> NeonObject<'cx, C> { - self.object +impl + 'static> NativeType> for NeonArray { + fn into_object(self) -> NeonObject { + self.object.upcast() } } -impl<'cx, C: Context<'cx> + 'cx> NativeArray> for NeonArray<'cx, C> { +impl + 'static> NativeArray> for NeonArray { fn len(&self) -> Result { self.object - .map_downcast_neon_object::(|cx, object| Ok(object.len(cx))) + .map_neon_object::<_, _>(|cx, object| Ok(object.len(cx)))? } - fn to_vec(&self) -> Result>>, CubeError> { - let neon_vec = self - .object - .map_downcast_neon_object::(|cx, object| { - object - .to_vec(cx) - .map_err(|_| CubeError::internal("Error converting JsArray to Vec".to_string())) - })?; + fn to_vec(&self) -> Result>>, CubeError> { + let neon_vec = self.object.map_neon_object::<_, _>(|cx, object| { + object + .to_vec(cx) + .map_err(|_| CubeError::internal("Error converting JsArray to Vec".to_string())) + })??; Ok(neon_vec .into_iter() @@ -50,24 +44,21 @@ impl<'cx, C: Context<'cx> + 'cx> NativeArray> for NeonArr fn set( &self, index: u32, - value: NativeObjectHandle>, + value: NativeObjectHandle>, ) -> Result { let value = value.into_object().into_object(); - self.object - .map_downcast_neon_object::(|cx, object| { - object - .set(cx, index, value) - .map_err(|_| CubeError::internal(format!("Error setting index {}", index))) - }) + self.object.map_neon_object::<_, _>(|cx, object| { + object + .set(cx, index, value) + .map_err(|_| CubeError::internal(format!("Error setting index {}", index))) + })? } - fn get(&self, index: u32) -> Result>, CubeError> { - let r = self - .object - .map_downcast_neon_object::(|cx, object| { - object - .get(cx, index) - .map_err(|_| CubeError::internal(format!("Error setting index {}", index))) - })?; + fn get(&self, index: u32) -> Result>, CubeError> { + let r = self.object.map_neon_object::<_, _>(|cx, object| { + object + .get(cx, index) + .map_err(|_| CubeError::internal(format!("Error setting index {}", index))) + })??; Ok(NativeObjectHandle::new(NeonObject::new( self.object.get_context(), r, diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs index c8fc68d372d50..192db172e1c8a 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs @@ -1,4 +1,4 @@ -use super::NeonObject; +use super::{NeonObject, NeonTypeHandle}; use crate::wrappers::{ neon::inner_types::NeonInnerTypes, object::{NativeFunction, NativeType}, @@ -10,39 +10,37 @@ use neon::prelude::*; use regex::Regex; #[derive(Clone)] -pub struct NeonFunction<'cx: 'static, C: Context<'cx>> { - object: NeonObject<'cx, C>, +pub struct NeonFunction> { + object: NeonTypeHandle, } -impl<'cx, C: Context<'cx> + 'cx> NeonFunction<'cx, C> { - pub fn new(object: NeonObject<'cx, C>) -> Self { +impl + 'static> NeonFunction { + pub fn new(object: NeonTypeHandle) -> Self { Self { object } } } -impl<'cx, C: Context<'cx> + 'cx> NativeType> for NeonFunction<'cx, C> { - fn into_object(self) -> NeonObject<'cx, C> { - self.object +impl + 'static> NativeType> for NeonFunction { + fn into_object(self) -> NeonObject { + self.object.upcast() } } -impl<'cx, C: Context<'cx> + 'cx> NativeFunction> for NeonFunction<'cx, C> { +impl + 'static> NativeFunction> for NeonFunction { fn call( &self, - args: Vec>>, - ) -> Result>, CubeError> { + args: Vec>>, + ) -> Result>, CubeError> { let neon_args = args .into_iter() .map(|arg| -> Result<_, CubeError> { Ok(arg.into_object().get_object()) }) .collect::, _>>()?; let neon_reuslt = self.object.map_neon_object(|cx, neon_object| { - let this = neon_object - .downcast::(cx) - .map_err(|_| CubeError::internal(format!("Neon object is not JsFunction")))?; let null = cx.null(); - this.call(cx, null, neon_args) + neon_object + .call(cx, null, neon_args) .map_err(|_| CubeError::internal(format!("Failed to call function "))) - })?; + })??; Ok(NativeObjectHandle::new(NeonObject::new( self.object.context.clone(), neon_reuslt, @@ -53,17 +51,14 @@ impl<'cx, C: Context<'cx> + 'cx> NativeFunction> for Neon let result = self.object .map_neon_object(|cx, neon_object| -> Result { - let this = neon_object.downcast::(cx).map_err(|_| { - CubeError::internal(format!("Neon object is not JsFunction")) - })?; - let res = this + let res = neon_object .to_string(cx) .map_err(|_| { CubeError::internal(format!("Can't convert function to string")) })? .value(cx); Ok(res) - })?; + })??; Ok(result) } diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs index 693c19aeb1da3..3d41ef9dbe5ff 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs @@ -1,4 +1,4 @@ -use super::NeonObject; +use super::{NeonObject, NeonTypeHandle}; use crate::wrappers::{ neon::inner_types::NeonInnerTypes, object::{NativeStruct, NativeType}, @@ -8,34 +8,32 @@ use cubesql::CubeError; use neon::prelude::*; #[derive(Clone)] -pub struct NeonStruct<'cx: 'static, C: Context<'cx>> { - object: NeonObject<'cx, C>, +pub struct NeonStruct> { + object: NeonTypeHandle, } -impl<'cx, C: Context<'cx> + 'cx> NeonStruct<'cx, C> { - pub fn new(object: NeonObject<'cx, C>) -> Self { +impl + 'static> NeonStruct { + pub fn new(object: NeonTypeHandle) -> Self { Self { object } } } -impl<'cx, C: Context<'cx> + 'cx> NativeType> for NeonStruct<'cx, C> { - fn into_object(self) -> NeonObject<'cx, C> { - self.object +impl + 'static> NativeType> for NeonStruct { + fn into_object(self) -> NeonObject { + self.object.upcast() } } -impl<'cx, C: Context<'cx> + 'cx> NativeStruct> for NeonStruct<'cx, C> { +impl + 'static> NativeStruct> for NeonStruct { fn get_field( &self, field_name: &str, - ) -> Result>, CubeError> { + ) -> Result>, CubeError> { let neon_result = self.object.map_neon_object(|cx, neon_object| { - let this = neon_object - .downcast::(cx) - .map_err(|_| CubeError::internal(format!("Neon object is not JsObject")))?; - this.get::(cx, field_name) + neon_object + .get::(cx, field_name) .map_err(|_| CubeError::internal(format!("Field `{}` not found", field_name))) - })?; + })??; Ok(NativeObjectHandle::new(NeonObject::new( self.object.context.clone(), neon_result, @@ -43,54 +41,47 @@ impl<'cx, C: Context<'cx> + 'cx> NativeStruct> for NeonSt } fn has_field(&self, field_name: &str) -> Result { - let result = self - .object - .map_neon_object(|cx, neon_object| -> Result { - let this = neon_object - .downcast::(cx) - .map_err(|_| CubeError::internal(format!("Neon object is not JsObject")))?; - let res = this - .get_opt::(cx, field_name) - .map_err(|_| { - CubeError::internal(format!( - "Error while getting field `{}` not found", - field_name - )) - })? - .is_some(); - Ok(res) - })?; + let result = + self.object + .map_neon_object(|cx, neon_object| -> Result { + let res = neon_object + .get_opt::(cx, field_name) + .map_err(|_| { + CubeError::internal(format!( + "Error while getting field `{}` not found", + field_name + )) + })? + .is_some(); + Ok(res) + })??; Ok(result) } fn set_field( &self, field_name: &str, - value: NativeObjectHandle>, + value: NativeObjectHandle>, ) -> Result { let value = value.into_object().into_object(); - self.object - .map_downcast_neon_object::(|cx, object| { - object - .set(cx, field_name, value) - .map_err(|_| CubeError::internal(format!("Error setting field {}", field_name))) - }) + self.object.map_neon_object::<_, _>(|cx, object| { + object + .set(cx, field_name, value) + .map_err(|_| CubeError::internal(format!("Error setting field {}", field_name))) + })? } fn get_own_property_names( &self, - ) -> Result>>, CubeError> { + ) -> Result>>, CubeError> { let neon_array = self.object.map_neon_object(|cx, neon_object| { - let this = neon_object - .downcast::(cx) - .map_err(|_| CubeError::internal(format!("Neon object is not JsObject")))?; - let neon_array = this + let neon_array = neon_object .get_own_property_names(cx) .map_err(|_| CubeError::internal(format!("Cannot get own properties not found")))?; neon_array .to_vec(cx) .map_err(|_| CubeError::internal(format!("Failed to convert array"))) - })?; + })??; Ok(neon_array .into_iter() .map(|o| NativeObjectHandle::new(NeonObject::new(self.object.context.clone(), o))) @@ -99,27 +90,26 @@ impl<'cx, C: Context<'cx> + 'cx> NativeStruct> for NeonSt fn call_method( &self, method: &str, - args: Vec>>, - ) -> Result>, CubeError> { + args: Vec>>, + ) -> Result>, CubeError> { let neon_args = args .into_iter() .map(|arg| -> Result<_, CubeError> { Ok(arg.into_object().get_object()) }) .collect::, _>>()?; let neon_reuslt = self.object.map_neon_object(|cx, neon_object| { - let this = neon_object - .downcast::(cx) - .map_err(|_| CubeError::internal(format!("Neon object is not JsObject")))?; - let neon_method = this + let neon_method = neon_object .get::(cx, method) .map_err(|_| CubeError::internal(format!("Method `{}` not found", method)))?; - neon_method.call(cx, this, neon_args).map_err(|err| { - CubeError::internal(format!( - "Failed to call method `{} {} {:?}", - method, err, err - )) - }) - })?; + neon_method + .call(cx, neon_object.clone(), neon_args) + .map_err(|err| { + CubeError::internal(format!( + "Failed to call method `{} {} {:?}", + method, err, err + )) + }) + })??; Ok(NativeObjectHandle::new(NeonObject::new( self.object.context.clone(), neon_reuslt, diff --git a/rust/cubenativeutils/src/wrappers/object.rs b/rust/cubenativeutils/src/wrappers/object.rs index bee3275ea3aac..401a0b35c2651 100644 --- a/rust/cubenativeutils/src/wrappers/object.rs +++ b/rust/cubenativeutils/src/wrappers/object.rs @@ -10,8 +10,8 @@ pub trait NativeObject: Clone { fn into_number(self) -> Result; fn into_boolean(self) -> Result; fn into_function(self) -> Result; - fn is_null(&self) -> bool; - fn is_undefined(&self) -> bool; + fn is_null(&self) -> Result; + fn is_undefined(&self) -> Result; } pub trait NativeType { @@ -56,3 +56,7 @@ pub trait NativeNumber: NativeType { pub trait NativeBoolean: NativeType { fn value(&self) -> Result; } + +pub trait NativeBox: NativeType { + fn deref_value(&self) -> &T; +} diff --git a/rust/cubenativeutils/src/wrappers/object_handle.rs b/rust/cubenativeutils/src/wrappers/object_handle.rs index 501c16e356be8..93429cacbc117 100644 --- a/rust/cubenativeutils/src/wrappers/object_handle.rs +++ b/rust/cubenativeutils/src/wrappers/object_handle.rs @@ -55,13 +55,12 @@ impl NativeObjectHandle { pub fn to_boolean(&self) -> Result { self.object.clone().into_boolean() } - pub fn is_null(&self) -> bool { + pub fn is_null(&self) -> Result { self.object.is_null() } - pub fn is_undefined(&self) -> bool { + pub fn is_undefined(&self) -> Result { self.object.is_undefined() } - pub fn get_context(&self) -> IT::Context { self.object.get_context() } diff --git a/rust/cubenativeutils/src/wrappers/serializer/deserializer.rs b/rust/cubenativeutils/src/wrappers/serializer/deserializer.rs index 9f3cc78582723..ff85659831fa6 100644 --- a/rust/cubenativeutils/src/wrappers/serializer/deserializer.rs +++ b/rust/cubenativeutils/src/wrappers/serializer/deserializer.rs @@ -33,7 +33,7 @@ impl<'de, IT: InnerTypes> Deserializer<'de> for NativeSerdeDeserializer { where V: Visitor<'de>, { - if self.input.is_null() || self.input.is_undefined() { + if self.input.is_null()? || self.input.is_undefined()? { visitor.visit_unit() } else if let Ok(val) = self.input.to_boolean() { visitor.visit_bool(val.value().unwrap()) @@ -58,7 +58,7 @@ impl<'de, IT: InnerTypes> Deserializer<'de> for NativeSerdeDeserializer { where V: Visitor<'de>, { - if self.input.is_null() || self.input.is_undefined() { + if self.input.is_null()? || self.input.is_undefined()? { visitor.visit_none() } else { visitor.visit_some(self) diff --git a/rust/cubenativeutils/src/wrappers/serializer/error.rs b/rust/cubenativeutils/src/wrappers/serializer/error.rs index 50e55c88da9f4..2b27014cf1a4c 100644 --- a/rust/cubenativeutils/src/wrappers/serializer/error.rs +++ b/rust/cubenativeutils/src/wrappers/serializer/error.rs @@ -1,3 +1,4 @@ +use cubesql::CubeError; use serde::{de, ser}; use std::{fmt, fmt::Display}; #[derive(Debug)] @@ -26,3 +27,9 @@ impl Display for NativeObjSerializerError { } impl std::error::Error for NativeObjSerializerError {} + +impl From for NativeObjSerializerError { + fn from(value: CubeError) -> Self { + Self::Message(value.to_string()) + } +} diff --git a/rust/cubenativeutils/src/wrappers/serializer/serializer.rs b/rust/cubenativeutils/src/wrappers/serializer/serializer.rs index 21463875cddd2..5750bc656a364 100644 --- a/rust/cubenativeutils/src/wrappers/serializer/serializer.rs +++ b/rust/cubenativeutils/src/wrappers/serializer/serializer.rs @@ -55,79 +55,79 @@ impl ser::Serializer for NativeSerdeSerializer { fn serialize_bool(self, v: bool) -> Result { Ok(NativeObjectHandle::new( - self.context.boolean(v).into_object(), + self.context.boolean(v)?.into_object(), )) } fn serialize_i8(self, v: i8) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_i16(self, v: i16) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_i32(self, v: i32) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_i64(self, v: i64) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_u8(self, v: u8) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_u16(self, v: u16) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_u32(self, v: u32) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_u64(self, v: u64) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_f32(self, v: f32) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_f64(self, v: f64) -> Result { Ok(NativeObjectHandle::new( - self.context.number(v as f64).into_object(), + self.context.number(v as f64)?.into_object(), )) } fn serialize_char(self, v: char) -> Result { Ok(NativeObjectHandle::new( - self.context.string(String::from(v)).into_object(), + self.context.string(String::from(v))?.into_object(), )) } fn serialize_str(self, v: &str) -> Result { Ok(NativeObjectHandle::new( - self.context.string(String::from(v)).into_object(), + self.context.string(String::from(v))?.into_object(), )) } @@ -138,7 +138,7 @@ impl ser::Serializer for NativeSerdeSerializer { } fn serialize_none(self) -> Result { - Ok(self.context.undefined()) + Ok(self.context.undefined()?) } fn serialize_some(self, value: &T) -> Result @@ -149,11 +149,11 @@ impl ser::Serializer for NativeSerdeSerializer { } fn serialize_unit(self) -> Result { - Ok(self.context.undefined()) + Ok(self.context.undefined()?) } fn serialize_unit_struct(self, _name: &'static str) -> Result { - Ok(self.context.undefined()) + Ok(self.context.undefined()?) } fn serialize_unit_variant( @@ -185,18 +185,16 @@ impl ser::Serializer for NativeSerdeSerializer { _name: &'static str, _variant_index: u32, _variant: &'static str, - _value: &T, + value: &T, ) -> Result where T: ?Sized + Serialize, { - Err(NativeObjSerializerError::Message( - "serialize_newtype_variant is not implemented".to_string(), - )) + NativeSerdeSerializer::serialize(value, self.context.clone()) } fn serialize_seq(self, _len: Option) -> Result { - let seq = self.context.empty_array(); + let seq = self.context.empty_array()?; Ok(NativeSeqSerializer { context: self.context.clone(), @@ -234,7 +232,7 @@ impl ser::Serializer for NativeSerdeSerializer { } fn serialize_map(self, _len: Option) -> Result { - let obj = self.context.empty_struct(); + let obj = self.context.empty_struct()?; Ok(NativeMapSerializer { context: self.context.clone(), obj, @@ -246,7 +244,7 @@ impl ser::Serializer for NativeSerdeSerializer { _name: &'static str, _len: usize, ) -> Result { - let obj = self.context.empty_struct(); + let obj = self.context.empty_struct()?; Ok(NativeMapSerializer { context: self.context.clone(), obj, diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs index 2e0571cfa0fb5..e5d75e4fab299 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs @@ -1,11 +1,11 @@ use super::join_graph::{JoinGraph, NativeJoinGraph}; +use super::options_member::OptionsMember; use crate::cube_bridge::base_tools::{BaseTools, NativeBaseTools}; use crate::cube_bridge::evaluator::{CubeEvaluator, NativeCubeEvaluator}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; -use cubenativeutils::wrappers::NativeContextHolder; -use cubenativeutils::wrappers::NativeObjectHandle; +use cubenativeutils::wrappers::{NativeArray, NativeContextHolder, NativeObjectHandle}; use cubenativeutils::CubeError; use serde::{Deserialize, Serialize}; use std::any::Any; @@ -50,7 +50,6 @@ impl FilterItem { #[derive(Serialize, Deserialize, Debug)] pub struct BaseQueryOptionsStatic { pub measures: Option>, - pub dimensions: Option>, #[serde(rename = "timeDimensions")] pub time_dimensions: Option>, pub timezone: Option, @@ -66,9 +65,13 @@ pub struct BaseQueryOptionsStatic { #[nativebridge::native_bridge(BaseQueryOptionsStatic)] pub trait BaseQueryOptions { #[field] - fn measures(&self) -> Result>, CubeError>; + #[optional] + #[vec] + fn measures(&self) -> Result>, CubeError>; #[field] - fn dimensions(&self) -> Result>, CubeError>; + #[optional] + #[vec] + fn dimensions(&self) -> Result>, CubeError>; #[field] fn cube_evaluator(&self) -> Result, CubeError>; #[field] diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs index ded10dda2e5d4..0ccc1567be747 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs @@ -1,8 +1,9 @@ use super::filter_group::{FilterGroup, NativeFilterGroup}; use super::filter_params::{FilterParams, NativeFilterParams}; -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::member_sql::{MemberSql, NativeMemberSql}; use super::security_context::{NativeSecurityContext, SecurityContext}; use super::sql_templates_render::{NativeSqlTemplatesRender, SqlTemplatesRender}; +use super::sql_utils::{NativeSqlUtils, SqlUtils}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; @@ -34,6 +35,7 @@ pub trait BaseTools { sql: Rc, ) -> Result, CubeError>; fn security_context_for_rust(&self) -> Result, CubeError>; + fn sql_utils_for_rust(&self) -> Result, CubeError>; fn filters_proxy(&self) -> Result, CubeError>; fn filter_group_function(&self) -> Result, CubeError>; fn timestamp_precision(&self) -> Result; @@ -45,4 +47,9 @@ pub trait BaseTools { ) -> Result>, CubeError>; fn get_allocated_params(&self) -> Result, CubeError>; fn all_cube_members(&self, path: String) -> Result, CubeError>; + //===== TODO Move to templates + fn hll_init(&self, sql: String) -> Result; + fn hll_merge(&self, sql: String) -> Result; + fn hll_cardinality_merge(&self, sql: String) -> Result; + fn count_distinct_approx(&self, sql: String) -> Result; } diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/cube_definition.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/cube_definition.rs index 6fa531ddbce7b..c8d9d9ef76da5 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/cube_definition.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/cube_definition.rs @@ -1,4 +1,4 @@ -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/dimension_definition.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/dimension_definition.rs index c4936c31259ac..6ca6e193edf42 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/dimension_definition.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/dimension_definition.rs @@ -1,4 +1,5 @@ -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::geo_item::{GeoItem, NativeGeoItem}; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; @@ -17,10 +18,23 @@ pub struct DimenstionDefinitionStatic { pub owned_by_cube: Option, #[serde(rename = "multiStage")] pub multi_stage: Option, + #[serde(rename = "subQuery")] + pub sub_query: Option, + #[serde(rename = "propagateFiltersToSubQuery")] + pub propagate_filters_to_sub_query: Option, } #[nativebridge::native_bridge(DimenstionDefinitionStatic)] pub trait DimensionDefinition { + #[optional] #[field] - fn sql(&self) -> Result, CubeError>; + fn sql(&self) -> Result>, CubeError>; + + #[optional] + #[field] + fn latitude(&self) -> Result>, CubeError>; + + #[optional] + #[field] + fn longitude(&self) -> Result>, CubeError>; } diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/evaluator.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/evaluator.rs index f076c1eb7c708..7c02a6f7a0afd 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/evaluator.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/evaluator.rs @@ -1,7 +1,7 @@ use super::cube_definition::{CubeDefinition, NativeCubeDefinition}; use super::dimension_definition::{DimensionDefinition, NativeDimensionDefinition}; use super::measure_definition::{MeasureDefinition, NativeMeasureDefinition}; -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/geo_item.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/geo_item.rs new file mode 100644 index 0000000000000..8742686db9555 --- /dev/null +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/geo_item.rs @@ -0,0 +1,15 @@ +use super::member_sql::{MemberSql, NativeMemberSql}; +use cubenativeutils::wrappers::serializer::{ + NativeDeserialize, NativeDeserializer, NativeSerialize, +}; +use cubenativeutils::wrappers::NativeContextHolder; +use cubenativeutils::wrappers::NativeObjectHandle; +use cubenativeutils::CubeError; +use std::any::Any; +use std::rc::Rc; + +#[nativebridge::native_bridge] +pub trait GeoItem { + #[field] + fn sql(&self) -> Result, CubeError>; +} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_definition.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_definition.rs index c224661d2a67b..020b3dd6b8d3c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_definition.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_definition.rs @@ -1,7 +1,8 @@ -use super::join_item::{JoinItemsVec, NativeJoinItemsVec}; +use super::join_item::{JoinItem, NativeJoinItem}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; +use cubenativeutils::wrappers::NativeArray; use cubenativeutils::wrappers::NativeContextHolder; use cubenativeutils::wrappers::NativeObjectHandle; use cubenativeutils::CubeError; @@ -20,5 +21,6 @@ pub struct JoinDefinitionStatic { #[nativebridge::native_bridge(JoinDefinitionStatic)] pub trait JoinDefinition { #[field] - fn joins(&self) -> Result, CubeError>; + #[vec] + fn joins(&self) -> Result>, CubeError>; } diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_graph.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_graph.rs index bb8f1c1227e57..32b776061054d 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_graph.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_graph.rs @@ -1,4 +1,5 @@ use super::join_definition::{JoinDefinition, NativeJoinDefinition}; +use super::join_hints::JoinHintItem; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; @@ -10,5 +11,8 @@ use std::rc::Rc; #[nativebridge::native_bridge] pub trait JoinGraph { - fn build_join(&self, cubes_to_join: Vec) -> Result, CubeError>; + fn build_join( + &self, + cubes_to_join: Vec, + ) -> Result, CubeError>; } diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_hints.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_hints.rs new file mode 100644 index 0000000000000..a3ef5d4044dfc --- /dev/null +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_hints.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub enum JoinHintItem { + Single(String), + Vector(Vec), +} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item.rs index f3130d0ec7f6f..c712cd3c0697c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item.rs @@ -1,5 +1,4 @@ use super::join_item_definition::{JoinItemDefinition, NativeJoinItemDefinition}; -use cubenativeutils::wrappers::object::NativeArray; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; @@ -8,7 +7,6 @@ use cubenativeutils::wrappers::NativeObjectHandle; use cubenativeutils::CubeError; use serde::{Deserialize, Serialize}; use std::any::Any; -use std::marker::PhantomData; use std::rc::Rc; #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash)] @@ -26,41 +24,3 @@ pub trait JoinItem { #[field] fn join(&self) -> Result, CubeError>; } - -pub trait JoinItemsVec { - fn items(&self) -> &Vec>; -} - -pub struct NativeJoinItemsVec { - items: Vec>, - phantom: PhantomData, -} - -impl NativeJoinItemsVec { - pub fn try_new(native_items: NativeObjectHandle) -> Result { - let items = native_items - .into_array()? - .to_vec()? - .into_iter() - .map(|v| -> Result, CubeError> { - Ok(Rc::new(NativeJoinItem::from_native(v)?)) - }) - .collect::, _>>()?; - Ok(Self { - items, - phantom: PhantomData::default(), - }) - } -} - -impl JoinItemsVec for NativeJoinItemsVec { - fn items(&self) -> &Vec> { - &self.items - } -} - -impl NativeDeserialize for NativeJoinItemsVec { - fn from_native(v: NativeObjectHandle) -> Result { - Self::try_new(v) - } -} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item_definition.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item_definition.rs index 2f532e3b7ee03..cca8d2cce702f 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item_definition.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/join_item_definition.rs @@ -1,4 +1,4 @@ -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_definition.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_definition.rs index 4c1cdb21f2596..54329c773894e 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_definition.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_definition.rs @@ -1,10 +1,11 @@ use super::cube_definition::{CubeDefinition, NativeCubeDefinition}; -use super::measure_filter::{MeasureFiltersVec, NativeMeasureFiltersVec}; -use super::member_order_by::{MemberOrderByVec, NativeMemberOrderByVec}; -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::measure_filter::{MeasureFilter, NativeMeasureFilter}; +use super::member_order_by::{MemberOrderBy, NativeMemberOrderBy}; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; +use cubenativeutils::wrappers::NativeArray; use cubenativeutils::wrappers::NativeContextHolder; use cubenativeutils::wrappers::NativeObjectHandle; use cubenativeutils::CubeError; @@ -26,6 +27,9 @@ pub struct RollingWindow { pub trailing: Option, pub leading: Option, pub offset: Option, + #[serde(rename = "type")] + pub rolling_type: Option, + pub granularity: Option, } #[derive(Serialize, Deserialize, Debug)] @@ -58,9 +62,16 @@ pub trait MeasureDefinition { #[optional] #[field] - fn filters(&self) -> Result>, CubeError>; + #[vec] + fn filters(&self) -> Result>>, CubeError>; + + #[optional] + #[field] + #[vec] + fn drill_filters(&self) -> Result>>, CubeError>; #[optional] #[field] - fn order_by(&self) -> Result>, CubeError>; + #[vec] + fn order_by(&self) -> Result>>, CubeError>; } diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_filter.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_filter.rs index a7973e0c6047d..500774e50b76f 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_filter.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/measure_filter.rs @@ -1,5 +1,4 @@ -use super::memeber_sql::{MemberSql, NativeMemberSql}; -use cubenativeutils::wrappers::object::NativeArray; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; @@ -7,7 +6,6 @@ use cubenativeutils::wrappers::NativeContextHolder; use cubenativeutils::wrappers::NativeObjectHandle; use cubenativeutils::CubeError; use std::any::Any; -use std::marker::PhantomData; use std::rc::Rc; #[nativebridge::native_bridge] @@ -15,41 +13,3 @@ pub trait MeasureFilter { #[field] fn sql(&self) -> Result, CubeError>; } - -pub trait MeasureFiltersVec { - fn items(&self) -> &Vec>; -} - -pub struct NativeMeasureFiltersVec { - items: Vec>, - phantom: PhantomData, -} - -impl NativeMeasureFiltersVec { - pub fn try_new(native_items: NativeObjectHandle) -> Result { - let items = native_items - .into_array()? - .to_vec()? - .into_iter() - .map(|v| -> Result, CubeError> { - Ok(Rc::new(NativeMeasureFilter::from_native(v)?)) - }) - .collect::, _>>()?; - Ok(Self { - items, - phantom: PhantomData::default(), - }) - } -} - -impl MeasureFiltersVec for NativeMeasureFiltersVec { - fn items(&self) -> &Vec> { - &self.items - } -} - -impl NativeDeserialize for NativeMeasureFiltersVec { - fn from_native(v: NativeObjectHandle) -> Result { - Self::try_new(v) - } -} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_definition.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_definition.rs index 52d88dfb0cd5c..a0b82971482c9 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_definition.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_definition.rs @@ -1,4 +1,4 @@ -use super::memeber_sql::{MemberSql, NativeMemberSql}; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_expression.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_expression.rs new file mode 100644 index 0000000000000..45d2a26ddeb90 --- /dev/null +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_expression.rs @@ -0,0 +1,24 @@ +use super::member_sql::{MemberSql, NativeMemberSql}; +use cubenativeutils::wrappers::serializer::{ + NativeDeserialize, NativeDeserializer, NativeSerialize, +}; +use cubenativeutils::wrappers::{NativeContextHolder, NativeObjectHandle}; +use cubenativeutils::CubeError; +use serde::{Deserialize, Serialize}; +use std::any::Any; +use std::rc::Rc; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct MemberExpressionDefinitionStatic { + #[serde(rename = "expressionName")] + pub expression_name: Option, + #[serde(rename = "cubeName")] + pub cube_name: Option, + pub definition: Option, +} + +#[nativebridge::native_bridge(MemberExpressionDefinitionStatic)] +pub trait MemberExpressionDefinition { + #[field] + fn expression(&self) -> Result, CubeError>; +} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_order_by.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_order_by.rs index 56905aa825306..0f56aeafc41f7 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_order_by.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_order_by.rs @@ -1,5 +1,4 @@ -use super::memeber_sql::{MemberSql, NativeMemberSql}; -use cubenativeutils::wrappers::object::NativeArray; +use super::member_sql::{MemberSql, NativeMemberSql}; use cubenativeutils::wrappers::serializer::{ NativeDeserialize, NativeDeserializer, NativeSerialize, }; @@ -7,7 +6,6 @@ use cubenativeutils::wrappers::NativeContextHolder; use cubenativeutils::wrappers::NativeObjectHandle; use cubenativeutils::CubeError; use std::any::Any; -use std::marker::PhantomData; use std::rc::Rc; #[nativebridge::native_bridge] @@ -17,41 +15,3 @@ pub trait MemberOrderBy { #[field] fn dir(&self) -> Result; } - -pub trait MemberOrderByVec { - fn items(&self) -> &Vec>; -} - -pub struct NativeMemberOrderByVec { - items: Vec>, - phantom: PhantomData, -} - -impl NativeMemberOrderByVec { - pub fn try_new(native_items: NativeObjectHandle) -> Result { - let items = native_items - .into_array()? - .to_vec()? - .into_iter() - .map(|v| -> Result, CubeError> { - Ok(Rc::new(NativeMemberOrderBy::from_native(v)?)) - }) - .collect::, _>>()?; - Ok(Self { - items, - phantom: PhantomData::default(), - }) - } -} - -impl MemberOrderByVec for NativeMemberOrderByVec { - fn items(&self) -> &Vec> { - &self.items - } -} - -impl NativeDeserialize for NativeMemberOrderByVec { - fn from_native(v: NativeObjectHandle) -> Result { - Self::try_new(v) - } -} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/memeber_sql.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_sql.rs similarity index 78% rename from rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/memeber_sql.rs rename to rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_sql.rs index 3dbf3a967f713..993fd76dc81d3 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/memeber_sql.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_sql.rs @@ -2,6 +2,7 @@ use super::{ filter_group::{FilterGroup, NativeFilterGroup}, filter_params::{FilterParams, NativeFilterParams}, security_context::{NativeSecurityContext, SecurityContext}, + sql_utils::{NativeSqlUtils, SqlUtils}, }; use cubenativeutils::wrappers::inner_types::InnerTypes; use cubenativeutils::wrappers::object::{NativeFunction, NativeStruct, NativeType}; @@ -24,6 +25,7 @@ pub struct MemberSqlStruct { pub enum ContextSymbolArg { SecurityContext(Rc), + SqlUtils(Rc), FilterParams(Rc), FilterGroup(Rc), } @@ -37,9 +39,39 @@ pub enum MemberSqlArg { pub trait MemberSql { fn call(&self, args: Vec) -> Result; fn args_names(&self) -> &Vec; + fn need_deps_resolve(&self) -> bool; fn as_any(self: Rc) -> Rc; } +pub struct CustomMemberSql { + sql: String, + args_names: Vec, +} + +impl CustomMemberSql { + pub fn new(sql: String) -> Rc { + Rc::new(Self { + sql, + args_names: vec![], + }) + } +} + +impl MemberSql for CustomMemberSql { + fn call(&self, _args: Vec) -> Result { + Ok(self.sql.clone()) + } + fn args_names(&self) -> &Vec { + &self.args_names + } + fn need_deps_resolve(&self) -> bool { + false + } + fn as_any(self: Rc) -> Rc { + self.clone() + } +} + pub struct NativeMemberSql { native_object: NativeObjectHandle, args_names: Vec, @@ -50,14 +82,20 @@ impl NativeSerialize for MemberSqlStruct { &self, context: NativeContextHolder, ) -> Result, CubeError> { - let res = context.empty_struct(); + let res = context.empty_struct()?; for (k, v) in self.properties.iter() { res.set_field(k, v.to_native(context.clone())?)?; } if let Some(to_string_fn) = &self.to_string_fn { res.set_field( "toString", - NativeObjectHandle::new(context.to_string_fn(to_string_fn.clone()).into_object()), + NativeObjectHandle::new(context.to_string_fn(to_string_fn.clone())?.into_object()), + )?; + } + if let Some(sql_fn) = &self.sql_fn { + res.set_field( + "sql", + NativeObjectHandle::new(context.to_string_fn(sql_fn.clone())?.into_object()), )?; } Ok(NativeObjectHandle::new(res.into_object())) @@ -79,6 +117,12 @@ impl NativeSerialize for MemberSqlArg { .downcast::>() .unwrap() .to_native(context_holder.clone()), + ContextSymbolArg::SqlUtils(context) => context + .clone() + .as_any() + .downcast::>() + .unwrap() + .to_native(context_holder.clone()), ContextSymbolArg::FilterParams(params) => params .clone() .as_any() @@ -131,6 +175,9 @@ impl MemberSql for NativeMemberSql { fn args_names(&self) -> &Vec { &self.args_names } + fn need_deps_resolve(&self) -> bool { + !self.args_names.is_empty() + } } impl NativeSerialize for NativeMemberSql { diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs index c32f95c33c2dd..6fa12c63c418c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs @@ -5,14 +5,19 @@ pub mod dimension_definition; pub mod evaluator; pub mod filter_group; pub mod filter_params; +pub mod geo_item; pub mod join_definition; pub mod join_graph; +pub mod join_hints; pub mod join_item; pub mod join_item_definition; pub mod measure_definition; pub mod measure_filter; pub mod member_definition; +pub mod member_expression; pub mod member_order_by; -pub mod memeber_sql; +pub mod member_sql; +pub mod options_member; pub mod security_context; pub mod sql_templates_render; +pub mod sql_utils; diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/options_member.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/options_member.rs new file mode 100644 index 0000000000000..11918839cd21c --- /dev/null +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/options_member.rs @@ -0,0 +1,25 @@ +use super::member_expression::{MemberExpressionDefinition, NativeMemberExpressionDefinition}; +use cubenativeutils::wrappers::inner_types::InnerTypes; +use cubenativeutils::wrappers::serializer::NativeDeserialize; +use cubenativeutils::wrappers::NativeObjectHandle; +use cubenativeutils::CubeError; +use std::rc::Rc; + +pub enum OptionsMember { + MemberName(String), + MemberExpression(Rc), +} + +impl NativeDeserialize for OptionsMember { + fn from_native(native_object: NativeObjectHandle) -> Result { + match String::from_native(native_object.clone()) { + Ok(name) => Ok(Self::MemberName(name)), + Err(_) => match NativeMemberExpressionDefinition::from_native(native_object) { + Ok(expr) => Ok(Self::MemberExpression(Rc::new(expr))), + Err(_) => Err(CubeError::user(format!( + "Member name or member expression map expected" + ))), + }, + } + } +} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/sql_utils.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/sql_utils.rs new file mode 100644 index 0000000000000..84d78dd137e34 --- /dev/null +++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/sql_utils.rs @@ -0,0 +1,9 @@ +use cubenativeutils::wrappers::serializer::{NativeDeserialize, NativeSerialize}; +use cubenativeutils::wrappers::NativeContextHolder; +use cubenativeutils::wrappers::NativeObjectHandle; +use cubenativeutils::CubeError; +use std::any::Any; +use std::rc::Rc; + +#[nativebridge::native_bridge] +pub trait SqlUtils {} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs b/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs index 1a9482f68715f..0631a868cec13 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs @@ -40,6 +40,22 @@ impl SelectBuilder { } } + pub fn new_from_select(select: Rc