@cicctencent/json-orm 0.1.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.
Files changed (116) hide show
  1. package/README.md +154 -0
  2. package/dist/cjs/index.d.ts +25 -0
  3. package/dist/cjs/index.d.ts.map +1 -0
  4. package/dist/cjs/index.js +66 -0
  5. package/dist/cjs/index.js.map +1 -0
  6. package/dist/cjs/json-backend-fs.d.ts +26 -0
  7. package/dist/cjs/json-backend-fs.d.ts.map +1 -0
  8. package/dist/cjs/json-backend-fs.js +278 -0
  9. package/dist/cjs/json-backend-fs.js.map +1 -0
  10. package/dist/cjs/json-collection.d.ts +70 -0
  11. package/dist/cjs/json-collection.d.ts.map +1 -0
  12. package/dist/cjs/json-collection.js +385 -0
  13. package/dist/cjs/json-collection.js.map +1 -0
  14. package/dist/cjs/json-config.d.ts +87 -0
  15. package/dist/cjs/json-config.d.ts.map +1 -0
  16. package/dist/cjs/json-config.js +77 -0
  17. package/dist/cjs/json-config.js.map +1 -0
  18. package/dist/cjs/json-datasource.d.ts +35 -0
  19. package/dist/cjs/json-datasource.d.ts.map +1 -0
  20. package/dist/cjs/json-datasource.js +131 -0
  21. package/dist/cjs/json-datasource.js.map +1 -0
  22. package/dist/cjs/json-entity-meta.d.ts +42 -0
  23. package/dist/cjs/json-entity-meta.d.ts.map +1 -0
  24. package/dist/cjs/json-entity-meta.js +128 -0
  25. package/dist/cjs/json-entity-meta.js.map +1 -0
  26. package/dist/cjs/json-query-builder.d.ts +83 -0
  27. package/dist/cjs/json-query-builder.d.ts.map +1 -0
  28. package/dist/cjs/json-query-builder.js +477 -0
  29. package/dist/cjs/json-query-builder.js.map +1 -0
  30. package/dist/cjs/json-repository.d.ts +59 -0
  31. package/dist/cjs/json-repository.d.ts.map +1 -0
  32. package/dist/cjs/json-repository.js +309 -0
  33. package/dist/cjs/json-repository.js.map +1 -0
  34. package/dist/cjs/json-sql-expr.d.ts +107 -0
  35. package/dist/cjs/json-sql-expr.d.ts.map +1 -0
  36. package/dist/cjs/json-sql-expr.js +857 -0
  37. package/dist/cjs/json-sql-expr.js.map +1 -0
  38. package/dist/cjs/json-sql-select.d.ts +9 -0
  39. package/dist/cjs/json-sql-select.d.ts.map +1 -0
  40. package/dist/cjs/json-sql-select.js +434 -0
  41. package/dist/cjs/json-sql-select.js.map +1 -0
  42. package/dist/cjs/json-sql-shared.d.ts +16 -0
  43. package/dist/cjs/json-sql-shared.d.ts.map +1 -0
  44. package/dist/cjs/json-sql-shared.js +12 -0
  45. package/dist/cjs/json-sql-shared.js.map +1 -0
  46. package/dist/cjs/json-sql.d.ts +8 -0
  47. package/dist/cjs/json-sql.d.ts.map +1 -0
  48. package/dist/cjs/json-sql.js +322 -0
  49. package/dist/cjs/json-sql.js.map +1 -0
  50. package/dist/cjs/json-where.d.ts +54 -0
  51. package/dist/cjs/json-where.d.ts.map +1 -0
  52. package/dist/cjs/json-where.js +352 -0
  53. package/dist/cjs/json-where.js.map +1 -0
  54. package/dist/cjs/package.json +3 -0
  55. package/dist/esm/index.d.ts +25 -0
  56. package/dist/esm/index.d.ts.map +1 -0
  57. package/dist/esm/index.js +26 -0
  58. package/dist/esm/index.js.map +1 -0
  59. package/dist/esm/json-backend-fs.d.ts +26 -0
  60. package/dist/esm/json-backend-fs.d.ts.map +1 -0
  61. package/dist/esm/json-backend-fs.js +241 -0
  62. package/dist/esm/json-backend-fs.js.map +1 -0
  63. package/dist/esm/json-collection.d.ts +70 -0
  64. package/dist/esm/json-collection.d.ts.map +1 -0
  65. package/dist/esm/json-collection.js +346 -0
  66. package/dist/esm/json-collection.js.map +1 -0
  67. package/dist/esm/json-config.d.ts +87 -0
  68. package/dist/esm/json-config.d.ts.map +1 -0
  69. package/dist/esm/json-config.js +69 -0
  70. package/dist/esm/json-config.js.map +1 -0
  71. package/dist/esm/json-datasource.d.ts +35 -0
  72. package/dist/esm/json-datasource.d.ts.map +1 -0
  73. package/dist/esm/json-datasource.js +123 -0
  74. package/dist/esm/json-datasource.js.map +1 -0
  75. package/dist/esm/json-entity-meta.d.ts +42 -0
  76. package/dist/esm/json-entity-meta.d.ts.map +1 -0
  77. package/dist/esm/json-entity-meta.js +120 -0
  78. package/dist/esm/json-entity-meta.js.map +1 -0
  79. package/dist/esm/json-query-builder.d.ts +83 -0
  80. package/dist/esm/json-query-builder.d.ts.map +1 -0
  81. package/dist/esm/json-query-builder.js +473 -0
  82. package/dist/esm/json-query-builder.js.map +1 -0
  83. package/dist/esm/json-repository.d.ts +59 -0
  84. package/dist/esm/json-repository.d.ts.map +1 -0
  85. package/dist/esm/json-repository.js +304 -0
  86. package/dist/esm/json-repository.js.map +1 -0
  87. package/dist/esm/json-sql-expr.d.ts +107 -0
  88. package/dist/esm/json-sql-expr.d.ts.map +1 -0
  89. package/dist/esm/json-sql-expr.js +847 -0
  90. package/dist/esm/json-sql-expr.js.map +1 -0
  91. package/dist/esm/json-sql-select.d.ts +9 -0
  92. package/dist/esm/json-sql-select.d.ts.map +1 -0
  93. package/dist/esm/json-sql-select.js +429 -0
  94. package/dist/esm/json-sql-select.js.map +1 -0
  95. package/dist/esm/json-sql-shared.d.ts +16 -0
  96. package/dist/esm/json-sql-shared.d.ts.map +1 -0
  97. package/dist/esm/json-sql-shared.js +9 -0
  98. package/dist/esm/json-sql-shared.js.map +1 -0
  99. package/dist/esm/json-sql.d.ts +8 -0
  100. package/dist/esm/json-sql.d.ts.map +1 -0
  101. package/dist/esm/json-sql.js +319 -0
  102. package/dist/esm/json-sql.js.map +1 -0
  103. package/dist/esm/json-where.d.ts +54 -0
  104. package/dist/esm/json-where.d.ts.map +1 -0
  105. package/dist/esm/json-where.js +342 -0
  106. package/dist/esm/json-where.js.map +1 -0
  107. package/dist/esm/package.json +3 -0
  108. package/examples/01-basic-entity.ts +89 -0
  109. package/examples/02-query-builder.ts +114 -0
  110. package/examples/03-raw-sql.ts +105 -0
  111. package/examples/04-non-entity-table.ts +70 -0
  112. package/examples/05-custom-backend.ts +145 -0
  113. package/examples/06-find-operators.ts +75 -0
  114. package/examples/README.md +73 -0
  115. package/examples/tsconfig.json +20 -0
  116. package/package.json +53 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-collection.d.ts","sourceRoot":"","sources":["../../src/json-collection.ts"],"names":[],"mappings":"AAgBA,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,sCAAsC;AACtC,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAuC9C,qBAAa,cAAc;IAsBM,OAAO,CAAC,IAAI;IArB3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAElC,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,GAAG,CAAqB;IAChC,2CAA2C;IAC3C,OAAO,CAAC,UAAU,CAAK;IACvB,4CAA4C;IAC5C,OAAO,CAAC,SAAS,CAAqB;IACtC,qCAAqC;IACrC,OAAO,CAAC,aAAa,CAAK;IAC1B,wDAAwD;IACxD,OAAO,CAAC,WAAW,CAA8B;gBAErC,SAAS,EAAE,MAAM,EAAU,IAAI,EAAE,cAAc,GAAG,IAAI;IAQlE;;;OAGG;IACG,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAK/B,qCAAqC;IAC/B,GAAG,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAMpD,qCAAqC;IAC/B,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAKpE,0BAA0B;IACpB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAkB3C,iBAAiB;IACX,MAAM,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAS3C,0CAA0C;IACpC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAe/B,sCAAsC;IAChC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B,mCAAmC;IACnC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B,mCAAmC;YACrB,YAAY;IAuB1B,oDAAoD;IACpD,OAAO,CAAC,gBAAgB;IAOxB,iCAAiC;IACjC,OAAO,CAAC,YAAY;IAKpB,kDAAkD;IAClD,OAAO,CAAC,eAAe;IASvB,gDAAgD;YAClC,iBAAiB;IA+D/B,oCAAoC;YACtB,iBAAiB;IAU/B,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,UAAU;CAKnB;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,cAAc,CAW5F;AAED,oBAAoB;AACpB,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
@@ -0,0 +1,385 @@
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.JsonCollection = void 0;
37
+ exports.getCollection = getCollection;
38
+ exports.resetCollectionsForTest = resetCollectionsForTest;
39
+ /**
40
+ * JSON 回退存储:文件型表集合(json-fallback-storage 规格)
41
+ *
42
+ * 落盘布局:`<根>/<表名>/<主键>.json`(每行一个 JSON 文件,属性名为键;
43
+ * 根经 `configureJsonStorage()` 注入的 `JsonStorageBackend` 解析),
44
+ * 自增序列器与表元信息存于 `<根>/_meta/<表名>.json`(与表目录分离,
45
+ * 序列器/锁写入不触发表级失效信号)。
46
+ *
47
+ * - 惰性加载:首次访问时把表目录经后端读入内存(single-flight 共享加载)
48
+ * - 原子写:先写临时文件再 rename,避免进程中断产生半截文件
49
+ * - datetime 类型列读取时还原为 Date(保证与 TypeORM 行为一致,可参与比较/排序)
50
+ * - 跨进程缓存失效:读取前经 `backend.stat(表目录)` 检测外部变更(etag 优先、
51
+ * mtime 兜底;stat 返回 null 视为无变更),变更则重载
52
+ * (`reloadTtlMs` 节流;默认 0 即每次访问校验)
53
+ */
54
+ const path = __importStar(require("path"));
55
+ const json_config_ts_1 = require("./json-config.js");
56
+ const json_entity_meta_ts_1 = require("./json-entity-meta.js");
57
+ const META_FILE = '_meta.json';
58
+ /**
59
+ * 深拷贝行值,保留 Date 等内置类型(递归,避免把 Date 折回 ISO 字符串)。
60
+ * 用于读路径隔离:调用方拿到的是独立副本,原地修改不会污染内存集合,
61
+ * 也不会在未 write 时与磁盘文件静默分叉(与 TypeORM「返回受管实体、未 save 不落库」一致)。
62
+ */
63
+ function cloneValue(value) {
64
+ if (value === null || typeof value !== 'object')
65
+ return value;
66
+ if (value instanceof Date)
67
+ return new Date(value.getTime());
68
+ if (Array.isArray(value))
69
+ return value.map(cloneValue);
70
+ // 内置容器保真:退化为索引对象/空对象会让落盘形态被静默改写
71
+ if (Buffer.isBuffer(value))
72
+ return Buffer.from(value);
73
+ if (ArrayBuffer.isView(value)) {
74
+ return value.slice();
75
+ }
76
+ if (value instanceof ArrayBuffer)
77
+ return value.slice(0);
78
+ if (value instanceof Map)
79
+ return new Map([...value].map(([k, v]) => [k, cloneValue(v)]));
80
+ if (value instanceof Set)
81
+ return new Set([...value].map(cloneValue));
82
+ if (value instanceof RegExp)
83
+ return new RegExp(value.source, value.flags);
84
+ // 类实例等非普通对象按引用返回:宁可共享引用,也不把形态改写成裸对象
85
+ const proto = Object.getPrototypeOf(value);
86
+ if (proto !== Object.prototype && proto !== null)
87
+ return value;
88
+ const out = {};
89
+ for (const k of Object.keys(value)) {
90
+ out[k] = cloneValue(value[k]);
91
+ }
92
+ return out;
93
+ }
94
+ /** 行深拷贝(见 cloneValue;保留 Date) */
95
+ function cloneRow(row) {
96
+ return cloneValue(row);
97
+ }
98
+ class JsonCollection {
99
+ meta;
100
+ tableName;
101
+ /** 主键属性(实体表)或主键列(非实体表);未知时为 undefined */
102
+ primaryProperty;
103
+ /** 当前集合使用的后端实例(供 getCollection 检测运行时重注后重建) */
104
+ backend;
105
+ metaRelPath;
106
+ reloadTtlMs;
107
+ rows = new Map();
108
+ loaded = false;
109
+ seq;
110
+ /** 已知后备存储(表目录)mtime;外部变更触发重载(etag 优先判定) */
111
+ cacheMtime = 0;
112
+ /** 已知后备存储(表目录)etag;后端提供时优先于 mtime 判定外部变更 */
113
+ cacheEtag;
114
+ /** 上次失效校验时间戳(ms),受 reloadTtlMs 节流 */
115
+ lastCheckedAt = 0;
116
+ /** 进行中的加载 Promise(single-flight:并发首载/重载共享,不重复整表 I/O) */
117
+ loadPromise = null;
118
+ constructor(tableName, meta) {
119
+ this.meta = meta;
120
+ this.tableName = tableName;
121
+ this.backend = (0, json_config_ts_1.requireStorageBackend)();
122
+ this.metaRelPath = path.join(tableName, META_FILE);
123
+ this.reloadTtlMs = (0, json_config_ts_1.getReloadTtlMs)();
124
+ this.primaryProperty = meta?.primaryProperty ?? (0, json_entity_meta_ts_1.getNonEntityPrimaryColumn)(tableName);
125
+ }
126
+ /**
127
+ * 表内全部行(惰性加载后返回**深拷贝**,调用方原地修改不会污染内存集合或静默分叉磁盘)。
128
+ * 与 TypeORM 一致:返回的行不会因未 save 而落库。
129
+ */
130
+ async all() {
131
+ await this.ensureLoaded();
132
+ return [...this.rows.values()].map(cloneRow);
133
+ }
134
+ /** 按主键取行(返回深拷贝,调用方原地修改不影响内存集合与磁盘) */
135
+ async get(pk) {
136
+ await this.ensureLoaded();
137
+ const row = this.rows.get(this.rowKey(pk));
138
+ return row ? cloneRow(row) : undefined;
139
+ }
140
+ /** 按谓词查找(返回深拷贝,调用方原地修改不影响内存集合与磁盘) */
141
+ async findWhere(pred) {
142
+ await this.ensureLoaded();
143
+ return [...this.rows.values()].filter(pred).map(cloneRow);
144
+ }
145
+ /** 写入(新增或整行覆盖),返回落盘后的行 */
146
+ async write(row) {
147
+ await this.ensureLoaded(true);
148
+ const pk = this.resolveKey(row);
149
+ // 显式写入更大的数字主键时抬升序列器,避免同进程/跨进程后续 nextId() 撞已有主键
150
+ const n = Number(row[this.primaryProperty]);
151
+ if (Number.isInteger(n) && n > (this.seq ?? 0)) {
152
+ this.seq = n;
153
+ await this.backend.ensureSeqAtLeast(this.metaRelPath, 'seq', n);
154
+ }
155
+ const stored = { ...row };
156
+ // 先落盘再更新内存:落盘失败不留「内存有、磁盘无」的幽灵行
157
+ await this.backend.writeFileAtomic(this.rowFileRel(pk), JSON.stringify(stored, null, 2));
158
+ // 内存快照存独立深拷贝:调用方原地修改返回值(或其嵌套对象)不污染集合
159
+ this.rows.set(pk, cloneRow(stored));
160
+ await this.refreshCacheMtime();
161
+ return stored;
162
+ }
163
+ /** 删除行,返回是否删除 */
164
+ async delete(pk) {
165
+ await this.ensureLoaded(true);
166
+ const key = this.rowKey(pk);
167
+ if (!this.rows.delete(key))
168
+ return false;
169
+ await this.backend.deleteFile(this.rowFileRel(key));
170
+ await this.refreshCacheMtime();
171
+ return true;
172
+ }
173
+ /** 分配下一个自增主键(后端级原子序列器,跨进程唯一;不低于集合已知水位) */
174
+ async nextId() {
175
+ await this.ensureLoaded(true);
176
+ let id = await this.backend.nextId(this.metaRelPath, 'seq');
177
+ const floor = this.seq ?? 0;
178
+ if (id <= floor) {
179
+ // 后端序列器损坏/丢失/被重置 → 回绕分配会撞存量主键并静默覆盖行:
180
+ // 先抬升后端序列器至水位再重取(异常路径,代价一次额外锁内往返)
181
+ await this.backend.ensureSeqAtLeast(this.metaRelPath, 'seq', floor);
182
+ id = await this.backend.nextId(this.metaRelPath, 'seq');
183
+ }
184
+ this.seq = id;
185
+ await this.refreshCacheMtime();
186
+ return id;
187
+ }
188
+ /** 清空内存缓存并删除落盘数据(TRUNCATE 与测试隔离使用) */
189
+ async clear() {
190
+ // 必须先加载:否则「本进程未读过该表」时 rows 为空,只删 meta 而行文件全残留
191
+ await this.ensureLoaded();
192
+ // 等待在飞的加载结束,避免其用已被删除的文件重新填充 rows
193
+ if (this.loadPromise)
194
+ await this.loadPromise;
195
+ const keys = [...this.rows.keys()];
196
+ for (const k of keys) {
197
+ await this.backend.deleteFile(this.rowFileRel(k));
198
+ }
199
+ await this.backend.deleteFile(this.metaRelPath);
200
+ this.rows.clear();
201
+ this.seq = undefined;
202
+ this.loaded = false;
203
+ this.loadPromise = null;
204
+ this.cacheMtime = 0;
205
+ this.cacheEtag = undefined;
206
+ this.lastCheckedAt = 0;
207
+ }
208
+ /** @deprecated 兼容别名,请使用 clear() */
209
+ clearForTest() {
210
+ return this.clear();
211
+ }
212
+ // ---- 内部实现 ----
213
+ /** 读取前确保集合已加载,并按 TTL 节流做跨进程失效校验 */
214
+ async ensureLoaded(force = false) {
215
+ if (this.loaded) {
216
+ const now = Date.now();
217
+ // 写路径强制校验(绕过 TTL 节流):确保写入前快照已含他进程写入,
218
+ // 使写入后记录的水位与实际快照一致,不掩蔽他进程变更
219
+ if (!force && now - this.lastCheckedAt < this.reloadTtlMs)
220
+ return;
221
+ const st = await this.backend.stat(this.tableName);
222
+ this.lastCheckedAt = now;
223
+ // 表目录不存在:视为无变更,保留内存快照(避免每次访问全量重载的读放大)
224
+ if (!st)
225
+ return;
226
+ if (this.isExternalChange(st)) {
227
+ // 外部进程已变更 → 丢弃内存快照后重载
228
+ this.rows.clear();
229
+ this.seq = undefined;
230
+ this.loaded = false;
231
+ }
232
+ else {
233
+ this.rememberStat(st);
234
+ return;
235
+ }
236
+ }
237
+ await this.loadFromBackend();
238
+ }
239
+ /** 失效判定:任一侧提供 etag 时以 etag 不等为变更,否则以 mtime 增大为变更 */
240
+ isExternalChange(st) {
241
+ if (st.etag !== undefined || this.cacheEtag !== undefined) {
242
+ return st.etag !== this.cacheEtag;
243
+ }
244
+ return st.mtimeMs > this.cacheMtime;
245
+ }
246
+ /** 记录一次已确认的后备状态(etag + mtime) */
247
+ rememberStat(st) {
248
+ this.cacheMtime = st.mtimeMs;
249
+ this.cacheEtag = st.etag;
250
+ }
251
+ /** 经后端把表目录读入内存(single-flight:并发加载共享同一 Promise) */
252
+ loadFromBackend() {
253
+ if (!this.loadPromise) {
254
+ this.loadPromise = this.doLoadFromBackend().finally(() => {
255
+ this.loadPromise = null;
256
+ });
257
+ }
258
+ return this.loadPromise;
259
+ }
260
+ /** 加载体:局部构建后整体交换;加载前后 stat 不一致(窗口内并发写入)则有界重试 */
261
+ async doLoadFromBackend() {
262
+ const datetimeProps = this.meta?.datetimeProperties ?? new Set();
263
+ for (let attempt = 0; attempt < 3; attempt += 1) {
264
+ const before = await this.backend.stat(this.tableName);
265
+ const rows = new Map();
266
+ const entries = await this.backend.readDir(this.tableName);
267
+ for (const name of entries) {
268
+ if (!name.endsWith('.json') || name === META_FILE)
269
+ continue;
270
+ try {
271
+ const raw = await this.backend.readFile(path.join(this.tableName, name));
272
+ if (!raw)
273
+ continue;
274
+ const row = JSON.parse(raw);
275
+ // datetime 列还原为 Date(ISO 字符串 → Date,与 TypeORM 读取行为一致)
276
+ for (const prop of datetimeProps) {
277
+ const v = row[prop];
278
+ if (typeof v === 'string' && v)
279
+ row[prop] = new Date(v);
280
+ }
281
+ const key = this.primaryProperty
282
+ ? this.rowKey(row[this.primaryProperty])
283
+ : decodeURIComponent(name.slice(0, -5));
284
+ if (key && key !== 'undefined')
285
+ rows.set(key, row);
286
+ }
287
+ catch (err) {
288
+ // 单个损坏文件不阻塞整表加载;fail-loud 记日志
289
+ // eslint-disable-next-line no-console
290
+ console.warn(`[json-storage] 跳过损坏文件 ${this.tableName}/${name}:`, err.message);
291
+ }
292
+ }
293
+ // 初始化序列器:取现有最大数字主键与 _meta.json 序列器较大者
294
+ let max = 0;
295
+ for (const key of rows.keys()) {
296
+ const n = Number(key);
297
+ if (Number.isInteger(n) && n > max)
298
+ max = n;
299
+ }
300
+ const metaRaw = await this.backend.readFile(this.metaRelPath);
301
+ if (metaRaw) {
302
+ try {
303
+ const metaFile = JSON.parse(metaRaw);
304
+ if (typeof metaFile.seq === 'number')
305
+ max = Math.max(max, metaFile.seq);
306
+ }
307
+ catch {
308
+ /* 无/损坏 _meta.json → 以现有最大主键为准 */
309
+ }
310
+ }
311
+ const after = await this.backend.stat(this.tableName);
312
+ // 加载窗口稳定:两侧 stat 一致(etag 与 mtime 均未变),或重试耗尽取最后快照
313
+ const stable = (before?.mtimeMs ?? 0) >= (after?.mtimeMs ?? 0) && (before?.etag ?? undefined) === (after?.etag ?? undefined);
314
+ if (stable || attempt === 2) {
315
+ this.rows = rows;
316
+ this.seq = max;
317
+ if (after)
318
+ this.rememberStat(after);
319
+ else {
320
+ // 目录不存在:水位基线记 0(而非墙上时钟),使目录后续出现时任何 mtime
321
+ // 都能被判定为变更(时钟回拨/备份恢复下 Date.now() 会永久失灵)
322
+ this.cacheMtime = 0;
323
+ this.cacheEtag = undefined;
324
+ }
325
+ this.loaded = true;
326
+ this.lastCheckedAt = Date.now();
327
+ return;
328
+ }
329
+ }
330
+ }
331
+ /** 写/删后同步已知后备状态,使下次失效校验以本进程写入为基准 */
332
+ async refreshCacheMtime() {
333
+ const st = await this.backend.stat(this.tableName);
334
+ if (st)
335
+ this.rememberStat(st);
336
+ else {
337
+ this.cacheMtime = 0;
338
+ this.cacheEtag = undefined;
339
+ }
340
+ this.lastCheckedAt = Date.now();
341
+ }
342
+ resolveKey(row) {
343
+ if (!this.primaryProperty) {
344
+ throw new Error(`[json-storage] 表 ${this.tableName} 缺少主键定义,无法落盘行:${JSON.stringify(row).slice(0, 200)}`);
345
+ }
346
+ const pk = row[this.primaryProperty];
347
+ if (pk === undefined || pk === null || pk === '') {
348
+ throw new Error(`[json-storage] 表 ${this.tableName} 行主键 ${this.primaryProperty} 为空,无法落盘`);
349
+ }
350
+ return this.rowKey(pk);
351
+ }
352
+ rowKey(pk) {
353
+ return String(pk);
354
+ }
355
+ rowFileRel(key) {
356
+ // 字符串主键(如 cacheKey、lock_name)经 encodeURIComponent 保证文件名安全;
357
+ // `*` 未被 encodeURIComponent 转义,需显式转义(Windows 非法文件名字符)
358
+ return path.join(this.tableName, `${encodeURIComponent(key).replace(/\*/g, '%2A')}.json`);
359
+ }
360
+ }
361
+ exports.JsonCollection = JsonCollection;
362
+ const collectionCache = new Map();
363
+ /**
364
+ * 获取(或创建)表的集合单例。
365
+ * 运行时重注后端(configureJsonStorage)后,旧集合的内存缓存属于旧数据源,
366
+ * 检测到后端实例变更即丢弃重建(已外传的旧 Repository/Collection 引用不追踪:
367
+ * 重注应在首次访问前完成,测试中配合 resetCollectionsForTest)。
368
+ */
369
+ function getCollection(tableName, meta) {
370
+ let c = collectionCache.get(tableName);
371
+ if (c && c.backend !== (0, json_config_ts_1.requireStorageBackend)()) {
372
+ collectionCache.delete(tableName);
373
+ c = undefined;
374
+ }
375
+ if (!c) {
376
+ c = new JsonCollection(tableName, meta);
377
+ collectionCache.set(tableName, c);
378
+ }
379
+ return c;
380
+ }
381
+ /** 仅供测试:清空全部集合缓存 */
382
+ function resetCollectionsForTest() {
383
+ collectionCache.clear();
384
+ }
385
+ //# sourceMappingURL=json-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-collection.js","sourceRoot":"","sources":["../../src/json-collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * JSON 存储引擎配置注入
3
+ *
4
+ * 引擎框架无关、业务解耦:不内置任何目录解析或表注册策略,接入方须在
5
+ * 首次访问前调用 `configureJsonStorage()` 注入存储根目录(必需)与非
6
+ * 实体表注册(可选)。未注入目录时引擎抛出明确错误,不静默回退。
7
+ *
8
+ * 存储 I/O 经可注入的 `JsonStorageBackend`(异步)完成,默认 `FsStorageBackend`
9
+ * (本地 JSON 文件);调用方亦可注入对象存储(COS/S3)等远程后端。
10
+ */
11
+ /** 文件/目录 stat 结果(供跨进程缓存失效检测) */
12
+ export interface JsonStorageFileStat {
13
+ mtimeMs: number;
14
+ size: number;
15
+ /**
16
+ * 可选内容版本标识(如对象存储的 ETag/版本号)。
17
+ * 引擎失效判定优先比较 etag(任一侧提供即生效),两侧均无 etag 时回落 mtimeMs。
18
+ */
19
+ etag?: string;
20
+ }
21
+ /**
22
+ * 异步存储后端契约:引擎全部持久化 I/O 经此后端完成,不直接依赖 `fs`。
23
+ * `relPath` 为相对存储根的 `表/文件` 路径,由后端拼接根目录。
24
+ */
25
+ export interface JsonStorageBackend {
26
+ /** 读文件;不存在返回 null */
27
+ readFile(relPath: string): Promise<string | null>;
28
+ /** 原子写:内部 tmp+rename,避免进程中断产生半截文件 */
29
+ writeFileAtomic(relPath: string, data: string): Promise<void>;
30
+ /** 列目录,返回文件名列表(调用方自行过滤 `.json` / `_meta.json`) */
31
+ readDir(relPath: string): Promise<string[]>;
32
+ /** 删文件(不存在忽略) */
33
+ deleteFile(relPath: string): Promise<void>;
34
+ /** 建目录(递归) */
35
+ mkdir(relPath: string): Promise<void>;
36
+ /**
37
+ * stat;文件/目录不存在返回 null。
38
+ * 对「表目录」的 stat MUST 返回能反映其内容变更的结果(失效检测依赖它):
39
+ * 对象存储无目录概念时,应合成 stat(如清单对象或最大 LastModified/版本号,
40
+ * 经 etag 提供更可靠);返回 null 即声明「不存在」,引擎视为无变更、不重载。
41
+ */
42
+ stat(relPath: string): Promise<JsonStorageFileStat | null>;
43
+ /**
44
+ * 跨进程临界区互斥(lock 文件 `O_EXCL` 实现,失败退避重试)。
45
+ * 实现 MUST 支持孤儿锁回收(锁文件 mtime 超阈值视为持有者崩溃,强制回收重试);
46
+ * 锁保护区 SHOULD 仅包裹毫秒级短临界区操作(如序列器读-改-写)。
47
+ */
48
+ withLock<T>(relPath: string, fn: () => Promise<T>): Promise<T>;
49
+ /** 后端级原子自增(跨进程唯一):读 `_meta.json` 中 `key` 字段 → +1 → 写回 */
50
+ nextId(relPath: string, key: string): Promise<number>;
51
+ /** 若 `value` 大于当前序列器则抬升(写显式大主键时跨进程保唯一) */
52
+ ensureSeqAtLeast(relPath: string, key: string, value: number): Promise<void>;
53
+ }
54
+ /** 非实体表注册项(仅经原始 SQL 访问、无 @Entity 定义的表) */
55
+ export interface NonEntityTableInfo {
56
+ primaryColumn: string;
57
+ /** 唯一列组(原始列名),供 ON DUPLICATE KEY UPDATE 冲突检测 */
58
+ uniqueColumns?: string[][];
59
+ }
60
+ /** `configureJsonStorage()` 可注入项(均可选、支持分次注入、后写覆盖) */
61
+ export interface JsonStorageOptions {
62
+ /** JSON 存储根目录(如 `<data>/db`);不注入 `backend` 时由默认 FsStorageBackend 使用 */
63
+ dbDir?: string;
64
+ /** 非实体表注册(表名 → 主键列/唯一列组) */
65
+ nonEntityTables?: Record<string, NonEntityTableInfo>;
66
+ /** 注入自定义异步存储后端(如 COS/S3);优先于 `dbDir`,两者皆无则抛错 */
67
+ backend?: JsonStorageBackend;
68
+ /** 跨进程缓存失效校验节流(ms);默认 0 即每次读取都校验 */
69
+ reloadTtlMs?: number;
70
+ }
71
+ /**
72
+ * 注入存储配置。可分次调用(如先注目录、后注非实体表),后写覆盖;
73
+ * 未提供的字段保持既有配置不变。仅注 `dbDir`(无 `backend`)时自动构造
74
+ * `FsStorageBackend(dbDir)`;显式注 `backend` 优先。
75
+ */
76
+ export declare function configureJsonStorage(options: JsonStorageOptions): void;
77
+ /** 仅供测试:清空全部已注入配置,回到未配置状态 */
78
+ export declare function resetJsonStorageForTest(): void;
79
+ /** 内部:读取非实体表注册(未注入时为空表,即无非实体表) */
80
+ export declare function getNonEntityTables(): Record<string, NonEntityTableInfo>;
81
+ /** 内部:惰性读取存储后端;未配置时抛出明确错误(不静默回退) */
82
+ export declare function requireStorageBackend(): JsonStorageBackend;
83
+ /** 内部:读取跨进程缓存失效节流(ms) */
84
+ export declare function getReloadTtlMs(): number;
85
+ /** 内部:惰性读取存储根目录;未配置时抛出明确错误(不静默回退) */
86
+ export declare function requireJsonDbDir(): string;
87
+ //# sourceMappingURL=json-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-config.d.ts","sourceRoot":"","sources":["../../src/json-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gCAAgC;AAChC,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,qBAAqB;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClD,qCAAqC;IACrC,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,kDAAkD;IAClD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,iBAAiB;IACjB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,cAAc;IACd,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,yDAAyD;IACzD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,0CAA0C;IAC1C,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E;AAED,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;CAC5B;AAED,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACrD,gDAAgD;IAChD,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AASD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAYtE;AAED,6BAA6B;AAC7B,wBAAgB,uBAAuB,IAAI,IAAI,CAK9C;AAED,kCAAkC;AAClC,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAEvE;AAED,oCAAoC;AACpC,wBAAgB,qBAAqB,IAAI,kBAAkB,CAQ1D;AAED,yBAAyB;AACzB,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,qCAAqC;AACrC,wBAAgB,gBAAgB,IAAI,MAAM,CAQzC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * JSON 存储引擎配置注入
4
+ *
5
+ * 引擎框架无关、业务解耦:不内置任何目录解析或表注册策略,接入方须在
6
+ * 首次访问前调用 `configureJsonStorage()` 注入存储根目录(必需)与非
7
+ * 实体表注册(可选)。未注入目录时引擎抛出明确错误,不静默回退。
8
+ *
9
+ * 存储 I/O 经可注入的 `JsonStorageBackend`(异步)完成,默认 `FsStorageBackend`
10
+ * (本地 JSON 文件);调用方亦可注入对象存储(COS/S3)等远程后端。
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.configureJsonStorage = configureJsonStorage;
14
+ exports.resetJsonStorageForTest = resetJsonStorageForTest;
15
+ exports.getNonEntityTables = getNonEntityTables;
16
+ exports.requireStorageBackend = requireStorageBackend;
17
+ exports.getReloadTtlMs = getReloadTtlMs;
18
+ exports.requireJsonDbDir = requireJsonDbDir;
19
+ const json_backend_fs_ts_1 = require("./json-backend-fs.js");
20
+ let configuredDbDir;
21
+ let configuredBackend;
22
+ let reloadTtlMsValue = 0;
23
+ let nonEntityTables = {};
24
+ /**
25
+ * 注入存储配置。可分次调用(如先注目录、后注非实体表),后写覆盖;
26
+ * 未提供的字段保持既有配置不变。仅注 `dbDir`(无 `backend`)时自动构造
27
+ * `FsStorageBackend(dbDir)`;显式注 `backend` 优先。
28
+ */
29
+ function configureJsonStorage(options) {
30
+ if (!options)
31
+ return;
32
+ if (options.dbDir !== undefined)
33
+ configuredDbDir = options.dbDir;
34
+ if (options.reloadTtlMs !== undefined)
35
+ reloadTtlMsValue = options.reloadTtlMs;
36
+ if (options.backend !== undefined) {
37
+ configuredBackend = options.backend;
38
+ }
39
+ else if (options.dbDir !== undefined) {
40
+ configuredBackend = new json_backend_fs_ts_1.FsStorageBackend(options.dbDir);
41
+ }
42
+ if (options.nonEntityTables !== undefined) {
43
+ nonEntityTables = { ...options.nonEntityTables };
44
+ }
45
+ }
46
+ /** 仅供测试:清空全部已注入配置,回到未配置状态 */
47
+ function resetJsonStorageForTest() {
48
+ configuredDbDir = undefined;
49
+ configuredBackend = undefined;
50
+ reloadTtlMsValue = 0;
51
+ nonEntityTables = {};
52
+ }
53
+ /** 内部:读取非实体表注册(未注入时为空表,即无非实体表) */
54
+ function getNonEntityTables() {
55
+ return nonEntityTables;
56
+ }
57
+ /** 内部:惰性读取存储后端;未配置时抛出明确错误(不静默回退) */
58
+ function requireStorageBackend() {
59
+ if (!configuredBackend) {
60
+ throw new Error('[json-orm] 存储后端未配置:请先调用 configureJsonStorage({ dbDir }) 或 configureJsonStorage({ backend })' +
61
+ '(应用接入方通常由框架适配层在启动时注入)');
62
+ }
63
+ return configuredBackend;
64
+ }
65
+ /** 内部:读取跨进程缓存失效节流(ms) */
66
+ function getReloadTtlMs() {
67
+ return reloadTtlMsValue;
68
+ }
69
+ /** 内部:惰性读取存储根目录;未配置时抛出明确错误(不静默回退) */
70
+ function requireJsonDbDir() {
71
+ if (!configuredDbDir) {
72
+ throw new Error('[json-orm] 存储根目录未配置:请先调用 configureJsonStorage({ dbDir: <目录> })' +
73
+ '(应用接入方通常由框架适配层在启动时注入)');
74
+ }
75
+ return configuredDbDir;
76
+ }
77
+ //# sourceMappingURL=json-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-config.js","sourceRoot":"","sources":["../../src/json-config.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AA8EH,oDAYC;AAGD,0DAKC;AAGD,gDAEC;AAGD,sDAQC;AAGD,wCAEC;AAGD,4CAQC;AAhED,6DAAwD;AAExD,IAAI,eAAmC,CAAC;AACxC,IAAI,iBAAiD,CAAC;AACtD,IAAI,gBAAgB,GAAG,CAAC,CAAC;AACzB,IAAI,eAAe,GAAuC,EAAE,CAAC;AAE7D;;;;GAIG;AACH,SAAgB,oBAAoB,CAAC,OAA2B;IAC9D,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC;IACjE,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAC9E,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IACtC,CAAC;SAAM,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACvC,iBAAiB,GAAG,IAAI,qCAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,eAAe,GAAG,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IACnD,CAAC;AACH,CAAC;AAED,6BAA6B;AAC7B,SAAgB,uBAAuB;IACrC,eAAe,GAAG,SAAS,CAAC;IAC5B,iBAAiB,GAAG,SAAS,CAAC;IAC9B,gBAAgB,GAAG,CAAC,CAAC;IACrB,eAAe,GAAG,EAAE,CAAC;AACvB,CAAC;AAED,kCAAkC;AAClC,SAAgB,kBAAkB;IAChC,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,oCAAoC;AACpC,SAAgB,qBAAqB;IACnC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,6FAA6F;YAC3F,uBAAuB,CAC1B,CAAC;IACJ,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,yBAAyB;AACzB,SAAgB,cAAc;IAC5B,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,qCAAqC;AACrC,SAAgB,gBAAgB;IAC9B,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,gEAAgE;YAC9D,uBAAuB,CAC1B,CAAC;IACJ,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { GetSqlTable } from './json-sql-shared.js';
2
+ /** 表名 → { meta, collection };未知表返回 null(fail-loud) */
3
+ export declare const sqlTableFor: GetSqlTable;
4
+ export declare class JsonEntityManager {
5
+ private readonly ds;
6
+ constructor(ds: JsonDataSource);
7
+ getRepository(target: Function | string): any;
8
+ /** save(实体 | 实体数组) 或 save(Entity, 实体 | 实体数组) */
9
+ save(targetOrEntity: unknown, maybeEntity?: unknown): Promise<any>;
10
+ query(sql: string, params?: unknown[] | Record<string, unknown>): Promise<any>;
11
+ transaction<T>(fn: (em: JsonEntityManager) => Promise<T>): Promise<T>;
12
+ createQueryBuilder(alias?: string): any;
13
+ }
14
+ export declare class JsonDataSource {
15
+ readonly isInitialized = true;
16
+ readonly manager: JsonEntityManager;
17
+ getRepository(target: Function | string): any;
18
+ query(sql: string, params?: unknown[] | Record<string, unknown>): Promise<any>;
19
+ /** EntityManager.save 语义:按实体构造器分组落库 */
20
+ save(targetOrEntity: unknown, maybeEntity?: unknown): Promise<any>;
21
+ transaction<T>(fn: (em: JsonEntityManager) => Promise<T>): Promise<T>;
22
+ /** DS 级 QueryBuilder:无表(insert().into(Entity) 后置)或带别名 */
23
+ createQueryBuilder(alias?: string): any;
24
+ /**
25
+ * DDL 探测 no-op(JSON 存储无 schema;hasTable 恒 true 跳过建表)。
26
+ * 注意:transaction 系列方法均为 no-op,不提供跨表/跨语句原子性与回滚——
27
+ * 仅用于 schema 探测路径,勿在依赖事务语义的代码中使用(JSON 模式仅保证单行文件级原子写)。
28
+ */
29
+ createQueryRunner(): any;
30
+ }
31
+ /** 进程级单例('default' 数据源) */
32
+ export declare function getJsonDataSource(): JsonDataSource;
33
+ /** 测试隔离:重置单例(配合集合 clear() 清空数据) */
34
+ export declare function resetJsonDataSourceForTest(): void;
35
+ //# sourceMappingURL=json-datasource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-datasource.d.ts","sourceRoot":"","sources":["../../src/json-datasource.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAY,MAAM,sBAAsB,CAAC;AAOlE,sDAAsD;AACtD,eAAO,MAAM,WAAW,EAAE,WAOzB,CAAC;AAEF,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,cAAc;IAE/C,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,GAAG;IAI7C,gDAAgD;IAC1C,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;IAIlE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAI9E,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAK3E,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG;CAGxC;AAED,qBAAa,cAAc;IACzB,QAAQ,CAAC,aAAa,QAAQ;IAC9B,QAAQ,CAAC,OAAO,oBAA+B;IAE/C,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,GAAG;IAIvC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAIpF,uCAAuC;IACjC,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;IAyBlE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAI3E,yDAAyD;IACzD,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG;IAIvC;;;;OAIG;IACH,iBAAiB,IAAI,GAAG;CAYzB;AAID,2BAA2B;AAC3B,wBAAgB,iBAAiB,IAAI,cAAc,CAGlD;AAED,mCAAmC;AACnC,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}