Coverage for mindsdb / integrations / handlers / lightdash_handler / lightdash_tables.py: 0%
329 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
1from typing import List
3import pandas as pd
4from mindsdb_sql_parser import ast
6from mindsdb.integrations.utilities.handlers.query_utilities import (
7 SELECTQueryExecutor,
8 SELECTQueryParser,
9)
10from mindsdb.integrations.libs.api_handler import APIHandler, APITable
11from mindsdb.integrations.utilities.sql_utils import conditions_to_filter
14def val_to_string(d, k):
15 if k in d:
16 d[k] = str(d[k])
19def move_under(d, key_contents_to_move, key_to_move_under=None):
20 if key_contents_to_move not in d:
21 return
22 for k, v in d[key_contents_to_move].items():
23 if key_to_move_under:
24 d[key_to_move_under][k] = v
25 else:
26 d[k] = v
27 del d[key_contents_to_move]
30def select_keys(d, keys):
31 new_d = {}
32 for key in keys:
33 new_d[key] = d.get(key, "")
34 return new_d
37class CustomAPITable(APITable):
39 def __init__(self, handler: APIHandler):
40 super().__init__(handler)
41 self.handler.connect()
43 def get_columns(self, ignore: List[str] = []) -> List[str]:
44 return [item for item in self.columns if item not in ignore]
46 def select(self, query: ast.Select) -> pd.DataFrame:
47 raise NotImplementedError()
49 def parse_select(self, query: ast.Select, table_name: str):
50 select_statement_parser = SELECTQueryParser(query, table_name, self.get_columns())
51 self.selected_columns, self.where_conditions, self.order_by_conditions, self.result_limit = select_statement_parser.parse_query()
53 def get_where_param(self, query: ast.Select, param: str):
54 params = conditions_to_filter(query.where)
55 if param not in params:
56 raise Exception(f"WHERE condition does not have '{param}' selector")
57 return params[param]
59 def apply_query_params(self, df, query):
60 select_statement_parser = SELECTQueryParser(query, self.name, self.get_columns())
61 selected_columns, _, order_by_conditions, result_limit = select_statement_parser.parse_query()
62 select_statement_executor = SELECTQueryExecutor(df, selected_columns, [], order_by_conditions, result_limit)
63 return select_statement_executor.execute_query()
66class UserTable(CustomAPITable):
67 name: str = "user"
68 columns: List[str] = [
69 'userUuid',
70 'email',
71 'firstName',
72 'lastName',
73 'organizationUuid',
74 'organizationName',
75 'organizationCreatedAt',
76 'isTrackingAnonymized',
77 'isMarketingOptedIn',
78 'isSetupComplete',
79 'role',
80 'isActive',
81 ]
83 def __init__(self, handler: APIHandler):
84 super().__init__(handler)
85 self.connection = self.handler.connect()
87 def select(self, query: ast.Select) -> pd.DataFrame:
88 data = select_keys(self.connection.get_user(), self.columns)
89 df = pd.DataFrame.from_records([data])
90 return self.apply_query_params(df, query)
93class UserAbilityTable(CustomAPITable):
94 name: str = "user_ability"
95 columns: List[str] = [
96 'action',
97 'subject',
98 'conditions'
99 ]
101 def __init__(self, handler: APIHandler):
102 super().__init__(handler)
103 self.connection = self.handler.connect()
105 def select(self, query: ast.Select) -> pd.DataFrame:
106 data = select_keys(self.connection.get_user(), ["abilityRules"])
107 for d in data:
108 val_to_string(d, "condition")
109 df = pd.DataFrame.from_records(data, columns=self.columns)
110 return self.apply_query_params(df, query)
113class OrgTable(CustomAPITable):
114 name: str = "org"
115 columns: List[str] = [
116 'organizationUuid',
117 'defaultProjectUuid'
118 'name',
119 'chartColors',
120 'needsProject',
121 ]
123 def __init__(self, handler: APIHandler):
124 super().__init__(handler)
125 self.connection = self.handler.connect()
127 def select(self, query: ast.Select) -> pd.DataFrame:
128 data = select_keys(self.connection.get_org(), self.columns)
129 val_to_string(data, "chartColors")
130 df = pd.DataFrame.from_records([data])
131 return self.apply_query_params(df, query)
134class OrgProjectsTable(CustomAPITable):
135 name: str = "org_projects"
136 columns: List[str] = [
137 'name',
138 'projectUuid',
139 'type',
140 ]
142 def __init__(self, handler: APIHandler):
143 super().__init__(handler)
144 self.connection = self.handler.connect()
146 def select(self, query: ast.Select) -> pd.DataFrame:
147 data = self.connection.get_projects()
148 df = pd.DataFrame.from_records(data, columns=self.columns)
149 return self.apply_query_params(df, query)
152class OrgMembersTable(CustomAPITable):
153 name: str = "org_members"
154 columns: List[str] = [
155 'userUuid',
156 'firstName',
157 'lastName',
158 'email',
159 'organizationUuid',
160 'role',
161 'isActive',
162 'isInviteExpired',
163 ]
165 def __init__(self, handler: APIHandler):
166 super().__init__(handler)
167 self.connection = self.handler.connect()
169 def select(self, query: ast.Select) -> pd.DataFrame:
170 data = self.connection.get_org_members()
171 df = pd.DataFrame.from_records(data, columns=self.columns)
172 return self.apply_query_params(df, query)
175class ProjectTable(CustomAPITable):
176 name: str = "project_table"
177 columns: List[str] = [
178 'organizationUuid',
179 'projectUuid',
180 'name',
181 'type',
182 'pinnedListUuid',
183 'copiedFromProjectUuid',
184 'dbtVersion',
185 ]
187 def __init__(self, handler: APIHandler):
188 super().__init__(handler)
189 self.connection = self.handler.connect()
191 def select(self, query: ast.Select) -> pd.DataFrame:
192 project_uuid = self.get_where_param(query, 'project_uuid')
193 data = select_keys(self.connection.get_project(project_uuid), self.columns)
194 df = pd.DataFrame.from_records([data])
195 return self.apply_query_params(df, query)
198class WarehouseConnectionTable(CustomAPITable):
199 name: str = "warehouse_connection"
200 columns: List[str] = [
201 "role",
202 "type",
203 "account",
204 "database",
205 "warehouse",
206 "schema",
207 "threads",
208 "clientSessionKeepAlive",
209 "queryTag",
210 "accessUrl",
211 "startOfWeek",
212 ]
214 def __init__(self, handler: APIHandler):
215 super().__init__(handler)
216 self.connection = self.handler.connect()
218 def select(self, query: ast.Select) -> pd.DataFrame:
219 project_uuid = self.get_where_param(query, 'project_uuid')
220 data = select_keys(self.connection.get_project(project_uuid).get("warehouseConnection", {}), self.columns)
221 df = pd.DataFrame.from_records([data])
222 return self.apply_query_params(df, query)
225class DBTConnectionTable(CustomAPITable):
226 name: str = "dbt_connection"
227 columns: List[str] = [
228 "type",
229 "target",
230 "profiles_dir",
231 "project_dir",
232 ]
234 def __init__(self, handler: APIHandler):
235 super().__init__(handler)
236 self.connection = self.handler.connect()
238 def select(self, query: ast.Select) -> pd.DataFrame:
239 project_uuid = self.get_where_param(query, "project_uuid")
240 data = select_keys(self.connection.get_project(project_uuid).get("dbtConnection", {}), self.columns)
241 df = pd.DataFrame.from_records([data])
242 return self.apply_query_params(df, query)
245class DBTEnvironmentVarsTable(CustomAPITable):
246 name: str = "dbt_env_vars"
247 columns: List[str] = [
248 "value",
249 "key",
250 ]
252 def __init__(self, handler: APIHandler):
253 super().__init__(handler)
254 self.connection = self.handler.connect()
256 def select(self, query: ast.Select) -> pd.DataFrame:
257 project_uuid = self.get_where_param(query, "project_uuid")
258 data = self.connection.get_project(project_uuid).get("dbtConnection", {}).get("environment", [])
259 df = pd.DataFrame.from_records(data, columns=self.columns)
260 return self.apply_query_params(df, query)
263class ChartsTable(CustomAPITable):
264 name: str = "charts"
265 columns: List[str] = [
266 "name",
267 "organizationUuid",
268 "uuid",
269 "description",
270 "projectUuid",
271 "spaceUuid",
272 "pinnedListUuid",
273 "spaceName",
274 "dashboardUuid",
275 "dashboardName",
276 "chartType",
277 ]
279 def __init__(self, handler: APIHandler):
280 super().__init__(handler)
281 self.connection = self.handler.connect()
283 def select(self, query: ast.Select) -> pd.DataFrame:
284 project_uuid = self.get_where_param(query, "project_uuid")
285 data = self.connection.get_charts_in_project(project_uuid)
286 df = pd.DataFrame.from_records(data, columns=self.columns)
287 return self.apply_query_params(df, query)
290class SpacesTable(CustomAPITable):
291 name: str = "spaces"
292 columns: List[str] = [
293 "name",
294 "organizationUuid",
295 "uuid",
296 "projectUuid",
297 "pinnedListUuid",
298 "pinnedListOrder",
299 "isPrivate",
300 "dashboardCount",
301 "chartCount",
302 "access",
303 ]
305 def __init__(self, handler: APIHandler):
306 super().__init__(handler)
307 self.connection = self.handler.connect()
309 def select(self, query: ast.Select) -> pd.DataFrame:
310 project_uuid = self.get_where_param(query, "project_uuid")
311 data = self.connection.get_spaces_in_project(project_uuid)
312 for d in data:
313 val_to_string(d, "access")
314 df = pd.DataFrame.from_records(data, columns=self.columns)
315 return self.apply_query_params(df, query)
318class AccessTable(CustomAPITable):
319 name: str = "access"
320 columns: List[str] = [
321 "lastName",
322 "firstName",
323 "email",
324 "role",
325 "projectUuid",
326 "userUuid",
327 ]
329 def __init__(self, handler: APIHandler):
330 super().__init__(handler)
331 self.connection = self.handler.connect()
333 def select(self, query: ast.Select) -> pd.DataFrame:
334 project_uuid = self.get_where_param(query, "project_uuid")
335 data = self.connection.get_project_access_list(project_uuid)
336 df = pd.DataFrame.from_records(data, columns=self.columns)
337 return self.apply_query_params(df, query)
340class ValidationTable(CustomAPITable):
341 name: str = "validation"
342 columns: List[str] = [
343 "source",
344 "spaceUuid",
345 "projectUuid",
346 "errorType",
347 "error",
348 "name",
349 "createdAt",
350 "validationId",
351 "chartName",
352 "chartViews",
353 "lastUpdatedAt",
354 "lastUpdatedBy",
355 "fieldName",
356 "chartType",
357 "chartUuid",
358 ]
360 def __init__(self, handler: APIHandler):
361 super().__init__(handler)
362 self.connection = self.handler.connect()
364 def select(self, query: ast.Select) -> pd.DataFrame:
365 project_uuid = self.get_where_param(query, "project_uuid")
366 data = self.connection.get_validation_results(project_uuid)
367 df = pd.DataFrame.from_records(data, columns=self.columns)
368 return self.apply_query_params(df, query)
371class DashboardsTable(CustomAPITable):
372 name: str = "dashboards"
373 columns: List[str] = [
374 "name",
375 "organizationUuid",
376 "uuid",
377 "description",
378 "updatedAt",
379 "projectUuid",
380 "spaceUuid",
381 "views",
382 "firstViewedAt",
383 "pinnedListUuid",
384 "pinnedListOrder",
385 ]
387 def __init__(self, handler: APIHandler):
388 super().__init__(handler)
389 self.connection = self.handler.connect()
391 def select(self, query: ast.Select) -> pd.DataFrame:
392 project_uuid = self.get_where_param(query, "project_uuid")
393 space_uuid = self.get_where_param(query, "space_uuid")
394 data = []
395 for row in self.connection.get_space(project_uuid, space_uuid).get("dashboards", []):
396 data.append(select_keys(row, self.columns))
397 df = pd.DataFrame.from_records(data, columns=self.columns)
398 return self.apply_query_params(df, query)
401class QueriesTable(CustomAPITable):
402 name: str = "queries"
403 columns: List[str] = [
404 "name",
405 "uuid",
406 "description",
407 "updatedAt",
408 "spaceUuid",
409 "pinnedListUuid",
410 "pinnedListOrder",
411 "firstViewedAt",
412 "views",
413 "chartType",
414 ]
416 def __init__(self, handler: APIHandler):
417 super().__init__(handler)
418 self.connection = self.handler.connect()
420 def select(self, query: ast.Select) -> pd.DataFrame:
421 project_uuid = self.get_where_param(query, "project_uuid")
422 space_uuid = self.get_where_param(query, "space_uuid")
423 data = []
424 for row in self.connection.get_space(project_uuid, space_uuid).get("queries", []):
425 data.append(select_keys(row, self.columns))
426 df = pd.DataFrame.from_records(data, columns=self.columns)
427 return self.apply_query_params(df, query)
430class ChartHistoryTable(CustomAPITable):
431 name: str = "chart_history"
432 columns: List[str] = [
433 "createdAt",
434 "chartUuid",
435 "versionUuid",
436 "createdBy",
437 ]
439 def __init__(self, handler: APIHandler):
440 super().__init__(handler)
441 self.connection = self.handler.connect()
443 def select(self, query: ast.Select) -> pd.DataFrame:
444 chart_uuid = self.get_where_param(query, "chart_uuid")
445 data = []
446 for row in self.connection.get_chart_version_history(chart_uuid):
447 d = select_keys(row, self.columns)
448 val_to_string(d, "createdBy")
449 data.append(d)
450 df = pd.DataFrame.from_records(data, columns=self.columns)
451 return self.apply_query_params(df, query)
454class ChartConfigTable(CustomAPITable):
455 name: str = "chart_config"
456 columns: List[str] = [
457 "legendPosition",
458 "showLegend",
459 "groupSortOverrides",
460 "groupValueOptionOverrides",
461 "groupColorOverrides",
462 "groupLabelOverrides",
463 "showPercentage",
464 "showValue",
465 "valueLabel",
466 "isDonut",
467 "metricId",
468 "groupFieldIds"
469 ]
471 def __init__(self, handler: APIHandler):
472 super().__init__(handler)
473 self.connection = self.handler.connect()
475 def select(self, query: ast.Select) -> pd.DataFrame:
476 chart_uuid = self.get_where_param(query, "chart_uuid")
477 version_uuid = self.get_where_param(query, "version_uuid")
478 raw_data = self.connection.get_chart(chart_uuid, version_uuid).get("chart", {}).get("chart_config", {})
479 config_data = raw_data.get("config", {})
480 val_to_string(config_data, "groupSortOverrides")
481 val_to_string(config_data, "groupValueOptionOverrides")
482 val_to_string(config_data, "groupColorOverrides")
483 val_to_string(config_data, "groupLabelOverrides")
484 val_to_string(config_data, "groupFieldIds")
485 config_data = select_keys(config_data, self.columns)
486 df = pd.DataFrame.from_records([{**config_data, "type": raw_data.get("type", "")}], columns=self.columns)
487 return self.apply_query_params(df, query)
490class ChartAdditionalMetricsTable(CustomAPITable):
491 name: str = "chart_additional_metrics"
492 columns: List[str] = [
493 "label",
494 "type",
495 "description",
496 "sql",
497 "hidden",
498 "round",
499 "compact",
500 "format",
501 "table",
502 "name",
503 "index",
504 "filters",
505 "baseDimensionName",
506 "uuid",
507 "percentile",
508 ]
510 def __init__(self, handler: APIHandler):
511 super().__init__(handler)
512 self.connection = self.handler.connect()
514 def select(self, query: ast.Select) -> pd.DataFrame:
515 chart_uuid = self.get_where_param(query, "chart_uuid")
516 version_uuid = self.get_where_param(query, "version_uuid")
517 data = self.connection.get_chart(chart_uuid, version_uuid).get("metricQuery", {}).get("additionalMetrics", [])
518 for d in data:
519 val_to_string(data, "filters")
520 d = select_keys(d, self.columns)
521 df = pd.DataFrame.from_records(data, columns=self.columns)
522 return self.apply_query_params(df, query)
525class ChartTableCalculationsTable(CustomAPITable):
526 name: str = "chart_table_calculations"
527 columns: List[str] = [
528 "suffix",
529 "prefix",
530 "compact",
531 "currency",
532 "separator",
533 "round",
534 "type",
535 "sql",
536 "displayName",
537 "name",
538 "index",
539 ]
541 def __init__(self, handler: APIHandler):
542 super().__init__(handler)
543 self.connection = self.handler.connect()
545 def select(self, query: ast.Select) -> pd.DataFrame:
546 chart_uuid = self.get_where_param(query, "chart_uuid")
547 version_uuid = self.get_where_param(query, "version_uuid")
548 data = self.connection.get_chart(chart_uuid, version_uuid).get("metricQuery", {}).get("tableCalculations", [])
549 for d in data:
550 move_under(d, "format")
551 d = select_keys(d, self.columns)
552 df = pd.DataFrame.from_records(data, columns=self.columns)
553 return self.apply_query_params(df, query)
556class SchedulerLogsTable(CustomAPITable):
557 name: str = "scheduler_logs"
558 columns: List[str] = [
559 "details",
560 "targetType",
561 "target",
562 "status",
563 "createdAt",
564 "scheduledTime",
565 "jobGroup",
566 "jobId",
567 "schedulerUuid",
568 "task",
569 ]
571 def __init__(self, handler: APIHandler):
572 super().__init__(handler)
573 self.connection = self.handler.connect()
575 def select(self, query: ast.Select) -> pd.DataFrame:
576 project_uuid = self.get_where_param(query, "project_uuid")
577 data = self.connection.get_scheduler_logs(project_uuid).get("logs", [])
578 for d in data:
579 val_to_string(d, "details")
580 d = select_keys(d, self.columns)
581 df = pd.DataFrame.from_records(data, columns=self.columns)
582 return self.apply_query_params(df, query)
585class SchedulerTable(CustomAPITable):
586 name: str = "scheduler"
587 columns: List[str] = [
588 "options",
589 "dashboardUuid",
590 "savedChartUuid",
591 "cron",
592 "format",
593 "createdBy",
594 "updatedAt",
595 "createdAt",
596 "message",
597 "name",
598 "schedulerUuid",
599 ]
601 def __init__(self, handler: APIHandler):
602 super().__init__(handler)
603 self.connection = self.handler.connect()
605 def select(self, query: ast.Select) -> pd.DataFrame:
606 scheduler_uuid = self.get_where_param(query, "scheduler_uuid")
607 data = select_keys(self.connection.get_scheduler(scheduler_uuid), self.columns)
608 val_to_string(data, "options")
609 df = pd.DataFrame.from_records([data], columns=self.columns)
610 return self.apply_query_params(df, query)
613class SchedulerJobsTable(CustomAPITable):
614 name: str = "scheduler_jobs"
615 columns: List[str] = [
616 "id",
617 "date",
618 ]
620 def __init__(self, handler: APIHandler):
621 super().__init__(handler)
622 self.connection = self.handler.connect()
624 def select(self, query: ast.Select) -> pd.DataFrame:
625 scheduler_uuid = self.get_where_param(query, "scheduler_uuid")
626 data = self.connection.get_scheduler_jobs(scheduler_uuid)
627 for d in data:
628 d = select_keys(d, self.columns)
629 df = pd.DataFrame.from_records(data, columns=self.columns)
630 return self.apply_query_params(df, query)
633class SchedulerJobStatus(CustomAPITable):
634 name: str = "scheduler_job_status"
635 columns: List[str] = [
636 "status",
637 ]
639 def __init__(self, handler: APIHandler):
640 super().__init__(handler)
641 self.connection = self.handler.connect()
643 def select(self, query: ast.Select) -> pd.DataFrame:
644 job_id = self.get_where_param(query, "job_id")
645 data = self.connection.get_scheduler_jobs(job_id)
646 data = select_keys(data, self.columns)
647 df = pd.DataFrame.from_records([data], columns=self.columns)
648 return self.apply_query_params(df, query)