doxum 0.1.18 → 0.1.19
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 +24 -0
- package/dist/advanced-BYZCjNWL.js +680 -0
- package/dist/advanced-BYZCjNWL.js.map +1 -0
- package/dist/{advanced-c0F3gpLG.d.ts → advanced-C2fpjbK3.d.ts} +35 -2
- package/dist/advanced-CMMNk49G.cjs +763 -0
- package/dist/advanced-CMMNk49G.cjs.map +1 -0
- package/dist/{advanced-GTwIWcn6.d.cts → advanced-DlOYk1vi.d.cts} +35 -2
- package/dist/advanced.cjs +1 -1
- package/dist/advanced.d.cts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.js +1 -1
- package/dist/index.cjs +477 -567
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +437 -527
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/doxum-runtime/references/projections.en.md +24 -0
- package/skills/doxum-runtime/references/projections.zh-CN.md +22 -0
- package/dist/advanced-DgRnyRAc.js +0 -233
- package/dist/advanced-DgRnyRAc.js.map +0 -1
- package/dist/advanced-Dgu8-bPS.cjs +0 -274
- package/dist/advanced-Dgu8-bPS.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@ const require_issue = require("./issue-DhrNdQNg.cjs");
|
|
|
3
3
|
const require_scope = require("./scope-Ezs-Y3TY.cjs");
|
|
4
4
|
const require_notification = require("./notification-CDSUfiip.cjs");
|
|
5
5
|
const require_driver = require("./driver-BCyfqxsl.cjs");
|
|
6
|
-
const require_advanced = require("./advanced-
|
|
6
|
+
const require_advanced = require("./advanced-CMMNk49G.cjs");
|
|
7
7
|
//#region core/src/schema.ts
|
|
8
8
|
const node = (value) => Object.freeze(value);
|
|
9
9
|
const field = (validator) => node({
|
|
@@ -1104,333 +1104,6 @@ const asReadable = (runtime) => {
|
|
|
1104
1104
|
//#region core/src/projection/select.ts
|
|
1105
1105
|
const read = (runtime, selector) => require_notification.readWith(runtime, selector);
|
|
1106
1106
|
//#endregion
|
|
1107
|
-
//#region core/src/projection/contract.ts
|
|
1108
|
-
var ProjectionError = class extends Error {
|
|
1109
|
-
constructor(phase, identity, revisions, cause) {
|
|
1110
|
-
super(`Projection ${phase} failed: ${identity}`, { cause });
|
|
1111
|
-
this.phase = phase;
|
|
1112
|
-
this.identity = identity;
|
|
1113
|
-
this.revisions = revisions;
|
|
1114
|
-
this.name = "ProjectionError";
|
|
1115
|
-
}
|
|
1116
|
-
};
|
|
1117
|
-
var ProjectionDisposedError = class extends Error {
|
|
1118
|
-
constructor() {
|
|
1119
|
-
super("Projection has been disposed.");
|
|
1120
|
-
this.name = "ProjectionDisposedError";
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
|
-
//#endregion
|
|
1124
|
-
//#region core/src/projection/scheduler.ts
|
|
1125
|
-
const projectionHandles = /* @__PURE__ */ new WeakSet();
|
|
1126
|
-
const createScheduler = (onError) => {
|
|
1127
|
-
let disposed = false;
|
|
1128
|
-
let depth = 0;
|
|
1129
|
-
let batchSequence = 0;
|
|
1130
|
-
let activeBatch;
|
|
1131
|
-
let phase = "idle";
|
|
1132
|
-
let sequence = 0;
|
|
1133
|
-
const records = /* @__PURE__ */ new Map();
|
|
1134
|
-
const nodes = /* @__PURE__ */ new Set();
|
|
1135
|
-
const pending = /* @__PURE__ */ new Set();
|
|
1136
|
-
const heap = [];
|
|
1137
|
-
const queued = /* @__PURE__ */ new Set();
|
|
1138
|
-
const completed = [];
|
|
1139
|
-
const emissions = /* @__PURE__ */ new Set();
|
|
1140
|
-
const errors = [];
|
|
1141
|
-
let reportingFailures = [];
|
|
1142
|
-
const guards = /* @__PURE__ */ new Set();
|
|
1143
|
-
const cleanups = /* @__PURE__ */ new Set();
|
|
1144
|
-
const assertActive = () => {
|
|
1145
|
-
if (disposed) throw new ProjectionDisposedError();
|
|
1146
|
-
};
|
|
1147
|
-
const assertIdle = () => {
|
|
1148
|
-
assertActive();
|
|
1149
|
-
if (phase !== "idle") throw new Error("Projection cannot be re-entered during processing or notification.");
|
|
1150
|
-
};
|
|
1151
|
-
const lock = (value) => guards.forEach((guard) => guard(value));
|
|
1152
|
-
const enqueue = (node) => {
|
|
1153
|
-
if (node.disposed || queued.has(node)) return;
|
|
1154
|
-
queued.add(node);
|
|
1155
|
-
require_issue.profile.projection("scheduledNodes");
|
|
1156
|
-
let i = heap.length;
|
|
1157
|
-
heap.push(node);
|
|
1158
|
-
while (i > 0) {
|
|
1159
|
-
const p = i - 1 >> 1;
|
|
1160
|
-
if (heap[p].order < node.order) break;
|
|
1161
|
-
heap[i] = heap[p];
|
|
1162
|
-
i = p;
|
|
1163
|
-
}
|
|
1164
|
-
heap[i] = node;
|
|
1165
|
-
};
|
|
1166
|
-
const pop = () => {
|
|
1167
|
-
const first = heap[0];
|
|
1168
|
-
const last = heap.pop();
|
|
1169
|
-
if (heap.length) {
|
|
1170
|
-
let i = 0;
|
|
1171
|
-
while (i * 2 + 1 < heap.length) {
|
|
1172
|
-
let c = i * 2 + 1;
|
|
1173
|
-
if (c + 1 < heap.length && heap[c + 1].order < heap[c].order) c++;
|
|
1174
|
-
if (last.order < heap[c].order) break;
|
|
1175
|
-
heap[i] = heap[c];
|
|
1176
|
-
i = c;
|
|
1177
|
-
}
|
|
1178
|
-
heap[i] = last;
|
|
1179
|
-
}
|
|
1180
|
-
return first;
|
|
1181
|
-
};
|
|
1182
|
-
const errorFor = (node, cause, kind = "processor") => new ProjectionError(kind, node.name, node.sources.map((source) => source.revision()), cause);
|
|
1183
|
-
const capture = (source) => {
|
|
1184
|
-
if (disposed) return;
|
|
1185
|
-
if (phase !== "idle") {
|
|
1186
|
-
source.fault = new ProjectionError("source", "reentrant source", [source.revision()], /* @__PURE__ */ new Error("Source changed while projection was running."));
|
|
1187
|
-
errors.push(source.fault);
|
|
1188
|
-
throw source.fault;
|
|
1189
|
-
}
|
|
1190
|
-
pending.add(source);
|
|
1191
|
-
require_issue.profile.projection("sourceEvents");
|
|
1192
|
-
if (source.fault) errors.push(source.fault);
|
|
1193
|
-
};
|
|
1194
|
-
const settle = () => {
|
|
1195
|
-
if (disposed || depth || phase !== "idle") return;
|
|
1196
|
-
phase = "compute";
|
|
1197
|
-
lock(true);
|
|
1198
|
-
try {
|
|
1199
|
-
pending.forEach((source) => {
|
|
1200
|
-
if (source.shouldSettle?.() ?? true) source.consumers.forEach(enqueue);
|
|
1201
|
-
});
|
|
1202
|
-
while (heap.length) {
|
|
1203
|
-
const node = pop();
|
|
1204
|
-
if (node.disposed) continue;
|
|
1205
|
-
const wasFaulted = node.fault !== void 0;
|
|
1206
|
-
require_issue.profile.projection("processedNodes");
|
|
1207
|
-
let changed = false;
|
|
1208
|
-
const blocked = node.sources.find((source) => source.fault || source.disposed);
|
|
1209
|
-
if (blocked) node.fault = errorFor(node, blocked.fault ?? new ProjectionDisposedError(), "blocked");
|
|
1210
|
-
else {
|
|
1211
|
-
const build = wasFaulted || node.sources.some((source) => source.reset());
|
|
1212
|
-
try {
|
|
1213
|
-
changed = node.evaluate(build);
|
|
1214
|
-
const failure = node.sources.find((source) => source.fault)?.fault;
|
|
1215
|
-
if (failure) throw failure;
|
|
1216
|
-
node.fault = void 0;
|
|
1217
|
-
} catch (cause) {
|
|
1218
|
-
const error = errorFor(node, cause);
|
|
1219
|
-
errors.push(error);
|
|
1220
|
-
node.fault = error;
|
|
1221
|
-
if (!build) try {
|
|
1222
|
-
changed = node.evaluate(true);
|
|
1223
|
-
const failure = node.sources.find((source) => source.fault)?.fault;
|
|
1224
|
-
if (failure) throw failure;
|
|
1225
|
-
node.fault = void 0;
|
|
1226
|
-
} catch (cause) {
|
|
1227
|
-
node.fault = errorFor(node, cause);
|
|
1228
|
-
errors.push(node.fault);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
completed.push(node);
|
|
1233
|
-
if (changed || wasFaulted || node.fault) {
|
|
1234
|
-
require_issue.profile.projection("publishedNodes");
|
|
1235
|
-
emissions.add(node);
|
|
1236
|
-
node.consumers.forEach(enqueue);
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
completed.forEach((node) => node.publish());
|
|
1240
|
-
} finally {
|
|
1241
|
-
lock(false);
|
|
1242
|
-
phase = "idle";
|
|
1243
|
-
}
|
|
1244
|
-
};
|
|
1245
|
-
const flush = () => {
|
|
1246
|
-
if (disposed || depth) return [];
|
|
1247
|
-
if (pending.size || completed.length) require_issue.profile.projection("flushes");
|
|
1248
|
-
phase = "notify";
|
|
1249
|
-
lock(true);
|
|
1250
|
-
const reportFailures = [];
|
|
1251
|
-
try {
|
|
1252
|
-
emissions.forEach((node) => node.emit((listener) => {
|
|
1253
|
-
try {
|
|
1254
|
-
listener();
|
|
1255
|
-
} catch (cause) {
|
|
1256
|
-
errors.push(errorFor(node, cause, "listener"));
|
|
1257
|
-
}
|
|
1258
|
-
}));
|
|
1259
|
-
for (const error of errors.slice()) try {
|
|
1260
|
-
onError(error);
|
|
1261
|
-
} catch (cause) {
|
|
1262
|
-
reportFailures.push(cause);
|
|
1263
|
-
}
|
|
1264
|
-
return Object.freeze([...errors.map((error) => Object.freeze({
|
|
1265
|
-
phase: error.phase === "listener" ? "listener" : "processor",
|
|
1266
|
-
error
|
|
1267
|
-
})), ...reportFailures.map((error) => Object.freeze({
|
|
1268
|
-
phase: "listener",
|
|
1269
|
-
error
|
|
1270
|
-
}))]);
|
|
1271
|
-
} finally {
|
|
1272
|
-
pending.forEach((source) => source.clear());
|
|
1273
|
-
completed.forEach((node) => node.clear());
|
|
1274
|
-
pending.clear();
|
|
1275
|
-
queued.clear();
|
|
1276
|
-
completed.length = 0;
|
|
1277
|
-
emissions.clear();
|
|
1278
|
-
errors.length = 0;
|
|
1279
|
-
reportingFailures = reportFailures;
|
|
1280
|
-
lock(false);
|
|
1281
|
-
phase = "idle";
|
|
1282
|
-
}
|
|
1283
|
-
};
|
|
1284
|
-
const run = () => {
|
|
1285
|
-
settle();
|
|
1286
|
-
const result = flush();
|
|
1287
|
-
const failures = reportingFailures;
|
|
1288
|
-
reportingFailures = [];
|
|
1289
|
-
if (failures.length) throw new AggregateError(failures, "Projection error reporter failed.");
|
|
1290
|
-
return result;
|
|
1291
|
-
};
|
|
1292
|
-
const batch = (optionsOrCallback, maybeCallback) => {
|
|
1293
|
-
assertIdle();
|
|
1294
|
-
const options = typeof optionsOrCallback === "function" ? void 0 : optionsOrCallback;
|
|
1295
|
-
const callback = typeof optionsOrCallback === "function" ? optionsOrCallback : maybeCallback;
|
|
1296
|
-
if (!callback) throw new TypeError("Projection batch requires a callback.");
|
|
1297
|
-
if (depth === 0) activeBatch = Object.freeze({
|
|
1298
|
-
id: ++batchSequence,
|
|
1299
|
-
...options?.cause === void 0 ? {} : { cause: options.cause }
|
|
1300
|
-
});
|
|
1301
|
-
depth++;
|
|
1302
|
-
let failed = false;
|
|
1303
|
-
try {
|
|
1304
|
-
const value = callback();
|
|
1305
|
-
assertSynchronous(value);
|
|
1306
|
-
return value;
|
|
1307
|
-
} catch (error) {
|
|
1308
|
-
failed = true;
|
|
1309
|
-
throw error;
|
|
1310
|
-
} finally {
|
|
1311
|
-
depth--;
|
|
1312
|
-
if (!depth) try {
|
|
1313
|
-
if (failed) try {
|
|
1314
|
-
run();
|
|
1315
|
-
} catch {}
|
|
1316
|
-
else run();
|
|
1317
|
-
} finally {
|
|
1318
|
-
activeBatch = void 0;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
};
|
|
1322
|
-
return {
|
|
1323
|
-
assertActive,
|
|
1324
|
-
assertIdle,
|
|
1325
|
-
capture,
|
|
1326
|
-
settle,
|
|
1327
|
-
flush,
|
|
1328
|
-
run,
|
|
1329
|
-
records,
|
|
1330
|
-
guards,
|
|
1331
|
-
cleanups,
|
|
1332
|
-
get active() {
|
|
1333
|
-
return !disposed;
|
|
1334
|
-
},
|
|
1335
|
-
register(handle, record) {
|
|
1336
|
-
assertIdle();
|
|
1337
|
-
records.set(handle, record);
|
|
1338
|
-
projectionHandles.add(handle);
|
|
1339
|
-
},
|
|
1340
|
-
unregisterSource(handle) {
|
|
1341
|
-
const record = records.get(handle);
|
|
1342
|
-
if (record) {
|
|
1343
|
-
assertIdle();
|
|
1344
|
-
if (record.consumers.size) throw new Error("Projection source is still used by a node.");
|
|
1345
|
-
record.disposed = true;
|
|
1346
|
-
pending.delete(record);
|
|
1347
|
-
record.clear();
|
|
1348
|
-
records.delete(handle);
|
|
1349
|
-
}
|
|
1350
|
-
},
|
|
1351
|
-
releaseNode(handle) {
|
|
1352
|
-
assertIdle();
|
|
1353
|
-
const node = records.get(handle);
|
|
1354
|
-
if (!node || !nodes.has(node)) throw new Error("Unknown projection node.");
|
|
1355
|
-
if (node.consumers.size) throw new Error("Projection node is still used by another node.");
|
|
1356
|
-
node.disposed = true;
|
|
1357
|
-
node.sources.forEach((source) => source.consumers.delete(node));
|
|
1358
|
-
node.release();
|
|
1359
|
-
node.clear();
|
|
1360
|
-
nodes.delete(node);
|
|
1361
|
-
records.delete(handle);
|
|
1362
|
-
pending.delete(node);
|
|
1363
|
-
queued.delete(node);
|
|
1364
|
-
emissions.delete(node);
|
|
1365
|
-
},
|
|
1366
|
-
source(handle) {
|
|
1367
|
-
assertActive();
|
|
1368
|
-
const source = records.get(handle);
|
|
1369
|
-
if (!source || source.disposed) throw new Error("Unknown, disposed, or foreign projection source.");
|
|
1370
|
-
return source;
|
|
1371
|
-
},
|
|
1372
|
-
addNode(node) {
|
|
1373
|
-
nodes.add(node);
|
|
1374
|
-
node.sources.forEach((source) => source.consumers.add(node));
|
|
1375
|
-
},
|
|
1376
|
-
order: () => sequence++,
|
|
1377
|
-
initialize(run) {
|
|
1378
|
-
assertIdle();
|
|
1379
|
-
phase = "compute";
|
|
1380
|
-
lock(true);
|
|
1381
|
-
try {
|
|
1382
|
-
return run();
|
|
1383
|
-
} finally {
|
|
1384
|
-
lock(false);
|
|
1385
|
-
phase = "idle";
|
|
1386
|
-
}
|
|
1387
|
-
},
|
|
1388
|
-
batch,
|
|
1389
|
-
batchContext: () => activeBatch,
|
|
1390
|
-
dispose() {
|
|
1391
|
-
if (disposed) return;
|
|
1392
|
-
assertIdle();
|
|
1393
|
-
disposed = true;
|
|
1394
|
-
const failures = [];
|
|
1395
|
-
cleanups.forEach((cleanup) => {
|
|
1396
|
-
try {
|
|
1397
|
-
cleanup();
|
|
1398
|
-
} catch (error) {
|
|
1399
|
-
failures.push(error);
|
|
1400
|
-
}
|
|
1401
|
-
});
|
|
1402
|
-
cleanups.clear();
|
|
1403
|
-
nodes.forEach((node) => {
|
|
1404
|
-
node.disposed = true;
|
|
1405
|
-
node.release();
|
|
1406
|
-
node.consumers.clear();
|
|
1407
|
-
});
|
|
1408
|
-
records.forEach((source) => {
|
|
1409
|
-
source.disposed = true;
|
|
1410
|
-
source.consumers.clear();
|
|
1411
|
-
source.clear();
|
|
1412
|
-
});
|
|
1413
|
-
nodes.clear();
|
|
1414
|
-
records.clear();
|
|
1415
|
-
pending.clear();
|
|
1416
|
-
heap.length = 0;
|
|
1417
|
-
completed.length = 0;
|
|
1418
|
-
queued.clear();
|
|
1419
|
-
emissions.clear();
|
|
1420
|
-
guards.clear();
|
|
1421
|
-
errors.length = 0;
|
|
1422
|
-
reportingFailures = [];
|
|
1423
|
-
if (failures.length) throw new AggregateError(failures, "Projection cleanup failed.");
|
|
1424
|
-
}
|
|
1425
|
-
};
|
|
1426
|
-
};
|
|
1427
|
-
const assertSynchronous = (value) => {
|
|
1428
|
-
if (value != null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function") throw new TypeError("Projection callbacks must be synchronous.");
|
|
1429
|
-
};
|
|
1430
|
-
const assertScope = (active) => {
|
|
1431
|
-
if (!active()) throw new Error("Projection reader or writer is no longer active.");
|
|
1432
|
-
};
|
|
1433
|
-
//#endregion
|
|
1434
1107
|
//#region core/src/projection/source.ts
|
|
1435
1108
|
const createSources = (scheduler) => {
|
|
1436
1109
|
const documents = /* @__PURE__ */ new Map();
|
|
@@ -1483,7 +1156,7 @@ const createSources = (scheduler) => {
|
|
|
1483
1156
|
nextBaselineIds = Object.freeze([]);
|
|
1484
1157
|
},
|
|
1485
1158
|
context: (active) => {
|
|
1486
|
-
assertScope(active);
|
|
1159
|
+
require_advanced.assertScope(active);
|
|
1487
1160
|
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1488
1161
|
const context = {
|
|
1489
1162
|
state,
|
|
@@ -1493,16 +1166,16 @@ const createSources = (scheduler) => {
|
|
|
1493
1166
|
const snapshots = collection ? /* @__PURE__ */ new Map() : void 0;
|
|
1494
1167
|
const read = collection ? Object.freeze({
|
|
1495
1168
|
get: (key) => {
|
|
1496
|
-
assertScope(active);
|
|
1169
|
+
require_advanced.assertScope(active);
|
|
1497
1170
|
if (!snapshots.has(key)) snapshots.set(key, require_scope.snapshot(rawRead.get(key)));
|
|
1498
1171
|
return snapshots.get(key);
|
|
1499
1172
|
},
|
|
1500
1173
|
has: (key) => {
|
|
1501
|
-
assertScope(active);
|
|
1174
|
+
require_advanced.assertScope(active);
|
|
1502
1175
|
return rawRead.has(key);
|
|
1503
1176
|
},
|
|
1504
1177
|
ids: () => {
|
|
1505
|
-
assertScope(active);
|
|
1178
|
+
require_advanced.assertScope(active);
|
|
1506
1179
|
return rawRead.ids();
|
|
1507
1180
|
}
|
|
1508
1181
|
}) : require_scope.createAccess(context);
|
|
@@ -1642,7 +1315,7 @@ const createSources = (scheduler) => {
|
|
|
1642
1315
|
flush: scheduler.flush,
|
|
1643
1316
|
dispose: () => {
|
|
1644
1317
|
bindings.forEach(({ record }) => {
|
|
1645
|
-
record.fault = new ProjectionError("source", "document disposed", [runtime.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1318
|
+
record.fault = new require_advanced.ProjectionError("source", "document disposed", [runtime.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1646
1319
|
scheduler.capture(record);
|
|
1647
1320
|
});
|
|
1648
1321
|
scheduler.run();
|
|
@@ -1672,7 +1345,7 @@ const createSources = (scheduler) => {
|
|
|
1672
1345
|
reset = false;
|
|
1673
1346
|
},
|
|
1674
1347
|
context: (active) => {
|
|
1675
|
-
assertScope(active);
|
|
1348
|
+
require_advanced.assertScope(active);
|
|
1676
1349
|
return Object.freeze({
|
|
1677
1350
|
kind: "value",
|
|
1678
1351
|
value,
|
|
@@ -1765,18 +1438,18 @@ const createSources = (scheduler) => {
|
|
|
1765
1438
|
cause = void 0;
|
|
1766
1439
|
},
|
|
1767
1440
|
context: (active) => {
|
|
1768
|
-
assertScope(active);
|
|
1441
|
+
require_advanced.assertScope(active);
|
|
1769
1442
|
const read = Object.freeze({
|
|
1770
1443
|
get: (key) => {
|
|
1771
|
-
assertScope(active);
|
|
1444
|
+
require_advanced.assertScope(active);
|
|
1772
1445
|
return values.get(key);
|
|
1773
1446
|
},
|
|
1774
1447
|
has: (key) => {
|
|
1775
|
-
assertScope(active);
|
|
1448
|
+
require_advanced.assertScope(active);
|
|
1776
1449
|
return values.has(key);
|
|
1777
1450
|
},
|
|
1778
1451
|
ids: () => {
|
|
1779
|
-
assertScope(active);
|
|
1452
|
+
require_advanced.assertScope(active);
|
|
1780
1453
|
return Object.freeze([...values.keys()]);
|
|
1781
1454
|
}
|
|
1782
1455
|
});
|
|
@@ -1798,17 +1471,17 @@ const createSources = (scheduler) => {
|
|
|
1798
1471
|
let active = true;
|
|
1799
1472
|
const draft = Object.freeze({
|
|
1800
1473
|
get: (key) => {
|
|
1801
|
-
assertScope(() => active);
|
|
1474
|
+
require_advanced.assertScope(() => active);
|
|
1802
1475
|
const entry = staged.get(key);
|
|
1803
1476
|
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
1804
1477
|
},
|
|
1805
1478
|
has: (key) => {
|
|
1806
|
-
assertScope(() => active);
|
|
1479
|
+
require_advanced.assertScope(() => active);
|
|
1807
1480
|
const entry = staged.get(key);
|
|
1808
1481
|
return entry ? entry.present : values.has(key);
|
|
1809
1482
|
},
|
|
1810
1483
|
set: (key, value) => {
|
|
1811
|
-
assertScope(() => active);
|
|
1484
|
+
require_advanced.assertScope(() => active);
|
|
1812
1485
|
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1813
1486
|
staged.set(key, {
|
|
1814
1487
|
present: true,
|
|
@@ -1816,13 +1489,13 @@ const createSources = (scheduler) => {
|
|
|
1816
1489
|
});
|
|
1817
1490
|
},
|
|
1818
1491
|
remove: (key) => {
|
|
1819
|
-
assertScope(() => active);
|
|
1492
|
+
require_advanced.assertScope(() => active);
|
|
1820
1493
|
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1821
1494
|
staged.set(key, { present: false });
|
|
1822
1495
|
}
|
|
1823
1496
|
});
|
|
1824
1497
|
try {
|
|
1825
|
-
assertSynchronous(run(draft));
|
|
1498
|
+
require_advanced.assertSynchronous(run(draft));
|
|
1826
1499
|
} finally {
|
|
1827
1500
|
active = false;
|
|
1828
1501
|
}
|
|
@@ -1854,7 +1527,7 @@ const createSources = (scheduler) => {
|
|
|
1854
1527
|
const input = valueSource(port.current(), equal);
|
|
1855
1528
|
const fail = (cause) => {
|
|
1856
1529
|
const record = scheduler.source(input.source);
|
|
1857
|
-
record.fault = new ProjectionError("source", "external source", [record.revision()], cause);
|
|
1530
|
+
record.fault = new require_advanced.ProjectionError("source", "external source", [record.revision()], cause);
|
|
1858
1531
|
scheduler.capture(record);
|
|
1859
1532
|
};
|
|
1860
1533
|
let unsubscribe;
|
|
@@ -1910,18 +1583,18 @@ const createSources = (scheduler) => {
|
|
|
1910
1583
|
transitionKeys.clear();
|
|
1911
1584
|
},
|
|
1912
1585
|
context: (active) => {
|
|
1913
|
-
assertScope(active);
|
|
1586
|
+
require_advanced.assertScope(active);
|
|
1914
1587
|
const currentRead = Object.freeze({
|
|
1915
1588
|
get: (key) => {
|
|
1916
|
-
assertScope(active);
|
|
1589
|
+
require_advanced.assertScope(active);
|
|
1917
1590
|
return read.get(key);
|
|
1918
1591
|
},
|
|
1919
1592
|
has: (key) => {
|
|
1920
|
-
assertScope(active);
|
|
1593
|
+
require_advanced.assertScope(active);
|
|
1921
1594
|
return read.has(key);
|
|
1922
1595
|
},
|
|
1923
1596
|
ids: () => {
|
|
1924
|
-
assertScope(active);
|
|
1597
|
+
require_advanced.assertScope(active);
|
|
1925
1598
|
return read.ids();
|
|
1926
1599
|
}
|
|
1927
1600
|
});
|
|
@@ -1936,7 +1609,7 @@ const createSources = (scheduler) => {
|
|
|
1936
1609
|
};
|
|
1937
1610
|
scheduler.register(handle, record);
|
|
1938
1611
|
const fail = (error) => {
|
|
1939
|
-
record.fault = new ProjectionError("source", "external collection source", [revision], error);
|
|
1612
|
+
record.fault = new require_advanced.ProjectionError("source", "external collection source", [revision], error);
|
|
1940
1613
|
scheduler.capture(record);
|
|
1941
1614
|
};
|
|
1942
1615
|
const deriveChange = () => {
|
|
@@ -2042,7 +1715,7 @@ const createSources = (scheduler) => {
|
|
|
2042
1715
|
collectionInput,
|
|
2043
1716
|
fromReadable: (readable, options) => {
|
|
2044
1717
|
scheduler.assertIdle();
|
|
2045
|
-
if (projectionHandles.has(readable)) throw new Error("Projection nodes must be declared directly as sources.");
|
|
1718
|
+
if (require_advanced.projectionHandles.has(readable)) throw new Error("Projection nodes must be declared directly as sources.");
|
|
2046
1719
|
const equal = options?.isEqual ?? Object.is;
|
|
2047
1720
|
let bindings = readables.get(readable);
|
|
2048
1721
|
const old = bindings?.get(equal);
|
|
@@ -2068,7 +1741,7 @@ const createSources = (scheduler) => {
|
|
|
2068
1741
|
} catch (cause) {
|
|
2069
1742
|
for (const member of members.values()) {
|
|
2070
1743
|
const record = scheduler.source(member.source);
|
|
2071
|
-
record.fault = new ProjectionError("source", "external readable", [record.revision()], cause);
|
|
1744
|
+
record.fault = new require_advanced.ProjectionError("source", "external readable", [record.revision()], cause);
|
|
2072
1745
|
scheduler.capture(record);
|
|
2073
1746
|
}
|
|
2074
1747
|
if (settle) scheduler.run();
|
|
@@ -2078,7 +1751,7 @@ const createSources = (scheduler) => {
|
|
|
2078
1751
|
member.accept(value);
|
|
2079
1752
|
} catch (cause) {
|
|
2080
1753
|
const record = scheduler.source(member.source);
|
|
2081
|
-
record.fault = new ProjectionError("source", "external readable", [record.revision()], cause);
|
|
1754
|
+
record.fault = new require_advanced.ProjectionError("source", "external readable", [record.revision()], cause);
|
|
2082
1755
|
scheduler.capture(record);
|
|
2083
1756
|
}
|
|
2084
1757
|
if (settle) scheduler.run();
|
|
@@ -2096,7 +1769,7 @@ const createSources = (scheduler) => {
|
|
|
2096
1769
|
dispose: () => {
|
|
2097
1770
|
for (const member of members.values()) {
|
|
2098
1771
|
const record = scheduler.source(member.source);
|
|
2099
|
-
record.fault = new ProjectionError("source", "document readable disposed", [record.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1772
|
+
record.fault = new require_advanced.ProjectionError("source", "document readable disposed", [record.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
2100
1773
|
scheduler.capture(record);
|
|
2101
1774
|
}
|
|
2102
1775
|
scheduler.run();
|
|
@@ -2133,6 +1806,7 @@ const createNode = (scheduler, spec, behavior) => {
|
|
|
2133
1806
|
const entries = Object.entries(spec.sources).map(([key, handle]) => [key, scheduler.source(handle)]);
|
|
2134
1807
|
const order = scheduler.order();
|
|
2135
1808
|
const node = {
|
|
1809
|
+
owner: void 0,
|
|
2136
1810
|
...behavior,
|
|
2137
1811
|
publish: () => {
|
|
2138
1812
|
if (node.fault) behavior.clear();
|
|
@@ -2155,15 +1829,16 @@ const createNode = (scheduler, spec, behavior) => {
|
|
|
2155
1829
|
}
|
|
2156
1830
|
}
|
|
2157
1831
|
};
|
|
1832
|
+
node.owner = node;
|
|
2158
1833
|
scheduler.initialize(() => {
|
|
2159
1834
|
const invalid = node.sources.find((source) => source.fault || source.disposed);
|
|
2160
|
-
if (invalid) throw invalid.fault ?? new ProjectionDisposedError();
|
|
1835
|
+
if (invalid) throw invalid.fault ?? new require_advanced.ProjectionDisposedError();
|
|
2161
1836
|
node.evaluate(true);
|
|
2162
1837
|
node.publish();
|
|
2163
1838
|
node.clear();
|
|
2164
1839
|
});
|
|
2165
1840
|
const check = () => {
|
|
2166
|
-
if (node.disposed || !scheduler.active) throw new ProjectionDisposedError();
|
|
1841
|
+
if (node.disposed || !scheduler.active) throw new require_advanced.ProjectionDisposedError();
|
|
2167
1842
|
if (node.fault) throw node.fault;
|
|
2168
1843
|
};
|
|
2169
1844
|
return {
|
|
@@ -2195,17 +1870,17 @@ const createValue = (scheduler, spec, options) => {
|
|
|
2195
1870
|
require_issue.profile.materialized.rebuilt();
|
|
2196
1871
|
instance = void 0;
|
|
2197
1872
|
const built = spec.build(sources);
|
|
2198
|
-
assertSynchronous(built);
|
|
1873
|
+
require_advanced.assertSynchronous(built);
|
|
2199
1874
|
instance = built;
|
|
2200
1875
|
candidate = built.value;
|
|
2201
1876
|
} else {
|
|
2202
1877
|
require_issue.profile.materialized.updated();
|
|
2203
1878
|
const result = instance.update(sources);
|
|
2204
|
-
assertSynchronous(result);
|
|
1879
|
+
require_advanced.assertSynchronous(result);
|
|
2205
1880
|
if (result.kind === "rebuild") {
|
|
2206
1881
|
instance = void 0;
|
|
2207
1882
|
const built = spec.build(sources);
|
|
2208
|
-
assertSynchronous(built);
|
|
1883
|
+
require_advanced.assertSynchronous(built);
|
|
2209
1884
|
instance = built;
|
|
2210
1885
|
candidate = built.value;
|
|
2211
1886
|
build = true;
|
|
@@ -2217,7 +1892,7 @@ const createValue = (scheduler, spec, options) => {
|
|
|
2217
1892
|
return changed;
|
|
2218
1893
|
},
|
|
2219
1894
|
context: (active) => {
|
|
2220
|
-
assertScope(active);
|
|
1895
|
+
require_advanced.assertScope(active);
|
|
2221
1896
|
return Object.freeze({
|
|
2222
1897
|
kind: "value",
|
|
2223
1898
|
value: next,
|
|
@@ -2271,7 +1946,7 @@ const createValue = (scheduler, spec, options) => {
|
|
|
2271
1946
|
return handle;
|
|
2272
1947
|
};
|
|
2273
1948
|
//#endregion
|
|
2274
|
-
//#region core/src/projection/collection.ts
|
|
1949
|
+
//#region core/src/projection/collection-state.ts
|
|
2275
1950
|
const height = (node) => node?.height ?? 0;
|
|
2276
1951
|
const makeTreeNode = (key, value, left, right) => Object.freeze({
|
|
2277
1952
|
key,
|
|
@@ -2337,214 +2012,197 @@ const treeFromSorted = (entries, start = 0, end = entries.length) => {
|
|
|
2337
2012
|
const [key, value] = entries[middle];
|
|
2338
2013
|
return makeTreeNode(key, value, treeFromSorted(entries, start, middle), treeFromSorted(entries, middle + 1, end));
|
|
2339
2014
|
};
|
|
2340
|
-
|
|
2015
|
+
/**
|
|
2016
|
+
* The one keyed publication kernel used by ordinary collection nodes and
|
|
2017
|
+
* processor-group output leaves. It owns staged intent, exact transitions and
|
|
2018
|
+
* the persistent published snapshot; callers only provide the processor
|
|
2019
|
+
* callback and the equality policy.
|
|
2020
|
+
*/
|
|
2021
|
+
const createCollectionState = () => {
|
|
2341
2022
|
const values = /* @__PURE__ */ new Map();
|
|
2342
2023
|
let ids = Object.freeze([]);
|
|
2343
2024
|
let staged = /* @__PURE__ */ new Map();
|
|
2344
2025
|
let nextIds = ids;
|
|
2345
2026
|
let change;
|
|
2346
|
-
let instance;
|
|
2347
2027
|
let initialized = false;
|
|
2348
2028
|
let reset = false;
|
|
2349
2029
|
let revision = 0;
|
|
2350
2030
|
let publishedRoot;
|
|
2351
|
-
let
|
|
2352
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
2353
|
-
const changedKeys = /* @__PURE__ */ new Set();
|
|
2031
|
+
let changedKeys = /* @__PURE__ */ new Set();
|
|
2354
2032
|
let orderChanged = false;
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
},
|
|
2360
|
-
has: (key) => {
|
|
2361
|
-
owner.check();
|
|
2362
|
-
return treeHas(root, key);
|
|
2363
|
-
},
|
|
2364
|
-
ids: () => {
|
|
2365
|
-
owner.check();
|
|
2366
|
-
return publishedIds;
|
|
2367
|
-
}
|
|
2368
|
-
});
|
|
2369
|
-
const hasNext = (key) => staged.has(key) ? staged.get(key).present : values.has(key);
|
|
2033
|
+
let explicitOrder;
|
|
2034
|
+
let cleared = false;
|
|
2035
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2036
|
+
const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && values.has(key);
|
|
2370
2037
|
const getNext = (key) => {
|
|
2371
2038
|
const entry = staged.get(key);
|
|
2372
|
-
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
2039
|
+
return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : values.get(key);
|
|
2373
2040
|
};
|
|
2374
|
-
const
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2041
|
+
const deriveIds = () => {
|
|
2042
|
+
const result = cleared ? [] : ids.filter(hasNext);
|
|
2043
|
+
for (const [key, entry] of staged) if (entry.present && (cleared || !values.has(key))) result.push(key);
|
|
2044
|
+
return result;
|
|
2045
|
+
};
|
|
2046
|
+
const begin = (active, nextReset) => {
|
|
2047
|
+
staged = /* @__PURE__ */ new Map();
|
|
2048
|
+
nextIds = ids;
|
|
2049
|
+
change = void 0;
|
|
2050
|
+
changedKeys = /* @__PURE__ */ new Set();
|
|
2051
|
+
explicitOrder = void 0;
|
|
2052
|
+
orderChanged = false;
|
|
2053
|
+
cleared = nextReset;
|
|
2054
|
+
const read = (next) => ({
|
|
2055
|
+
get: (key) => {
|
|
2056
|
+
require_advanced.assertScope(active);
|
|
2057
|
+
return next ? getNext(key) : values.get(key);
|
|
2058
|
+
},
|
|
2059
|
+
has: (key) => {
|
|
2060
|
+
require_advanced.assertScope(active);
|
|
2061
|
+
return next ? hasNext(key) : values.has(key);
|
|
2062
|
+
},
|
|
2063
|
+
ids: () => {
|
|
2064
|
+
require_advanced.assertScope(active);
|
|
2065
|
+
return next ? Object.freeze(explicitOrder ? [...explicitOrder] : [...deriveIds()]) : ids;
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
return {
|
|
2069
|
+
previous: read(false),
|
|
2070
|
+
next: read(true),
|
|
2071
|
+
output: {
|
|
2072
|
+
set: (key, value) => {
|
|
2073
|
+
require_advanced.assertScope(active);
|
|
2074
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
2075
|
+
staged.set(key, {
|
|
2076
|
+
present: true,
|
|
2077
|
+
value
|
|
2078
|
+
});
|
|
2397
2079
|
},
|
|
2398
|
-
|
|
2399
|
-
assertScope(active);
|
|
2400
|
-
|
|
2080
|
+
remove: (key) => {
|
|
2081
|
+
require_advanced.assertScope(active);
|
|
2082
|
+
staged.set(key, { present: false });
|
|
2401
2083
|
},
|
|
2402
|
-
|
|
2403
|
-
assertScope(active);
|
|
2404
|
-
|
|
2405
|
-
}
|
|
2406
|
-
});
|
|
2407
|
-
const input = {
|
|
2408
|
-
sources,
|
|
2409
|
-
previous: read(false),
|
|
2410
|
-
next: read(true),
|
|
2411
|
-
output: {
|
|
2412
|
-
set: (key, value) => {
|
|
2413
|
-
assertScope(active);
|
|
2414
|
-
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
2415
|
-
staged.set(key, {
|
|
2416
|
-
present: true,
|
|
2417
|
-
value
|
|
2418
|
-
});
|
|
2419
|
-
},
|
|
2420
|
-
remove: (key) => {
|
|
2421
|
-
assertScope(active);
|
|
2422
|
-
staged.set(key, { present: false });
|
|
2423
|
-
},
|
|
2424
|
-
order: (order) => {
|
|
2425
|
-
assertScope(active);
|
|
2426
|
-
explicitOrder = order.slice();
|
|
2427
|
-
}
|
|
2084
|
+
order: (order) => {
|
|
2085
|
+
require_advanced.assertScope(active);
|
|
2086
|
+
explicitOrder = Object.freeze([...order]);
|
|
2428
2087
|
}
|
|
2429
|
-
};
|
|
2430
|
-
if (build || !instance) {
|
|
2431
|
-
require_issue.profile.materialized.rebuilt();
|
|
2432
|
-
instance = void 0;
|
|
2433
|
-
cleared = true;
|
|
2434
|
-
const built = spec.build(input);
|
|
2435
|
-
assertSynchronous(built);
|
|
2436
|
-
instance = built;
|
|
2437
|
-
} else {
|
|
2438
|
-
require_issue.profile.materialized.updated();
|
|
2439
|
-
const result = instance.update(input);
|
|
2440
|
-
assertSynchronous(result);
|
|
2441
|
-
if (result?.kind === "rebuild") {
|
|
2442
|
-
staged.clear();
|
|
2443
|
-
cleared = true;
|
|
2444
|
-
explicitOrder = void 0;
|
|
2445
|
-
instance = void 0;
|
|
2446
|
-
const built = spec.build(input);
|
|
2447
|
-
assertSynchronous(built);
|
|
2448
|
-
instance = built;
|
|
2449
|
-
build = true;
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
if (cleared) {
|
|
2453
|
-
for (const key of values.keys()) if (!staged.has(key)) staged.set(key, { present: false });
|
|
2454
|
-
}
|
|
2455
|
-
const added = /* @__PURE__ */ new Set();
|
|
2456
|
-
const removed = /* @__PURE__ */ new Set();
|
|
2457
|
-
const updated = /* @__PURE__ */ new Set();
|
|
2458
|
-
require_issue.profile.projection("touchedKeys", staged.size);
|
|
2459
|
-
for (const [key, entry] of staged) {
|
|
2460
|
-
const existed = values.has(key);
|
|
2461
|
-
if (entry.present) if (!existed) added.add(key);
|
|
2462
|
-
else if (!(spec.isEqual ?? Object.is)(values.get(key), entry.value)) updated.add(key);
|
|
2463
|
-
else staged.delete(key);
|
|
2464
|
-
else if (existed) removed.add(key);
|
|
2465
|
-
else staged.delete(key);
|
|
2466
2088
|
}
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2089
|
+
};
|
|
2090
|
+
};
|
|
2091
|
+
const seal = (nextReset, isEqual) => {
|
|
2092
|
+
if (cleared) {
|
|
2093
|
+
for (const key of values.keys()) if (!staged.has(key)) staged.set(key, { present: false });
|
|
2094
|
+
}
|
|
2095
|
+
require_issue.profile.projection("touchedKeys", staged.size);
|
|
2096
|
+
const added = /* @__PURE__ */ new Set();
|
|
2097
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2098
|
+
const updated = /* @__PURE__ */ new Set();
|
|
2099
|
+
for (const [key, entry] of staged) {
|
|
2100
|
+
const existed = values.has(key);
|
|
2101
|
+
if (entry.present) {
|
|
2102
|
+
if (!existed) added.add(key);
|
|
2103
|
+
else if (!isEqual(values.get(key), entry.value)) updated.add(key);
|
|
2104
|
+
else if (!nextReset) staged.delete(key);
|
|
2105
|
+
} else if (existed) removed.add(key);
|
|
2106
|
+
else staged.delete(key);
|
|
2107
|
+
}
|
|
2108
|
+
if (explicitOrder || added.size || removed.size) {
|
|
2109
|
+
const order = explicitOrder ?? [...ids.filter((key) => !removed.has(key)), ...added];
|
|
2110
|
+
if (new Set(order).size !== order.length || order.length !== values.size + added.size - removed.size || order.some((key) => !hasNext(key))) throw new TypeError("Projection order must contain every key exactly once.");
|
|
2111
|
+
nextIds = ids.length === order.length && ids.every((key, index) => key === order[index]) ? ids : Object.freeze([...order]);
|
|
2112
|
+
} else nextIds = ids;
|
|
2113
|
+
orderChanged = nextIds !== ids;
|
|
2114
|
+
for (const key of added) changedKeys.add(key);
|
|
2115
|
+
for (const key of removed) changedKeys.add(key);
|
|
2116
|
+
for (const key of updated) changedKeys.add(key);
|
|
2117
|
+
require_issue.profile.projection("changedKeys", changedKeys.size);
|
|
2118
|
+
const addedEntries = [];
|
|
2119
|
+
const updatedEntries = [];
|
|
2120
|
+
const removedEntries = [];
|
|
2121
|
+
for (const key of changedKeys) {
|
|
2122
|
+
const beforePresent = values.has(key);
|
|
2123
|
+
const afterPresent = hasNext(key);
|
|
2124
|
+
if (beforePresent === afterPresent) {
|
|
2125
|
+
if (!beforePresent || isEqual(values.get(key), getNext(key))) continue;
|
|
2471
2126
|
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
else if (!afterPresent) removedEntries.push({
|
|
2494
|
-
key,
|
|
2495
|
-
before: values.get(key)
|
|
2496
|
-
});
|
|
2497
|
-
else updatedEntries.push({
|
|
2498
|
-
key,
|
|
2499
|
-
before: values.get(key),
|
|
2500
|
-
after: getNext(key)
|
|
2501
|
-
});
|
|
2127
|
+
if (!beforePresent) addedEntries.push({
|
|
2128
|
+
key,
|
|
2129
|
+
after: getNext(key)
|
|
2130
|
+
});
|
|
2131
|
+
else if (!afterPresent) removedEntries.push({
|
|
2132
|
+
key,
|
|
2133
|
+
before: values.get(key)
|
|
2134
|
+
});
|
|
2135
|
+
else updatedEntries.push({
|
|
2136
|
+
key,
|
|
2137
|
+
before: values.get(key),
|
|
2138
|
+
after: getNext(key)
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
if (nextReset) change = Object.freeze({ kind: "reset" });
|
|
2142
|
+
else if (addedEntries.length || updatedEntries.length || removedEntries.length || orderChanged) {
|
|
2143
|
+
let commonOrderChanged = false;
|
|
2144
|
+
if (orderChanged) {
|
|
2145
|
+
const before = ids.filter((key) => !removed.has(key));
|
|
2146
|
+
const after = nextIds.filter((key) => !added.has(key));
|
|
2147
|
+
commonOrderChanged = before.some((key, index) => after[index] !== key);
|
|
2502
2148
|
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2149
|
+
change = Object.freeze({
|
|
2150
|
+
kind: "incremental",
|
|
2151
|
+
added: Object.freeze(addedEntries),
|
|
2152
|
+
updated: Object.freeze(updatedEntries),
|
|
2153
|
+
removed: Object.freeze(removedEntries),
|
|
2154
|
+
...commonOrderChanged ? { order: Object.freeze({
|
|
2155
|
+
before: Object.freeze([...ids]),
|
|
2156
|
+
after: Object.freeze([...nextIds])
|
|
2157
|
+
}) } : {}
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
reset = nextReset;
|
|
2161
|
+
return change !== void 0;
|
|
2162
|
+
};
|
|
2163
|
+
const context = (active, cause) => Object.freeze({
|
|
2164
|
+
kind: "collection",
|
|
2165
|
+
read: {
|
|
2166
|
+
get: (key) => {
|
|
2167
|
+
require_advanced.assertScope(active);
|
|
2168
|
+
return getNext(key);
|
|
2169
|
+
},
|
|
2170
|
+
has: (key) => {
|
|
2171
|
+
require_advanced.assertScope(active);
|
|
2172
|
+
return hasNext(key);
|
|
2173
|
+
},
|
|
2174
|
+
ids: () => {
|
|
2175
|
+
require_advanced.assertScope(active);
|
|
2176
|
+
return nextIds;
|
|
2521
2177
|
}
|
|
2522
|
-
reset = build;
|
|
2523
|
-
return change !== void 0;
|
|
2524
|
-
},
|
|
2525
|
-
context: (active) => {
|
|
2526
|
-
const input = {
|
|
2527
|
-
kind: "collection",
|
|
2528
|
-
read: {
|
|
2529
|
-
get: (key) => {
|
|
2530
|
-
assertScope(active);
|
|
2531
|
-
return getNext(key);
|
|
2532
|
-
},
|
|
2533
|
-
has: (key) => {
|
|
2534
|
-
assertScope(active);
|
|
2535
|
-
return hasNext(key);
|
|
2536
|
-
},
|
|
2537
|
-
ids: () => {
|
|
2538
|
-
assertScope(active);
|
|
2539
|
-
return nextIds;
|
|
2540
|
-
}
|
|
2541
|
-
},
|
|
2542
|
-
change,
|
|
2543
|
-
revision: revision + (change ? 1 : 0),
|
|
2544
|
-
cause
|
|
2545
|
-
};
|
|
2546
|
-
return Object.freeze(input);
|
|
2547
2178
|
},
|
|
2179
|
+
change,
|
|
2180
|
+
revision: revision + (change ? 1 : 0),
|
|
2181
|
+
cause
|
|
2182
|
+
});
|
|
2183
|
+
const current = (check) => {
|
|
2184
|
+
const root = publishedRoot;
|
|
2185
|
+
const publishedIds = ids;
|
|
2186
|
+
return Object.freeze({
|
|
2187
|
+
get: (key) => {
|
|
2188
|
+
check();
|
|
2189
|
+
return treeGet(root, key);
|
|
2190
|
+
},
|
|
2191
|
+
has: (key) => {
|
|
2192
|
+
check();
|
|
2193
|
+
return treeHas(root, key);
|
|
2194
|
+
},
|
|
2195
|
+
ids: () => {
|
|
2196
|
+
check();
|
|
2197
|
+
return publishedIds;
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
};
|
|
2201
|
+
return {
|
|
2202
|
+
begin,
|
|
2203
|
+
seal,
|
|
2204
|
+
context,
|
|
2205
|
+
current,
|
|
2548
2206
|
revision: () => revision,
|
|
2549
2207
|
reset: () => reset,
|
|
2550
2208
|
publish: () => {
|
|
@@ -2556,14 +2214,11 @@ const createCollection = (scheduler, spec) => {
|
|
|
2556
2214
|
} else for (const [key, entry] of staged) publishedRoot = entry.present ? treeSet(publishedRoot, key, entry.value) : treeRemove(publishedRoot, key);
|
|
2557
2215
|
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
2558
2216
|
else values.delete(key);
|
|
2559
|
-
if (change)
|
|
2560
|
-
if (initialized) revision++;
|
|
2561
|
-
}
|
|
2217
|
+
if (change && initialized) revision++;
|
|
2562
2218
|
ids = nextIds;
|
|
2563
2219
|
initialized = true;
|
|
2564
2220
|
},
|
|
2565
2221
|
emit: (call) => {
|
|
2566
|
-
require_issue.profile.materialized.notification();
|
|
2567
2222
|
const resetEvent = Object.freeze({ kind: "reset" });
|
|
2568
2223
|
Array.from(listeners).forEach((listener) => call(() => listener(change ?? resetEvent)));
|
|
2569
2224
|
},
|
|
@@ -2573,8 +2228,9 @@ const createCollection = (scheduler, spec) => {
|
|
|
2573
2228
|
change = void 0;
|
|
2574
2229
|
reset = false;
|
|
2575
2230
|
changedKeys.clear();
|
|
2576
|
-
|
|
2231
|
+
explicitOrder = void 0;
|
|
2577
2232
|
orderChanged = false;
|
|
2233
|
+
cleared = false;
|
|
2578
2234
|
},
|
|
2579
2235
|
release: () => {
|
|
2580
2236
|
values.clear();
|
|
@@ -2582,6 +2238,66 @@ const createCollection = (scheduler, spec) => {
|
|
|
2582
2238
|
publishedRoot = void 0;
|
|
2583
2239
|
listeners.clear();
|
|
2584
2240
|
ids = nextIds = Object.freeze([]);
|
|
2241
|
+
change = void 0;
|
|
2242
|
+
initialized = false;
|
|
2243
|
+
revision = 0;
|
|
2244
|
+
},
|
|
2245
|
+
subscribe: (listener) => {
|
|
2246
|
+
listeners.add(listener);
|
|
2247
|
+
},
|
|
2248
|
+
unsubscribe: (listener) => {
|
|
2249
|
+
listeners.delete(listener);
|
|
2250
|
+
}
|
|
2251
|
+
};
|
|
2252
|
+
};
|
|
2253
|
+
//#endregion
|
|
2254
|
+
//#region core/src/projection/collection.ts
|
|
2255
|
+
const createCollection = (scheduler, spec) => {
|
|
2256
|
+
const state = createCollectionState();
|
|
2257
|
+
let instance;
|
|
2258
|
+
let cause;
|
|
2259
|
+
const owner = createNode(scheduler, spec, {
|
|
2260
|
+
evaluate: (sources, build, active) => {
|
|
2261
|
+
cause = Object.values(sources).find((value) => value && typeof value === "object" && "cause" in value && value.cause !== void 0)?.cause ?? scheduler.batchContext()?.cause;
|
|
2262
|
+
const input = state.begin(active, build);
|
|
2263
|
+
if (build || !instance) {
|
|
2264
|
+
require_issue.profile.materialized.rebuilt();
|
|
2265
|
+
instance = void 0;
|
|
2266
|
+
const built = spec.build({
|
|
2267
|
+
sources,
|
|
2268
|
+
...input
|
|
2269
|
+
});
|
|
2270
|
+
require_advanced.assertSynchronous(built);
|
|
2271
|
+
instance = built;
|
|
2272
|
+
} else {
|
|
2273
|
+
require_issue.profile.materialized.updated();
|
|
2274
|
+
const result = instance.update({
|
|
2275
|
+
sources,
|
|
2276
|
+
...input
|
|
2277
|
+
});
|
|
2278
|
+
require_advanced.assertSynchronous(result);
|
|
2279
|
+
if (result?.kind === "rebuild") {
|
|
2280
|
+
const rebuildInput = state.begin(active, true);
|
|
2281
|
+
instance = void 0;
|
|
2282
|
+
const built = spec.build({
|
|
2283
|
+
sources,
|
|
2284
|
+
...rebuildInput
|
|
2285
|
+
});
|
|
2286
|
+
require_advanced.assertSynchronous(built);
|
|
2287
|
+
instance = built;
|
|
2288
|
+
build = true;
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
return state.seal(build, spec.isEqual ?? Object.is);
|
|
2292
|
+
},
|
|
2293
|
+
context: (active) => state.context(active, cause),
|
|
2294
|
+
revision: state.revision,
|
|
2295
|
+
reset: state.reset,
|
|
2296
|
+
publish: state.publish,
|
|
2297
|
+
emit: state.emit,
|
|
2298
|
+
clear: state.clear,
|
|
2299
|
+
release: () => {
|
|
2300
|
+
state.release();
|
|
2585
2301
|
instance = void 0;
|
|
2586
2302
|
}
|
|
2587
2303
|
});
|
|
@@ -2589,34 +2305,186 @@ const createCollection = (scheduler, spec) => {
|
|
|
2589
2305
|
kind: "collection",
|
|
2590
2306
|
current: () => {
|
|
2591
2307
|
owner.check();
|
|
2592
|
-
return
|
|
2308
|
+
return state.current(owner.check);
|
|
2593
2309
|
},
|
|
2594
2310
|
revision: () => {
|
|
2595
2311
|
owner.check();
|
|
2596
|
-
return revision;
|
|
2312
|
+
return state.revision();
|
|
2597
2313
|
},
|
|
2598
2314
|
subscribe: (listener) => {
|
|
2599
2315
|
owner.check();
|
|
2600
|
-
|
|
2601
|
-
return () =>
|
|
2602
|
-
listeners.delete(listener);
|
|
2603
|
-
};
|
|
2316
|
+
state.subscribe(listener);
|
|
2317
|
+
return () => state.unsubscribe(listener);
|
|
2604
2318
|
}
|
|
2605
2319
|
};
|
|
2606
2320
|
owner.install(handle);
|
|
2607
2321
|
return Object.freeze(handle);
|
|
2608
2322
|
};
|
|
2609
2323
|
//#endregion
|
|
2324
|
+
//#region core/src/projection/group.ts
|
|
2325
|
+
/**
|
|
2326
|
+
* Materializes one processor callback with several keyed output leaves. The
|
|
2327
|
+
* scheduler sees one node and the output leaves remain ordinary source records
|
|
2328
|
+
* for dependency, revision and listener matching.
|
|
2329
|
+
*/
|
|
2330
|
+
const createCollectionGroup = (scheduler, spec) => {
|
|
2331
|
+
scheduler.assertIdle();
|
|
2332
|
+
const sources = Object.entries(spec.sources).map(([key, handle]) => [key, scheduler.source(handle)]);
|
|
2333
|
+
const states = spec.outputs.map(() => createCollectionState());
|
|
2334
|
+
let instance;
|
|
2335
|
+
let cause;
|
|
2336
|
+
let changedOutputs = Object.freeze([]);
|
|
2337
|
+
let node;
|
|
2338
|
+
const order = scheduler.order();
|
|
2339
|
+
const outputs = states.map((state, index) => {
|
|
2340
|
+
const output = {
|
|
2341
|
+
owner: void 0,
|
|
2342
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
2343
|
+
context: (active) => state.context(active, cause),
|
|
2344
|
+
revision: state.revision,
|
|
2345
|
+
reset: state.reset,
|
|
2346
|
+
fault: void 0,
|
|
2347
|
+
disposed: false,
|
|
2348
|
+
clear: state.clear,
|
|
2349
|
+
emit: state.emit
|
|
2350
|
+
};
|
|
2351
|
+
Object.defineProperty(output, "fault", {
|
|
2352
|
+
configurable: false,
|
|
2353
|
+
enumerable: true,
|
|
2354
|
+
get: () => node.fault,
|
|
2355
|
+
set: (value) => {
|
|
2356
|
+
node.fault = value;
|
|
2357
|
+
}
|
|
2358
|
+
});
|
|
2359
|
+
return output;
|
|
2360
|
+
});
|
|
2361
|
+
const check = () => {
|
|
2362
|
+
if (node.disposed || !scheduler.active) throw new require_advanced.ProjectionDisposedError();
|
|
2363
|
+
if (node.fault) throw node.fault;
|
|
2364
|
+
};
|
|
2365
|
+
const evaluate = (inputSources, build, active) => {
|
|
2366
|
+
cause = Object.values(inputSources).find((value) => value && typeof value === "object" && "cause" in value && value.cause !== void 0)?.cause ?? scheduler.batchContext()?.cause;
|
|
2367
|
+
const makeInput = (reset) => {
|
|
2368
|
+
const evaluations = states.map((state) => state.begin(active, reset));
|
|
2369
|
+
return {
|
|
2370
|
+
sources: inputSources,
|
|
2371
|
+
previous: evaluations.map((evaluation) => evaluation.previous),
|
|
2372
|
+
next: evaluations.map((evaluation) => evaluation.next),
|
|
2373
|
+
outputs: evaluations.map((evaluation) => evaluation.output)
|
|
2374
|
+
};
|
|
2375
|
+
};
|
|
2376
|
+
let input = makeInput(build);
|
|
2377
|
+
if (build || !instance) {
|
|
2378
|
+
require_issue.profile.materialized.rebuilt();
|
|
2379
|
+
instance = void 0;
|
|
2380
|
+
const built = spec.build(input);
|
|
2381
|
+
require_advanced.assertSynchronous(built);
|
|
2382
|
+
instance = built;
|
|
2383
|
+
} else {
|
|
2384
|
+
require_issue.profile.materialized.updated();
|
|
2385
|
+
const result = instance.update(input);
|
|
2386
|
+
require_advanced.assertSynchronous(result);
|
|
2387
|
+
if (result?.kind === "rebuild") {
|
|
2388
|
+
input = makeInput(true);
|
|
2389
|
+
instance = void 0;
|
|
2390
|
+
const built = spec.build(input);
|
|
2391
|
+
require_advanced.assertSynchronous(built);
|
|
2392
|
+
instance = built;
|
|
2393
|
+
build = true;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
changedOutputs = Object.freeze(states.flatMap((state, index) => state.seal(build, spec.outputs[index].isEqual ?? Object.is) ? [outputs[index]] : []));
|
|
2397
|
+
return changedOutputs.length > 0;
|
|
2398
|
+
};
|
|
2399
|
+
node = {
|
|
2400
|
+
owner: void 0,
|
|
2401
|
+
order,
|
|
2402
|
+
name: `processor-group (${order})`,
|
|
2403
|
+
sources: sources.map(([, source]) => source),
|
|
2404
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
2405
|
+
outputs,
|
|
2406
|
+
disposed: false,
|
|
2407
|
+
fault: void 0,
|
|
2408
|
+
context: (active) => {
|
|
2409
|
+
require_advanced.assertScope(active);
|
|
2410
|
+
return Object.freeze({ kind: "group" });
|
|
2411
|
+
},
|
|
2412
|
+
revision: () => Math.max(0, ...states.map((state) => state.revision())),
|
|
2413
|
+
reset: () => states.some((state) => state.reset()),
|
|
2414
|
+
evaluate: (build) => {
|
|
2415
|
+
let active = true;
|
|
2416
|
+
try {
|
|
2417
|
+
const scopeActive = () => active;
|
|
2418
|
+
return evaluate(Object.fromEntries(sources.map(([key, source]) => [key, source.context(scopeActive)])), build, scopeActive);
|
|
2419
|
+
} finally {
|
|
2420
|
+
active = false;
|
|
2421
|
+
}
|
|
2422
|
+
},
|
|
2423
|
+
changedOutputs: () => changedOutputs,
|
|
2424
|
+
publish: () => {
|
|
2425
|
+
if (node.fault) states.forEach((state) => state.clear());
|
|
2426
|
+
else states.forEach((state) => state.publish());
|
|
2427
|
+
},
|
|
2428
|
+
emit: () => void 0,
|
|
2429
|
+
clear: () => {
|
|
2430
|
+
states.forEach((state) => state.clear());
|
|
2431
|
+
changedOutputs = Object.freeze([]);
|
|
2432
|
+
cause = void 0;
|
|
2433
|
+
},
|
|
2434
|
+
release: () => {
|
|
2435
|
+
states.forEach((state) => state.release());
|
|
2436
|
+
outputs.forEach((output) => {
|
|
2437
|
+
output.disposed = true;
|
|
2438
|
+
output.consumers.clear();
|
|
2439
|
+
});
|
|
2440
|
+
instance = void 0;
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2443
|
+
node.owner = node;
|
|
2444
|
+
outputs.forEach((output) => {
|
|
2445
|
+
output.owner = node;
|
|
2446
|
+
});
|
|
2447
|
+
scheduler.initialize(() => {
|
|
2448
|
+
const invalid = node.sources.find((source) => source.fault || source.disposed);
|
|
2449
|
+
if (invalid) throw invalid.fault ?? new require_advanced.ProjectionDisposedError();
|
|
2450
|
+
node.evaluate(true);
|
|
2451
|
+
node.publish();
|
|
2452
|
+
node.clear();
|
|
2453
|
+
});
|
|
2454
|
+
const handles = outputs.map((output, index) => {
|
|
2455
|
+
const handle = {
|
|
2456
|
+
kind: "collection",
|
|
2457
|
+
current: () => {
|
|
2458
|
+
check();
|
|
2459
|
+
return states[index].current(check);
|
|
2460
|
+
},
|
|
2461
|
+
revision: () => {
|
|
2462
|
+
check();
|
|
2463
|
+
return states[index].revision();
|
|
2464
|
+
},
|
|
2465
|
+
subscribe: (listener) => {
|
|
2466
|
+
check();
|
|
2467
|
+
states[index].subscribe(listener);
|
|
2468
|
+
return () => states[index].unsubscribe(listener);
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2471
|
+
scheduler.register(handle, output);
|
|
2472
|
+
return Object.freeze(handle);
|
|
2473
|
+
});
|
|
2474
|
+
scheduler.addNode(node);
|
|
2475
|
+
return Object.freeze(handles);
|
|
2476
|
+
};
|
|
2477
|
+
//#endregion
|
|
2610
2478
|
//#region core/src/projection/graph.ts
|
|
2611
2479
|
const createProjectionGraph = (options) => {
|
|
2612
|
-
const scheduler = createScheduler(options.onError);
|
|
2480
|
+
const scheduler = require_advanced.createScheduler(options.onError);
|
|
2613
2481
|
const sources = createSources(scheduler);
|
|
2614
2482
|
const value = (spec, options) => createValue(scheduler, spec, options);
|
|
2615
2483
|
const map = (source, mapper, options) => {
|
|
2616
2484
|
sources.assertCollection(source);
|
|
2617
2485
|
const calculate = (id, entry) => {
|
|
2618
2486
|
const value = mapper(id, entry);
|
|
2619
|
-
assertSynchronous(value);
|
|
2487
|
+
require_advanced.assertSynchronous(value);
|
|
2620
2488
|
return value;
|
|
2621
2489
|
};
|
|
2622
2490
|
return createCollection(scheduler, {
|
|
@@ -2664,6 +2532,7 @@ const createProjectionGraph = (options) => {
|
|
|
2664
2532
|
fromReadable: sources.fromReadable,
|
|
2665
2533
|
value,
|
|
2666
2534
|
collection: (spec) => createCollection(scheduler, spec),
|
|
2535
|
+
group: (spec) => createCollectionGroup(scheduler, spec),
|
|
2667
2536
|
map,
|
|
2668
2537
|
batch: scheduler.batch,
|
|
2669
2538
|
assertIdle: scheduler.assertIdle,
|
|
@@ -2838,17 +2707,42 @@ const sourceOf = (instance) => instance;
|
|
|
2838
2707
|
const createProjectionRuntime = (options) => {
|
|
2839
2708
|
const runtime = createProjectionGraph({ onError: options?.onError ?? (() => void 0) });
|
|
2840
2709
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
2710
|
+
const groups = /* @__PURE__ */ new WeakMap();
|
|
2841
2711
|
let disposed = false;
|
|
2842
2712
|
const scopes = /* @__PURE__ */ new Set();
|
|
2843
|
-
|
|
2713
|
+
let materialize;
|
|
2714
|
+
const materializeGroup = (definition, requester) => {
|
|
2715
|
+
const existing = groups.get(definition);
|
|
2716
|
+
if (existing) return existing;
|
|
2717
|
+
if (definition.projections.map((projection) => require_advanced.ownerOf(projection)).filter((owner) => owner !== void 0).some((owner) => owner !== requester)) throw new TypeError("Projection group belongs to another scope.");
|
|
2718
|
+
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, requester))]));
|
|
2719
|
+
const nodes = runtime.group({
|
|
2720
|
+
sources,
|
|
2721
|
+
outputs: definition.outputs,
|
|
2722
|
+
build: definition.build
|
|
2723
|
+
});
|
|
2724
|
+
const group = Object.freeze({
|
|
2725
|
+
definition,
|
|
2726
|
+
nodes
|
|
2727
|
+
});
|
|
2728
|
+
groups.set(definition, group);
|
|
2729
|
+
for (let index = 0; index < definition.projections.length; index++) materialized.set(definition.projections[index], {
|
|
2730
|
+
kind: "projection",
|
|
2731
|
+
node: nodes[index]
|
|
2732
|
+
});
|
|
2733
|
+
if (requester) requester.materialized.push(definition);
|
|
2734
|
+
return group;
|
|
2735
|
+
};
|
|
2736
|
+
materialize = (projection, requester) => {
|
|
2844
2737
|
const owner = require_advanced.ownerOf(projection);
|
|
2845
2738
|
if (owner) {
|
|
2846
2739
|
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
2847
|
-
if (!requester.active) throw new ProjectionDisposedError();
|
|
2740
|
+
if (!requester.active) throw new require_advanced.ProjectionDisposedError();
|
|
2848
2741
|
}
|
|
2849
2742
|
const old = materialized.get(projection);
|
|
2850
2743
|
if (old) return old.node;
|
|
2851
2744
|
const definition = require_advanced.definitionOf(projection);
|
|
2745
|
+
if (definition.kind === "incremental-group-output") return materializeGroup(definition.group, requester).nodes[definition.output];
|
|
2852
2746
|
let instance;
|
|
2853
2747
|
let write;
|
|
2854
2748
|
switch (definition.kind) {
|
|
@@ -3156,12 +3050,12 @@ const createProjectionRuntime = (options) => {
|
|
|
3156
3050
|
};
|
|
3157
3051
|
scopes.add(state);
|
|
3158
3052
|
const assertActive = () => {
|
|
3159
|
-
if (!state.active) throw new ProjectionDisposedError();
|
|
3053
|
+
if (!state.active) throw new require_advanced.ProjectionDisposedError();
|
|
3160
3054
|
};
|
|
3161
3055
|
const own = (projection) => {
|
|
3162
3056
|
assertActive();
|
|
3163
3057
|
const definition = require_advanced.definitionOf(projection);
|
|
3164
|
-
const dependencies = definition.kind === "derive" ? definition.dependencies : definition.kind === "incremental-value" || definition.kind === "incremental-collection" ? Object.values(definition.dependencies) : [];
|
|
3058
|
+
const dependencies = definition.kind === "derive" ? definition.dependencies : definition.kind === "incremental-value" || definition.kind === "incremental-collection" ? Object.values(definition.dependencies) : definition.kind === "incremental-group-output" ? Object.values(definition.group.dependencies) : [];
|
|
3165
3059
|
for (const dependency of dependencies) {
|
|
3166
3060
|
const dependencyOwner = require_advanced.ownerOf(dependency);
|
|
3167
3061
|
if (dependencyOwner && dependencyOwner !== state) throw new TypeError("A scope cannot depend on another scope.");
|
|
@@ -3171,7 +3065,16 @@ const createProjectionRuntime = (options) => {
|
|
|
3171
3065
|
};
|
|
3172
3066
|
const scopedInput = Object.assign((initial, equality) => own(require_advanced.input(initial, equality)), { collection: (initial) => own(require_advanced.input.collection(initial)) });
|
|
3173
3067
|
const scopedDerive = (dependencies, compute, equality) => own(require_advanced.derive(dependencies, compute, equality));
|
|
3174
|
-
const
|
|
3068
|
+
const ownOutputTree = (tree) => {
|
|
3069
|
+
if (require_advanced.isProjection(tree)) return own(tree);
|
|
3070
|
+
if (!tree || typeof tree !== "object") throw new TypeError("Incremental group output tree must be an object.");
|
|
3071
|
+
for (const value of Object.values(tree)) ownOutputTree(value);
|
|
3072
|
+
return tree;
|
|
3073
|
+
};
|
|
3074
|
+
const scopedIncremental = Object.assign((dependencies, processor) => own(require_advanced.incremental(dependencies, processor)), {
|
|
3075
|
+
collection: (dependencies, processor) => own(require_advanced.incremental.collection(dependencies, processor)),
|
|
3076
|
+
group: (dependencies, defineOutputs, processor) => ownOutputTree(require_advanced.incremental.group(dependencies, defineOutputs, processor))
|
|
3077
|
+
});
|
|
3175
3078
|
function scopeReadable(projection, selector, equality) {
|
|
3176
3079
|
assertActive();
|
|
3177
3080
|
materialize(projection, state);
|
|
@@ -3228,6 +3131,13 @@ const createProjectionRuntime = (options) => {
|
|
|
3228
3131
|
state.active = false;
|
|
3229
3132
|
state.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
3230
3133
|
for (const definition of state.materialized.reverse()) {
|
|
3134
|
+
const group = groups.get(definition);
|
|
3135
|
+
if (group) {
|
|
3136
|
+
runtime.releaseNode(group.nodes[0]);
|
|
3137
|
+
groups.delete(definition);
|
|
3138
|
+
group.definition.projections.forEach((projection) => materialized.delete(projection));
|
|
3139
|
+
continue;
|
|
3140
|
+
}
|
|
3231
3141
|
const record = materialized.get(definition);
|
|
3232
3142
|
if (!record) continue;
|
|
3233
3143
|
runtime.releaseNode(record.node);
|
|
@@ -3266,8 +3176,8 @@ const createProjectionRuntime = (options) => {
|
|
|
3266
3176
|
exports.DocumentDisposedError = require_notification.DocumentDisposedError;
|
|
3267
3177
|
exports.DocumentReentrancyError = require_notification.DocumentReentrancyError;
|
|
3268
3178
|
exports.ParseError = require_scope.ParseError;
|
|
3269
|
-
exports.ProjectionDisposedError = ProjectionDisposedError;
|
|
3270
|
-
exports.ProjectionError = ProjectionError;
|
|
3179
|
+
exports.ProjectionDisposedError = require_advanced.ProjectionDisposedError;
|
|
3180
|
+
exports.ProjectionError = require_advanced.ProjectionError;
|
|
3271
3181
|
exports.TransactionRejected = require_notification.TransactionRejected;
|
|
3272
3182
|
exports.asReadable = asReadable;
|
|
3273
3183
|
exports.createDocument = createDocument;
|