nodejs-store 2.4.0 → 2.6.0
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 +49 -7
- package/README.zh-CN.md +53 -5
- package/package.json +1 -1
- package/src/crud/exec.js +68 -2
- package/src/crud/mutation.js +3 -7
- package/src/crud/write.js +87 -19
- package/src/datasource.js +652 -30
- package/src/ddl.js +68 -11
- package/src/executors/index.js +53 -3
- package/src/executors/mongo.js +78 -15
- package/src/executors/mysql.js +63 -24
- package/src/executors/postgres.js +57 -35
- package/src/executors/sqlite.js +56 -20
- package/src/index.js +76 -4
package/src/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const { AsyncLocalStorage } = require('node:async_hooks');
|
|
|
25
25
|
|
|
26
26
|
const crud = require('./crud');
|
|
27
27
|
const datasource = require('./datasource');
|
|
28
|
+
const { Session, NonAtomicWriteError } = require('./datasource');
|
|
28
29
|
const ddl = require('./ddl');
|
|
29
30
|
const executors = require('./executors');
|
|
30
31
|
const feedback = require('./feedback');
|
|
@@ -146,21 +147,87 @@ class Store {
|
|
|
146
147
|
* fn 内 executeRaw / CRUD 均落到该源的事务连接(commit/rollback 一体);
|
|
147
148
|
* Mongo 源或执行器未实现 withTransaction 时按原样执行(跨源无法原子),
|
|
148
149
|
* 绝不静默假装已事务化。单源场景 source 传 'default'。
|
|
150
|
+
*
|
|
151
|
+
* 同源嵌套 transaction 会开保存点(内层失败只回滚本层);句柄无保存点原语时
|
|
152
|
+
* 降级并入外层并发 nested_savepoint_unsupported。
|
|
149
153
|
*/
|
|
150
154
|
async transaction(source, fn) {
|
|
151
155
|
return datasource.runInTransaction(source, fn);
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
/**
|
|
155
|
-
*
|
|
159
|
+
* 会话(工作单元):回调式,退出统一提交 / 异常统一回滚
|
|
160
|
+
*
|
|
161
|
+
* 用法:
|
|
162
|
+
* await store.session(async (s) => {
|
|
163
|
+
* await s.insert('Order', { ... });
|
|
164
|
+
* await s.update('Account', cond, { ... });
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* 约束:同一会话内写命令只允许落在**单一数据源**;跨源写退出时抛
|
|
168
|
+
* NonAtomicWriteError(先全部回滚,绝不提交半截)。
|
|
156
169
|
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
170
|
+
* 嵌套:内层会话作为嵌套作用域在已有事务上开保存点,内层失败只回滚本层
|
|
171
|
+
* (生命周期仍交外层)。
|
|
159
172
|
*/
|
|
160
|
-
async
|
|
173
|
+
async session(fn) {
|
|
174
|
+
if (typeof fn !== 'function') {
|
|
175
|
+
throw new TypeError('store.session(fn) 需要回调函数:await store.session(async (s) => { ... })');
|
|
176
|
+
}
|
|
177
|
+
const s = new Session();
|
|
178
|
+
const parent = datasource.currentSession();
|
|
179
|
+
if (parent !== null) {
|
|
180
|
+
// 嵌套:生命周期交外层;本层作为嵌套作用域(保存点隔离,失败只回滚本层)
|
|
181
|
+
s.bindOuter(parent);
|
|
182
|
+
const scope = parent.pushScope();
|
|
183
|
+
try {
|
|
184
|
+
const out = await fn(s);
|
|
185
|
+
await parent.popScope(scope, false);
|
|
186
|
+
return out;
|
|
187
|
+
} catch (err) {
|
|
188
|
+
await parent.popScope(scope, true);
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return datasource.runWithSession(s, async () => {
|
|
193
|
+
try {
|
|
194
|
+
const out = await fn(s);
|
|
195
|
+
await s.exit(null);
|
|
196
|
+
return out;
|
|
197
|
+
} catch (err) {
|
|
198
|
+
await s.exit(err);
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 在指定 SQL 源执行原生 SQL(事务内可用;编译由 core rawStmtCompile 完成)
|
|
206
|
+
*
|
|
207
|
+
* 两档参数风格:位置档(params 为数组/null)→ SQL 原样透传,占位符为各后端
|
|
208
|
+
* 原生风格(mysql/sqlite 用 `?`,postgres 用 `$1..$n`);命名档(params 为对象)
|
|
209
|
+
* → SQL 文本中的 `:name` 编译为方言占位符(同名复用、跳过 `::` cast / 引号 /
|
|
210
|
+
* 注释边界;缺名 / 多余名显式报错)。isWrite 缺省时按 SQL 首词推断(读白名单外
|
|
211
|
+
* 一律按写——安全方向)。仅支持 SQL 源(Mongo 源抛 RawSqlError)。
|
|
212
|
+
* 对齐 py-store store.execute_raw。
|
|
213
|
+
*/
|
|
214
|
+
async executeRaw(source, sql, params = null, isWrite = null) {
|
|
161
215
|
return datasource.executeRaw(source, sql, params, isWrite);
|
|
162
216
|
}
|
|
163
217
|
|
|
218
|
+
/**
|
|
219
|
+
* 在指定 Mongo 源执行原生聚合管道(事务内可用;对标 SQL 侧 executeRaw)
|
|
220
|
+
*
|
|
221
|
+
* pipeline 为原生聚合管道(数组),options 为驱动原生透传项(allowDiskUse /
|
|
222
|
+
* batchSize / hint / maxTimeMS…,宿主不做白名单)。事务 / 会话作用域内自动透传
|
|
223
|
+
* session(由事务强制接管,options.session 不可覆盖);统一按读路径解析,
|
|
224
|
+
* $merge / $out 写管道请自行开事务。仅支持 Mongo 源(SQL 源抛 NativeCommandError
|
|
225
|
+
* 并指引 executeRaw)。返回 { rows }。对齐 py-store store.execute_native。
|
|
226
|
+
*/
|
|
227
|
+
async executeNative(source, collection, pipeline = [], options = null) {
|
|
228
|
+
return datasource.executeNative(source, collection, pipeline, options);
|
|
229
|
+
}
|
|
230
|
+
|
|
164
231
|
/** 从已注册 schema def 生成指定后端 DDL 文本(纯函数,不连库、不回写;铁律 6) */
|
|
165
232
|
generateDdl(backend, names) {
|
|
166
233
|
return ddl.generate(backend, names);
|
|
@@ -240,6 +307,8 @@ Store.prototype.PermissionError = permission.PermissionError;
|
|
|
240
307
|
Store.prototype.ProfileViolation = crud.ProfileViolation;
|
|
241
308
|
/** 原生 SQL 入口错误(实例可被 store.RawSqlError 捕获) */
|
|
242
309
|
Store.prototype.RawSqlError = datasource.RawSqlError;
|
|
310
|
+
/** 原生 Mongo 命令入口错误(实例可被 store.NativeCommandError 捕获) */
|
|
311
|
+
Store.prototype.NativeCommandError = datasource.NativeCommandError;
|
|
243
312
|
|
|
244
313
|
const store = new Store();
|
|
245
314
|
|
|
@@ -331,10 +400,13 @@ module.exports = {
|
|
|
331
400
|
store,
|
|
332
401
|
Store,
|
|
333
402
|
text2query,
|
|
403
|
+
Session,
|
|
404
|
+
NonAtomicWriteError,
|
|
334
405
|
PermissionError: permission.PermissionError,
|
|
335
406
|
ProfileViolation: crud.ProfileViolation,
|
|
336
407
|
PushdownUnsupportedError: datasource.PushdownUnsupportedError,
|
|
337
408
|
RawSqlError: datasource.RawSqlError,
|
|
409
|
+
NativeCommandError: datasource.NativeCommandError,
|
|
338
410
|
datasource,
|
|
339
411
|
ddl,
|
|
340
412
|
schema,
|