@harneon-ai/db 0.0.1
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/README.md +338 -0
- package/config/datasource.example.yaml +62 -0
- package/dist/config/parser.d.ts +61 -0
- package/dist/config/parser.js +165 -0
- package/dist/config/types.d.ts +358 -0
- package/dist/config/types.js +86 -0
- package/dist/config/writer.d.ts +49 -0
- package/dist/config/writer.js +129 -0
- package/dist/db/connection-manager.d.ts +41 -0
- package/dist/db/connection-manager.js +83 -0
- package/dist/db/metadata-queries.d.ts +82 -0
- package/dist/db/metadata-queries.js +113 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +92 -0
- package/dist/tools/describe-indexes.d.ts +11 -0
- package/dist/tools/describe-indexes.js +36 -0
- package/dist/tools/describe-table.d.ts +14 -0
- package/dist/tools/describe-table.js +45 -0
- package/dist/tools/list-datasources.d.ts +11 -0
- package/dist/tools/list-datasources.js +40 -0
- package/dist/tools/list-tables.d.ts +10 -0
- package/dist/tools/list-tables.js +34 -0
- package/dist/tools/query-metadata.d.ts +17 -0
- package/dist/tools/query-metadata.js +83 -0
- package/dist/tools/save-datasource-config.d.ts +15 -0
- package/dist/tools/save-datasource-config.js +112 -0
- package/dist/tools/sharding-topology.d.ts +20 -0
- package/dist/tools/sharding-topology.js +111 -0
- package/dist/tools/test-connection.d.ts +9 -0
- package/dist/tools/test-connection.js +100 -0
- package/package.json +42 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置类型定义
|
|
3
|
+
*
|
|
4
|
+
* 使用 Zod 定义配置文件的 schema,兼容 ShardingSphere YAML 格式。
|
|
5
|
+
* 所有 Zod schema 同时导出对应的 TypeScript 类型,供其他模块使用。
|
|
6
|
+
*
|
|
7
|
+
* 配置文件结构层次:
|
|
8
|
+
* - dataSources: 数据源连接信息(多个 PostgreSQL 实例)
|
|
9
|
+
* - rules[].!SHARDING: 分片规则
|
|
10
|
+
* - tables: 逻辑表 → 分片配置映射
|
|
11
|
+
* - shardingAlgorithms: 分片算法定义
|
|
12
|
+
* - defaultDatabaseStrategy/defaultTableStrategy: 默认分片策略
|
|
13
|
+
* - props: 额外属性(如 sql-show 等)
|
|
14
|
+
*
|
|
15
|
+
* 关键设计说明:
|
|
16
|
+
* - none 策略字段使用 z.union([z.null(), z.object({})]) 是因为 YAML 中 `none:` 解析为 null 而非 {}
|
|
17
|
+
* - DataSourceConfig 同时支持 jdbcUrl 和 url 字段,兼容不同版本的 ShardingSphere 配置
|
|
18
|
+
*/
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
/**
|
|
21
|
+
* 单个数据源的连接配置
|
|
22
|
+
* 对应 YAML 中 dataSources.ds_X 节点
|
|
23
|
+
* jdbcUrl 格式: jdbc:postgresql://host:port/database
|
|
24
|
+
*/
|
|
25
|
+
export declare const DataSourceConfigSchema: z.ZodObject<{
|
|
26
|
+
dataSourceClassName: z.ZodOptional<z.ZodString>;
|
|
27
|
+
driverClassName: z.ZodOptional<z.ZodString>;
|
|
28
|
+
jdbcUrl: z.ZodOptional<z.ZodString>;
|
|
29
|
+
url: z.ZodOptional<z.ZodString>;
|
|
30
|
+
username: z.ZodString;
|
|
31
|
+
password: z.ZodString;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
username: string;
|
|
34
|
+
password: string;
|
|
35
|
+
dataSourceClassName?: string | undefined;
|
|
36
|
+
driverClassName?: string | undefined;
|
|
37
|
+
jdbcUrl?: string | undefined;
|
|
38
|
+
url?: string | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
username: string;
|
|
41
|
+
password: string;
|
|
42
|
+
dataSourceClassName?: string | undefined;
|
|
43
|
+
driverClassName?: string | undefined;
|
|
44
|
+
jdbcUrl?: string | undefined;
|
|
45
|
+
url?: string | undefined;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* 单个逻辑表的分片配置
|
|
49
|
+
* actualDataNodes 使用 ShardingSphere 表达式语法,如: ds_$->{0..1}.tbl_order_$->{0..1}
|
|
50
|
+
* 表达式由 parser.ts 中的 expandDataNodes() 展开为具体节点列表
|
|
51
|
+
*/
|
|
52
|
+
export declare const ShardingTableConfigSchema: z.ZodObject<{
|
|
53
|
+
actualDataNodes: z.ZodString;
|
|
54
|
+
tableStrategy: z.ZodOptional<z.ZodObject<{
|
|
55
|
+
none: z.ZodOptional<z.ZodUnion<[z.ZodNull, z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>]>>;
|
|
56
|
+
standard: z.ZodOptional<z.ZodObject<{
|
|
57
|
+
shardingColumn: z.ZodString;
|
|
58
|
+
shardingAlgorithmName: z.ZodString;
|
|
59
|
+
}, "strip", z.ZodTypeAny, {
|
|
60
|
+
shardingColumn: string;
|
|
61
|
+
shardingAlgorithmName: string;
|
|
62
|
+
}, {
|
|
63
|
+
shardingColumn: string;
|
|
64
|
+
shardingAlgorithmName: string;
|
|
65
|
+
}>>;
|
|
66
|
+
complex: z.ZodOptional<z.ZodObject<{
|
|
67
|
+
shardingColumns: z.ZodString;
|
|
68
|
+
shardingAlgorithmName: z.ZodString;
|
|
69
|
+
}, "strip", z.ZodTypeAny, {
|
|
70
|
+
shardingAlgorithmName: string;
|
|
71
|
+
shardingColumns: string;
|
|
72
|
+
}, {
|
|
73
|
+
shardingAlgorithmName: string;
|
|
74
|
+
shardingColumns: string;
|
|
75
|
+
}>>;
|
|
76
|
+
}, "strip", z.ZodTypeAny, {
|
|
77
|
+
none?: {} | null | undefined;
|
|
78
|
+
standard?: {
|
|
79
|
+
shardingColumn: string;
|
|
80
|
+
shardingAlgorithmName: string;
|
|
81
|
+
} | undefined;
|
|
82
|
+
complex?: {
|
|
83
|
+
shardingAlgorithmName: string;
|
|
84
|
+
shardingColumns: string;
|
|
85
|
+
} | undefined;
|
|
86
|
+
}, {
|
|
87
|
+
none?: {} | null | undefined;
|
|
88
|
+
standard?: {
|
|
89
|
+
shardingColumn: string;
|
|
90
|
+
shardingAlgorithmName: string;
|
|
91
|
+
} | undefined;
|
|
92
|
+
complex?: {
|
|
93
|
+
shardingAlgorithmName: string;
|
|
94
|
+
shardingColumns: string;
|
|
95
|
+
} | undefined;
|
|
96
|
+
}>>;
|
|
97
|
+
}, "strip", z.ZodTypeAny, {
|
|
98
|
+
actualDataNodes: string;
|
|
99
|
+
tableStrategy?: {
|
|
100
|
+
none?: {} | null | undefined;
|
|
101
|
+
standard?: {
|
|
102
|
+
shardingColumn: string;
|
|
103
|
+
shardingAlgorithmName: string;
|
|
104
|
+
} | undefined;
|
|
105
|
+
complex?: {
|
|
106
|
+
shardingAlgorithmName: string;
|
|
107
|
+
shardingColumns: string;
|
|
108
|
+
} | undefined;
|
|
109
|
+
} | undefined;
|
|
110
|
+
}, {
|
|
111
|
+
actualDataNodes: string;
|
|
112
|
+
tableStrategy?: {
|
|
113
|
+
none?: {} | null | undefined;
|
|
114
|
+
standard?: {
|
|
115
|
+
shardingColumn: string;
|
|
116
|
+
shardingAlgorithmName: string;
|
|
117
|
+
} | undefined;
|
|
118
|
+
complex?: {
|
|
119
|
+
shardingAlgorithmName: string;
|
|
120
|
+
shardingColumns: string;
|
|
121
|
+
} | undefined;
|
|
122
|
+
} | undefined;
|
|
123
|
+
}>;
|
|
124
|
+
/**
|
|
125
|
+
* 分片算法配置
|
|
126
|
+
* type 常见值: INLINE, MOD, HASH_MOD 等
|
|
127
|
+
* props 中 algorithm-expression 定义分片表达式,如: tbl_order_$->{order_id % 2}
|
|
128
|
+
*/
|
|
129
|
+
export declare const ShardingAlgorithmConfigSchema: z.ZodObject<{
|
|
130
|
+
type: z.ZodString;
|
|
131
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber]>>>;
|
|
132
|
+
}, "strip", z.ZodTypeAny, {
|
|
133
|
+
type: string;
|
|
134
|
+
props?: Record<string, string | number> | undefined;
|
|
135
|
+
}, {
|
|
136
|
+
type: string;
|
|
137
|
+
props?: Record<string, string | number> | undefined;
|
|
138
|
+
}>;
|
|
139
|
+
/**
|
|
140
|
+
* 完整的分片规则配置
|
|
141
|
+
* 包含所有逻辑表定义、默认策略和算法定义
|
|
142
|
+
*/
|
|
143
|
+
export declare const ShardingRuleConfigSchema: z.ZodObject<{
|
|
144
|
+
tables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
145
|
+
actualDataNodes: z.ZodString;
|
|
146
|
+
tableStrategy: z.ZodOptional<z.ZodObject<{
|
|
147
|
+
none: z.ZodOptional<z.ZodUnion<[z.ZodNull, z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>]>>;
|
|
148
|
+
standard: z.ZodOptional<z.ZodObject<{
|
|
149
|
+
shardingColumn: z.ZodString;
|
|
150
|
+
shardingAlgorithmName: z.ZodString;
|
|
151
|
+
}, "strip", z.ZodTypeAny, {
|
|
152
|
+
shardingColumn: string;
|
|
153
|
+
shardingAlgorithmName: string;
|
|
154
|
+
}, {
|
|
155
|
+
shardingColumn: string;
|
|
156
|
+
shardingAlgorithmName: string;
|
|
157
|
+
}>>;
|
|
158
|
+
complex: z.ZodOptional<z.ZodObject<{
|
|
159
|
+
shardingColumns: z.ZodString;
|
|
160
|
+
shardingAlgorithmName: z.ZodString;
|
|
161
|
+
}, "strip", z.ZodTypeAny, {
|
|
162
|
+
shardingAlgorithmName: string;
|
|
163
|
+
shardingColumns: string;
|
|
164
|
+
}, {
|
|
165
|
+
shardingAlgorithmName: string;
|
|
166
|
+
shardingColumns: string;
|
|
167
|
+
}>>;
|
|
168
|
+
}, "strip", z.ZodTypeAny, {
|
|
169
|
+
none?: {} | null | undefined;
|
|
170
|
+
standard?: {
|
|
171
|
+
shardingColumn: string;
|
|
172
|
+
shardingAlgorithmName: string;
|
|
173
|
+
} | undefined;
|
|
174
|
+
complex?: {
|
|
175
|
+
shardingAlgorithmName: string;
|
|
176
|
+
shardingColumns: string;
|
|
177
|
+
} | undefined;
|
|
178
|
+
}, {
|
|
179
|
+
none?: {} | null | undefined;
|
|
180
|
+
standard?: {
|
|
181
|
+
shardingColumn: string;
|
|
182
|
+
shardingAlgorithmName: string;
|
|
183
|
+
} | undefined;
|
|
184
|
+
complex?: {
|
|
185
|
+
shardingAlgorithmName: string;
|
|
186
|
+
shardingColumns: string;
|
|
187
|
+
} | undefined;
|
|
188
|
+
}>>;
|
|
189
|
+
}, "strip", z.ZodTypeAny, {
|
|
190
|
+
actualDataNodes: string;
|
|
191
|
+
tableStrategy?: {
|
|
192
|
+
none?: {} | null | undefined;
|
|
193
|
+
standard?: {
|
|
194
|
+
shardingColumn: string;
|
|
195
|
+
shardingAlgorithmName: string;
|
|
196
|
+
} | undefined;
|
|
197
|
+
complex?: {
|
|
198
|
+
shardingAlgorithmName: string;
|
|
199
|
+
shardingColumns: string;
|
|
200
|
+
} | undefined;
|
|
201
|
+
} | undefined;
|
|
202
|
+
}, {
|
|
203
|
+
actualDataNodes: string;
|
|
204
|
+
tableStrategy?: {
|
|
205
|
+
none?: {} | null | undefined;
|
|
206
|
+
standard?: {
|
|
207
|
+
shardingColumn: string;
|
|
208
|
+
shardingAlgorithmName: string;
|
|
209
|
+
} | undefined;
|
|
210
|
+
complex?: {
|
|
211
|
+
shardingAlgorithmName: string;
|
|
212
|
+
shardingColumns: string;
|
|
213
|
+
} | undefined;
|
|
214
|
+
} | undefined;
|
|
215
|
+
}>>>;
|
|
216
|
+
defaultShardingColumn: z.ZodOptional<z.ZodString>;
|
|
217
|
+
defaultDatabaseStrategy: z.ZodOptional<z.ZodObject<{
|
|
218
|
+
standard: z.ZodOptional<z.ZodObject<{
|
|
219
|
+
shardingColumn: z.ZodString;
|
|
220
|
+
shardingAlgorithmName: z.ZodString;
|
|
221
|
+
}, "strip", z.ZodTypeAny, {
|
|
222
|
+
shardingColumn: string;
|
|
223
|
+
shardingAlgorithmName: string;
|
|
224
|
+
}, {
|
|
225
|
+
shardingColumn: string;
|
|
226
|
+
shardingAlgorithmName: string;
|
|
227
|
+
}>>;
|
|
228
|
+
none: z.ZodOptional<z.ZodUnion<[z.ZodNull, z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>]>>;
|
|
229
|
+
}, "strip", z.ZodTypeAny, {
|
|
230
|
+
none?: {} | null | undefined;
|
|
231
|
+
standard?: {
|
|
232
|
+
shardingColumn: string;
|
|
233
|
+
shardingAlgorithmName: string;
|
|
234
|
+
} | undefined;
|
|
235
|
+
}, {
|
|
236
|
+
none?: {} | null | undefined;
|
|
237
|
+
standard?: {
|
|
238
|
+
shardingColumn: string;
|
|
239
|
+
shardingAlgorithmName: string;
|
|
240
|
+
} | undefined;
|
|
241
|
+
}>>;
|
|
242
|
+
defaultTableStrategy: z.ZodOptional<z.ZodObject<{
|
|
243
|
+
standard: z.ZodOptional<z.ZodObject<{
|
|
244
|
+
shardingColumn: z.ZodString;
|
|
245
|
+
shardingAlgorithmName: z.ZodString;
|
|
246
|
+
}, "strip", z.ZodTypeAny, {
|
|
247
|
+
shardingColumn: string;
|
|
248
|
+
shardingAlgorithmName: string;
|
|
249
|
+
}, {
|
|
250
|
+
shardingColumn: string;
|
|
251
|
+
shardingAlgorithmName: string;
|
|
252
|
+
}>>;
|
|
253
|
+
none: z.ZodOptional<z.ZodUnion<[z.ZodNull, z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>]>>;
|
|
254
|
+
}, "strip", z.ZodTypeAny, {
|
|
255
|
+
none?: {} | null | undefined;
|
|
256
|
+
standard?: {
|
|
257
|
+
shardingColumn: string;
|
|
258
|
+
shardingAlgorithmName: string;
|
|
259
|
+
} | undefined;
|
|
260
|
+
}, {
|
|
261
|
+
none?: {} | null | undefined;
|
|
262
|
+
standard?: {
|
|
263
|
+
shardingColumn: string;
|
|
264
|
+
shardingAlgorithmName: string;
|
|
265
|
+
} | undefined;
|
|
266
|
+
}>>;
|
|
267
|
+
shardingAlgorithms: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
268
|
+
type: z.ZodString;
|
|
269
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber]>>>;
|
|
270
|
+
}, "strip", z.ZodTypeAny, {
|
|
271
|
+
type: string;
|
|
272
|
+
props?: Record<string, string | number> | undefined;
|
|
273
|
+
}, {
|
|
274
|
+
type: string;
|
|
275
|
+
props?: Record<string, string | number> | undefined;
|
|
276
|
+
}>>>;
|
|
277
|
+
}, "strip", z.ZodTypeAny, {
|
|
278
|
+
tables?: Record<string, {
|
|
279
|
+
actualDataNodes: string;
|
|
280
|
+
tableStrategy?: {
|
|
281
|
+
none?: {} | null | undefined;
|
|
282
|
+
standard?: {
|
|
283
|
+
shardingColumn: string;
|
|
284
|
+
shardingAlgorithmName: string;
|
|
285
|
+
} | undefined;
|
|
286
|
+
complex?: {
|
|
287
|
+
shardingAlgorithmName: string;
|
|
288
|
+
shardingColumns: string;
|
|
289
|
+
} | undefined;
|
|
290
|
+
} | undefined;
|
|
291
|
+
}> | undefined;
|
|
292
|
+
defaultShardingColumn?: string | undefined;
|
|
293
|
+
defaultDatabaseStrategy?: {
|
|
294
|
+
none?: {} | null | undefined;
|
|
295
|
+
standard?: {
|
|
296
|
+
shardingColumn: string;
|
|
297
|
+
shardingAlgorithmName: string;
|
|
298
|
+
} | undefined;
|
|
299
|
+
} | undefined;
|
|
300
|
+
defaultTableStrategy?: {
|
|
301
|
+
none?: {} | null | undefined;
|
|
302
|
+
standard?: {
|
|
303
|
+
shardingColumn: string;
|
|
304
|
+
shardingAlgorithmName: string;
|
|
305
|
+
} | undefined;
|
|
306
|
+
} | undefined;
|
|
307
|
+
shardingAlgorithms?: Record<string, {
|
|
308
|
+
type: string;
|
|
309
|
+
props?: Record<string, string | number> | undefined;
|
|
310
|
+
}> | undefined;
|
|
311
|
+
}, {
|
|
312
|
+
tables?: Record<string, {
|
|
313
|
+
actualDataNodes: string;
|
|
314
|
+
tableStrategy?: {
|
|
315
|
+
none?: {} | null | undefined;
|
|
316
|
+
standard?: {
|
|
317
|
+
shardingColumn: string;
|
|
318
|
+
shardingAlgorithmName: string;
|
|
319
|
+
} | undefined;
|
|
320
|
+
complex?: {
|
|
321
|
+
shardingAlgorithmName: string;
|
|
322
|
+
shardingColumns: string;
|
|
323
|
+
} | undefined;
|
|
324
|
+
} | undefined;
|
|
325
|
+
}> | undefined;
|
|
326
|
+
defaultShardingColumn?: string | undefined;
|
|
327
|
+
defaultDatabaseStrategy?: {
|
|
328
|
+
none?: {} | null | undefined;
|
|
329
|
+
standard?: {
|
|
330
|
+
shardingColumn: string;
|
|
331
|
+
shardingAlgorithmName: string;
|
|
332
|
+
} | undefined;
|
|
333
|
+
} | undefined;
|
|
334
|
+
defaultTableStrategy?: {
|
|
335
|
+
none?: {} | null | undefined;
|
|
336
|
+
standard?: {
|
|
337
|
+
shardingColumn: string;
|
|
338
|
+
shardingAlgorithmName: string;
|
|
339
|
+
} | undefined;
|
|
340
|
+
} | undefined;
|
|
341
|
+
shardingAlgorithms?: Record<string, {
|
|
342
|
+
type: string;
|
|
343
|
+
props?: Record<string, string | number> | undefined;
|
|
344
|
+
}> | undefined;
|
|
345
|
+
}>;
|
|
346
|
+
export type DataSourceConfig = z.infer<typeof DataSourceConfigSchema>;
|
|
347
|
+
export type ShardingTableConfig = z.infer<typeof ShardingTableConfigSchema>;
|
|
348
|
+
export type ShardingAlgorithmConfig = z.infer<typeof ShardingAlgorithmConfigSchema>;
|
|
349
|
+
export type ShardingRuleConfig = z.infer<typeof ShardingRuleConfigSchema>;
|
|
350
|
+
/**
|
|
351
|
+
* 解析后的配置(应用内部使用的最终结构)
|
|
352
|
+
* 与原始 YAML 的区别: shardingRule 从 rules 数组中提取为单独字段
|
|
353
|
+
*/
|
|
354
|
+
export interface ParsedConfig {
|
|
355
|
+
dataSources: Record<string, DataSourceConfig>;
|
|
356
|
+
shardingRule?: ShardingRuleConfig;
|
|
357
|
+
props?: Record<string, unknown>;
|
|
358
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置类型定义
|
|
3
|
+
*
|
|
4
|
+
* 使用 Zod 定义配置文件的 schema,兼容 ShardingSphere YAML 格式。
|
|
5
|
+
* 所有 Zod schema 同时导出对应的 TypeScript 类型,供其他模块使用。
|
|
6
|
+
*
|
|
7
|
+
* 配置文件结构层次:
|
|
8
|
+
* - dataSources: 数据源连接信息(多个 PostgreSQL 实例)
|
|
9
|
+
* - rules[].!SHARDING: 分片规则
|
|
10
|
+
* - tables: 逻辑表 → 分片配置映射
|
|
11
|
+
* - shardingAlgorithms: 分片算法定义
|
|
12
|
+
* - defaultDatabaseStrategy/defaultTableStrategy: 默认分片策略
|
|
13
|
+
* - props: 额外属性(如 sql-show 等)
|
|
14
|
+
*
|
|
15
|
+
* 关键设计说明:
|
|
16
|
+
* - none 策略字段使用 z.union([z.null(), z.object({})]) 是因为 YAML 中 `none:` 解析为 null 而非 {}
|
|
17
|
+
* - DataSourceConfig 同时支持 jdbcUrl 和 url 字段,兼容不同版本的 ShardingSphere 配置
|
|
18
|
+
*/
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
/**
|
|
21
|
+
* 单个数据源的连接配置
|
|
22
|
+
* 对应 YAML 中 dataSources.ds_X 节点
|
|
23
|
+
* jdbcUrl 格式: jdbc:postgresql://host:port/database
|
|
24
|
+
*/
|
|
25
|
+
export const DataSourceConfigSchema = z.object({
|
|
26
|
+
dataSourceClassName: z.string().optional(), // 如 com.zaxxer.hikari.HikariDataSource
|
|
27
|
+
driverClassName: z.string().optional(), // 如 org.postgresql.Driver
|
|
28
|
+
jdbcUrl: z.string().optional(), // JDBC 连接 URL(优先使用)
|
|
29
|
+
url: z.string().optional(), // 备选 URL 字段(部分配置使用 url 而非 jdbcUrl)
|
|
30
|
+
username: z.string(),
|
|
31
|
+
password: z.string(),
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* 单个逻辑表的分片配置
|
|
35
|
+
* actualDataNodes 使用 ShardingSphere 表达式语法,如: ds_$->{0..1}.tbl_order_$->{0..1}
|
|
36
|
+
* 表达式由 parser.ts 中的 expandDataNodes() 展开为具体节点列表
|
|
37
|
+
*/
|
|
38
|
+
export const ShardingTableConfigSchema = z.object({
|
|
39
|
+
actualDataNodes: z.string(),
|
|
40
|
+
tableStrategy: z.object({
|
|
41
|
+
// none 表示不分表(使用默认策略);YAML 中 `none:` 解析为 null,故需兼容 null
|
|
42
|
+
none: z.union([z.null(), z.object({})]).optional(),
|
|
43
|
+
// standard 策略: 单分片键
|
|
44
|
+
standard: z.object({
|
|
45
|
+
shardingColumn: z.string(),
|
|
46
|
+
shardingAlgorithmName: z.string(), // 引用 shardingAlgorithms 中的算法名称
|
|
47
|
+
}).optional(),
|
|
48
|
+
// complex 策略: 多分片键(逗号分隔)
|
|
49
|
+
complex: z.object({
|
|
50
|
+
shardingColumns: z.string(), // 多个分片列,逗号分隔
|
|
51
|
+
shardingAlgorithmName: z.string(),
|
|
52
|
+
}).optional(),
|
|
53
|
+
}).optional(),
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* 分片算法配置
|
|
57
|
+
* type 常见值: INLINE, MOD, HASH_MOD 等
|
|
58
|
+
* props 中 algorithm-expression 定义分片表达式,如: tbl_order_$->{order_id % 2}
|
|
59
|
+
*/
|
|
60
|
+
export const ShardingAlgorithmConfigSchema = z.object({
|
|
61
|
+
type: z.string(),
|
|
62
|
+
props: z.record(z.string(), z.union([z.string(), z.number()])).optional(),
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* 完整的分片规则配置
|
|
66
|
+
* 包含所有逻辑表定义、默认策略和算法定义
|
|
67
|
+
*/
|
|
68
|
+
export const ShardingRuleConfigSchema = z.object({
|
|
69
|
+
tables: z.record(z.string(), ShardingTableConfigSchema).optional(),
|
|
70
|
+
defaultShardingColumn: z.string().optional(), // 全局默认分片列
|
|
71
|
+
defaultDatabaseStrategy: z.object({
|
|
72
|
+
standard: z.object({
|
|
73
|
+
shardingColumn: z.string(),
|
|
74
|
+
shardingAlgorithmName: z.string(),
|
|
75
|
+
}).optional(),
|
|
76
|
+
none: z.union([z.null(), z.object({})]).optional(),
|
|
77
|
+
}).optional(),
|
|
78
|
+
defaultTableStrategy: z.object({
|
|
79
|
+
standard: z.object({
|
|
80
|
+
shardingColumn: z.string(),
|
|
81
|
+
shardingAlgorithmName: z.string(),
|
|
82
|
+
}).optional(),
|
|
83
|
+
none: z.union([z.null(), z.object({})]).optional(),
|
|
84
|
+
}).optional(),
|
|
85
|
+
shardingAlgorithms: z.record(z.string(), ShardingAlgorithmConfigSchema).optional(),
|
|
86
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置序列化与合并
|
|
3
|
+
*
|
|
4
|
+
* 负责将 ParsedConfig 对象序列化为 ShardingSphere 兼容的 YAML 格式,
|
|
5
|
+
* 以及将新配置合并到现有配置中。
|
|
6
|
+
*
|
|
7
|
+
* 核心难点:
|
|
8
|
+
* 1. ShardingSphere 要求分片规则使用 `!SHARDING` 自定义 YAML 标签
|
|
9
|
+
* 解决: 使用 yaml 库的 Document API 构建 AST,手动为分片规则节点设置 tag
|
|
10
|
+
* 2. 合并策略需要按 key 合并而非简单覆盖,避免丢失已有配置
|
|
11
|
+
*/
|
|
12
|
+
import type { ParsedConfig } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* 将 ParsedConfig 序列化为 ShardingSphere 兼容的 YAML 字符串
|
|
15
|
+
*
|
|
16
|
+
* 序列化策略:
|
|
17
|
+
* - dataSources / props: 直接使用 yaml Document 的 createNode 转换
|
|
18
|
+
* - shardingRule: 需要包裹在 rules 数组中,并为节点添加 `!SHARDING` 标签
|
|
19
|
+
* - none 策略: ShardingSphere 中 `none:` 后无值,序列化时需保持为 null
|
|
20
|
+
*
|
|
21
|
+
* @param config 解析后的配置对象
|
|
22
|
+
* @returns ShardingSphere 兼容的 YAML 字符串
|
|
23
|
+
*/
|
|
24
|
+
export declare function serializeConfig(config: ParsedConfig): string;
|
|
25
|
+
/**
|
|
26
|
+
* 合并新配置到现有配置中
|
|
27
|
+
*
|
|
28
|
+
* 合并策略:
|
|
29
|
+
* - dataSources: 按 key 合并,同名数据源会被覆盖
|
|
30
|
+
* - shardingRule.tables: 按逻辑表名合并
|
|
31
|
+
* - shardingRule.shardingAlgorithms: 按算法名合并
|
|
32
|
+
* - shardingRule 其他字段(defaultDatabaseStrategy 等): 新值覆盖旧值
|
|
33
|
+
* - props: 浅合并
|
|
34
|
+
*
|
|
35
|
+
* @param existing 现有配置
|
|
36
|
+
* @param incoming 待合并的新配置(部分字段)
|
|
37
|
+
* @returns 合并后的完整配置
|
|
38
|
+
*/
|
|
39
|
+
export declare function mergeConfigs(existing: ParsedConfig, incoming: Partial<ParsedConfig>): ParsedConfig;
|
|
40
|
+
/**
|
|
41
|
+
* 将配置写入 YAML 文件
|
|
42
|
+
*
|
|
43
|
+
* 写入前会将原文件备份为 .bak 后缀,防止写入中断导致配置丢失。
|
|
44
|
+
* 如果原文件不存在则直接写入(首次创建场景)。
|
|
45
|
+
*
|
|
46
|
+
* @param filePath 配置文件路径
|
|
47
|
+
* @param config 要写入的配置对象
|
|
48
|
+
*/
|
|
49
|
+
export declare function writeConfigFile(filePath: string, config: ParsedConfig): void;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置序列化与合并
|
|
3
|
+
*
|
|
4
|
+
* 负责将 ParsedConfig 对象序列化为 ShardingSphere 兼容的 YAML 格式,
|
|
5
|
+
* 以及将新配置合并到现有配置中。
|
|
6
|
+
*
|
|
7
|
+
* 核心难点:
|
|
8
|
+
* 1. ShardingSphere 要求分片规则使用 `!SHARDING` 自定义 YAML 标签
|
|
9
|
+
* 解决: 使用 yaml 库的 Document API 构建 AST,手动为分片规则节点设置 tag
|
|
10
|
+
* 2. 合并策略需要按 key 合并而非简单覆盖,避免丢失已有配置
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { Document, YAMLMap, YAMLSeq, Pair, Scalar } from 'yaml';
|
|
15
|
+
/**
|
|
16
|
+
* 将 ParsedConfig 序列化为 ShardingSphere 兼容的 YAML 字符串
|
|
17
|
+
*
|
|
18
|
+
* 序列化策略:
|
|
19
|
+
* - dataSources / props: 直接使用 yaml Document 的 createNode 转换
|
|
20
|
+
* - shardingRule: 需要包裹在 rules 数组中,并为节点添加 `!SHARDING` 标签
|
|
21
|
+
* - none 策略: ShardingSphere 中 `none:` 后无值,序列化时需保持为 null
|
|
22
|
+
*
|
|
23
|
+
* @param config 解析后的配置对象
|
|
24
|
+
* @returns ShardingSphere 兼容的 YAML 字符串
|
|
25
|
+
*/
|
|
26
|
+
export function serializeConfig(config) {
|
|
27
|
+
const doc = new Document();
|
|
28
|
+
const root = new YAMLMap();
|
|
29
|
+
// dataSources 节点
|
|
30
|
+
root.add(new Pair(new Scalar('dataSources'), doc.createNode(config.dataSources)));
|
|
31
|
+
// rules 节点: 将 shardingRule 包裹在数组中,添加 !SHARDING 标签
|
|
32
|
+
if (config.shardingRule) {
|
|
33
|
+
const rulesSeq = new YAMLSeq();
|
|
34
|
+
const shardingNode = doc.createNode(config.shardingRule);
|
|
35
|
+
shardingNode.tag = '!SHARDING';
|
|
36
|
+
rulesSeq.add(shardingNode);
|
|
37
|
+
root.add(new Pair(new Scalar('rules'), rulesSeq));
|
|
38
|
+
}
|
|
39
|
+
// props 节点
|
|
40
|
+
if (config.props && Object.keys(config.props).length > 0) {
|
|
41
|
+
root.add(new Pair(new Scalar('props'), doc.createNode(config.props)));
|
|
42
|
+
}
|
|
43
|
+
doc.contents = root;
|
|
44
|
+
return doc.toString({ lineWidth: 0 });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 合并新配置到现有配置中
|
|
48
|
+
*
|
|
49
|
+
* 合并策略:
|
|
50
|
+
* - dataSources: 按 key 合并,同名数据源会被覆盖
|
|
51
|
+
* - shardingRule.tables: 按逻辑表名合并
|
|
52
|
+
* - shardingRule.shardingAlgorithms: 按算法名合并
|
|
53
|
+
* - shardingRule 其他字段(defaultDatabaseStrategy 等): 新值覆盖旧值
|
|
54
|
+
* - props: 浅合并
|
|
55
|
+
*
|
|
56
|
+
* @param existing 现有配置
|
|
57
|
+
* @param incoming 待合并的新配置(部分字段)
|
|
58
|
+
* @returns 合并后的完整配置
|
|
59
|
+
*/
|
|
60
|
+
export function mergeConfigs(existing, incoming) {
|
|
61
|
+
const merged = {
|
|
62
|
+
dataSources: { ...existing.dataSources },
|
|
63
|
+
shardingRule: existing.shardingRule ? structuredClone(existing.shardingRule) : undefined,
|
|
64
|
+
props: existing.props ? { ...existing.props } : undefined,
|
|
65
|
+
};
|
|
66
|
+
// 合并数据源: 按 key 合并,同名覆盖
|
|
67
|
+
if (incoming.dataSources) {
|
|
68
|
+
for (const [name, ds] of Object.entries(incoming.dataSources)) {
|
|
69
|
+
merged.dataSources[name] = ds;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// 合并分片规则
|
|
73
|
+
if (incoming.shardingRule) {
|
|
74
|
+
if (!merged.shardingRule) {
|
|
75
|
+
merged.shardingRule = structuredClone(incoming.shardingRule);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
mergeShardingRule(merged.shardingRule, incoming.shardingRule);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// 合并 props: 浅合并
|
|
82
|
+
if (incoming.props) {
|
|
83
|
+
merged.props = { ...(merged.props || {}), ...incoming.props };
|
|
84
|
+
}
|
|
85
|
+
return merged;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 合并分片规则(原地修改 target)
|
|
89
|
+
* tables 和 shardingAlgorithms 按 key 合并,其他字段新值覆盖旧值
|
|
90
|
+
*/
|
|
91
|
+
function mergeShardingRule(target, source) {
|
|
92
|
+
if (source.tables) {
|
|
93
|
+
target.tables = { ...(target.tables || {}), ...source.tables };
|
|
94
|
+
}
|
|
95
|
+
if (source.shardingAlgorithms) {
|
|
96
|
+
target.shardingAlgorithms = { ...(target.shardingAlgorithms || {}), ...source.shardingAlgorithms };
|
|
97
|
+
}
|
|
98
|
+
if (source.defaultDatabaseStrategy !== undefined) {
|
|
99
|
+
target.defaultDatabaseStrategy = source.defaultDatabaseStrategy;
|
|
100
|
+
}
|
|
101
|
+
if (source.defaultTableStrategy !== undefined) {
|
|
102
|
+
target.defaultTableStrategy = source.defaultTableStrategy;
|
|
103
|
+
}
|
|
104
|
+
if (source.defaultShardingColumn !== undefined) {
|
|
105
|
+
target.defaultShardingColumn = source.defaultShardingColumn;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 将配置写入 YAML 文件
|
|
110
|
+
*
|
|
111
|
+
* 写入前会将原文件备份为 .bak 后缀,防止写入中断导致配置丢失。
|
|
112
|
+
* 如果原文件不存在则直接写入(首次创建场景)。
|
|
113
|
+
*
|
|
114
|
+
* @param filePath 配置文件路径
|
|
115
|
+
* @param config 要写入的配置对象
|
|
116
|
+
*/
|
|
117
|
+
export function writeConfigFile(filePath, config) {
|
|
118
|
+
// 确保配置文件所在目录存在(全局安装时 ~/.harneon-ai/db/ 可能尚未创建)
|
|
119
|
+
const dir = path.dirname(filePath);
|
|
120
|
+
if (!fs.existsSync(dir)) {
|
|
121
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
122
|
+
}
|
|
123
|
+
// 备份原文件(如果存在)
|
|
124
|
+
if (fs.existsSync(filePath)) {
|
|
125
|
+
fs.copyFileSync(filePath, `${filePath}.bak`);
|
|
126
|
+
}
|
|
127
|
+
const yamlContent = serializeConfig(config);
|
|
128
|
+
fs.writeFileSync(filePath, yamlContent, 'utf-8');
|
|
129
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据库连接池管理器
|
|
3
|
+
*
|
|
4
|
+
* 管理多个 PostgreSQL 数据源的连接池,采用懒初始化策略:
|
|
5
|
+
* - 构造时不创建任何连接,首次调用 getPool() 时才创建对应数据源的连接池
|
|
6
|
+
* - 使用 Promise Map 避免并发调用时重复创建连接池(竞态安全)
|
|
7
|
+
* - 所有连接池强制设置 default_transaction_read_only=on(数据库层面只读保护)
|
|
8
|
+
*
|
|
9
|
+
* 连接池参数:
|
|
10
|
+
* - max=3: 元数据查询不需要大连接池,3 个连接足够
|
|
11
|
+
* - idleTimeoutMillis=30000: 空闲 30 秒后释放连接
|
|
12
|
+
*/
|
|
13
|
+
import pg from 'pg';
|
|
14
|
+
import { type ParsedConfig } from '../config/types.js';
|
|
15
|
+
export declare class ConnectionManager {
|
|
16
|
+
/**
|
|
17
|
+
* 使用 Promise<pg.Pool> 而非 pg.Pool 存储,确保并发调用 getPool() 时
|
|
18
|
+
* 多个调用者 await 同一个 Promise,避免重复创建连接池导致资源泄漏
|
|
19
|
+
*/
|
|
20
|
+
private poolPromises;
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: ParsedConfig);
|
|
23
|
+
/**
|
|
24
|
+
* 获取指定数据源的连接池(懒初始化,并发安全)
|
|
25
|
+
* @param dsName 数据源名称,对应 YAML 配置中 dataSources 下的 key(如 ds_0, ds_1)
|
|
26
|
+
* @throws 数据源不存在或 JDBC URL 解析失败时抛出错误
|
|
27
|
+
*/
|
|
28
|
+
getPool(dsName: string): Promise<pg.Pool>;
|
|
29
|
+
private createPool;
|
|
30
|
+
/** 返回所有已配置的数据源名称列表 */
|
|
31
|
+
getAllDataSourceNames(): string[];
|
|
32
|
+
/**
|
|
33
|
+
* 重新加载配置: 关闭所有已创建的连接池并清空缓存
|
|
34
|
+
*
|
|
35
|
+
* 调用前应先原地修改 config 对象(因为所有 tool 闭包引用同一对象)。
|
|
36
|
+
* 调用后,下次 getPool() 会基于更新后的 config 懒初始化新连接池。
|
|
37
|
+
*/
|
|
38
|
+
reloadConfig(): Promise<void>;
|
|
39
|
+
/** 关闭所有已创建的连接池,用于进程退出时的资源清理 */
|
|
40
|
+
shutdown(): Promise<void>;
|
|
41
|
+
}
|