@aetherframework/database 1.1.0 → 1.1.2
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/examples/mysql-test-pressure.js +1530 -0
- package/examples/test-direct.js +116 -0
- package/examples/transaction_example.js +127 -0
- package/package.json +3 -1
- package/src/DatabaseManager.js +565 -0
- package/src/core/ConnectionManager.js +351 -0
- package/src/core/DatabaseFactory.js +188 -0
- package/src/core/MongoQueryBuilder.js +576 -0
- package/src/core/PluginManager.js +968 -0
- package/src/core/QueryBuilder.js +4394 -0
- package/src/core/TransactionManager.js +40 -0
- package/src/drivers/clickhouse-driver.js +272 -0
- package/src/drivers/index.js +273 -0
- package/src/drivers/mongodb-driver.js +87 -0
- package/src/drivers/mssql-driver.js +117 -0
- package/src/drivers/mysql-driver.js +169 -0
- package/src/drivers/oracle-driver.js +101 -0
- package/src/drivers/postgres-driver.js +234 -0
- package/src/drivers/redis-driver.js +52 -0
- package/src/drivers/sqlite-driver.js +67 -0
- package/src/middleware/connection-pool.js +455 -0
- package/src/middleware/performance-monitor.js +652 -0
- package/src/middleware/query-cache.js +500 -0
- package/src/middleware/query-logger.js +262 -0
- package/src/plugins/AuditPlugin.js +447 -0
- package/src/plugins/BasePlugin.js +418 -0
- package/src/plugins/BatchOperationPlugin.js +165 -0
- package/src/plugins/CachePlugin.js +407 -0
- package/src/plugins/CtePlugin.js +523 -0
- package/src/plugins/DistributedPlugin.js +543 -0
- package/src/plugins/EncryptionPlugin.js +211 -0
- package/src/plugins/FullTextSearchPlugin.js +164 -0
- package/src/plugins/GeospatialPlugin.js +219 -0
- package/src/plugins/GraphQLPlugin.js +162 -0
- package/src/plugins/HookPlugin.js +211 -0
- package/src/plugins/JsonPlugin.js +366 -0
- package/src/plugins/OptimisticLockPlugin.js +374 -0
- package/src/plugins/PerformancePlugin.js +175 -0
- package/src/plugins/ResiliencePlugin.js +114 -0
- package/src/plugins/ShardingPlugin.js +227 -0
- package/src/plugins/SoftDeletePlugin.js +258 -0
- package/src/plugins/SyncPlugin.js +373 -0
- package/src/plugins/VersioningPlugin.js +314 -0
- package/src/plugins/WindowFunctionPlugin.js +343 -0
- package/src/utils/config-loader.js +632 -0
- package/src/utils/error-handler.js +724 -0
- package/src/utils/migration-runner.js +1066 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
* @module @aetherframework/database/plugin/WindowFunctionPlugin
|
|
6
|
+
*/
|
|
7
|
+
import { BasePlugin } from "./BasePlugin.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 窗口函数插件 - 提供标准 SQL 窗口函数的链式调用支持
|
|
11
|
+
*/
|
|
12
|
+
export class WindowFunctionPlugin extends BasePlugin {
|
|
13
|
+
constructor(queryBuilder) {
|
|
14
|
+
super(queryBuilder);
|
|
15
|
+
this.pluginName = "WindowFunctionPlugin";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_registerMethods() {
|
|
19
|
+
// 注册窗口函数方法到 QueryBuilder
|
|
20
|
+
this.queryBuilder.windowFrame = this.windowFrame.bind(this);
|
|
21
|
+
this.queryBuilder.ntile = this.ntile.bind(this);
|
|
22
|
+
this.queryBuilder.partitionBy = this.partitionBy.bind(this);
|
|
23
|
+
this.queryBuilder.over = this.over.bind(this);
|
|
24
|
+
this.queryBuilder.rowNumber = this.rowNumber.bind(this);
|
|
25
|
+
this.queryBuilder.rank = this.rank.bind(this);
|
|
26
|
+
this.queryBuilder.denseRank = this.denseRank.bind(this);
|
|
27
|
+
this.queryBuilder.lead = this.lead.bind(this);
|
|
28
|
+
this.queryBuilder.lag = this.lag.bind(this);
|
|
29
|
+
this.queryBuilder.firstValue = this.firstValue.bind(this);
|
|
30
|
+
this.queryBuilder.lastValue = this.lastValue.bind(this);
|
|
31
|
+
this.queryBuilder.nthValue = this.nthValue.bind(this);
|
|
32
|
+
this.queryBuilder.cumeDist = this.cumeDist.bind(this);
|
|
33
|
+
this.queryBuilder.percentRank = this.percentRank.bind(this);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 定义窗口框架
|
|
38
|
+
* @param {Object} frame - 窗口框架配置
|
|
39
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
40
|
+
*/
|
|
41
|
+
windowFrame(frame) {
|
|
42
|
+
if (!this.queryBuilder.query.window) {
|
|
43
|
+
this.queryBuilder.query.window = {};
|
|
44
|
+
}
|
|
45
|
+
this.queryBuilder.query.window.frame = frame;
|
|
46
|
+
return this.queryBuilder;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* NTILE 窗口函数
|
|
51
|
+
* @param {number} buckets - 桶数
|
|
52
|
+
* @param {string} alias - 列别名
|
|
53
|
+
* @param {string} windowName - 窗口名称
|
|
54
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
55
|
+
*/
|
|
56
|
+
ntile(buckets, alias = "ntile", windowName = null) {
|
|
57
|
+
return this.over("NTILE", [buckets], windowName, alias);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 窗口分区
|
|
62
|
+
* @param {...string} columns - 分区列
|
|
63
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
64
|
+
*/
|
|
65
|
+
partitionBy(...columns) {
|
|
66
|
+
if (!this.queryBuilder.query.window) {
|
|
67
|
+
this.queryBuilder.query.window = {};
|
|
68
|
+
}
|
|
69
|
+
this.queryBuilder.query.window.partitionBy = columns;
|
|
70
|
+
return this.queryBuilder;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 应用窗口函数
|
|
75
|
+
* @param {string} functionName - 窗口函数名
|
|
76
|
+
* @param {Array} args - 函数参数
|
|
77
|
+
* @param {string} windowName - 窗口名称
|
|
78
|
+
* @param {string} alias - 列别名
|
|
79
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
80
|
+
*/
|
|
81
|
+
over(functionName, args = [], windowName = null, alias = null) {
|
|
82
|
+
const argsStr =
|
|
83
|
+
args.length > 0
|
|
84
|
+
? args.map((arg) => this.queryBuilder.wrapColumn(arg)).join(", ")
|
|
85
|
+
: "*";
|
|
86
|
+
|
|
87
|
+
const windowClause = windowName ? `OVER (${windowName})` : "OVER ()";
|
|
88
|
+
const selectExpr = `${functionName}(${argsStr}) ${windowClause}`;
|
|
89
|
+
|
|
90
|
+
if (alias) {
|
|
91
|
+
this.queryBuilder.query.columns.push(`${selectExpr} as ${alias}`);
|
|
92
|
+
} else {
|
|
93
|
+
this.queryBuilder.query.columns.push(selectExpr);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return this.queryBuilder;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 行号窗口函数
|
|
101
|
+
* @param {string} alias - 列别名
|
|
102
|
+
* @param {string} windowName - 窗口名称
|
|
103
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
104
|
+
*/
|
|
105
|
+
rowNumber(alias = "row_number", windowName = null) {
|
|
106
|
+
return this.over("ROW_NUMBER", [], windowName, alias);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 排名窗口函数
|
|
111
|
+
* @param {string} alias - 列别名
|
|
112
|
+
* @param {string} windowName - 窗口名称
|
|
113
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
114
|
+
*/
|
|
115
|
+
rank(alias = "rank", windowName = null) {
|
|
116
|
+
return this.over("RANK", [], windowName, alias);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 密集排名窗口函数
|
|
121
|
+
* @param {string} alias - 列别名
|
|
122
|
+
* @param {string} windowName - 窗口名称
|
|
123
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
124
|
+
*/
|
|
125
|
+
denseRank(alias = "dense_rank", windowName = null) {
|
|
126
|
+
return this.over("DENSE_RANK", [], windowName, alias);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* LEAD 窗口函数
|
|
131
|
+
* @param {string} column - 列名
|
|
132
|
+
* @param {number} offset - 偏移量(默认:1)
|
|
133
|
+
* @param {*} defaultValue - 默认值
|
|
134
|
+
* @param {string} alias - 列别名
|
|
135
|
+
* @param {string} windowName - 窗口名称
|
|
136
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
137
|
+
*/
|
|
138
|
+
lead(column, offset = 1, defaultValue = null, alias = null, windowName = null) {
|
|
139
|
+
const args = [this.queryBuilder.wrapColumn(column), offset];
|
|
140
|
+
if (defaultValue !== null) {
|
|
141
|
+
args.push(defaultValue);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const finalAlias = alias || `lead_${column}`;
|
|
145
|
+
return this.over("LEAD", args, windowName, finalAlias);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* LAG 窗口函数
|
|
150
|
+
* @param {string} column - 列名
|
|
151
|
+
* @param {number} offset - 偏移量(默认:1)
|
|
152
|
+
* @param {*} defaultValue - 默认值
|
|
153
|
+
* @param {string} alias - 列别名
|
|
154
|
+
* @param {string} windowName - 窗口名称
|
|
155
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
156
|
+
*/
|
|
157
|
+
lag(column, offset = 1, defaultValue = null, alias = null, windowName = null) {
|
|
158
|
+
const args = [this.queryBuilder.wrapColumn(column), offset];
|
|
159
|
+
if (defaultValue !== null) {
|
|
160
|
+
args.push(defaultValue);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const finalAlias = alias || `lag_${column}`;
|
|
164
|
+
return this.over("LAG", args, windowName, finalAlias);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* FIRST_VALUE 窗口函数
|
|
169
|
+
* @param {string} column - 列名
|
|
170
|
+
* @param {string} alias - 列别名
|
|
171
|
+
* @param {string} windowName - 窗口名称
|
|
172
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
173
|
+
*/
|
|
174
|
+
firstValue(column, alias = null, windowName = null) {
|
|
175
|
+
const finalAlias = alias || `first_value_${column}`;
|
|
176
|
+
return this.over(
|
|
177
|
+
"FIRST_VALUE",
|
|
178
|
+
[this.queryBuilder.wrapColumn(column)],
|
|
179
|
+
windowName,
|
|
180
|
+
finalAlias
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* LAST_VALUE 窗口函数
|
|
186
|
+
* @param {string} column - 列名
|
|
187
|
+
* @param {string} alias - 列别名
|
|
188
|
+
* @param {string} windowName - 窗口名称
|
|
189
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
190
|
+
*/
|
|
191
|
+
lastValue(column, alias = null, windowName = null) {
|
|
192
|
+
const finalAlias = alias || `last_value_${column}`;
|
|
193
|
+
return this.over(
|
|
194
|
+
"LAST_VALUE",
|
|
195
|
+
[this.queryBuilder.wrapColumn(column)],
|
|
196
|
+
windowName,
|
|
197
|
+
finalAlias
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* NTH_VALUE 窗口函数
|
|
203
|
+
* @param {string} column - 列名
|
|
204
|
+
* @param {number} n - 第 N 个值
|
|
205
|
+
* @param {string} alias - 列别名
|
|
206
|
+
* @param {string} windowName - 窗口名称
|
|
207
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
208
|
+
*/
|
|
209
|
+
nthValue(column, n, alias = null, windowName = null) {
|
|
210
|
+
const finalAlias = alias || `nth_value_${column}_${n}`;
|
|
211
|
+
return this.over(
|
|
212
|
+
"NTH_VALUE",
|
|
213
|
+
[this.queryBuilder.wrapColumn(column), n],
|
|
214
|
+
windowName,
|
|
215
|
+
finalAlias
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 累积分布窗口函数
|
|
221
|
+
* @param {string} alias - 列别名
|
|
222
|
+
* @param {string} windowName - 窗口名称
|
|
223
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
224
|
+
*/
|
|
225
|
+
cumeDist(alias = "cume_dist", windowName = null) {
|
|
226
|
+
return this.over("CUME_DIST", [], windowName, alias);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 百分比排名窗口函数
|
|
231
|
+
* @param {string} alias - 列别名
|
|
232
|
+
* @param {string} windowName - 窗口名称
|
|
233
|
+
* @returns {QueryBuilder} QueryBuilder 实例
|
|
234
|
+
*/
|
|
235
|
+
percentRank(alias = "percent_rank", windowName = null) {
|
|
236
|
+
return this.over("PERCENT_RANK", [], windowName, alias);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 构建窗口函数 SQL
|
|
241
|
+
* @param {Object} windowConfig - 窗口配置
|
|
242
|
+
* @returns {string} SQL 片段
|
|
243
|
+
*/
|
|
244
|
+
buildWindowSQL(windowConfig) {
|
|
245
|
+
if (!windowConfig) return "";
|
|
246
|
+
|
|
247
|
+
const parts = [];
|
|
248
|
+
|
|
249
|
+
if (windowConfig.partitionBy && windowConfig.partitionBy.length > 0) {
|
|
250
|
+
const partitionColumns = windowConfig.partitionBy
|
|
251
|
+
.map((col) => this.queryBuilder.wrapColumn(col))
|
|
252
|
+
.join(", ");
|
|
253
|
+
parts.push(`PARTITION BY ${partitionColumns}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (windowConfig.orderBy && windowConfig.orderBy.length > 0) {
|
|
257
|
+
const orderColumns = windowConfig.orderBy
|
|
258
|
+
.map((order) => {
|
|
259
|
+
if (typeof order === "object" && order.raw) {
|
|
260
|
+
return order.raw;
|
|
261
|
+
}
|
|
262
|
+
return `${this.queryBuilder.wrapColumn(order.column)} ${order.direction}`;
|
|
263
|
+
})
|
|
264
|
+
.join(", ");
|
|
265
|
+
parts.push(`ORDER BY ${orderColumns}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (windowConfig.frame) {
|
|
269
|
+
parts.push(this.buildWindowFrameSQL(windowConfig.frame));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return parts.length > 0 ? `(${parts.join(" ")})` : "()";
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* 构建窗口框架 SQL
|
|
277
|
+
* @param {Object} frame - 窗口框架配置
|
|
278
|
+
* @returns {string} SQL 片段
|
|
279
|
+
*/
|
|
280
|
+
buildWindowFrameSQL(frame) {
|
|
281
|
+
if (!frame) return "";
|
|
282
|
+
|
|
283
|
+
const { type = "ROWS", start, end } = frame;
|
|
284
|
+
let frameStr = `${type}`;
|
|
285
|
+
|
|
286
|
+
if (start) {
|
|
287
|
+
frameStr += ` ${this.buildWindowFrameBound(start)}`;
|
|
288
|
+
if (end) {
|
|
289
|
+
frameStr += ` AND ${this.buildWindowFrameBound(end)}`;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return frameStr;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* 构建窗口框架边界
|
|
298
|
+
* @param {Object|string} bound - 边界配置
|
|
299
|
+
* @returns {string} SQL 片段
|
|
300
|
+
*/
|
|
301
|
+
buildWindowFrameBound(bound) {
|
|
302
|
+
if (typeof bound === "string") {
|
|
303
|
+
return bound;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (bound.type === "PRECEDING") {
|
|
307
|
+
return `${bound.value} PRECEDING`;
|
|
308
|
+
} else if (bound.type === "FOLLOWING") {
|
|
309
|
+
return `${bound.value} FOLLOWING`;
|
|
310
|
+
} else if (bound.type === "CURRENT_ROW") {
|
|
311
|
+
return "CURRENT ROW";
|
|
312
|
+
} else if (bound.type === "UNBOUNDED") {
|
|
313
|
+
return "UNBOUNDED PRECEDING";
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return "CURRENT ROW";
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 获取支持的窗口函数列表
|
|
321
|
+
* @returns {Array} 支持的窗口函数
|
|
322
|
+
*/
|
|
323
|
+
getSupportedFunctions() {
|
|
324
|
+
return [
|
|
325
|
+
"ROW_NUMBER",
|
|
326
|
+
"RANK",
|
|
327
|
+
"DENSE_RANK",
|
|
328
|
+
"NTILE",
|
|
329
|
+
"LEAD",
|
|
330
|
+
"LAG",
|
|
331
|
+
"FIRST_VALUE",
|
|
332
|
+
"LAST_VALUE",
|
|
333
|
+
"NTH_VALUE",
|
|
334
|
+
"CUME_DIST",
|
|
335
|
+
"PERCENT_RANK",
|
|
336
|
+
"AVG",
|
|
337
|
+
"SUM",
|
|
338
|
+
"COUNT",
|
|
339
|
+
"MIN",
|
|
340
|
+
"MAX",
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
}
|