diff --git a/backend/apps/datasource/api/datasource.py b/backend/apps/datasource/api/datasource.py index 081367af..924ed850 100644 --- a/backend/apps/datasource/api/datasource.py +++ b/backend/apps/datasource/api/datasource.py @@ -1,5 +1,5 @@ from fastapi import APIRouter -from ..crud.datasource import get_datasource_list, check_status, create_ds, update_ds, delete_ds, getTables, getFields +from ..crud.datasource import get_datasource_list, check_status, create_ds, update_ds, delete_ds, getTables, getFields, execSql from common.core.deps import SessionDep from ..models.datasource import CoreDatasource @@ -39,3 +39,8 @@ async def get_tables(session: SessionDep, id: int): @router.post("/getFields/{id}/{table_name}") async def get_tables(session: SessionDep, id: int, table_name: str): return getFields(session, id, table_name) + + +@router.post("/execSql/{id}/{sql}") +async def exec_sql(session: SessionDep, id: int, sql: str): + return execSql(session, id, sql) diff --git a/backend/apps/datasource/crud/datasource.py b/backend/apps/datasource/crud/datasource.py index 4f6af1b0..eaec1c0f 100644 --- a/backend/apps/datasource/crud/datasource.py +++ b/backend/apps/datasource/crud/datasource.py @@ -2,9 +2,7 @@ from sqlmodel import select from ..models.datasource import CoreDatasource, DatasourceConf import datetime from common.core.deps import SessionDep -import json -from ..utils.utils import aes_decrypt -from apps.db.db import get_session, get_tables, get_fields +from apps.db.db import get_session, get_tables, get_fields, exec_sql from sqlalchemy import text @@ -15,8 +13,7 @@ def get_datasource_list(session: SessionDep) -> CoreDatasource: def check_status(session: SessionDep, ds: CoreDatasource): - conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) - conn = get_session(conf, ds) + conn = get_session(ds) try: conn.execute(text("SELECT 1")).scalar() print("success") @@ -59,13 +56,16 @@ def delete_ds(session: SessionDep, id: int): def getTables(session: SessionDep, id: int): ds = session.exec(select(CoreDatasource).where(CoreDatasource.id == id)).first() - conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) - tables = get_tables(conf, ds) + tables = get_tables(ds) return tables def getFields(session: SessionDep, id: int, table_name: str): ds = session.exec(select(CoreDatasource).where(CoreDatasource.id == id)).first() - conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) - fields = get_fields(conf, ds, table_name) + fields = get_fields(ds, table_name) return fields + + +def execSql(session: SessionDep, id: int, sql: str): + ds = session.exec(select(CoreDatasource).where(CoreDatasource.id == id)).first() + return exec_sql(ds, sql) diff --git a/backend/apps/db/db.py b/backend/apps/db/db.py index 02d37e7f..90b374d3 100644 --- a/backend/apps/db/db.py +++ b/backend/apps/db/db.py @@ -3,9 +3,12 @@ from sqlalchemy.orm import sessionmaker from apps.datasource.models.datasource import DatasourceConf, CoreDatasource, TableSchema, ColumnSchema import urllib.parse from typing import Any +import json +from apps.datasource.utils.utils import aes_decrypt -def get_session(conf: DatasourceConf, ds: CoreDatasource): +def get_session(ds: CoreDatasource): + conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) db_url: str if ds.type == "mysql": db_url = f"mysql+pymysql://{urllib.parse.quote(conf.username)}:{urllib.parse.quote(conf.password)}@{conf.host}:{conf.port}/{urllib.parse.quote(conf.database)}" @@ -17,39 +20,71 @@ def get_session(conf: DatasourceConf, ds: CoreDatasource): return session -def get_tables(conf: DatasourceConf, ds: CoreDatasource): - session = get_session(conf, ds) +def get_tables(ds: CoreDatasource): + conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) + session = get_session(ds) result: Result[Any] - if ds.type == "mysql": - sql = f"""SELECT - TABLE_NAME, - TABLE_COMMENT - FROM - information_schema.TABLES - WHERE - TABLE_SCHEMA = '{conf.database}';""" - result = session.execute(text(sql)) + try: + if ds.type == "mysql": + sql = f"""SELECT + TABLE_NAME, + TABLE_COMMENT + FROM + information_schema.TABLES + WHERE + TABLE_SCHEMA = '{conf.database}';""" + result = session.execute(text(sql)) - res = result.fetchall() - res_list = [TableSchema(*item) for item in res] - return res_list + res = result.fetchall() + res_list = [TableSchema(*item) for item in res] + return res_list + finally: + if result is not None: + result.close() + if session is not None: + session.close() -def get_fields(conf: DatasourceConf, ds: CoreDatasource, table_name: str): - session = get_session(conf, ds) +def get_fields(ds: CoreDatasource, table_name: str): + conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) + session = get_session(ds) result: Result[Any] - if ds.type == "mysql": - sql = f"""SELECT - COLUMN_NAME, - DATA_TYPE, - COLUMN_COMMENT - FROM - INFORMATION_SCHEMA.COLUMNS - WHERE - TABLE_SCHEMA = '{conf.database}' AND - TABLE_NAME = '{table_name}';""" - result = session.execute(text(sql)) + try: + if ds.type == "mysql": + sql = f"""SELECT + COLUMN_NAME, + DATA_TYPE, + COLUMN_COMMENT + FROM + INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_SCHEMA = '{conf.database}' AND + TABLE_NAME = '{table_name}';""" + result = session.execute(text(sql)) - res = result.fetchall() - res_list = [ColumnSchema(*item) for item in res] - return res_list + res = result.fetchall() + res_list = [ColumnSchema(*item) for item in res] + return res_list + finally: + if result is not None: + result.close() + if session is not None: + session.close() + + +def exec_sql(ds: CoreDatasource, sql: str): + session = get_session(ds) + result = session.execute(text(sql)) + try: + columns = result.keys()._keys + res = result.fetchall() + result_list = [ + {columns[i]: value for i, value in enumerate(tuple_item)} + for tuple_item in res + ] + return {"fields": columns, "data": result_list} + finally: + if result is not None: + result.close() + if session is not None: + session.close() diff --git a/frontend/src/api/datasource.ts b/frontend/src/api/datasource.ts index 52b2d31c..1fb27de9 100644 --- a/frontend/src/api/datasource.ts +++ b/frontend/src/api/datasource.ts @@ -8,4 +8,5 @@ export const datasourceApi = { delete: (id: Number) => request.post(`/datasource/delete/${id}`), getTables: (id: Number) => request.post(`/datasource/getTables/${id}`), getFields: (id: Number, table_name: string) => request.post(`/datasource/getFields/${id}/${table_name}`), + execSql: (id: Number, sql: string) => request.post(`/datasource/execSql/${id}/${sql}`), } \ No newline at end of file diff --git a/frontend/src/views/ds/index.vue b/frontend/src/views/ds/index.vue index 0eb4f4df..c445a3ef 100644 --- a/frontend/src/views/ds/index.vue +++ b/frontend/src/views/ds/index.vue @@ -120,7 +120,11 @@ const getTables = (id: Number) => { // console.log(res) // }) - datasourceApi.getFields(id,'core_dataset_table').then((res) => { + // datasourceApi.getFields(id,'core_dataset_table').then((res) => { + // console.log(res) + // }) + + datasourceApi.execSql(id,'select id,name,table_name from core_dataset_table limit 10').then((res) => { console.log(res) }) }