Skip to content

Commit 5e5fb18

Browse files
authored
feat(native): Cube.py - support all options (#7145)
1 parent ea48b12 commit 5e5fb18

File tree

7 files changed

+210
-132
lines changed

7 files changed

+210
-132
lines changed

packages/cubejs-backend-native/js/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ export const shutdownInterface = async (instance: SqlInterfaceInstance): Promise
313313

314314
export interface PyConfiguration {
315315
repositoryFactory?: (ctx: unknown) => Promise<unknown>,
316+
logger?: (msg: string, params: Record<string, any>) => void,
316317
checkAuth?: (req: unknown, authorization: string) => Promise<void>
317318
queryRewrite?: (query: unknown, ctx: unknown) => Promise<unknown>
318319
contextToApiScopes?: () => Promise<string[]>
@@ -348,6 +349,15 @@ export const pythonLoadConfig = async (content: string, options: { fileName: str
348349
});
349350
}
350351

352+
if (config.logger) {
353+
const nativeLogger = config.logger;
354+
config.logger = (msg: string, params: Record<string, any>) => {
355+
nativeLogger(msg, params).catch((e: any) => {
356+
console.error(e);
357+
});
358+
};
359+
}
360+
351361
return config;
352362
};
353363

Lines changed: 54 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
2-
from typing import Union, Callable, Dict
2+
from typing import Union, Callable, Dict, Any
33

44

55
def file_repository(path):
@@ -31,22 +31,39 @@ class RequestContext:
3131

3232

3333
class Configuration:
34+
web_sockets: bool
35+
http: Dict
36+
graceful_shutdown: int
37+
process_subscriptions_interval: int
38+
web_sockets_base_path: str
3439
schema_path: str
3540
base_path: str
36-
web_sockets_base_path: str
37-
compiler_cache_size: int
38-
telemetry: bool
39-
pg_sql_port: int
41+
dev_server: bool
42+
api_secret: str
4043
cache_and_queue_driver: str
4144
allow_js_duplicate_props_in_schema: bool
42-
process_subscriptions_interval: int
43-
http: Dict
4445
jwt: Dict
46+
scheduled_refresh_timer: Any
47+
scheduled_refresh_timezones: list[str]
48+
scheduled_refresh_concurrency: int
49+
scheduled_refresh_batch_size: int
50+
compiler_cache_size: int
51+
update_compiler_cache_keep_alive: bool
52+
max_compiler_cache_keep_alive: int
53+
telemetry: bool
54+
sql_cache: bool
55+
live_preview: bool
56+
# SQL API
57+
pg_sql_port: int
58+
sql_super_user: str
59+
sql_user: str
60+
sql_password: str
4561
# Functions
4662
logger: Callable
4763
context_to_app_id: Union[str, Callable[[RequestContext], str]]
4864
context_to_orchestrator_id: Union[str, Callable[[RequestContext], str]]
49-
driver_factory: Callable
65+
driver_factory: Callable[[RequestContext], Dict]
66+
external_driver_factory: Callable[[RequestContext], Dict]
5067
db_type: Union[str, Callable[[RequestContext], str]]
5168
check_auth: Callable
5269
check_sql_auth: Callable
@@ -61,22 +78,38 @@ class Configuration:
6178
orchestrator_options: Union[Dict, Callable[[RequestContext], Dict]]
6279

6380
def __init__(self):
81+
self.web_sockets = None
82+
self.http = None
83+
self.graceful_shutdown = None
6484
self.schema_path = None
6585
self.base_path = None
86+
self.dev_server = None
87+
self.api_secret = None
6688
self.web_sockets_base_path = None
67-
self.compiler_cache_size = None
68-
self.telemetry = None
6989
self.pg_sql_port = None
7090
self.cache_and_queue_driver = None
7191
self.allow_js_duplicate_props_in_schema = None
7292
self.process_subscriptions_interval = None
73-
self.http = None
7493
self.jwt = None
94+
self.scheduled_refresh_timer = None
95+
self.scheduled_refresh_timezones = None
96+
self.scheduled_refresh_concurrency = None
97+
self.scheduled_refresh_batch_size = None
98+
self.compiler_cache_size = None
99+
self.update_compiler_cache_keep_alive = None
100+
self.max_compiler_cache_keep_alive = None
101+
self.telemetry = None
102+
self.sql_cache = None
103+
self.live_preview = None
104+
self.sql_super_user = None
105+
self.sql_user = None
106+
self.sql_password = None
75107
# Functions
76108
self.logger = None
77109
self.context_to_app_id = None
78110
self.context_to_orchestrator_id = None
79111
self.driver_factory = None
112+
self.external_driver_factory = None
80113
self.db_type = None
81114
self.check_auth = None
82115
self.check_sql_auth = None
@@ -91,89 +124,15 @@ def __init__(self):
91124
self.pre_aggregations_schema = None
92125
self.orchestrator_options = None
93126

94-
def set_schema_path(self, schema_path: str):
95-
self.schema_path = schema_path
96-
97-
def set_base_path(self, base_path: str):
98-
self.base_path = base_path
99-
100-
def set_web_sockets_base_path(self, web_sockets_base_path: str):
101-
self.web_sockets_base_path = web_sockets_base_path
102-
103-
def set_compiler_cache_size(self, compiler_cache_size: int):
104-
self.compiler_cache_size = compiler_cache_size
105-
106-
def set_telemetry(self, telemetry: bool):
107-
self.telemetry = telemetry
108-
109-
def set_pg_sql_port(self, pg_sql_port: int):
110-
self.pg_sql_port = pg_sql_port
111-
112-
def set_cache_and_queue_driver(self, cache_and_queue_driver: str):
113-
self.cache_and_queue_driver = cache_and_queue_driver
114-
115-
def set_allow_js_duplicate_props_in_schema(self, allow_js_duplicate_props_in_schema: bool):
116-
self.allow_js_duplicate_props_in_schema = allow_js_duplicate_props_in_schema
117-
118-
def set_process_subscriptions_interval(self, process_subscriptions_interval: int):
119-
self.process_subscriptions_interval = process_subscriptions_interval
120-
121-
def set_logger(self, logger: Callable):
122-
self.logger = logger
123-
124-
def set_context_to_app_id(self, context_to_app_id: Union[str, Callable[[RequestContext], str]]):
125-
self.context_to_app_id = context_to_app_id
126-
127-
def set_context_to_orchestrator_id(self, context_to_orchestrator_id: Union[str, Callable[[RequestContext], str]]):
128-
self.context_to_orchestrator_id = context_to_orchestrator_id
129-
130-
def set_driver_factory(self, driver_factory: Callable):
131-
self.driver_factory = driver_factory
132-
133-
def set_db_type(self, db_type: Union[str, Callable[[RequestContext], str]]):
134-
self.db_type = db_type
135-
136-
def set_check_auth(self, check_auth: Callable):
137-
self.check_auth = check_auth
138-
139-
def set_check_sql_auth(self, check_sql_auth: Callable):
140-
self.check_sql_auth = check_sql_auth
141-
142-
def set_can_switch_sql_user(self, can_switch_sql_user: Callable):
143-
self.can_switch_sql_user = can_switch_sql_user
144-
145-
def set_query_rewrite(self, query_rewrite: Callable):
146-
self.query_rewrite = query_rewrite
147-
148-
def set_extend_context(self, extend_context: Callable[[RequestContext], Dict]):
149-
self.extend_context = extend_context
150-
151-
def set_scheduled_refresh_contexts(self, scheduled_refresh_contexts: Callable):
152-
self.scheduled_refresh_contexts = scheduled_refresh_contexts
153-
154-
def set_repository_factory(self, repository_factory: Callable):
155-
self.repository_factory = repository_factory
156-
157-
def set_schema_version(self, schema_version: Union[str, Callable[[RequestContext], str]]):
158-
self.schema_version = schema_version
159-
160-
def set_semantic_layer_sync(self, semantic_layer_sync: Union[Dict, Callable[[], Dict]]):
161-
self.semantic_layer_sync = semantic_layer_sync
162-
163-
def set_pre_aggregations_schema(self, pre_aggregations_schema: Union[str, Callable[[RequestContext], str]]):
164-
self.pre_aggregations_schema = pre_aggregations_schema
165-
166-
def set_orchestrator_options(self, orchestrator_options: Union[Dict, Callable[[RequestContext], Dict]]):
167-
self.orchestrator_options = orchestrator_options
168-
169-
170-
settings = Configuration()
127+
def __call__(self, func):
128+
if not callable(func):
129+
raise ConfigurationException("@config decorator must be used with functions, actual: '%s'" % type(func).__name__)
171130

172-
def config(func):
173-
if not callable(func):
174-
raise ConfigurationException("@config decorator must be used with functions, actual: '%s'" % type(func).__name__)
131+
if hasattr(self, func.__name__):
132+
setattr(self, func.__name__, func)
133+
else:
134+
raise ConfigurationException("Unknown configuration property: '%s'" % func.__name__)
175135

176-
if hasattr(settings, func.__name__):
177-
setattr(settings, func.__name__, func)
178-
else:
179-
raise ConfigurationException("Unknown settings property: '%s'" % func.__name__)
136+
config = Configuration()
137+
# backward compatibility
138+
settings = config

packages/cubejs-backend-native/src/python/cube_config.rs

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,56 @@ impl CubeConfigPy {
1515
}
1616
}
1717

18-
pub fn get_static_attrs(&self) -> Vec<&'static str> {
18+
pub fn get_attrs(&self) -> Vec<&'static str> {
1919
vec![
20+
"web_sockets",
21+
"http",
22+
"graceful_shutdown",
23+
"process_subscriptions_interval",
24+
"web_sockets_base_path",
2025
"schema_path",
2126
"base_path",
22-
"web_sockets_base_path",
23-
"compiler_cache_size",
24-
"telemetry",
25-
"pg_sql_port",
27+
"dev_server",
28+
"api_secret",
2629
"cache_and_queue_driver",
2730
"allow_js_duplicate_props_in_schema",
28-
"process_subscriptions_interval",
29-
"http",
3031
"jwt",
32+
"scheduled_refresh_timer",
33+
"scheduled_refresh_timezones",
34+
"scheduled_refresh_concurrency",
35+
"scheduled_refresh_batch_size",
36+
"compiler_cache_size",
37+
"update_compiler_cache_keep_alive",
38+
"max_compiler_cache_keep_alive",
39+
"telemetry",
40+
"sql_cache",
41+
"live_preview",
42+
"pg_sql_port",
43+
"sql_super_user",
44+
"sql_user",
45+
"sql_password",
46+
// functions
47+
"logger",
48+
"context_to_app_id",
49+
"context_to_orchestrator_id",
50+
"driver_factory",
51+
"external_driver_factory",
52+
"db_type",
53+
"check_auth",
54+
"check_sql_auth",
55+
"can_switch_sql_user",
56+
"query_rewrite",
57+
"extend_context",
58+
"scheduled_refresh_contexts",
59+
"context_to_api_scopes",
60+
"repository_factory",
61+
"semantic_layer_sync",
62+
"schema_version",
63+
"pre_aggregations_schema",
64+
"orchestrator_options",
3165
]
3266
}
3367

34-
pub fn apply_dynamic_functions(&mut self, config_module: &PyAny) -> PyResult<()> {
35-
self.attr(config_module, "logger")?;
36-
self.attr(config_module, "context_to_app_id")?;
37-
self.attr(config_module, "context_to_orchestrator_id")?;
38-
self.attr(config_module, "driver_factory")?;
39-
self.attr(config_module, "db_type")?;
40-
self.attr(config_module, "check_auth")?;
41-
self.attr(config_module, "check_sql_auth")?;
42-
self.attr(config_module, "can_switch_sql_user")?;
43-
self.attr(config_module, "query_rewrite")?;
44-
self.attr(config_module, "extend_context")?;
45-
self.attr(config_module, "scheduled_refresh_contexts")?;
46-
self.attr(config_module, "context_to_api_scopes")?;
47-
self.attr(config_module, "repository_factory")?;
48-
self.attr(config_module, "semantic_layer_sync")?;
49-
self.attr(config_module, "schema_version")?;
50-
self.attr(config_module, "pre_aggregations_schema")?;
51-
self.attr(config_module, "orchestrator_options")?;
52-
53-
Ok(())
54-
}
55-
5668
pub fn attr(&mut self, config_module: &PyAny, key: &str) -> PyResult<()> {
5769
let v = config_module.getattr(&*key)?;
5870
if !v.is_none() {

packages/cubejs-backend-native/src/python/entry.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,19 @@ fn python_load_config(mut cx: FunctionContext) -> JsResult<JsPromise> {
3030
let settings_py = if config_module.hasattr("__execution_context_locals")? {
3131
let execution_context_locals = config_module.getattr("__execution_context_locals")?;
3232
execution_context_locals.get_item("settings")?
33+
} else if config_module.hasattr("config")? {
34+
config_module.getattr("config")?
3335
} else {
36+
// backward compatibility
3437
config_module.getattr("settings")?
3538
};
3639

3740
let mut cube_conf = CubeConfigPy::new();
3841

39-
for attr_name in cube_conf.get_static_attrs() {
42+
for attr_name in cube_conf.get_attrs() {
4043
cube_conf.attr(settings_py, attr_name)?;
4144
}
4245

43-
cube_conf.apply_dynamic_functions(settings_py)?;
44-
4546
Ok(cube_conf)
4647
});
4748

packages/cubejs-backend-native/test/config.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from cube.conf import (
22
config,
3-
settings,
43
file_repository
54
)
65

7-
settings.schema_path = "models"
8-
settings.pg_sql_port = 5555
9-
settings.telemetry = False
6+
config.schema_path = "models"
7+
config.pg_sql_port = 5555
8+
config.telemetry = False
109

1110
@config
1211
def query_rewrite(query, ctx):
@@ -27,3 +26,19 @@ async def repository_factory(ctx):
2726
async def context_to_api_scopes():
2827
print('[python] context_to_api_scopes')
2928
return ['meta', 'data', 'jobs']
29+
30+
@config
31+
def schema_version(ctx):
32+
print('[python] schema_version', ctx)
33+
34+
return '1'
35+
36+
@config
37+
def pre_aggregations_schema(ctx):
38+
print('[python] pre_aggregations_schema', ctx)
39+
40+
return 'schema'
41+
42+
@config
43+
def logger(msg, params):
44+
print('[python] logger msg', msg, 'params=', params)

0 commit comments

Comments
 (0)