fdb2 1.0.33 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/public/explorer.css +42 -42
- package/dist/public/explorer.js +35 -24
- package/dist/public/index.js +2 -0
- package/dist/public/layout.css +69 -54
- package/dist/public/layout.js +15 -8
- package/dist/server/core/db-api.js +5 -0
- package/dist/server/core/db-api.js.map +1 -1
- package/dist/server/core/db-api.ts +5 -0
- package/dist/server/core/dialect.d.ts +1 -1
- package/dist/server/core/dialect.d.ts.map +1 -1
- package/dist/server/core/dialect.js +21 -1
- package/dist/server/core/dialect.js.map +1 -1
- package/dist/server/core/dialect.ts +23 -2
- package/dist/server/service/connection.service.d.ts.map +1 -1
- package/dist/server/service/connection.service.js +17 -1
- package/dist/server/service/connection.service.js.map +1 -1
- package/dist/server/service/connection.service.ts +17 -1
- package/dist/server/service/database/clickhouse-connection.d.ts +44 -0
- package/dist/server/service/database/clickhouse-connection.d.ts.map +1 -0
- package/dist/server/service/database/clickhouse-connection.js +210 -0
- package/dist/server/service/database/clickhouse-connection.js.map +1 -0
- package/dist/server/service/database/clickhouse-connection.ts +182 -0
- package/dist/server/service/database/clickhouse.service.d.ts +138 -0
- package/dist/server/service/database/clickhouse.service.d.ts.map +1 -0
- package/dist/server/service/database/clickhouse.service.js +794 -0
- package/dist/server/service/database/clickhouse.service.js.map +1 -0
- package/dist/server/service/database/clickhouse.service.ts +853 -0
- package/dist/server/service/database/database.service.d.ts +42 -0
- package/dist/server/service/database/database.service.d.ts.map +1 -1
- package/dist/server/service/database/database.service.js +37 -0
- package/dist/server/service/database/database.service.js.map +1 -1
- package/dist/server/service/database/database.service.ts +37 -0
- package/dist/server/service/database/index.d.ts +1 -0
- package/dist/server/service/database/index.d.ts.map +1 -1
- package/dist/server/service/database/index.js +3 -1
- package/dist/server/service/database/index.js.map +1 -1
- package/dist/server/service/database/index.ts +1 -0
- package/package.json +1 -4
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClickHouse 连接封装
|
|
3
|
+
* ClickHouse 没有官方 TypeORM 驱动,这里直接使用其 HTTP 接口(默认端口 8123)。
|
|
4
|
+
* 该对象对外暴露与 TypeORM DataSource 类似的最小接口:
|
|
5
|
+
* query(sql, params?) / options / isInitialized / destroy()
|
|
6
|
+
* 以便复用现有 BaseDatabaseService 体系。
|
|
7
|
+
*/
|
|
8
|
+
export declare class ClickHouseConnection {
|
|
9
|
+
options: any;
|
|
10
|
+
isInitialized: boolean;
|
|
11
|
+
private baseUrl;
|
|
12
|
+
private auth?;
|
|
13
|
+
private defaultDatabase;
|
|
14
|
+
private timeout;
|
|
15
|
+
constructor(connectionConfig: any);
|
|
16
|
+
/**
|
|
17
|
+
* 执行 SQL。
|
|
18
|
+
* - 读查询(SELECT/SHOW/DESCRIBE/EXPLAIN/WITH)返回解析后的行数组(JSONEachRow)。
|
|
19
|
+
* - 其它(DDL/DML)返回空数组。
|
|
20
|
+
*/
|
|
21
|
+
query(sql: string, params?: any[]): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* 解析 JSONEachRow 单行。
|
|
24
|
+
* ClickHouse 可能输出 NaN/Infinity(非法 JSON),解析失败时回退为原始字符串。
|
|
25
|
+
*/
|
|
26
|
+
private static safeParse;
|
|
27
|
+
/**
|
|
28
|
+
* 执行查询并返回原始文本(用于导出 CSV/原生格式)。
|
|
29
|
+
*/
|
|
30
|
+
queryRaw(sql: string, format?: string): Promise<string>;
|
|
31
|
+
destroy(): Promise<void>;
|
|
32
|
+
private databasePath;
|
|
33
|
+
private post;
|
|
34
|
+
/** 将 SQL 中的 ? 占位符按顺序替换为安全字面量(仅用于服务内部兜底) */
|
|
35
|
+
private static fillParams;
|
|
36
|
+
/**
|
|
37
|
+
* 转义 ClickHouse 字符串字面量。
|
|
38
|
+
* ClickHouse 字符串中以反斜杠作为转义符:\\ 表示反斜杠,\' 表示单引号,
|
|
39
|
+
* 不能使用 SQL 标准的双写单引号('')。
|
|
40
|
+
*/
|
|
41
|
+
static escapeLiteral(value: any): string;
|
|
42
|
+
private static escapeString;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=clickhouse-connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse-connection.d.ts","sourceRoot":"","sources":["../../../../server/service/database/clickhouse-connection.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,qBAAa,oBAAoB;IACxB,OAAO,EAAE,GAAG,CAAC;IACb,aAAa,UAAQ;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,OAAO,CAAS;gBAEZ,gBAAgB,EAAE,GAAG;IA0BjC;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAsBtD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAgBxB;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIvE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,IAAI;IA0CZ,2CAA2C;IAC3C,OAAO,CAAC,MAAM,CAAC,UAAU;IAQzB;;;;OAIG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM;IAcxC,OAAO,CAAC,MAAM,CAAC,YAAY;CAG5B"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ClickHouseConnection = void 0;
|
|
37
|
+
const http = __importStar(require("http"));
|
|
38
|
+
const https = __importStar(require("https"));
|
|
39
|
+
const url = __importStar(require("url"));
|
|
40
|
+
/**
|
|
41
|
+
* ClickHouse 连接封装
|
|
42
|
+
* ClickHouse 没有官方 TypeORM 驱动,这里直接使用其 HTTP 接口(默认端口 8123)。
|
|
43
|
+
* 该对象对外暴露与 TypeORM DataSource 类似的最小接口:
|
|
44
|
+
* query(sql, params?) / options / isInitialized / destroy()
|
|
45
|
+
* 以便复用现有 BaseDatabaseService 体系。
|
|
46
|
+
*/
|
|
47
|
+
class ClickHouseConnection {
|
|
48
|
+
options;
|
|
49
|
+
isInitialized = true;
|
|
50
|
+
baseUrl;
|
|
51
|
+
auth;
|
|
52
|
+
defaultDatabase;
|
|
53
|
+
timeout;
|
|
54
|
+
constructor(connectionConfig) {
|
|
55
|
+
const config = connectionConfig || {};
|
|
56
|
+
const secure = !!(config.options && (config.options.secure || config.options.ssl));
|
|
57
|
+
const proto = secure ? 'https' : 'http';
|
|
58
|
+
const host = config.host || 'localhost';
|
|
59
|
+
const port = config.port || 8123;
|
|
60
|
+
this.baseUrl = `${proto}://${host}:${port}`;
|
|
61
|
+
this.defaultDatabase = config.database && config.database !== 'default' ? config.database : 'default';
|
|
62
|
+
this.timeout = Number((config.options && config.options.requestTimeout) || 30000);
|
|
63
|
+
this.options = {
|
|
64
|
+
type: 'clickhouse',
|
|
65
|
+
host,
|
|
66
|
+
port,
|
|
67
|
+
username: config.username,
|
|
68
|
+
password: config.password,
|
|
69
|
+
database: config.database || this.defaultDatabase,
|
|
70
|
+
...(config.options || {})
|
|
71
|
+
};
|
|
72
|
+
// ClickHouse 默认用户为 default;即使未填用户名也应携带鉴权头
|
|
73
|
+
const username = config.username || 'default';
|
|
74
|
+
const token = Buffer.from(`${username}:${config.password || ''}`).toString('base64');
|
|
75
|
+
this.auth = `Basic ${token}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 执行 SQL。
|
|
79
|
+
* - 读查询(SELECT/SHOW/DESCRIBE/EXPLAIN/WITH)返回解析后的行数组(JSONEachRow)。
|
|
80
|
+
* - 其它(DDL/DML)返回空数组。
|
|
81
|
+
*/
|
|
82
|
+
async query(sql, params) {
|
|
83
|
+
let finalSql = sql;
|
|
84
|
+
if (params && params.length) {
|
|
85
|
+
finalSql = ClickHouseConnection.fillParams(sql, params);
|
|
86
|
+
}
|
|
87
|
+
const isRead = /^\s*(select|with|show|describe|desc|explain|exists|use)\b/i.test(finalSql);
|
|
88
|
+
if (isRead) {
|
|
89
|
+
// 去掉结尾分号,避免 "...; FORMAT ..." 语法错误
|
|
90
|
+
const cleanSql = finalSql.replace(/;\s*$/, '');
|
|
91
|
+
// 使用 JSONStringsEachRow:所有值均以字符串返回,避免 UInt64 等超出 JS 安全整数范围导致精度丢失
|
|
92
|
+
const text = await this.post(`${cleanSql} FORMAT JSONStringsEachRow`);
|
|
93
|
+
if (!text || !text.trim())
|
|
94
|
+
return [];
|
|
95
|
+
return text
|
|
96
|
+
.split('\n')
|
|
97
|
+
.map((line) => line.trim())
|
|
98
|
+
.filter((line) => line.length > 0)
|
|
99
|
+
.map((line) => ClickHouseConnection.safeParse(line));
|
|
100
|
+
}
|
|
101
|
+
await this.post(finalSql);
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 解析 JSONEachRow 单行。
|
|
106
|
+
* ClickHouse 可能输出 NaN/Infinity(非法 JSON),解析失败时回退为原始字符串。
|
|
107
|
+
*/
|
|
108
|
+
static safeParse(line) {
|
|
109
|
+
try {
|
|
110
|
+
return JSON.parse(line);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
try {
|
|
114
|
+
const normalized = line
|
|
115
|
+
.replace(/:\s*NaN/g, ': null')
|
|
116
|
+
.replace(/:\s*Infinity/g, ': null')
|
|
117
|
+
.replace(/:\s*-Infinity/g, ': null');
|
|
118
|
+
return JSON.parse(normalized);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return line;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 执行查询并返回原始文本(用于导出 CSV/原生格式)。
|
|
127
|
+
*/
|
|
128
|
+
async queryRaw(sql, format = 'CSVWithNames') {
|
|
129
|
+
return this.post(`${sql.replace(/;\s*$/, '')} FORMAT ${format}`);
|
|
130
|
+
}
|
|
131
|
+
async destroy() {
|
|
132
|
+
this.isInitialized = false;
|
|
133
|
+
}
|
|
134
|
+
databasePath() {
|
|
135
|
+
return `/?database=${encodeURIComponent(this.defaultDatabase)}`;
|
|
136
|
+
}
|
|
137
|
+
post(body) {
|
|
138
|
+
return new Promise((resolve, reject) => {
|
|
139
|
+
const parsed = url.parse(this.baseUrl);
|
|
140
|
+
const data = Buffer.from(body, 'utf8');
|
|
141
|
+
const headers = {
|
|
142
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
143
|
+
'Content-Length': data.length
|
|
144
|
+
};
|
|
145
|
+
if (this.auth)
|
|
146
|
+
headers['Authorization'] = this.auth;
|
|
147
|
+
const lib = parsed.protocol === 'https:' ? https : http;
|
|
148
|
+
const req = lib.request({
|
|
149
|
+
hostname: parsed.hostname,
|
|
150
|
+
port: parsed.port,
|
|
151
|
+
path: this.databasePath(),
|
|
152
|
+
method: 'POST',
|
|
153
|
+
headers
|
|
154
|
+
}, (res) => {
|
|
155
|
+
const chunks = [];
|
|
156
|
+
res.on('data', (c) => chunks.push(c));
|
|
157
|
+
res.on('end', () => {
|
|
158
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
159
|
+
const status = res.statusCode || 0;
|
|
160
|
+
if (status >= 400) {
|
|
161
|
+
reject(new Error(`ClickHouse 错误 (${status}): ${text.trim()}`));
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
resolve(text);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
req.on('error', (err) => reject(err));
|
|
169
|
+
req.setTimeout(this.timeout, () => {
|
|
170
|
+
req.destroy(new Error(`ClickHouse 请求超时(${this.timeout}ms)`));
|
|
171
|
+
});
|
|
172
|
+
req.write(data);
|
|
173
|
+
req.end();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/** 将 SQL 中的 ? 占位符按顺序替换为安全字面量(仅用于服务内部兜底) */
|
|
177
|
+
static fillParams(sql, params) {
|
|
178
|
+
let i = 0;
|
|
179
|
+
return sql.replace(/\?/g, () => {
|
|
180
|
+
const v = params[i++];
|
|
181
|
+
return ClickHouseConnection.escapeLiteral(v);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* 转义 ClickHouse 字符串字面量。
|
|
186
|
+
* ClickHouse 字符串中以反斜杠作为转义符:\\ 表示反斜杠,\' 表示单引号,
|
|
187
|
+
* 不能使用 SQL 标准的双写单引号('')。
|
|
188
|
+
*/
|
|
189
|
+
static escapeLiteral(value) {
|
|
190
|
+
if (value === null || value === undefined)
|
|
191
|
+
return 'NULL';
|
|
192
|
+
if (typeof value === 'number')
|
|
193
|
+
return String(value);
|
|
194
|
+
if (typeof value === 'boolean')
|
|
195
|
+
return value ? 'true' : 'false';
|
|
196
|
+
if (value instanceof Date) {
|
|
197
|
+
const s = value.toISOString().slice(0, 19).replace('T', ' ');
|
|
198
|
+
return `'${ClickHouseConnection.escapeString(s)}'`;
|
|
199
|
+
}
|
|
200
|
+
if (typeof value === 'object') {
|
|
201
|
+
return `'${ClickHouseConnection.escapeString(JSON.stringify(value))}'`;
|
|
202
|
+
}
|
|
203
|
+
return `'${ClickHouseConnection.escapeString(String(value))}'`;
|
|
204
|
+
}
|
|
205
|
+
static escapeString(s) {
|
|
206
|
+
return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
exports.ClickHouseConnection = ClickHouseConnection;
|
|
210
|
+
//# sourceMappingURL=clickhouse-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse-connection.js","sourceRoot":"","sources":["../../../../server/service/database/clickhouse-connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
import * as https from 'https';
|
|
3
|
+
import * as url from 'url';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ClickHouse 连接封装
|
|
7
|
+
* ClickHouse 没有官方 TypeORM 驱动,这里直接使用其 HTTP 接口(默认端口 8123)。
|
|
8
|
+
* 该对象对外暴露与 TypeORM DataSource 类似的最小接口:
|
|
9
|
+
* query(sql, params?) / options / isInitialized / destroy()
|
|
10
|
+
* 以便复用现有 BaseDatabaseService 体系。
|
|
11
|
+
*/
|
|
12
|
+
export class ClickHouseConnection {
|
|
13
|
+
public options: any;
|
|
14
|
+
public isInitialized = true;
|
|
15
|
+
private baseUrl: string;
|
|
16
|
+
private auth?: string;
|
|
17
|
+
private defaultDatabase: string;
|
|
18
|
+
|
|
19
|
+
private timeout: number;
|
|
20
|
+
|
|
21
|
+
constructor(connectionConfig: any) {
|
|
22
|
+
const config = connectionConfig || {};
|
|
23
|
+
const secure = !!(config.options && (config.options.secure || config.options.ssl));
|
|
24
|
+
const proto = secure ? 'https' : 'http';
|
|
25
|
+
const host = config.host || 'localhost';
|
|
26
|
+
const port = config.port || 8123;
|
|
27
|
+
this.baseUrl = `${proto}://${host}:${port}`;
|
|
28
|
+
this.defaultDatabase = config.database && config.database !== 'default' ? config.database : 'default';
|
|
29
|
+
this.timeout = Number((config.options && config.options.requestTimeout) || 30000);
|
|
30
|
+
|
|
31
|
+
this.options = {
|
|
32
|
+
type: 'clickhouse',
|
|
33
|
+
host,
|
|
34
|
+
port,
|
|
35
|
+
username: config.username,
|
|
36
|
+
password: config.password,
|
|
37
|
+
database: config.database || this.defaultDatabase,
|
|
38
|
+
...(config.options || {})
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ClickHouse 默认用户为 default;即使未填用户名也应携带鉴权头
|
|
42
|
+
const username = config.username || 'default';
|
|
43
|
+
const token = Buffer.from(`${username}:${config.password || ''}`).toString('base64');
|
|
44
|
+
this.auth = `Basic ${token}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 执行 SQL。
|
|
49
|
+
* - 读查询(SELECT/SHOW/DESCRIBE/EXPLAIN/WITH)返回解析后的行数组(JSONEachRow)。
|
|
50
|
+
* - 其它(DDL/DML)返回空数组。
|
|
51
|
+
*/
|
|
52
|
+
async query(sql: string, params?: any[]): Promise<any> {
|
|
53
|
+
let finalSql = sql;
|
|
54
|
+
if (params && params.length) {
|
|
55
|
+
finalSql = ClickHouseConnection.fillParams(sql, params);
|
|
56
|
+
}
|
|
57
|
+
const isRead = /^\s*(select|with|show|describe|desc|explain|exists|use)\b/i.test(finalSql);
|
|
58
|
+
if (isRead) {
|
|
59
|
+
// 去掉结尾分号,避免 "...; FORMAT ..." 语法错误
|
|
60
|
+
const cleanSql = finalSql.replace(/;\s*$/, '');
|
|
61
|
+
// 使用 JSONStringsEachRow:所有值均以字符串返回,避免 UInt64 等超出 JS 安全整数范围导致精度丢失
|
|
62
|
+
const text = await this.post(`${cleanSql} FORMAT JSONStringsEachRow`);
|
|
63
|
+
if (!text || !text.trim()) return [];
|
|
64
|
+
return text
|
|
65
|
+
.split('\n')
|
|
66
|
+
.map((line) => line.trim())
|
|
67
|
+
.filter((line) => line.length > 0)
|
|
68
|
+
.map((line) => ClickHouseConnection.safeParse(line));
|
|
69
|
+
}
|
|
70
|
+
await this.post(finalSql);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 解析 JSONEachRow 单行。
|
|
76
|
+
* ClickHouse 可能输出 NaN/Infinity(非法 JSON),解析失败时回退为原始字符串。
|
|
77
|
+
*/
|
|
78
|
+
private static safeParse(line: string): any {
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(line);
|
|
81
|
+
} catch {
|
|
82
|
+
try {
|
|
83
|
+
const normalized = line
|
|
84
|
+
.replace(/:\s*NaN/g, ': null')
|
|
85
|
+
.replace(/:\s*Infinity/g, ': null')
|
|
86
|
+
.replace(/:\s*-Infinity/g, ': null');
|
|
87
|
+
return JSON.parse(normalized);
|
|
88
|
+
} catch {
|
|
89
|
+
return line;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 执行查询并返回原始文本(用于导出 CSV/原生格式)。
|
|
96
|
+
*/
|
|
97
|
+
async queryRaw(sql: string, format: string = 'CSVWithNames'): Promise<string> {
|
|
98
|
+
return this.post(`${sql.replace(/;\s*$/, '')} FORMAT ${format}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async destroy(): Promise<void> {
|
|
102
|
+
this.isInitialized = false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private databasePath(): string {
|
|
106
|
+
return `/?database=${encodeURIComponent(this.defaultDatabase)}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private post(body: string): Promise<string> {
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
const parsed = url.parse(this.baseUrl);
|
|
112
|
+
const data = Buffer.from(body, 'utf8');
|
|
113
|
+
const headers: Record<string, any> = {
|
|
114
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
115
|
+
'Content-Length': data.length
|
|
116
|
+
};
|
|
117
|
+
if (this.auth) headers['Authorization'] = this.auth;
|
|
118
|
+
|
|
119
|
+
const lib = parsed.protocol === 'https:' ? https : http;
|
|
120
|
+
const req = lib.request(
|
|
121
|
+
{
|
|
122
|
+
hostname: parsed.hostname,
|
|
123
|
+
port: parsed.port,
|
|
124
|
+
path: this.databasePath(),
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers
|
|
127
|
+
},
|
|
128
|
+
(res) => {
|
|
129
|
+
const chunks: Buffer[] = [];
|
|
130
|
+
res.on('data', (c: Buffer) => chunks.push(c));
|
|
131
|
+
res.on('end', () => {
|
|
132
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
133
|
+
const status = res.statusCode || 0;
|
|
134
|
+
if (status >= 400) {
|
|
135
|
+
reject(new Error(`ClickHouse 错误 (${status}): ${text.trim()}`));
|
|
136
|
+
} else {
|
|
137
|
+
resolve(text);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
req.on('error', (err) => reject(err));
|
|
143
|
+
req.setTimeout(this.timeout, () => {
|
|
144
|
+
req.destroy(new Error(`ClickHouse 请求超时(${this.timeout}ms)`));
|
|
145
|
+
});
|
|
146
|
+
req.write(data);
|
|
147
|
+
req.end();
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** 将 SQL 中的 ? 占位符按顺序替换为安全字面量(仅用于服务内部兜底) */
|
|
152
|
+
private static fillParams(sql: string, params: any[]): string {
|
|
153
|
+
let i = 0;
|
|
154
|
+
return sql.replace(/\?/g, () => {
|
|
155
|
+
const v = params[i++];
|
|
156
|
+
return ClickHouseConnection.escapeLiteral(v);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 转义 ClickHouse 字符串字面量。
|
|
162
|
+
* ClickHouse 字符串中以反斜杠作为转义符:\\ 表示反斜杠,\' 表示单引号,
|
|
163
|
+
* 不能使用 SQL 标准的双写单引号('')。
|
|
164
|
+
*/
|
|
165
|
+
static escapeLiteral(value: any): string {
|
|
166
|
+
if (value === null || value === undefined) return 'NULL';
|
|
167
|
+
if (typeof value === 'number') return String(value);
|
|
168
|
+
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
169
|
+
if (value instanceof Date) {
|
|
170
|
+
const s = value.toISOString().slice(0, 19).replace('T', ' ');
|
|
171
|
+
return `'${ClickHouseConnection.escapeString(s)}'`;
|
|
172
|
+
}
|
|
173
|
+
if (typeof value === 'object') {
|
|
174
|
+
return `'${ClickHouseConnection.escapeString(JSON.stringify(value))}'`;
|
|
175
|
+
}
|
|
176
|
+
return `'${ClickHouseConnection.escapeString(String(value))}'`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private static escapeString(s: string): string {
|
|
180
|
+
return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { DataSource } from 'typeorm';
|
|
2
|
+
import { BaseDatabaseService } from './base.service';
|
|
3
|
+
import { TableEntity, ColumnEntity, IndexEntity, ForeignKeyEntity } from '../../model/database.entity';
|
|
4
|
+
/**
|
|
5
|
+
* ClickHouse数据库服务实现
|
|
6
|
+
* ClickHouse 是列式 OLAP 数据库,使用 HTTP 接口(默认 8123)。
|
|
7
|
+
* 注意:ClickHouse 不支持事务、外键、存储过程,主键通过 ORDER BY 体现。
|
|
8
|
+
*/
|
|
9
|
+
export declare class ClickHouseService extends BaseDatabaseService {
|
|
10
|
+
getDatabaseType(): string;
|
|
11
|
+
private escape;
|
|
12
|
+
/**
|
|
13
|
+
* 获取ClickHouse数据库列表
|
|
14
|
+
*/
|
|
15
|
+
getDatabases(dataSource: DataSource): Promise<string[]>;
|
|
16
|
+
/**
|
|
17
|
+
* 获取ClickHouse表/视图列表
|
|
18
|
+
*/
|
|
19
|
+
getTables(dataSource: DataSource, database: string): Promise<TableEntity[]>;
|
|
20
|
+
/**
|
|
21
|
+
* 获取表数据(分页)。
|
|
22
|
+
* 必须使用 `库`.`表` 限定名,因为连接默认库可能与目标库不同。
|
|
23
|
+
*/
|
|
24
|
+
getTableData(dataSource: DataSource, databaseName: string, tableName: string, page?: number, pageSize?: number, where?: string, orderBy?: string): Promise<{
|
|
25
|
+
data: any[];
|
|
26
|
+
total: number;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* 获取ClickHouse列信息
|
|
30
|
+
*/
|
|
31
|
+
getColumns(dataSource: DataSource, database: string, table: string): Promise<ColumnEntity[]>;
|
|
32
|
+
/**
|
|
33
|
+
* 获取ClickHouse索引信息(主键 + 数据跳数索引)
|
|
34
|
+
*/
|
|
35
|
+
getIndexes(dataSource: DataSource, database: string, table: string): Promise<IndexEntity[]>;
|
|
36
|
+
/**
|
|
37
|
+
* ClickHouse不支持外键
|
|
38
|
+
*/
|
|
39
|
+
getForeignKeys(dataSource: DataSource, database: string, table: string): Promise<ForeignKeyEntity[]>;
|
|
40
|
+
/**
|
|
41
|
+
* 获取ClickHouse数据库大小
|
|
42
|
+
*/
|
|
43
|
+
getDatabaseSize(dataSource: DataSource, database: string): Promise<number>;
|
|
44
|
+
/**
|
|
45
|
+
* 获取ClickHouse视图列表
|
|
46
|
+
*/
|
|
47
|
+
getViews(dataSource: DataSource, database: string): Promise<any[]>;
|
|
48
|
+
/**
|
|
49
|
+
* 获取ClickHouse视图定义
|
|
50
|
+
*/
|
|
51
|
+
getViewDefinition(dataSource: DataSource, database: string, viewName: string): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* ClickHouse不支持存储过程
|
|
54
|
+
*/
|
|
55
|
+
getProcedures(dataSource: DataSource, database: string): Promise<any[]>;
|
|
56
|
+
getProcedureDefinition(dataSource: DataSource, database: string, procedureName: string): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* 创建ClickHouse数据库
|
|
59
|
+
*/
|
|
60
|
+
createDatabase(dataSource: DataSource, databaseName: string, options?: any): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* 删除ClickHouse数据库
|
|
63
|
+
*/
|
|
64
|
+
dropDatabase(dataSource: DataSource, databaseName: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* 导出数据库架构
|
|
67
|
+
*/
|
|
68
|
+
exportSchema(dataSource: DataSource, databaseName: string): Promise<string>;
|
|
69
|
+
/**
|
|
70
|
+
* 查看ClickHouse日志(query_log,可能未开启)
|
|
71
|
+
*/
|
|
72
|
+
viewLogs(dataSource: DataSource, database?: string, limit?: number): Promise<any[]>;
|
|
73
|
+
/**
|
|
74
|
+
* 备份ClickHouse数据库
|
|
75
|
+
*/
|
|
76
|
+
backupDatabase(dataSource: DataSource, databaseName: string, options?: any): Promise<string>;
|
|
77
|
+
/**
|
|
78
|
+
* 将单表数据以 INSERT 语句追加到备份文件中。
|
|
79
|
+
* 使用 JSONStringsEachRow(见连接封装),UInt64 等大整数以字符串形式安全导出。
|
|
80
|
+
*/
|
|
81
|
+
private appendTableData;
|
|
82
|
+
/**
|
|
83
|
+
* 将 SQL 文本拆分为语句,正确处理单/双引号、反引号标识符与 -- /* 注释中的分号。
|
|
84
|
+
*/
|
|
85
|
+
private static splitSqlStatements;
|
|
86
|
+
/**
|
|
87
|
+
* 恢复ClickHouse数据库
|
|
88
|
+
*/
|
|
89
|
+
restoreDatabase(dataSource: DataSource, databaseName: string, filePath: string, options?: any): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* 导出表数据到 SQL 文件
|
|
92
|
+
*/
|
|
93
|
+
exportTableDataToSQL(dataSource: DataSource, databaseName: string, tableName: string, options?: any): Promise<string>;
|
|
94
|
+
/**
|
|
95
|
+
* 导出表数据到 CSV 文件
|
|
96
|
+
*/
|
|
97
|
+
exportTableDataToCSV(dataSource: DataSource, databaseName: string, tableName: string, options?: any): Promise<string>;
|
|
98
|
+
/**
|
|
99
|
+
* 导出表数据到 JSON 文件
|
|
100
|
+
*/
|
|
101
|
+
exportTableDataToJSON(dataSource: DataSource, databaseName: string, tableName: string, options?: any): Promise<string>;
|
|
102
|
+
/**
|
|
103
|
+
* 导出表数据到 Excel 文件
|
|
104
|
+
*/
|
|
105
|
+
exportTableDataToExcel(dataSource: DataSource, databaseName: string, tableName: string, options?: any): Promise<string>;
|
|
106
|
+
/**
|
|
107
|
+
* ClickHouse使用反引号作为标识符
|
|
108
|
+
*/
|
|
109
|
+
quoteIdentifier(identifier: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* 解析列类型:可空且类型本身不是 Nullable(...) 时包装 Nullable;
|
|
112
|
+
* 不附加 NOT NULL,避免与 Nullable(...) 冲突(ClickHouse 默认即非空)。
|
|
113
|
+
*/
|
|
114
|
+
private resolveColumnType;
|
|
115
|
+
/**
|
|
116
|
+
* 修改表结构
|
|
117
|
+
* ClickHouse支持 ADD/MODIFY/DROP/COMMENT COLUMN,但不支持事务。
|
|
118
|
+
*/
|
|
119
|
+
alterTable(dataSource: DataSource, databaseName: string, tableDiff: any): Promise<any>;
|
|
120
|
+
/**
|
|
121
|
+
* 批量插入数据
|
|
122
|
+
*/
|
|
123
|
+
bulkInsert(dataSource: DataSource, databaseName: string, tableName: string, data: any[]): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* 插入单条数据
|
|
126
|
+
*/
|
|
127
|
+
insertData(dataSource: DataSource, databaseName: string, tableName: string, data: any): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* 删除表
|
|
130
|
+
*/
|
|
131
|
+
dropTable(dataSource: DataSource, databaseName: string, tableName: string): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* 创建表
|
|
134
|
+
* ClickHouse要求指定 ENGINE,默认使用 MergeTree。
|
|
135
|
+
*/
|
|
136
|
+
createTable(dataSource: DataSource, databaseName: string, table: any): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=clickhouse.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse.service.d.ts","sourceRoot":"","sources":["../../../../server/service/database/clickhouse.service.ts"],"names":[],"mappings":"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"}
|