@aiao/rxdb-plugin-history 0.0.0-stage → 0.0.28
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/LICENSE +21 -0
- package/README.md +70 -2
- package/dist/HistoryManager.d.ts +87 -0
- package/dist/HistoryManager.d.ts.map +1 -0
- package/dist/VersionManager.d.ts +243 -0
- package/dist/VersionManager.d.ts.map +1 -0
- package/dist/create-branch.d.ts +35 -0
- package/dist/create-branch.d.ts.map +1 -0
- package/dist/detached-event-error.d.ts +28 -0
- package/dist/detached-event-error.d.ts.map +1 -0
- package/dist/find-switch-branch-step.d.ts +94 -0
- package/dist/find-switch-branch-step.d.ts.map +1 -0
- package/dist/history-filters.d.ts +78 -0
- package/dist/history-filters.d.ts.map +1 -0
- package/dist/history-item-builder.d.ts +25 -0
- package/dist/history-item-builder.d.ts.map +1 -0
- package/dist/history-scope-api.d.ts +41 -0
- package/dist/history-scope-api.d.ts.map +1 -0
- package/dist/history-undo-session.types.d.ts +32 -0
- package/dist/history-undo-session.types.d.ts.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1565 -0
- package/dist/merge-branch.d.ts +22 -0
- package/dist/merge-branch.d.ts.map +1 -0
- package/dist/plugin.d.ts +58 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/pullable-count.d.ts +37 -0
- package/dist/pullable-count.d.ts.map +1 -0
- package/dist/push-inflight.d.ts +60 -0
- package/dist/push-inflight.d.ts.map +1 -0
- package/dist/redo-stack.d.ts +56 -0
- package/dist/redo-stack.d.ts.map +1 -0
- package/dist/remove-branch.d.ts +16 -0
- package/dist/remove-branch.d.ts.map +1 -0
- package/dist/restore-entity.d.ts +15 -0
- package/dist/restore-entity.d.ts.map +1 -0
- package/dist/scope-selection.d.ts +56 -0
- package/dist/scope-selection.d.ts.map +1 -0
- package/dist/switch-branch-actions.d.ts +87 -0
- package/dist/switch-branch-actions.d.ts.map +1 -0
- package/dist/sync-history-bridge.d.ts +87 -0
- package/dist/sync-history-bridge.d.ts.map +1 -0
- package/dist/undo-redo-apply.d.ts +47 -0
- package/dist/undo-redo-apply.d.ts.map +1 -0
- package/dist/version-manager.utils.d.ts +30 -0
- package/dist/version-manager.utils.d.ts.map +1 -0
- package/package.json +59 -3
- package/src/HistoryManager.ts +800 -0
- package/src/VersionManager.ts +617 -0
- package/src/create-branch.ts +178 -0
- package/src/detached-event-error.ts +43 -0
- package/src/find-switch-branch-step.ts +313 -0
- package/src/history-filters.ts +157 -0
- package/src/history-item-builder.ts +101 -0
- package/src/history-scope-api.ts +189 -0
- package/src/history-undo-session.types.ts +37 -0
- package/src/index.ts +61 -0
- package/src/merge-branch.ts +192 -0
- package/src/plugin.ts +93 -0
- package/src/pullable-count.ts +67 -0
- package/src/push-inflight.ts +91 -0
- package/src/redo-stack.ts +79 -0
- package/src/remove-branch.ts +100 -0
- package/src/restore-entity.ts +124 -0
- package/src/scope-selection.ts +133 -0
- package/src/switch-branch-actions.ts +319 -0
- package/src/sync-history-bridge.ts +131 -0
- package/src/undo-redo-apply.ts +270 -0
- package/src/version-manager.utils.ts +43 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EntityStaticType,
|
|
3
|
+
getRxDBChangeKey,
|
|
4
|
+
RxDBBranch,
|
|
5
|
+
RxDBChange,
|
|
6
|
+
RxDBError,
|
|
7
|
+
SwitchVersionActions
|
|
8
|
+
} from '@aiao/rxdb';
|
|
9
|
+
import { find_switch_branch_step } from './find-switch-branch-step.js';
|
|
10
|
+
import { VersionManager } from './VersionManager.js';
|
|
11
|
+
/**
|
|
12
|
+
* 计算切换分支所需的操作
|
|
13
|
+
* @param version
|
|
14
|
+
* @param branchId 要切换到的分支ID
|
|
15
|
+
* @returns 返回切换分支所需的操作序列
|
|
16
|
+
*/
|
|
17
|
+
export const switch_branch_actions = async (version: VersionManager, branchId: string) =>
|
|
18
|
+
compute_switch_branch_actions(await version.getLocalRepositories(), branchId);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 算切换分支所需操作要用到的最小仓库能力。
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* 与 {@link BranchChangeReader} 同一个理由写成结构化接口:本地仓库与事务执行器给出的
|
|
25
|
+
* `IRepository` 都接得住,两边的 `find` 入参本就是同一个类型。
|
|
26
|
+
*/
|
|
27
|
+
export interface SwitchBranchActionReaders {
|
|
28
|
+
/** 读分支行 */
|
|
29
|
+
readonly branchRepository: {
|
|
30
|
+
/**
|
|
31
|
+
* 按条件查分支
|
|
32
|
+
*
|
|
33
|
+
* @param options - 查询选项
|
|
34
|
+
* @returns 命中的分支行
|
|
35
|
+
*/
|
|
36
|
+
find(options: EntityStaticType<typeof RxDBBranch, 'findOptions'>): Promise<RxDBBranch[]>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** 读变更行;见 {@link BranchChangeReader} */
|
|
40
|
+
readonly changeRepository: BranchChangeReader;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 用给定的仓库算「从当前 active 分支切到 `branchId`」要落的增删改——
|
|
45
|
+
* {@link switch_branch_actions} 的本体。
|
|
46
|
+
*
|
|
47
|
+
* @param readers - 见 {@link SwitchBranchActionReaders}
|
|
48
|
+
* @param branchId - 要切换到的分支 id
|
|
49
|
+
* @returns 切换分支所需的操作序列
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* 拆出来是给 `@aiao/rxdb-plugin-working-tree` 的物化屏障用的:屏障要先把来源分支的投影撤掉,
|
|
53
|
+
* 再铺目标分支的快照,而它跑在 `switchBranch` 的 `prepare` 里,手上只有事务执行器的仓库——
|
|
54
|
+
* 绑在适配器上的本地仓库会在同一条连接上等屏障自己那笔事务,死锁。另写一份同义计算,
|
|
55
|
+
* 迟早会在「回滚标记算不算」上与普通切换分叉。
|
|
56
|
+
*
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export const compute_switch_branch_actions = async (
|
|
60
|
+
readers: SwitchBranchActionReaders,
|
|
61
|
+
branchId: string
|
|
62
|
+
): Promise<SwitchVersionActions> => {
|
|
63
|
+
const { branchRepository, changeRepository } = readers;
|
|
64
|
+
const current_branch = (
|
|
65
|
+
await branchRepository.find({
|
|
66
|
+
where: {
|
|
67
|
+
combinator: 'and',
|
|
68
|
+
rules: [{ field: 'activated', operator: '=', value: true }]
|
|
69
|
+
},
|
|
70
|
+
limit: 1
|
|
71
|
+
})
|
|
72
|
+
)[0];
|
|
73
|
+
if (!current_branch) throw new RxDBError('Current branch not found');
|
|
74
|
+
const all_branches = await branchRepository.find({
|
|
75
|
+
where: {
|
|
76
|
+
combinator: 'and',
|
|
77
|
+
rules: []
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const next_branch = all_branches.find(b => b.id === branchId);
|
|
81
|
+
if (!next_branch) throw new RxDBError(`Branch (${branchId}) not found`);
|
|
82
|
+
if (current_branch.id === next_branch.id) {
|
|
83
|
+
throw new RxDBError('Cannot switch to the same branch');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const currentChange = await get_branch_max_change(changeRepository, current_branch.id);
|
|
87
|
+
const nextChange = await get_branch_max_change(changeRepository, next_branch.id);
|
|
88
|
+
|
|
89
|
+
const steps = find_switch_branch_step({
|
|
90
|
+
branches: all_branches,
|
|
91
|
+
currentBranch: current_branch,
|
|
92
|
+
currentChangeId: currentChange ? currentChange.id : null,
|
|
93
|
+
nextBranch: next_branch,
|
|
94
|
+
nextChangeId: nextChange ? nextChange.id : null
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const actions: SwitchVersionActions = {
|
|
98
|
+
deletes: new Map(),
|
|
99
|
+
updates: new Map(),
|
|
100
|
+
inserts: new Map()
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
for (let i = 0; i < steps.length; i++) {
|
|
104
|
+
const { branch, fromChangeId, toChangeId } = steps[i];
|
|
105
|
+
const is_patch = fromChangeId < toChangeId;
|
|
106
|
+
const is_inverse_patch = fromChangeId > toChangeId;
|
|
107
|
+
|
|
108
|
+
// 构建查询条件:查询 fromChangeId 和 toChangeId 之间的变更
|
|
109
|
+
// 注意:区间是开区间 (min, max],不包含起点但包含终点
|
|
110
|
+
// 因为起点代表的状态已经存在,只需要应用之后的变更
|
|
111
|
+
const minId = Math.min(fromChangeId, toChangeId);
|
|
112
|
+
const maxId = Math.max(fromChangeId, toChangeId);
|
|
113
|
+
|
|
114
|
+
const options: EntityStaticType<typeof RxDBChange, 'findAllOptions'> = {
|
|
115
|
+
where: {
|
|
116
|
+
combinator: 'and',
|
|
117
|
+
rules: [
|
|
118
|
+
{ field: 'branchId', operator: '=', value: branch.id },
|
|
119
|
+
{ field: 'id', operator: '>', value: minId },
|
|
120
|
+
{ field: 'id', operator: '<=', value: maxId },
|
|
121
|
+
{ field: 'revertChangeId', operator: '=', value: null }
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// 对于子分支,需要额外限制:不处理 branch.fromChangeId 及之前的变更
|
|
127
|
+
// 因为这些变更属于父分支的历史,不属于当前子分支的变更范围
|
|
128
|
+
// 注意:这个限制对 is_patch 和 is_inverse_patch 都适用
|
|
129
|
+
if (branch.fromChangeId) {
|
|
130
|
+
// 已经通过 minId > branch.fromChangeId 限制过了
|
|
131
|
+
// 所以这里不需要额外处理,minId 已经确保大于 branch.fromChangeId
|
|
132
|
+
// 但为了代码清晰,明确检查一下
|
|
133
|
+
if (minId < branch.fromChangeId) {
|
|
134
|
+
options.where.rules.push({ field: 'id', operator: '>', value: branch.fromChangeId });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const changes = await changeRepository.find(options);
|
|
138
|
+
if (is_inverse_patch) {
|
|
139
|
+
inverse_patch_all(changes, actions);
|
|
140
|
+
} else if (is_patch) {
|
|
141
|
+
patch_all(changes, actions);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return actions;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 应用所有补丁
|
|
149
|
+
* @param changes 需要计算的 changes
|
|
150
|
+
* @param actions 现有的操作结果
|
|
151
|
+
*/
|
|
152
|
+
const patch_all = (changes: RxDBChange[], actions?: SwitchVersionActions) =>
|
|
153
|
+
get_switch_version_actions(changes, true, actions);
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 反向应用所有补丁
|
|
157
|
+
* @param changes 需要计算的 changes
|
|
158
|
+
* @param actions 现有的操作结果
|
|
159
|
+
*/
|
|
160
|
+
const inverse_patch_all = (changes: RxDBChange[], actions?: SwitchVersionActions) =>
|
|
161
|
+
get_switch_version_actions(changes, false, actions);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 计算切换版本所需的操作
|
|
165
|
+
* @param changes 需要计算的 changes
|
|
166
|
+
* @param options
|
|
167
|
+
*/
|
|
168
|
+
export const get_switch_version_actions = (
|
|
169
|
+
changes: RxDBChange[],
|
|
170
|
+
isPatch: boolean,
|
|
171
|
+
actions: SwitchVersionActions = {
|
|
172
|
+
deletes: new Map(),
|
|
173
|
+
updates: new Map(),
|
|
174
|
+
inserts: new Map()
|
|
175
|
+
}
|
|
176
|
+
): SwitchVersionActions => {
|
|
177
|
+
if (isPatch) {
|
|
178
|
+
const need_changes = [...changes].sort((a, b) => a.id - b.id);
|
|
179
|
+
for (const change of need_changes) {
|
|
180
|
+
const changeKey = getRxDBChangeKey(change);
|
|
181
|
+
switch (change.type) {
|
|
182
|
+
case 'INSERT':
|
|
183
|
+
// 浅拷贝:actions 不得持有 change.patch 的引用,否则后续 Object.assign 合并会原地
|
|
184
|
+
// 改写源 change(可能是 EntityManager 缓存实例),污染缓存
|
|
185
|
+
actions.inserts.set(changeKey, {
|
|
186
|
+
patch: { ...change.patch! },
|
|
187
|
+
inversePatch: null
|
|
188
|
+
});
|
|
189
|
+
break;
|
|
190
|
+
case 'UPDATE':
|
|
191
|
+
{
|
|
192
|
+
const existing = actions.inserts.get(changeKey) || actions.updates.get(changeKey);
|
|
193
|
+
if (existing) {
|
|
194
|
+
// 合并补丁:正向补丁累加,反向补丁保持最早的
|
|
195
|
+
if (existing.patch && change.patch) {
|
|
196
|
+
Object.assign(existing.patch, change.patch);
|
|
197
|
+
}
|
|
198
|
+
if (existing.inversePatch === null && change.inversePatch) {
|
|
199
|
+
existing.inversePatch = { ...change.inversePatch };
|
|
200
|
+
} else if (existing.inversePatch && change.inversePatch) {
|
|
201
|
+
Object.assign(existing.inversePatch, change.inversePatch);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
actions.updates.set(changeKey, {
|
|
205
|
+
patch: { ...change.patch! },
|
|
206
|
+
inversePatch: { ...change.inversePatch! }
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
case 'DELETE':
|
|
212
|
+
actions.deletes.set(changeKey, {
|
|
213
|
+
patch: null,
|
|
214
|
+
inversePatch: { ...change.inversePatch! }
|
|
215
|
+
});
|
|
216
|
+
actions.inserts.delete(changeKey);
|
|
217
|
+
actions.updates.delete(changeKey);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
const need_changes = [...changes].sort((a, b) => b.id - a.id);
|
|
223
|
+
for (const change of need_changes) {
|
|
224
|
+
const changeKey = getRxDBChangeKey(change);
|
|
225
|
+
switch (change.type) {
|
|
226
|
+
case 'INSERT':
|
|
227
|
+
// 浅拷贝的理由同正向分支:actions 不得持有 change 的补丁引用,
|
|
228
|
+
// 否则后续 Object.assign 合并会原地改写源 change(可能是 EntityManager 缓存实例)
|
|
229
|
+
actions.deletes.set(changeKey, {
|
|
230
|
+
patch: null,
|
|
231
|
+
inversePatch: { ...change.patch! }
|
|
232
|
+
});
|
|
233
|
+
actions.inserts.delete(changeKey);
|
|
234
|
+
actions.updates.delete(changeKey);
|
|
235
|
+
break;
|
|
236
|
+
case 'UPDATE':
|
|
237
|
+
{
|
|
238
|
+
// 同时查 inserts:逆向按 id 降序处理,撤销 DELETE 会先落一条 inserts,
|
|
239
|
+
// 紧接着更早的 UPDATE 必须并进那条 inserts。只查 updates 会让同一实体
|
|
240
|
+
// 同时出现在 inserts 与 updates 两张表里。
|
|
241
|
+
const existing = actions.inserts.get(changeKey) || actions.updates.get(changeKey);
|
|
242
|
+
if (existing) {
|
|
243
|
+
// 反向合并:正向补丁用 inversePatch,反向补丁用 patch
|
|
244
|
+
if (existing.patch && change.inversePatch) {
|
|
245
|
+
Object.assign(existing.patch, change.inversePatch);
|
|
246
|
+
}
|
|
247
|
+
if (existing.inversePatch && change.patch) {
|
|
248
|
+
Object.assign(existing.inversePatch, change.patch);
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
actions.updates.set(changeKey, {
|
|
252
|
+
patch: { ...change.inversePatch! },
|
|
253
|
+
inversePatch: { ...change.patch! }
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
case 'DELETE':
|
|
259
|
+
actions.inserts.set(changeKey, {
|
|
260
|
+
patch: { ...change.inversePatch! },
|
|
261
|
+
inversePatch: null
|
|
262
|
+
});
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return actions;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 读一条分支 tip 所需要的最小仓库能力。
|
|
272
|
+
*
|
|
273
|
+
* @remarks
|
|
274
|
+
* 写成结构化的最小接口而不是直接用本地仓库类型,是为了让 {@link get_branch_max_change}
|
|
275
|
+
* 同时接得住事务执行器给出的 `IRepository<typeof RxDBChange>`——`enable-migration.ts`
|
|
276
|
+
* 跑在事务里,拿不到本地仓库。两边的 `find` 入参本就是同一个类型
|
|
277
|
+
* (`RxDBChangeStaticTypes['findOptions']`),所以这不是放宽,只是把已有的共同点写出来。
|
|
278
|
+
*/
|
|
279
|
+
export interface BranchChangeReader {
|
|
280
|
+
/**
|
|
281
|
+
* 按条件查变更
|
|
282
|
+
*
|
|
283
|
+
* @param options - 查询选项
|
|
284
|
+
* @returns 命中的变更行
|
|
285
|
+
*/
|
|
286
|
+
find(options: EntityStaticType<typeof RxDBChange, 'findOptions'>): Promise<RxDBChange[]>;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 读一条分支当前的 tip:它自己那些未被回滚的变更里 id 最大的那条。
|
|
291
|
+
*
|
|
292
|
+
* @param changeRepository - 见 {@link BranchChangeReader}
|
|
293
|
+
* @param branchId - 分支 id
|
|
294
|
+
* @returns tip 变更行;该分支一条自有变更都没有时为 `undefined`(调用方据此退回分叉点)
|
|
295
|
+
*
|
|
296
|
+
* @remarks
|
|
297
|
+
* 导出是给 `enable-migration.ts` 复用的:「一条分支现在停在哪」这一问必须全局只有一个
|
|
298
|
+
* 答案(research.md R11)。迁移期另写一条同义查询,迟早会在「回滚标记算不算」
|
|
299
|
+
* 或「排序列是哪一个」上与切换路径分叉,表现为迁移放行了一条 `switchBranch` 走不通的分支。
|
|
300
|
+
*
|
|
301
|
+
* @internal
|
|
302
|
+
*/
|
|
303
|
+
export const get_branch_max_change = async (
|
|
304
|
+
changeRepository: BranchChangeReader,
|
|
305
|
+
branchId: string
|
|
306
|
+
): Promise<RxDBChange | undefined> => {
|
|
307
|
+
const changes = await changeRepository.find({
|
|
308
|
+
where: {
|
|
309
|
+
combinator: 'and',
|
|
310
|
+
rules: [
|
|
311
|
+
{ field: 'branchId', operator: '=', value: branchId },
|
|
312
|
+
{ field: 'revertChangeId', operator: '=', value: null }
|
|
313
|
+
]
|
|
314
|
+
},
|
|
315
|
+
orderBy: [{ field: 'id', sort: 'desc' }],
|
|
316
|
+
limit: 1
|
|
317
|
+
});
|
|
318
|
+
return changes[0];
|
|
319
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview 同步插件向历史插件借的那一小块面
|
|
3
|
+
*
|
|
4
|
+
* US-025 阶段 D 把推拉同步从 `@aiao/rxdb-plugin-history` 切到
|
|
5
|
+
* `@aiao/rxdb-plugin-sync` 之后,两边仍有一条**单向**耦合:一次 pull / push 结束时,
|
|
6
|
+
* undo 边界要作废、待拉计数要结算 —— 这些状态的主人是 {@link HistoryManager},
|
|
7
|
+
* 而触发时机只有同步侧知道。
|
|
8
|
+
*
|
|
9
|
+
* 因此不把 {@link HistoryManager} 整个交出去,只交这一张接口:
|
|
10
|
+
*
|
|
11
|
+
* - 方向是单向的。同步插件 `inject: ['plugin:history']`,历史插件对同步插件一无所知,
|
|
12
|
+
* `@aiao/rxdb-plugin-history` 的 `dependencies` 里也不会出现同步包 —— 否则两包互指。
|
|
13
|
+
* - 面是窄的。八个成员,全部围绕「一次同步往返结束后历史该怎么变」,不透出 undo 栈、
|
|
14
|
+
* redo 栈、作用域 API 这些同步侧根本不该碰的东西。
|
|
15
|
+
* - 结算口径留在历史侧。{@link SyncHistoryBridge.settlePull} 收 `PullOptions` /
|
|
16
|
+
* `PullResult` 原件,「这次算不算完整同步」由 `pullable-count.ts` 判定;
|
|
17
|
+
* 同步侧不复制一份判据,两边也就不会漂。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { PullOptions, PullResult } from '@aiao/rxdb';
|
|
21
|
+
import type { HistoryManager } from './HistoryManager.js';
|
|
22
|
+
import { isCompletePull } from './pullable-count.js';
|
|
23
|
+
import type { PushInFlightRegistry } from './push-inflight.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 同步插件可见的历史侧能力。
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* 由 `VersionManager.syncBridge` 提供,`SyncManager` 在构造时接过去。
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export interface SyncHistoryBridge {
|
|
34
|
+
/**
|
|
35
|
+
* 「哪些变更此刻正在飞往远端」的登记处。
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* push 与 undo 唯一的会合点,主人是 {@link VersionManager} —— undo 侧经
|
|
39
|
+
* `rxdb.versionManager.pushInFlight` 读它,push 侧经本桥认领区间。
|
|
40
|
+
* 两边读的必须是同一个实例,见 {@link PushInFlightRegistry}。
|
|
41
|
+
*/
|
|
42
|
+
readonly pushInFlight: PushInFlightRegistry;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 在可重入同步上下文中执行:期间产生的本地写入不进 undo/redo 栈。
|
|
46
|
+
*
|
|
47
|
+
* @param fn - 同步动作
|
|
48
|
+
*/
|
|
49
|
+
syncing<T>(fn: () => Promise<T>): Promise<T>;
|
|
50
|
+
|
|
51
|
+
/** 与远端合并之后清空当前分支的 undo/redo —— 合并前的内容已经 undo 不回去了 */
|
|
52
|
+
clearUndoHistory(): void;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* pull 开始前签发结算令牌。
|
|
56
|
+
*
|
|
57
|
+
* @returns 令牌,交回 {@link settlePull} / {@link settleAbortedPull} /
|
|
58
|
+
* {@link reconcilePullableCount}
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* 必须在真正发起 pull **之前**取:拉取期间到达的远端事件描述的是快照之后的新变更,
|
|
62
|
+
* 结算时要能看出来,否则「完整同步」的归零会把它们一起吞掉。
|
|
63
|
+
*/
|
|
64
|
+
beginPullableSettlement(): number;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 按一次成功 pull 的实际覆盖范围结算待拉计数。
|
|
68
|
+
*
|
|
69
|
+
* @param token - {@link beginPullableSettlement} 签发的令牌
|
|
70
|
+
* @param options - 发起 pull 时的选项
|
|
71
|
+
* @param result - pull 的结果
|
|
72
|
+
*/
|
|
73
|
+
settlePull(token: number, options: PullOptions | undefined, result: PullResult): void;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 按一次抛错 pull 已落库的部分结算待拉计数。
|
|
77
|
+
*
|
|
78
|
+
* @param token - {@link beginPullableSettlement} 签发的令牌
|
|
79
|
+
* @param pulled - 抛错前已经真实落库的条数,一条都没落时传 0
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* 令牌必须收回,否则代次永远停在旧值,后续结算全被判成「并发」。
|
|
83
|
+
*/
|
|
84
|
+
settleAbortedPull(token: number, pulled: number): void;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 用远端水位线校准待拉计数。
|
|
88
|
+
*
|
|
89
|
+
* @param token - {@link beginPullableSettlement} 签发的令牌
|
|
90
|
+
* @param count - 按各仓库持久化水位线算出的待拉总数
|
|
91
|
+
*/
|
|
92
|
+
reconcilePullableCount(token: number, count: number): void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 远端事件到达时累加待拉计数。
|
|
96
|
+
*
|
|
97
|
+
* @param count - 本次事件里属于当前激活分支的条数
|
|
98
|
+
*/
|
|
99
|
+
incrementPullableCount(count: number): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 造一座桥。
|
|
104
|
+
*
|
|
105
|
+
* @param historyManager - 取当前 {@link HistoryManager} 的闭包
|
|
106
|
+
* @param pushInFlight - 飞行登记处
|
|
107
|
+
*
|
|
108
|
+
* @remarks
|
|
109
|
+
* 第一个参数是闭包而不是实例:`VersionManager` 在 `init()` 里会重建
|
|
110
|
+
* {@link HistoryManager}(上一纪元 destroy 过),桥若捏着旧实例,重连后所有结算
|
|
111
|
+
* 都会打进一个已经拆掉事件总线的管理器。
|
|
112
|
+
*
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
export const createSyncHistoryBridge = (
|
|
116
|
+
historyManager: () => HistoryManager,
|
|
117
|
+
pushInFlight: PushInFlightRegistry
|
|
118
|
+
): SyncHistoryBridge => ({
|
|
119
|
+
pushInFlight,
|
|
120
|
+
syncing: fn => historyManager().syncing(fn),
|
|
121
|
+
clearUndoHistory: () => historyManager().clearUndoHistory(),
|
|
122
|
+
beginPullableSettlement: () => historyManager().beginPullableSettlement(),
|
|
123
|
+
settlePull: (token, options, result) =>
|
|
124
|
+
historyManager().settlePullableCount(token, {
|
|
125
|
+
complete: isCompletePull(options, result),
|
|
126
|
+
pulled: result.pulled
|
|
127
|
+
}),
|
|
128
|
+
settleAbortedPull: (token, pulled) => historyManager().settlePullableCount(token, { complete: false, pulled }),
|
|
129
|
+
reconcilePullableCount: (token, count) => historyManager().reconcilePullableCount(token, count),
|
|
130
|
+
incrementPullableCount: count => historyManager().incrementPullableCount(count)
|
|
131
|
+
});
|