Skip to content

Commit f586aec

Browse files
committed
feat: support ClickHouse datasource
1 parent e1e482e commit f586aec

File tree

8 files changed

+37
-3
lines changed

8 files changed

+37
-3
lines changed

backend/apps/datasource/crud/datasource.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ def preview(session: SessionDep, current_user: CurrentUser, id: int, data: Table
293293
{where}
294294
ORDER BY "{fields[0]}"
295295
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY"""
296+
elif ds.type == "ck":
297+
sql = f"""SELECT "{'", "'.join(fields)}" FROM "{data.table.table_name}"
298+
{where}
299+
LIMIT 100"""
296300
return exec_sql(ds, sql)
297301

298302

backend/apps/db/constant.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class DB(Enum):
1010
pg = ('pg', '"', '"')
1111
excel = ('excel', '"', '"')
1212
oracle = ('oracle', '"', '"')
13+
ck = ('ClickHouse', '"', '"')
1314

1415
def __init__(self, type, prefix, suffix):
1516
self.type = type

backend/apps/db/db.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def get_uri_from_config(type: str, conf: DatasourceConf) -> str:
4646
db_url = f"oracle+oracledb://{urllib.parse.quote(conf.username)}:{urllib.parse.quote(conf.password)}@{conf.host}:{conf.port}/{conf.database}?{conf.extraJdbc}"
4747
else:
4848
db_url = f"oracle+oracledb://{urllib.parse.quote(conf.username)}:{urllib.parse.quote(conf.password)}@{conf.host}:{conf.port}/{conf.database}"
49+
elif type == "ck":
50+
if conf.extraJdbc is not None and conf.extraJdbc != '':
51+
db_url = f"clickhouse+http://{urllib.parse.quote(conf.username)}:{urllib.parse.quote(conf.password)}@{conf.host}:{conf.port}/{conf.database}?{conf.extraJdbc}"
52+
else:
53+
db_url = f"clickhouse+http://{urllib.parse.quote(conf.username)}:{urllib.parse.quote(conf.password)}@{conf.host}:{conf.port}/{conf.database}"
4954
else:
5055
raise 'The datasource type not support.'
5156
return db_url
@@ -67,7 +72,7 @@ def get_engine(ds: CoreDatasource, timeout: int = 0) -> Engine:
6772
elif ds.type == 'oracle':
6873
engine = create_engine(get_uri(ds),
6974
pool_timeout=conf.timeout)
70-
else:
75+
else: # mysql, ck
7176
engine = create_engine(get_uri(ds), connect_args={"connect_timeout": conf.timeout}, pool_timeout=conf.timeout)
7277
return engine
7378

@@ -144,6 +149,14 @@ def get_tables(ds: CoreDatasource):
144149
AND c.OWNER = '{conf.dbSchema}'
145150
ORDER BY t.TABLE_NAME
146151
"""
152+
elif ds.type == "ck":
153+
sql = f"""
154+
SELECT name, engine
155+
FROM system.tables
156+
WHERE database = '{conf.database}'
157+
AND engine NOT IN ('Dictionary')
158+
ORDER BY name
159+
"""
147160
with session.execute(text(sql)) as result:
148161
res = result.fetchall()
149162
res_list = [TableSchema(*item) for item in res]
@@ -226,6 +239,17 @@ def get_fields(ds: CoreDatasource, table_name: str = None):
226239
"""
227240
sql2 = f" AND col.TABLE_NAME = '{table_name}'" if table_name is not None and table_name != "" else ""
228241
sql = sql1 + sql2
242+
elif ds.type == "ck":
243+
sql1 = f"""
244+
SELECT
245+
name AS COLUMN_NAME,
246+
type AS DATA_TYPE,
247+
comment AS COLUMN_COMMENT
248+
FROM system.columns
249+
WHERE database = '{conf.database}'
250+
"""
251+
sql2 = f" AND table = '{table_name}'" if table_name is not None and table_name != "" else ""
252+
sql = sql1 + sql2
229253

230254
with session.execute(text(sql)) as result:
231255
res = result.fetchall()

backend/apps/db/type.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ def db_type_relation() -> Dict:
99
"sqlServer": "Microsoft SQL Server",
1010
"pg": "PostgreSQL",
1111
"excel": "Excel/CSV",
12-
"oracle": "Oracle"
12+
"oracle": "Oracle",
13+
"ck": "ClickHouse"
1314
}

backend/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dependencies = [
4343
"xlsxwriter>=3.2.5",
4444
"python-calamine>=0.4.0",
4545
"xlrd>=2.0.2",
46+
"clickhouse-sqlalchemy>=0.3.2",
4647
]
4748
[[tool.uv.index]]
4849
name = "default"

backend/template.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ template:
2727
- SQL查询的字段若是函数字段,如 COUNT(),CAST() 等,必须加上别名
2828
- 计算占比,百分比类型字段,保留两位小数,以%结尾。
2929
- 生成SQL时,必须避免关键字冲突。
30-
- 如数据库引擎是 PostgreSQL、Oracle,则在schema、表名、字段名、别名外层加双引号;
30+
- 如数据库引擎是 PostgreSQL、Oracle、ClickHouse,则在schema、表名、字段名、别名外层加双引号;
3131
- 如数据库引擎是 MySQL,则在表名、字段名、别名外层加反引号;
3232
- 如数据库引擎是 Microsoft SQL Server,则在schema、表名、字段名、别名外层加方括号。
3333
- 以PostgreSQL为例,查询Schema为TEST表TABLE下所有数据,则生成的SQL为:
286 Bytes
Loading

frontend/src/views/ds/js/ds-type.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import excel from '@/assets/datasource/icon_excel.png'
33
import oracle from '@/assets/datasource/icon_oracle.png'
44
import pg from '@/assets/datasource/icon_PostgreSQL.png'
55
import sqlServer from '@/assets/datasource/icon_SQL_Server.png'
6+
import ck from '@/assets/datasource/icon_ck.png'
67
import { i18n } from '@/i18n'
78

89
const t = i18n.global.t
@@ -12,6 +13,7 @@ export const dsType = [
1213
{ label: 'Oracle', value: 'oracle' },
1314
{ label: 'PostgreSQL', value: 'pg' },
1415
{ label: 'SQL Server', value: 'sqlServer' },
16+
{ label: 'ClickHouse', value: 'ck' },
1517
]
1618

1719
export const dsTypeWithImg = [
@@ -20,6 +22,7 @@ export const dsTypeWithImg = [
2022
{ name: 'Oracle', type: 'oracle', img: oracle },
2123
{ name: 'PostgreSQL', type: 'pg', img: pg },
2224
{ name: 'SQL Server', type: 'sqlServer', img: sqlServer },
25+
{ name: 'ClickHouse', type: 'ck', img: ck },
2326
]
2427

2528
export const haveSchema = ['sqlServer', 'pg', 'oracle']

0 commit comments

Comments
 (0)