doxum 0.1.4 → 0.1.6
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 +46 -5
- package/dist/{contract-BsY1XLiG.d.ts → contract-I99DUMbN.d.ts} +53 -40
- package/dist/{contract-D8kjdfqT.d.cts → contract-uYJTmT8o.d.cts} +53 -40
- package/dist/index.cjs +244 -630
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -64
- package/dist/index.d.ts +3 -64
- package/dist/index.js +182 -569
- package/dist/index.js.map +1 -1
- package/dist/integration-Bs3pOk65.cjs +35 -0
- package/dist/integration-Bs3pOk65.cjs.map +1 -0
- package/dist/integration-xupBIKjU.js +30 -0
- package/dist/integration-xupBIKjU.js.map +1 -0
- package/dist/integration.cjs +4 -14
- package/dist/integration.d.cts +3 -2
- package/dist/integration.d.ts +3 -2
- package/dist/integration.js +3 -14
- package/dist/local-sync.cjs +1 -1
- package/dist/local-sync.d.cts +1 -1
- package/dist/local-sync.d.ts +1 -1
- package/dist/local-sync.js +1 -1
- package/dist/{ownership-CU-9DKJQ.cjs → ownership-CY0nPXGF.cjs} +4 -1
- package/dist/ownership-CY0nPXGF.cjs.map +1 -0
- package/dist/{ownership-B-VAPcce.js → ownership-CduRygE7.js} +4 -1
- package/dist/ownership-CduRygE7.js.map +1 -0
- package/dist/react.cjs +1 -1
- package/dist/react.js +1 -1
- package/dist/runtime-BJRXF0gq.js +1735 -0
- package/dist/runtime-BJRXF0gq.js.map +1 -0
- package/dist/runtime-CRijXjYp.cjs +1991 -0
- package/dist/runtime-CRijXjYp.cjs.map +1 -0
- package/dist/runtime-CUcvhFNP.d.ts +152 -0
- package/dist/runtime-C_vKHmhy.d.cts +152 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/references/guide.en.md +35 -18
- package/skills/doxum-runtime/references/guide.zh-CN.md +26 -14
- package/skills/doxum-runtime/references/invariants.en.md +12 -9
- package/skills/doxum-runtime/references/invariants.zh-CN.md +2 -2
- package/skills/doxum-runtime/references/patterns.en.md +36 -56
- package/skills/doxum-runtime/references/patterns.zh-CN.md +27 -45
- package/dist/dependency-C5_R1tvQ.js +0 -496
- package/dist/dependency-C5_R1tvQ.js.map +0 -1
- package/dist/dependency-Dfzs3khk.cjs +0 -722
- package/dist/dependency-Dfzs3khk.cjs.map +0 -1
- package/dist/integration.cjs.map +0 -1
- package/dist/integration.js.map +0 -1
- package/dist/ownership-B-VAPcce.js.map +0 -1
- package/dist/ownership-CU-9DKJQ.cjs.map +0 -1
package/package.json
CHANGED
|
@@ -24,8 +24,8 @@ resolution.
|
|
|
24
24
|
| Replace an entire trusted snapshot | `runtime.replace(document, options)` |
|
|
25
25
|
| Observe one schema location | `schema.value` plus `runtime.subscribe` |
|
|
26
26
|
| Observe a table or map | `schema.collection` plus `runtime.subscribe` |
|
|
27
|
-
| Maintain mapped collection data | `
|
|
28
|
-
| Maintain an aggregate or index | `
|
|
27
|
+
| Maintain mapped collection data | `projection.map` |
|
|
28
|
+
| Maintain an aggregate or index | `projection.value / projection.collection` |
|
|
29
29
|
| Read in React | `useDocumentSelector`, `useReadable`, or `useReadable` |
|
|
30
30
|
|
|
31
31
|
Do not write a second mutable copy of the document. `createDocument` is the
|
|
@@ -163,6 +163,11 @@ the same API except `move`, because it is unordered. Lists offer `insert`,
|
|
|
163
163
|
specified in the schema. See [patterns.en.md](patterns.en.md) for complete
|
|
164
164
|
collection and tree examples.
|
|
165
165
|
|
|
166
|
+
Optional field, variant, dict, list, and tree writers expose `clear()`. Optional
|
|
167
|
+
structured leaves can also be initialized from an absent state with `replace()`.
|
|
168
|
+
Optional objects, tables, and maps have no whole-value clear; modify them through
|
|
169
|
+
their child writers or collection operations.
|
|
170
|
+
|
|
166
171
|
## Replay operations at the boundary
|
|
167
172
|
|
|
168
173
|
Use `apply` for operation batches that came from persistence, a network
|
|
@@ -288,26 +293,38 @@ comparison helpers in application modules.
|
|
|
288
293
|
|
|
289
294
|
## Build derived read models
|
|
290
295
|
|
|
291
|
-
`createCollectionView` maps one table or map into stable ids, cached `item(id)`
|
|
292
|
-
readables, and a lazy `all` array. It updates only affected entries where possible.
|
|
293
|
-
|
|
294
296
|
```ts
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
const projection = createProjectionRuntime({ onError: error => console.error(error) });
|
|
298
|
+
const document = projection.document(runtime);
|
|
299
|
+
const notes = document.collection(path => path.notes);
|
|
300
|
+
const noteSummaries = projection.map(
|
|
301
|
+
notes,
|
|
302
|
+
(id, note) => ({ id, preview: note.body.get().slice(0, 80) }),
|
|
303
|
+
{ isEqual: (a, b) => a.id === b.id && a.preview === b.preview }
|
|
304
|
+
);
|
|
305
|
+
const noteCount = projection.value({
|
|
306
|
+
sources: { notes },
|
|
307
|
+
build: ({ notes }) => ({
|
|
308
|
+
value: notes.read.ids().length,
|
|
309
|
+
update: ({ notes }) => ({
|
|
310
|
+
kind: 'changed',
|
|
311
|
+
value: notes.read.ids().length,
|
|
312
|
+
}),
|
|
313
|
+
}),
|
|
301
314
|
});
|
|
302
|
-
|
|
303
|
-
taskTitles.item('write-guide').current();
|
|
304
|
-
taskTitles.all.current();
|
|
305
315
|
```
|
|
306
316
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
317
|
+
projection.map produces stable ids/item readables and lazy all. Declare a
|
|
318
|
+
DocumentCollectionSource directly in any processor's sources, or use
|
|
319
|
+
projection.value and projection.collection for explicit incremental logic.
|
|
320
|
+
There is no automatic keyed dependency tracking. All sources belong to the
|
|
321
|
+
same projection owner, but may refer to different document runtimes.
|
|
322
|
+
|
|
323
|
+
Use projection.input(initial, { isEqual }) for boundary values; give processors
|
|
324
|
+
its source and keep set at the application boundary. fromReadable attaches an
|
|
325
|
+
existing external source without taking ownership of it. Batch synchronous
|
|
326
|
+
multi-source changes before the first commit. Dispose the projection at service
|
|
327
|
+
shutdown; React unmount only unsubscribes. Disposed handles throw.
|
|
311
328
|
|
|
312
329
|
## React integration
|
|
313
330
|
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
| 整体替换可信快照 | `runtime.replace(document, options)` |
|
|
18
18
|
| 监听一个 schema 位置 | `schema.value` + `runtime.subscribe` |
|
|
19
19
|
| 监听 table 或 map | `schema.collection` + `runtime.subscribe` |
|
|
20
|
-
| 维护映射后的集合数据 | `
|
|
21
|
-
| 维护聚合或索引 | `
|
|
20
|
+
| 维护映射后的集合数据 | `projection.map` |
|
|
21
|
+
| 维护聚合或索引 | `projection.value / projection.collection` |
|
|
22
22
|
| 在 React 中读取 | `useDocumentSelector`、`useReadable` 或 `useReadable` |
|
|
23
23
|
|
|
24
24
|
不要再维护一份可写的文档副本。`createDocument` 是 canonical state 的唯一所有者。
|
|
@@ -135,6 +135,10 @@ runtime.update(tx => {
|
|
|
135
135
|
|
|
136
136
|
table 支持 `create`、`item`、`remove` 和 `move`。map 与之相同,但没有 `move`,因为它无顺序。list 支持 `insert`、`move`、`remove` 与 `replace`;其身份来自 schema 中的 `keyOf`。完整的集合与 tree 模式见 [patterns.zh-CN.md](patterns.zh-CN.md)。
|
|
137
137
|
|
|
138
|
+
optional 的 field、variant、dict、list 和 tree writer 提供 `clear()`;其中结构化叶子也可
|
|
139
|
+
在当前缺失时直接调用 `replace()` 建立值。optional object、table 和 map 没有整体 clear,
|
|
140
|
+
应通过子 writer 或集合操作修改。
|
|
141
|
+
|
|
138
142
|
## 在边界回放 operation
|
|
139
143
|
|
|
140
144
|
来自持久化、网络适配器或其他外部边界的 operation batch 应通过 `apply` 回放。Doxum 会在 mutation code 看到数据前解码未知 operation payload,按 schema 解析每个地址,并原子地执行整个 batch。
|
|
@@ -239,22 +243,30 @@ value selector 使用 `commit.impact.affects(target)`;table 或 map selector
|
|
|
239
243
|
|
|
240
244
|
## 构建派生读模型
|
|
241
245
|
|
|
242
|
-
`createCollectionView` 将一个 table 或 map 映射为稳定的 ids、缓存的 `item(id)` readable 和惰性 `all` 数组;在可能的情况下只更新受影响的条目。
|
|
243
|
-
|
|
244
246
|
```ts
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
247
|
+
const projection = createProjectionRuntime({ onError: error => console.error(error) });
|
|
248
|
+
const document = projection.document(runtime);
|
|
249
|
+
const notes = document.collection(path => path.notes);
|
|
250
|
+
const noteSummaries = projection.map(
|
|
251
|
+
notes,
|
|
252
|
+
(id, note) => ({ id, preview: note.body.get().slice(0, 80) }),
|
|
253
|
+
{ isEqual: (a, b) => a.id === b.id && a.preview === b.preview }
|
|
254
|
+
);
|
|
255
|
+
const noteCount = projection.value({
|
|
256
|
+
sources: { notes },
|
|
257
|
+
build: ({ notes }) => ({
|
|
258
|
+
value: notes.read.ids().length,
|
|
259
|
+
update: ({ notes }) => ({
|
|
260
|
+
kind: 'changed',
|
|
261
|
+
value: notes.read.ids().length,
|
|
262
|
+
}),
|
|
263
|
+
}),
|
|
251
264
|
});
|
|
252
|
-
|
|
253
|
-
taskTitles.item('write-guide').current();
|
|
254
|
-
taskTitles.all.current();
|
|
255
265
|
```
|
|
256
266
|
|
|
257
|
-
|
|
267
|
+
projection.map 提供稳定的 ids/item readable 和惰性 all。DocumentCollectionSource 可直接用于自定义 processor 的 sources;projection.value 和 projection.collection 承载显式增量计算。不自动跟踪 keyed 依赖。sources 属于同一 projection owner,但可接入不同 document runtime。
|
|
268
|
+
|
|
269
|
+
projection.input(initial, { isEqual }) 用于边界值;应用保留 set,processor 只接收 source。fromReadable 接入已有外部 source,不取得其生命周期所有权。多 source 同步更新应在首次 commit 前进入 batch。projection 随 service 销毁,React unmount 只取消订阅,disposed handle 明确抛错。
|
|
258
270
|
|
|
259
271
|
## React 集成
|
|
260
272
|
|
|
@@ -117,15 +117,18 @@ and history stay settled.
|
|
|
117
117
|
|
|
118
118
|
## Derived state is declared, not synchronized by callers
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
ProjectionCollection and ProjectionValue share one explicit source graph and
|
|
121
|
+
publication mechanism. Only scoped processors write derived output. Application
|
|
122
|
+
code selects candidate keys from native impacts; Doxum owns final change,
|
|
123
|
+
equality, revision and notification. Never expose mutable private indexes or
|
|
124
|
+
retain scoped readers/writers. Updates must be synchronous.
|
|
125
|
+
|
|
126
|
+
All affected nodes settle before listeners; failures discard staged output and
|
|
127
|
+
attempt one fresh build before faulting. Faulted ancestors block descendants.
|
|
128
|
+
Listener exceptions are isolated. Source writes are forbidden during graph
|
|
129
|
+
processing and notification. Explicit batch defers graph publication, not
|
|
130
|
+
canonical commits or document listeners, and never promises source rollback.
|
|
131
|
+
Dispose the owner; do not dispose a node while it still has consumers.
|
|
129
132
|
|
|
130
133
|
## Framework and product boundaries
|
|
131
134
|
|
|
@@ -78,9 +78,9 @@ update 与 notification 窗口中禁止写入。processor、flush 和 listener e
|
|
|
78
78
|
|
|
79
79
|
## 派生状态应声明,而不是由调用方同步
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
ProjectionCollection 和 ProjectionValue 共用显式 source 图与发布机制。只有 scoped processor 写入派生输出。应用根据原生 impact 选择候选 key,Doxum 拥有最终 change、equality、revision 和 notification。不能泄漏可变私有索引,也不能保留 scoped reader/writer。update 必须同步。
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
受影响节点全部 settle 后再通知。失败丢弃候选输出,限一次全新 build 恢复,持续失败阻断下游;listener 错误逐个隔离。处理和通知期间禁止 source write。显式 batch 延迟派生图发布,不延迟 canonical commit 或 document listener,不承诺 source rollback。owner 负责 dispose,仍有消费者的节点不能单独释放。
|
|
84
84
|
|
|
85
85
|
## Framework 与产品边界
|
|
86
86
|
|
|
@@ -24,6 +24,13 @@ array of ids: that creates two mutation protocols and two sources of order.
|
|
|
24
24
|
Use a list only when every item has a stable, unique application key; never use
|
|
25
25
|
the current index as `keyOf`.
|
|
26
26
|
|
|
27
|
+
Entry readers and writers for tables and maps are derived directly from the entry
|
|
28
|
+
schema node. Structured entries retain their specialized tree, list, dict, or
|
|
29
|
+
variant access instead of being reconstructed from runtime values into a broad
|
|
30
|
+
object union. Optional fields and optional variant, dict, list, and tree leaves
|
|
31
|
+
also expose `clear()` and can be initialized from an absent state with
|
|
32
|
+
`replace()`; objects, tables, and maps keep their child or collection operations.
|
|
33
|
+
|
|
27
34
|
```ts
|
|
28
35
|
import { field, list, map, object, schema, table, tree } from 'doxum';
|
|
29
36
|
|
|
@@ -181,68 +188,41 @@ as values. Use `target.address`, `target.id`, `target.belongs`, and
|
|
|
181
188
|
`target.bucket` rather than duplicating their interpretation in a framework
|
|
182
189
|
adapter or local helper.
|
|
183
190
|
|
|
184
|
-
## Build
|
|
185
|
-
|
|
186
|
-
Use a collection view when a table or map needs a reusable read model. Its
|
|
187
|
-
mapping callback can read the entry's typed fields; `isEqual` lets the view
|
|
188
|
-
retain a previous mapped value when a remapped row is semantically unchanged.
|
|
189
|
-
|
|
190
|
-
```ts
|
|
191
|
-
const notes = documentSchema.collection(path => path.notes);
|
|
192
|
-
|
|
193
|
-
const noteSummaries = createCollectionView({
|
|
194
|
-
runtime,
|
|
195
|
-
source: notes,
|
|
196
|
-
map: (id, note) => ({ id, preview: note.body.get().slice(0, 80) }),
|
|
197
|
-
isEqual: (left, right) => left.id === right.id && left.preview === right.preview,
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const stop = noteSummaries.item('a').subscribe(() => rerenderRow('a'));
|
|
201
|
-
const all = noteSummaries.all.current();
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Do not make callers push changes into the view. It listens to its declared
|
|
205
|
-
source and recomputes from runtime state. Dispose `noteSummaries` and `stop`
|
|
206
|
-
with the UI or service that owns them.
|
|
207
|
-
|
|
208
|
-
## Build a materialized aggregate or index
|
|
209
|
-
|
|
210
|
-
Use a materialized view when you own an aggregate that can update from a
|
|
211
|
-
commit. During `update`, inspect the impact through the provided `impact`
|
|
212
|
-
object. That records the actual dependencies, so future unrelated commits can
|
|
213
|
-
skip this update.
|
|
191
|
+
## Build explicit projections
|
|
214
192
|
|
|
215
193
|
```ts
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
kind: 'changed',
|
|
234
|
-
value: read.notes.ids().length,
|
|
235
|
-
change,
|
|
236
|
-
};
|
|
237
|
-
},
|
|
194
|
+
const projection = createProjectionRuntime({ onError: error => console.error(error) });
|
|
195
|
+
const document = projection.document(runtime);
|
|
196
|
+
const notes = document.collection(path => path.notes);
|
|
197
|
+
const noteSummaries = projection.map(
|
|
198
|
+
notes,
|
|
199
|
+
(id, note) => ({ id, preview: note.body.get().slice(0, 80) }),
|
|
200
|
+
{ isEqual: (a, b) => a.id === b.id && a.preview === b.preview }
|
|
201
|
+
);
|
|
202
|
+
const noteCount = projection.value({
|
|
203
|
+
sources: { notes },
|
|
204
|
+
build: ({ notes }) => ({
|
|
205
|
+
value: notes.read.ids().length,
|
|
206
|
+
update: ({ notes }) => ({
|
|
207
|
+
kind: 'changed',
|
|
208
|
+
value: notes.read.ids().length,
|
|
209
|
+
}),
|
|
238
210
|
}),
|
|
239
211
|
});
|
|
240
212
|
```
|
|
241
213
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
commit.
|
|
214
|
+
Use map for one-to-one collection transforms. For custom indexes, use
|
|
215
|
+
projection.collection with declared sources and scoped writer.set/remove/order/replace.
|
|
216
|
+
Its previous and next readers separate published values from staged writes.
|
|
217
|
+
Inspect each document source commit.impact, or an upstream collection change,
|
|
218
|
+
to determine candidate keys. Dependencies are explicit and fixed, not learned
|
|
219
|
+
from reads. Doxum determines final changes through equality.
|
|
220
|
+
|
|
221
|
+
A failed update discards its instance and attempts one fresh build. Persistent
|
|
222
|
+
faults block descendants; independent branches continue. Call rebuild through
|
|
223
|
+
the node API, never manually emit. Dispose the projection with its owner.
|
|
224
|
+
Wrap document mutation and editor cleanup in projection.batch before the first
|
|
225
|
+
commit; reads inside the batch remain at the last published projection.
|
|
246
226
|
|
|
247
227
|
## Bind read models in React
|
|
248
228
|
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
|
|
20
20
|
当顺序对产品可见时使用 table。不要用 map 加另一份 ids array 表示顺序:这会产生两套 mutation protocol 和两个顺序来源。list 只适合每个条目都有稳定、唯一应用 key 的情形;不能把当前 index 当作 `keyOf`。
|
|
21
21
|
|
|
22
|
+
table/map 的 entry reader 与 writer 直接由 entry schema node 推导。结构化 entry 会保留
|
|
23
|
+
自己的 tree、list、dict、variant 等专用 access,而不会从运行时 value 反推成普通对象或
|
|
24
|
+
产生 value union。optional field 以及 optional 的 variant、dict、list、tree 结构叶子额外
|
|
25
|
+
提供 `clear()`,并可在缺失状态通过 `replace()` 初始化;object、table、map 仍使用各自的
|
|
26
|
+
子 writer 或集合操作。
|
|
27
|
+
|
|
22
28
|
```ts
|
|
23
29
|
import { field, list, map, object, schema, table, tree } from 'doxum';
|
|
24
30
|
|
|
@@ -151,58 +157,34 @@ const unsubscribe = runtime.subscribe([notes, body], commit => {
|
|
|
151
157
|
|
|
152
158
|
只有需要将两个 impact target 当作值比较时,使用 `target.same(left, right)`。应使用 `target.address`、`target.id`、`target.belongs` 与 `target.bucket`,不要在 framework adapter 或局部 helper 中复制它们的解释逻辑。
|
|
153
159
|
|
|
154
|
-
##
|
|
155
|
-
|
|
156
|
-
当一个 table 或 map 需要可复用 read model 时,使用 collection view。mapping callback 可以读取 entry 的类型化字段;`isEqual` 允许 view 在重新映射出的 row 语义不变时保留旧值。
|
|
160
|
+
## 构建显式派生图
|
|
157
161
|
|
|
158
162
|
```ts
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
isEqual: (
|
|
163
|
+
const projection = createProjectionRuntime({ onError: error => console.error(error) });
|
|
164
|
+
const document = projection.document(runtime);
|
|
165
|
+
const notes = document.collection(path => path.notes);
|
|
166
|
+
const noteSummaries = projection.map(
|
|
167
|
+
notes,
|
|
168
|
+
(id, note) => ({ id, preview: note.body.get().slice(0, 80) }),
|
|
169
|
+
{ isEqual: (a, b) => a.id === b.id && a.preview === b.preview }
|
|
170
|
+
);
|
|
171
|
+
const noteCount = projection.value({
|
|
172
|
+
sources: { notes },
|
|
173
|
+
build: ({ notes }) => ({
|
|
174
|
+
value: notes.read.ids().length,
|
|
175
|
+
update: ({ notes }) => ({
|
|
176
|
+
kind: 'changed',
|
|
177
|
+
value: notes.read.ids().length,
|
|
178
|
+
}),
|
|
179
|
+
}),
|
|
166
180
|
});
|
|
167
|
-
|
|
168
|
-
const stop = noteSummaries.item('a').subscribe(() => rerenderRow('a'));
|
|
169
|
-
const all = noteSummaries.all.current();
|
|
170
181
|
```
|
|
171
182
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
## 用 MaterializedView 构建聚合或索引
|
|
183
|
+
map 用于保留 key 和顺序的一对一映射。自定义索引使用 projection.collection,声明 sources,并通过 scoped writer.set/remove/order/replace 更新。previous 与 next 分别读取上次输出和本轮暂存结果。
|
|
175
184
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
const notes = documentSchema.collection(path => path.notes);
|
|
180
|
-
|
|
181
|
-
const noteCount = createMaterializedView(runtime, {
|
|
182
|
-
build: ({ read }) => ({
|
|
183
|
-
value: read.notes.ids().length,
|
|
184
|
-
update: ({ impact, read }) => {
|
|
185
|
-
const change = impact.collection(notes);
|
|
186
|
-
if (
|
|
187
|
-
change.kind === 'incremental' &&
|
|
188
|
-
change.added.size === 0 &&
|
|
189
|
-
change.removed.size === 0 &&
|
|
190
|
-
change.updated.size === 0 &&
|
|
191
|
-
!change.orderChanged
|
|
192
|
-
) {
|
|
193
|
-
return { kind: 'unchanged' };
|
|
194
|
-
}
|
|
195
|
-
return {
|
|
196
|
-
kind: 'changed',
|
|
197
|
-
value: read.notes.ids().length,
|
|
198
|
-
change,
|
|
199
|
-
};
|
|
200
|
-
},
|
|
201
|
-
}),
|
|
202
|
-
});
|
|
203
|
-
```
|
|
185
|
+
根据每个 document source 的 commits 中的 impact,或上游 collection change,决定候选 key。依赖显式固定,不通过 reader 自动学习。Doxum 根据 equality 决定最终 change。
|
|
204
186
|
|
|
205
|
-
|
|
187
|
+
update 失败后丢弃实例并限一次全新 build 恢复;持续失败阻断下游,独立分支继续。rebuild 经过同一调度图,不手动 emit。projection 随 owner dispose。使用 projection.batch 包住首次 document commit 之前到 editor cleanup 结束的完整同步动作;batch 内派生读取保持上次发布状态。
|
|
206
188
|
|
|
207
189
|
## 在 React 中绑定读模型
|
|
208
190
|
|