WorkingTreeCaptureRuntime
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:304
捕获运行时
Remarks
一个数据库一个实例,由 RxDB.connect()(能力位已开)或 workingTree.enable()(刚翻开)
装到本地适配器上。没启用提交能力的库上这个类一次都不会被构造。
Implements
Constructors
Constructor
new WorkingTreeCaptureRuntime(options): WorkingTreeCaptureRuntime;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:338
由 createWorkingTreeCaptureRuntime 构造;没启用提交能力的库上一次都不会被调到。
Parameters
| Parameter | Type | Description |
|---|---|---|
options | WorkingTreeCaptureRuntimeOptions | 全部依赖,见 WorkingTreeCaptureRuntimeOptions |
Returns
WorkingTreeCaptureRuntime
Remarks
全部注入且构造后不可换:版本化域与系统表清单在这里定格,于是「这张表受不受保护」
在本运行时的整个生命周期里只有一个答案。构造器不碰挂载目标——#target 由
bindMountTarget 在装到适配器上的那一刻才写入,因此同一个运行时可以先造出来、
再决定装到哪个适配器上。
Accessors
domain
Get Signature
get domain(): VersionedDomain;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:323
本运行时认的那份版本化域
Remarks
不在核心的 WorkingTreeCaptureHook 契约上:核心一次都不读它。摆上去等于让核心 替「判定认什么」的形状背书,而那正是随捕获规则变、必须留在本包的东西。
暴露在类上是给本包自己与一致性套件用的:套件要在表 / 列平面核对「哪些表受保护」, 而那份清单只有运行时手上有。交出的是清单本身不是拷贝——拷一份出来之后,插件后续登记的 派生索引列只会落进其中一份,raw 通道与捕获会对同一张表给出不同结论。
Returns
Methods
bindMountTarget()
bindMountTarget(target): void;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:354
认领安装宿主与它那份未拦截原语;installWorkingTreeCapture 之后立刻调用一次
Parameters
| Parameter | Type | Description |
|---|---|---|
target | WorkingTreeCaptureMountTarget | 被装上挂载点的适配器实例;同时是适配器级写意图声明的作用域键 |
Returns
void
Remarks
两样东西都只有安装方知道,而两样运行时都要:target 是
declareTrustedWrite 用的作用域身份——挂载点 2 / 3 的调用方把意图声明在适配器上,
运行时得拿同一个对象才查得到;raw 则是捕获自己发写的唯一安全入口,
走被拦截的那份会立刻递归回挂载点自己。
Implementation of
WorkingTreeCaptureHook.bindMountTarget
gateExternalNotify()
gateExternalNotify<T>(
entityName,
namespace,
notify
): T;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:524
转交门 2:一次 notifyExternalUpdate()(写入口语义矩阵行 11)
Type Parameters
| Type Parameter | Description |
|---|---|
T | 通知体的返回类型;放行时原样透传 |
Parameters
| Parameter | Type | Description |
|---|---|---|
entityName | string | 被通知的实体名 |
namespace | string | undefined | 已知时直接用;rxdb 即系统表 |
notify | () => T | 还没被调用的通知体 |
Returns
T
notify() 的返回值本身
Throws
目标是版本化业务实体时抛出;此时一条事件都不会派发
Remarks
与 gateRawWrite 同一个理由挂在这张契约上:核心的 notifyExternalUpdate() 拦得住
自己,却回答不了「这个实体归哪一类」——那要问域,而域是捕获的。核心因此只交出实体身份,
把「归哪类、这一类在行 11 上是放是拒」整段留给运行时。
门包着通知体,不是通知之后补的一句断言:拿到的是还没被调用的回调,「先判定」于是在 类型上就是唯一写法;写成先派发再检查的话,拒绝也阻止不了事件已经发出去。
Implementation of
WorkingTreeCaptureHook.gateExternalNotify
gateRawWrite()
gateRawWrite<T>(sql, execute): Promise<T>;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:512
转交门 1:一条 raw 写语句(adapter-contract.md §2 的 4 步判定)
Type Parameters
| Type Parameter | Description |
|---|---|
T | 语句执行体的返回类型;放行时原样透传 |
Parameters
| Parameter | Type | Description |
|---|---|---|
sql | string | 待判定的语句原文 |
execute | () => T | Promise<T> | 还没被调用的执行体 |
Returns
Promise<T>
execute() 的返回值本身
Throws
目标落在版本化业务表且不满足任何放行条件时抛出;此时 execute 一次都不会被调用
Remarks
rawQuery?() 是适配器接口上的可选方法,核心包没法像四个挂载点那样替适配器包住它,
判定只能由各适配器自己的实现调用 gateRawWrite。而那个函数在核心里只剩一句分派:
能力位为假直接放行,为真转交到这里。判定实现一个字都不在核心——它认的是语句词法、
表名的六种物理形态与受信意图,三样都随捕获规则变。
Implementation of
WorkingTreeCaptureHook.gateRawWrite
interceptBulkWrite()
interceptBulkWrite(
_host,
next,
entityName,
operation
): Observable<void>;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:460
挂载点 4:upsertMany / deleteByIds 的门禁
Parameters
| Parameter | Type |
|---|---|
_host | WorkingTreeWriteHost |
next | () => Observable<void> |
entityName | string |
operation | InterceptedBulkWrite |
Returns
Observable<void>
Remarks
同步转发,中间没有 await:门禁必须在 Observable 存在之前抛(adapter-contract.md §1.1)。
entityName 按 namespace:entity 拆一次再判:这一层的契约里没有独立的命名空间参数,
而限定名是既有写法(resolveQueryCacheTarget 就这么解析)。送进门禁的仍是原样的
entityName,拒绝信息才指得回调用方写下的那个名字。
Implementation of
WorkingTreeCaptureHook.interceptBulkWrite
interceptMergeChanges()
interceptMergeChanges(
host,
next,
actions,
localChanges?,
disableTriggers?
): Promise<number | void>;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:408
挂载点 2:本地 mergeChanges
Parameters
| Parameter | Type |
|---|---|
host | WorkingTreeWriteHost |
next | MergeChangesNext |
actions | SwitchVersionActions |
localChanges? | Omit<RxDBChange, "id">[] |
disableTriggers? | boolean |
Returns
Promise<number | void>
Remarks
业务写与捕获共用 host.runInTransaction() 要来的那一个事务:mergeChanges 内部走的也是
runInTransaction,把它发到该事务 executor 的门面上,它就复用而不是新开。于是
「写了业务表却没留下单元」在这个挂载点上不存在崩溃窗口。
本次写产生的变更行要登记进 CONSUMED_CHANGE_IDS:嵌在挂载点 1 的事务体里时
(merge_branch 的 normal 策略就是这个形状),外层的增量读否则会把同一批写再判一遍。
不在嵌套形态下时格子不存在,has() 为假,连那次水位线读都不发。
Implementation of
WorkingTreeCaptureHook.interceptMergeChanges
interceptSwitchBranch()
interceptSwitchBranch(
host,
next,
options
): Promise<void>;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:436
挂载点 3:switchBranch
Parameters
| Parameter | Type |
|---|---|
host | WorkingTreeWriteHost |
next | (options) => Promise<void> |
options | SwitchBranchOptions |
Returns
Promise<void>
Remarks
拒绝判定在 next() 之前同步完成,所以未登记的调用一行业务数据都改不了。捕获则只能在
next() 之后另开事务——switch_branch() 自己要开事务并在前后刷变更管道,包不进来。
见本文件顶部关于 §5 偏离的说明。
Implementation of
WorkingTreeCaptureHook.interceptSwitchBranch
interceptTransaction()
interceptTransaction(
_host,
next,
fun,
transactionLog?
): Promise<unknown>;
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:371
挂载点 1:整事务共享一个 unitId
Parameters
| Parameter | Type |
|---|---|
_host | WorkingTreeWriteHost |
next | (fun, transactionLog?) => Promise<unknown> |
fun | TransactionFun |
transactionLog? | boolean |
Returns
Promise<unknown>
Remarks
水位线读在 fun 之前、增量读在 fun 之后,两次都用同一个 executor:换成适配器级读取
会在事务外看见一个尚未提交的区间,捕获到的行数取决于别的事务提交得多快。
没有意图声明时入口是 crud 而不是拒绝——transaction() 是所有业务写的正常通道,
对它 fail-closed 等于把整个库变成只读。受信路径的 fail-closed 落在挂载点 2 / 3 上。
带 CAPTURE_OWNED_TRANSACTION 标的事务体原样放行:那是挂载点 2 / 3 为了写工作树行 自己开的事务,业务写已经在那边按受信入口捕获过了。
Implementation of
WorkingTreeCaptureHook.interceptTransaction
targetClassOf()
targetClassOf(entityName, namespace?): "system" | "versioned" | "query_cache";
Defined in: packages/rxdb-plugin-working-tree/src/working-tree/capture-hook.ts:500
实体名 → 写入口语义矩阵里的目标类别
Parameters
| Parameter | Type | Description |
|---|---|---|
entityName | string | 实体名(不含命名空间) |
namespace? | string | 已知时按身份精确判;省略时按裸名判 |
Returns
"system" | "versioned" | "query_cache"
system / query_cache / versioned 三者之一
Remarks
先问域,域不认得才问系统表清单。 域里只有业务实体(createWorkingTreeCaptureRuntime
建域时已把系统表摘出去),所以「域认得这个名字」本身就是「它不是系统表」的证明。反过来
先判系统表就是评审 #5 那个洞:接入方把实体取名 Commit(epic-006 恰好有一张 rxdb:Commit)
之后,那张业务表的写会被整批判成 system 而静默绕过捕获——改动不进提交,且没有报错形态。
系统表清单的两种投影按手上有没有命名空间选:有就比身份(rxdb:RxDBBranch),没有才比裸名。
两者是同一份登记簿算出来的(getSystemEntityNames / getSystemEntityIdentities),
不是两份清单。不再按 namespace === 'rxdb' 一刀切:命名空间是接入方可以自己取的,
恰好叫 rxdb 的业务实体没有理由整批退出版本控制。
与 domain 同理不在核心契约上:核心的 notifyExternalUpdate() 从前要自己问一次
归类再把结果送进门禁,现在只交出实体身份、整段判定走 gateExternalNotify。
于是「归哪一类」这件事在核心侧一次都不出现。