reactronic 0.24.275 → 0.24.301
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 +2 -2
- package/build/dist/source/Options.d.ts +10 -4
- package/build/dist/source/Options.js +8 -0
- package/build/dist/source/RxSystem.d.ts +2 -2
- package/build/dist/source/RxSystem.js +21 -10
- package/build/dist/source/api.d.ts +2 -2
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/core/Changeset.d.ts +23 -21
- package/build/dist/source/core/Changeset.js +145 -143
- package/build/dist/source/core/Data.d.ts +17 -18
- package/build/dist/source/core/Data.js +8 -7
- package/build/dist/source/core/Indicator.js +9 -8
- package/build/dist/source/core/Journal.d.ts +2 -2
- package/build/dist/source/core/Journal.js +36 -35
- package/build/dist/source/core/Mvcc.d.ts +12 -12
- package/build/dist/source/core/Mvcc.js +47 -62
- package/build/dist/source/core/{Reaction.d.ts → Operation.d.ts} +21 -19
- package/build/dist/source/core/{Reaction.js → Operation.js} +181 -152
- package/build/dist/source/core/RxNode.js +5 -5
- package/build/dist/source/core/Transaction.d.ts +61 -2
- package/build/dist/source/core/Transaction.js +175 -16
- package/package.json +3 -3
|
@@ -4,22 +4,23 @@ import { Sealant } from "../util/Sealant.js";
|
|
|
4
4
|
import { SealedArray } from "../util/SealedArray.js";
|
|
5
5
|
import { SealedMap } from "../util/SealedMap.js";
|
|
6
6
|
import { SealedSet } from "../util/SealedSet.js";
|
|
7
|
-
import {
|
|
7
|
+
import { Isolation } from "../Options.js";
|
|
8
|
+
import { ObjectVersion, ObjectHandle, FieldVersion, Meta } from "./Data.js";
|
|
8
9
|
export const MAX_REVISION = Number.MAX_SAFE_INTEGER;
|
|
9
10
|
export const UNDEFINED_REVISION = MAX_REVISION - 1;
|
|
10
11
|
Object.defineProperty(ObjectHandle.prototype, "#this#", {
|
|
11
12
|
configurable: false, enumerable: false,
|
|
12
13
|
get() {
|
|
13
14
|
const result = {};
|
|
14
|
-
const data = Changeset.current().
|
|
15
|
-
for (const
|
|
16
|
-
const v = data[
|
|
17
|
-
if (v instanceof
|
|
18
|
-
result[
|
|
15
|
+
const data = Changeset.current().getObjectVersion(this, "#this#").data;
|
|
16
|
+
for (const fk in data) {
|
|
17
|
+
const v = data[fk];
|
|
18
|
+
if (v instanceof FieldVersion)
|
|
19
|
+
result[fk] = v.content;
|
|
19
20
|
else if (v === Meta.Raw)
|
|
20
|
-
result[
|
|
21
|
+
result[fk] = this.data[fk];
|
|
21
22
|
else
|
|
22
|
-
result[
|
|
23
|
+
result[fk] = v;
|
|
23
24
|
}
|
|
24
25
|
return result;
|
|
25
26
|
},
|
|
@@ -29,56 +30,82 @@ const EMPTY_MAP = Utils.freezeMap(new Map());
|
|
|
29
30
|
export class Changeset {
|
|
30
31
|
get hint() { var _a; return (_a = this.options.hint) !== null && _a !== void 0 ? _a : "noname"; }
|
|
31
32
|
get timestamp() { return this.revision; }
|
|
32
|
-
constructor(options) {
|
|
33
|
+
constructor(options, parent) {
|
|
33
34
|
this.id = ++Changeset.idGen;
|
|
34
35
|
this.options = options !== null && options !== void 0 ? options : DefaultSnapshotOptions;
|
|
36
|
+
this.parent = parent;
|
|
35
37
|
this.revision = UNDEFINED_REVISION;
|
|
36
38
|
this.bumper = 100;
|
|
37
39
|
this.items = new Map();
|
|
38
40
|
this.obsolete = [];
|
|
39
41
|
this.sealed = false;
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
h.editing =
|
|
43
|
+
lookupObjectVersion(h, fk, editing) {
|
|
44
|
+
let ov = h.editing;
|
|
45
|
+
if (ov && ov.changeset !== this) {
|
|
46
|
+
ov = this.items.get(h);
|
|
47
|
+
if (ov)
|
|
48
|
+
h.editing = ov;
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const parent = this.parent;
|
|
51
|
+
if (!ov) {
|
|
52
|
+
if (!parent) {
|
|
53
|
+
ov = h.applied;
|
|
54
|
+
while (ov !== EMPTY_OBJECT_VERSION && ov.changeset.timestamp > this.timestamp)
|
|
55
|
+
ov = ov.former.objectVersion;
|
|
56
|
+
}
|
|
57
|
+
else
|
|
58
|
+
ov = parent.lookupObjectVersion(h, fk, editing);
|
|
52
59
|
}
|
|
53
|
-
|
|
60
|
+
else if (!editing && parent && !ov.changes.has(fk) && ov.former.objectVersion !== EMPTY_OBJECT_VERSION)
|
|
61
|
+
ov = parent.lookupObjectVersion(h, fk, editing);
|
|
62
|
+
return ov;
|
|
54
63
|
}
|
|
55
|
-
|
|
56
|
-
const r = this.
|
|
57
|
-
if (r ===
|
|
58
|
-
throw misuse(`${Dump.obj(h,
|
|
64
|
+
getObjectVersion(h, fk) {
|
|
65
|
+
const r = this.lookupObjectVersion(h, fk, false);
|
|
66
|
+
if (r === EMPTY_OBJECT_VERSION)
|
|
67
|
+
throw misuse(`${Dump.obj(h, fk)} is not yet available for T${this.id}[${this.hint}] because ${h.editing ? `T${h.editing.changeset.id}[${h.editing.changeset.hint}]` : ""} is not yet applied (last applied T${h.applied.changeset.id}[${h.applied.changeset.hint}])`);
|
|
59
68
|
return r;
|
|
60
69
|
}
|
|
61
|
-
|
|
62
|
-
let
|
|
63
|
-
const existing =
|
|
70
|
+
getEditableObjectVersion(h, fk, value, token) {
|
|
71
|
+
let ov = this.lookupObjectVersion(h, fk, true);
|
|
72
|
+
const existing = ov.data[fk];
|
|
64
73
|
if (existing !== Meta.Raw) {
|
|
65
|
-
if (this.
|
|
66
|
-
this.bumpBy(
|
|
67
|
-
const revision =
|
|
68
|
-
const data = Object.assign({},
|
|
74
|
+
if (this.isNewObjectVersionRequired(h, ov, fk, existing, value, token)) {
|
|
75
|
+
this.bumpBy(ov.changeset.timestamp);
|
|
76
|
+
const revision = fk === Meta.Handle ? 1 : ov.revision + 1;
|
|
77
|
+
const data = Object.assign({}, fk === Meta.Handle ? value : ov.data);
|
|
69
78
|
Meta.set(data, Meta.Handle, h);
|
|
70
|
-
Meta.set(data, Meta.Revision, new
|
|
71
|
-
|
|
72
|
-
this.items.set(h,
|
|
73
|
-
h.editing =
|
|
79
|
+
Meta.set(data, Meta.Revision, new FieldVersion(revision));
|
|
80
|
+
ov = new ObjectVersion(this, ov, data);
|
|
81
|
+
this.items.set(h, ov);
|
|
82
|
+
h.editing = ov;
|
|
74
83
|
h.editors++;
|
|
75
84
|
if (Log.isOn && Log.opt.write)
|
|
76
85
|
Log.write("║", " ++", `${Dump.obj(h)} - new snapshot is created (revision ${revision})`);
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
88
|
else
|
|
80
|
-
|
|
81
|
-
return
|
|
89
|
+
ov = EMPTY_OBJECT_VERSION;
|
|
90
|
+
return ov;
|
|
91
|
+
}
|
|
92
|
+
setFieldContent(h, fk, ov, content, receiver, sensitivity) {
|
|
93
|
+
let existing = ov.data[fk];
|
|
94
|
+
if (existing !== undefined || (ov.former.objectVersion.changeset === EMPTY_OBJECT_VERSION.changeset && (fk in h.data) === false)) {
|
|
95
|
+
if (existing === undefined || existing.content !== content || sensitivity) {
|
|
96
|
+
const existingContent = existing === null || existing === void 0 ? void 0 : existing.content;
|
|
97
|
+
if (ov.former.objectVersion.data[fk] === existing) {
|
|
98
|
+
existing = ov.data[fk] = new FieldVersion(content);
|
|
99
|
+
Changeset.markEdited(existingContent, content, true, ov, fk, h);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
existing.content = content;
|
|
103
|
+
Changeset.markEdited(existingContent, content, true, ov, fk, h);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
Reflect.set(h.data, fk, content, receiver);
|
|
82
109
|
}
|
|
83
110
|
static takeSnapshot(obj) {
|
|
84
111
|
return obj[Meta.Handle]["#this#"];
|
|
@@ -90,25 +117,23 @@ export class Changeset {
|
|
|
90
117
|
Changeset.doDispose(ctx, h);
|
|
91
118
|
}
|
|
92
119
|
static doDispose(ctx, h) {
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
return
|
|
120
|
+
const ov = ctx.getEditableObjectVersion(h, Meta.Revision, Meta.Undefined);
|
|
121
|
+
if (ov !== EMPTY_OBJECT_VERSION)
|
|
122
|
+
ov.disposed = true;
|
|
123
|
+
return ov;
|
|
97
124
|
}
|
|
98
|
-
|
|
99
|
-
if (this.sealed &&
|
|
100
|
-
throw misuse(`observable property ${Dump.obj(h,
|
|
101
|
-
if (
|
|
125
|
+
isNewObjectVersionRequired(h, ov, fk, existing, value, token) {
|
|
126
|
+
if (this.sealed && ov.changeset !== EMPTY_OBJECT_VERSION.changeset)
|
|
127
|
+
throw misuse(`observable property ${Dump.obj(h, fk)} can only be modified inside transaction`);
|
|
128
|
+
if (fk !== Meta.Handle) {
|
|
102
129
|
if (value !== Meta.Handle) {
|
|
103
|
-
if (
|
|
130
|
+
if (ov.changeset !== this || ov.former.objectVersion !== EMPTY_OBJECT_VERSION) {
|
|
104
131
|
if (this.options.token !== undefined && token !== this.options.token)
|
|
105
|
-
throw misuse(`${this.hint} should not have side effects (trying to change ${Dump.snapshot(
|
|
132
|
+
throw misuse(`${this.hint} should not have side effects (trying to change ${Dump.snapshot(ov, fk)})`);
|
|
106
133
|
}
|
|
107
134
|
}
|
|
108
|
-
if (os === EMPTY_SNAPSHOT)
|
|
109
|
-
throw misuse(`${Dump.snapshot(os, m)} is not yet available for T${this.id}[${this.hint}] because of uncommitted ${h.editing ? `T${h.editing.changeset.id}[${h.editing.changeset.hint}]` : ""} (last committed T${h.head.changeset.id}[${h.head.changeset.hint}])`);
|
|
110
135
|
}
|
|
111
|
-
return
|
|
136
|
+
return ov.changeset !== this && !this.sealed;
|
|
112
137
|
}
|
|
113
138
|
acquire(outer) {
|
|
114
139
|
if (!this.sealed && this.revision === UNDEFINED_REVISION) {
|
|
@@ -128,16 +153,17 @@ export class Changeset {
|
|
|
128
153
|
rebase() {
|
|
129
154
|
let conflicts = undefined;
|
|
130
155
|
if (this.items.size > 0) {
|
|
131
|
-
this.items.forEach((
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
156
|
+
this.items.forEach((ov, h) => {
|
|
157
|
+
const theirs = this.parent ? this.parent.lookupObjectVersion(h, Meta.Handle, false) : h.applied;
|
|
158
|
+
if (ov.former.objectVersion !== theirs) {
|
|
159
|
+
const merged = this.merge(h, ov, theirs);
|
|
160
|
+
if (ov.conflicts.size > 0) {
|
|
135
161
|
if (!conflicts)
|
|
136
162
|
conflicts = [];
|
|
137
|
-
conflicts.push(
|
|
163
|
+
conflicts.push(ov);
|
|
138
164
|
}
|
|
139
165
|
if (Log.isOn && Log.opt.transaction)
|
|
140
|
-
Log.write("╠╝", "", `${Dump.snapshot2(h,
|
|
166
|
+
Log.write("╠╝", "", `${Dump.snapshot2(h, ov.changeset)} is merged with ${Dump.snapshot2(h, theirs.changeset)} among ${merged} properties with ${ov.conflicts.size} conflicts.`);
|
|
141
167
|
}
|
|
142
168
|
});
|
|
143
169
|
if (this.options.token === undefined) {
|
|
@@ -154,92 +180,68 @@ export class Changeset {
|
|
|
154
180
|
}
|
|
155
181
|
return conflicts;
|
|
156
182
|
}
|
|
157
|
-
merge(h, ours) {
|
|
183
|
+
merge(h, ours, theirs) {
|
|
158
184
|
let counter = 0;
|
|
159
|
-
const
|
|
160
|
-
const headDisposed = head.disposed;
|
|
185
|
+
const theirsDisposed = theirs.disposed;
|
|
161
186
|
const oursDisposed = ours.disposed;
|
|
162
|
-
const merged = Object.assign({},
|
|
163
|
-
ours.changes.forEach((o,
|
|
187
|
+
const merged = Object.assign({}, theirs.data);
|
|
188
|
+
ours.changes.forEach((o, fk) => {
|
|
164
189
|
counter++;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
190
|
+
const ourFieldVersion = ours.data[fk];
|
|
191
|
+
merged[fk] = ourFieldVersion;
|
|
192
|
+
if (theirsDisposed || oursDisposed) {
|
|
193
|
+
if (theirsDisposed !== oursDisposed) {
|
|
194
|
+
if (theirsDisposed || this.options.isolation !== Isolation.disjoinForInternalDisposal) {
|
|
169
195
|
if (Log.isOn && Log.opt.change)
|
|
170
|
-
Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset,
|
|
171
|
-
ours.conflicts.set(
|
|
196
|
+
Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset, fk)} <> ${Dump.snapshot2(h, theirs.changeset, fk)}`, 0, " *** CONFLICT ***");
|
|
197
|
+
ours.conflicts.set(fk, theirs);
|
|
172
198
|
}
|
|
173
199
|
}
|
|
174
200
|
}
|
|
175
201
|
else {
|
|
176
|
-
const conflict = Changeset.isConflicting(
|
|
202
|
+
const conflict = Changeset.isConflicting(theirs.data[fk], ours.former.objectVersion.data[fk]);
|
|
177
203
|
if (conflict)
|
|
178
|
-
ours.conflicts.set(
|
|
204
|
+
ours.conflicts.set(fk, theirs);
|
|
179
205
|
if (Log.isOn && Log.opt.change)
|
|
180
|
-
Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset,
|
|
206
|
+
Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset, fk)} ${conflict ? "<>" : "=="} ${Dump.snapshot2(h, theirs.changeset, fk)}`, 0, conflict ? " *** CONFLICT ***" : undefined);
|
|
181
207
|
}
|
|
182
208
|
});
|
|
183
209
|
Utils.copyAllMembers(merged, ours.data);
|
|
184
|
-
ours.former.
|
|
210
|
+
ours.former.objectVersion = theirs;
|
|
185
211
|
return counter;
|
|
186
212
|
}
|
|
187
|
-
|
|
213
|
+
seal() {
|
|
188
214
|
this.sealed = true;
|
|
189
|
-
this.items.forEach((os, h) => {
|
|
190
|
-
Changeset.sealObjectSnapshot(h, os);
|
|
191
|
-
h.editors--;
|
|
192
|
-
if (h.editors === 0)
|
|
193
|
-
h.editing = undefined;
|
|
194
|
-
if (!error) {
|
|
195
|
-
h.head = os;
|
|
196
|
-
if (Changeset.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
197
|
-
Changeset.totalObjectSnapshotCount++;
|
|
198
|
-
if (os.former.snapshot === EMPTY_SNAPSHOT)
|
|
199
|
-
Changeset.totalObjectHandleCount++;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
if (Log.isOn) {
|
|
204
|
-
if (Log.opt.change && !error) {
|
|
205
|
-
this.items.forEach((os, h) => {
|
|
206
|
-
const members = [];
|
|
207
|
-
os.changes.forEach((o, m) => members.push(m.toString()));
|
|
208
|
-
const s = members.join(", ");
|
|
209
|
-
Log.write("║", "√", `${Dump.snapshot2(h, os.changeset)} (${s}) is ${os.former.snapshot === EMPTY_SNAPSHOT ? "constructed" : `applied over #${h.id}t${os.former.snapshot.changeset.id}s${os.former.snapshot.changeset.timestamp}`}`);
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
if (Log.opt.transaction)
|
|
213
|
-
Log.write(this.revision < UNDEFINED_REVISION ? "╚══" : "═══", `s${this.revision}`, `${this.hint} - ${error ? "CANCEL" : "APPLY"}(${this.items.size})${error ? ` - ${error}` : ""}`);
|
|
214
|
-
}
|
|
215
|
-
if (!error)
|
|
216
|
-
Changeset.propagateAllChangesThroughSubscriptions(this);
|
|
217
|
-
return this.obsolete;
|
|
218
215
|
}
|
|
219
|
-
|
|
220
|
-
if (!
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
216
|
+
sealObjectVersion(h, ov) {
|
|
217
|
+
if (!this.parent) {
|
|
218
|
+
if (!ov.disposed)
|
|
219
|
+
ov.changes.forEach((o, fk) => Changeset.sealFieldVersion(ov.data[fk], fk, h.proxy.constructor.name));
|
|
220
|
+
else
|
|
221
|
+
for (const fk in ov.former.objectVersion.data)
|
|
222
|
+
ov.data[fk] = Meta.Undefined;
|
|
223
|
+
if (Log.isOn)
|
|
224
|
+
Changeset.freezeObjectVersion(ov);
|
|
225
|
+
}
|
|
226
|
+
h.editors--;
|
|
227
|
+
if (h.editors === 0)
|
|
228
|
+
h.editing = undefined;
|
|
227
229
|
}
|
|
228
|
-
static
|
|
229
|
-
if (
|
|
230
|
-
const
|
|
231
|
-
if (
|
|
232
|
-
const sealedType = Object.getPrototypeOf(
|
|
230
|
+
static sealFieldVersion(fv, fk, typeName) {
|
|
231
|
+
if (fv instanceof FieldVersion) {
|
|
232
|
+
const content = fv.content;
|
|
233
|
+
if (content !== undefined && content !== null) {
|
|
234
|
+
const sealedType = Object.getPrototypeOf(content)[Sealant.SealedType];
|
|
233
235
|
if (sealedType)
|
|
234
|
-
|
|
236
|
+
fv.content = Sealant.seal(content, sealedType, typeName, fk);
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
}
|
|
238
|
-
static
|
|
239
|
-
Object.freeze(
|
|
240
|
-
Utils.freezeSet(
|
|
241
|
-
Utils.freezeMap(
|
|
242
|
-
return
|
|
240
|
+
static freezeObjectVersion(ov) {
|
|
241
|
+
Object.freeze(ov.data);
|
|
242
|
+
Utils.freezeSet(ov.changes);
|
|
243
|
+
Utils.freezeMap(ov.conflicts);
|
|
244
|
+
return ov;
|
|
243
245
|
}
|
|
244
246
|
triggerGarbageCollection() {
|
|
245
247
|
if (this.revision !== 0) {
|
|
@@ -264,16 +266,16 @@ export class Changeset {
|
|
|
264
266
|
unlinkHistory() {
|
|
265
267
|
if (Log.isOn && Log.opt.gc)
|
|
266
268
|
Log.write("", "[G]", `Dismiss history below t${this.id}s${this.revision} (${this.hint})`);
|
|
267
|
-
this.items.forEach((
|
|
268
|
-
if (Log.isOn && Log.opt.gc &&
|
|
269
|
-
Log.write(" ", " ", `${Dump.snapshot2(h,
|
|
269
|
+
this.items.forEach((ov, h) => {
|
|
270
|
+
if (Log.isOn && Log.opt.gc && ov.former.objectVersion !== EMPTY_OBJECT_VERSION)
|
|
271
|
+
Log.write(" ", " ", `${Dump.snapshot2(h, ov.former.objectVersion.changeset)} is ready for GC because overwritten by ${Dump.snapshot2(h, ov.changeset)}`);
|
|
270
272
|
if (Changeset.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
271
|
-
if (
|
|
273
|
+
if (ov.former.objectVersion !== EMPTY_OBJECT_VERSION)
|
|
272
274
|
Changeset.totalObjectSnapshotCount--;
|
|
273
|
-
if (
|
|
275
|
+
if (ov.disposed)
|
|
274
276
|
Changeset.totalObjectHandleCount--;
|
|
275
277
|
}
|
|
276
|
-
|
|
278
|
+
ov.former.objectVersion = EMPTY_OBJECT_VERSION;
|
|
277
279
|
});
|
|
278
280
|
this.items = EMPTY_MAP;
|
|
279
281
|
this.obsolete = EMPTY_ARRAY;
|
|
@@ -281,11 +283,11 @@ export class Changeset {
|
|
|
281
283
|
Object.freeze(this);
|
|
282
284
|
}
|
|
283
285
|
static _init() {
|
|
284
|
-
const boot =
|
|
286
|
+
const boot = EMPTY_OBJECT_VERSION.changeset;
|
|
285
287
|
boot.acquire(boot);
|
|
286
|
-
boot.
|
|
288
|
+
boot.seal();
|
|
287
289
|
boot.triggerGarbageCollection();
|
|
288
|
-
Changeset.
|
|
290
|
+
Changeset.freezeObjectVersion(EMPTY_OBJECT_VERSION);
|
|
289
291
|
Changeset.idGen = 100;
|
|
290
292
|
Changeset.stampGen = 101;
|
|
291
293
|
Changeset.oldest = undefined;
|
|
@@ -311,8 +313,8 @@ Changeset.propagateAllChangesThroughSubscriptions = (changeset) => { };
|
|
|
311
313
|
Changeset.revokeAllSubscriptions = (changeset) => { };
|
|
312
314
|
Changeset.enqueueReactiveFunctionsToRun = (reactive) => { };
|
|
313
315
|
export class Dump {
|
|
314
|
-
static obj(h,
|
|
315
|
-
const member =
|
|
316
|
+
static obj(h, fk, stamp, snapshotId, originSnapshotId, value) {
|
|
317
|
+
const member = fk !== undefined ? `.${fk.toString()}` : "";
|
|
316
318
|
let result;
|
|
317
319
|
if (h !== undefined) {
|
|
318
320
|
const v = value !== undefined && value !== Meta.Undefined ? `[=${Dump.valueHint(value)}]` : "";
|
|
@@ -325,33 +327,33 @@ export class Dump {
|
|
|
325
327
|
result = `boot${member}`;
|
|
326
328
|
return result;
|
|
327
329
|
}
|
|
328
|
-
static snapshot2(h, s,
|
|
330
|
+
static snapshot2(h, s, fk, o) {
|
|
329
331
|
var _a;
|
|
330
|
-
return Dump.obj(h,
|
|
332
|
+
return Dump.obj(h, fk, s.timestamp, s.id, o === null || o === void 0 ? void 0 : o.originSnapshotId, (_a = o === null || o === void 0 ? void 0 : o.content) !== null && _a !== void 0 ? _a : Meta.Undefined);
|
|
331
333
|
}
|
|
332
|
-
static snapshot(
|
|
333
|
-
const h = Meta.get(
|
|
334
|
-
const
|
|
335
|
-
return Dump.obj(h,
|
|
334
|
+
static snapshot(ov, fk) {
|
|
335
|
+
const h = Meta.get(ov.data, Meta.Handle);
|
|
336
|
+
const fv = fk !== undefined ? ov.data[fk] : undefined;
|
|
337
|
+
return Dump.obj(h, fk, ov.changeset.timestamp, ov.changeset.id, fv === null || fv === void 0 ? void 0 : fv.originSnapshotId);
|
|
336
338
|
}
|
|
337
339
|
static conflicts(conflicts) {
|
|
338
340
|
return conflicts.map(ours => {
|
|
339
341
|
const items = [];
|
|
340
|
-
ours.conflicts.forEach((theirs,
|
|
341
|
-
items.push(Dump.conflictingMemberHint(
|
|
342
|
+
ours.conflicts.forEach((theirs, fk) => {
|
|
343
|
+
items.push(Dump.conflictingMemberHint(fk, ours, theirs));
|
|
342
344
|
});
|
|
343
345
|
return items.join(", ");
|
|
344
346
|
}).join(", ");
|
|
345
347
|
}
|
|
346
|
-
static conflictingMemberHint(
|
|
347
|
-
return `${theirs.changeset.hint} (${Dump.snapshot(theirs,
|
|
348
|
+
static conflictingMemberHint(fk, ours, theirs) {
|
|
349
|
+
return `${theirs.changeset.hint} (${Dump.snapshot(theirs, fk)})`;
|
|
348
350
|
}
|
|
349
351
|
}
|
|
350
352
|
Dump.valueHint = (value) => "???";
|
|
351
|
-
export const
|
|
353
|
+
export const EMPTY_OBJECT_VERSION = new ObjectVersion(new Changeset({ hint: "<boot>" }), undefined, {});
|
|
352
354
|
export const DefaultSnapshotOptions = Object.freeze({
|
|
353
355
|
hint: "noname",
|
|
354
|
-
|
|
356
|
+
isolation: Isolation.joinToCurrentTransaction,
|
|
355
357
|
journal: undefined,
|
|
356
358
|
logging: undefined,
|
|
357
359
|
token: undefined,
|
|
@@ -5,36 +5,35 @@ export type AbstractChangeset = {
|
|
|
5
5
|
readonly timestamp: number;
|
|
6
6
|
readonly sealed: boolean;
|
|
7
7
|
};
|
|
8
|
-
export declare class
|
|
8
|
+
export declare class FieldVersion<T = any> {
|
|
9
9
|
content: T;
|
|
10
10
|
observers?: Set<Observer>;
|
|
11
|
-
get
|
|
11
|
+
get isLaunch(): boolean;
|
|
12
12
|
get originSnapshotId(): number | undefined;
|
|
13
13
|
constructor(content: T);
|
|
14
14
|
}
|
|
15
|
-
export type SeparationMode = boolean | "isolated" | "disposal";
|
|
16
15
|
export type Observer = {
|
|
17
16
|
readonly order: number;
|
|
18
|
-
readonly observables: Map<
|
|
17
|
+
readonly observables: Map<FieldVersion, Subscription> | undefined;
|
|
19
18
|
readonly obsoleteSince: number;
|
|
20
19
|
hint(nop?: boolean): string;
|
|
21
|
-
markObsoleteDueTo(observable:
|
|
20
|
+
markObsoleteDueTo(observable: FieldVersion, fk: FieldKey, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, reactive: Array<Observer>): void;
|
|
22
21
|
relaunchIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
23
22
|
};
|
|
24
|
-
export type
|
|
23
|
+
export type FieldKey = PropertyKey;
|
|
25
24
|
export type Subscription = {
|
|
26
25
|
readonly memberHint: string;
|
|
27
26
|
readonly usageCount: number;
|
|
28
27
|
};
|
|
29
|
-
export declare class
|
|
28
|
+
export declare class ObjectVersion {
|
|
30
29
|
readonly changeset: AbstractChangeset;
|
|
31
30
|
readonly former: {
|
|
32
|
-
|
|
31
|
+
objectVersion: ObjectVersion;
|
|
33
32
|
};
|
|
34
33
|
readonly data: any;
|
|
35
|
-
readonly changes: Set<
|
|
36
|
-
readonly conflicts: Map<
|
|
37
|
-
constructor(changeset: AbstractChangeset, former:
|
|
34
|
+
readonly changes: Set<FieldKey>;
|
|
35
|
+
readonly conflicts: Map<FieldKey, ObjectVersion>;
|
|
36
|
+
constructor(changeset: AbstractChangeset, former: ObjectVersion | undefined, data: object);
|
|
38
37
|
get revision(): number;
|
|
39
38
|
get disposed(): boolean;
|
|
40
39
|
set disposed(value: boolean);
|
|
@@ -44,17 +43,17 @@ export declare class ObjectHandle {
|
|
|
44
43
|
readonly id: number;
|
|
45
44
|
readonly data: any;
|
|
46
45
|
readonly proxy: any;
|
|
47
|
-
|
|
48
|
-
editing?:
|
|
46
|
+
applied: ObjectVersion;
|
|
47
|
+
editing?: ObjectVersion;
|
|
49
48
|
editors: number;
|
|
50
49
|
hint: string;
|
|
51
|
-
constructor(data: any, proxy: any, handler: ProxyHandler<ObjectHandle>,
|
|
50
|
+
constructor(data: any, proxy: any, handler: ProxyHandler<ObjectHandle>, applied: ObjectVersion, hint: string);
|
|
52
51
|
static getHint(obj: object, full: boolean): string | undefined;
|
|
53
52
|
}
|
|
54
|
-
export type PatchSet = Map<object, Map<
|
|
53
|
+
export type PatchSet = Map<object, Map<FieldKey, ValuePatch>>;
|
|
55
54
|
export type ValuePatch = {
|
|
56
|
-
|
|
55
|
+
fieldKey: FieldKey;
|
|
57
56
|
patchKind: "update" | "add" | "remove";
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
freshContent: any;
|
|
58
|
+
formerContent: any;
|
|
60
59
|
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Log } from "../util/Dbg.js";
|
|
2
2
|
import { Meta } from "./Meta.js";
|
|
3
3
|
export { Meta } from "./Meta.js";
|
|
4
|
-
export class
|
|
5
|
-
get
|
|
4
|
+
export class FieldVersion {
|
|
5
|
+
get isLaunch() { return false; }
|
|
6
6
|
get originSnapshotId() { return 0; }
|
|
7
7
|
constructor(content) { this.content = content; }
|
|
8
8
|
}
|
|
9
|
-
export class
|
|
9
|
+
export class ObjectVersion {
|
|
10
10
|
constructor(changeset, former, data) {
|
|
11
11
|
this.changeset = changeset;
|
|
12
|
-
this.former = {
|
|
12
|
+
this.former = { objectVersion: former || this };
|
|
13
13
|
this.data = data;
|
|
14
14
|
this.changes = new Set();
|
|
15
15
|
this.conflicts = new Map();
|
|
@@ -17,7 +17,8 @@ export class ObjectSnapshot {
|
|
|
17
17
|
Object.freeze(this);
|
|
18
18
|
}
|
|
19
19
|
get revision() {
|
|
20
|
-
|
|
20
|
+
var _a, _b;
|
|
21
|
+
return (_b = (_a = this.data[Meta.Revision]) === null || _a === void 0 ? void 0 : _a.content) !== null && _b !== void 0 ? _b : 0;
|
|
21
22
|
}
|
|
22
23
|
get disposed() { return this.revision < 0; }
|
|
23
24
|
set disposed(value) {
|
|
@@ -27,11 +28,11 @@ export class ObjectSnapshot {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
export class ObjectHandle {
|
|
30
|
-
constructor(data, proxy, handler,
|
|
31
|
+
constructor(data, proxy, handler, applied, hint) {
|
|
31
32
|
this.id = ++ObjectHandle.generator;
|
|
32
33
|
this.data = data;
|
|
33
34
|
this.proxy = proxy || new Proxy(this, handler);
|
|
34
|
-
this.
|
|
35
|
+
this.applied = applied;
|
|
35
36
|
this.editing = undefined;
|
|
36
37
|
this.editors = 0;
|
|
37
38
|
this.hint = hint;
|
|
@@ -7,6 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
import { Isolation } from "../Options.js";
|
|
10
11
|
import { ObservableObject, Mvcc } from "./Mvcc.js";
|
|
11
12
|
import { Transaction } from "./Transaction.js";
|
|
12
13
|
export class Indicator extends ObservableObject {
|
|
@@ -80,12 +81,12 @@ export class IndicatorImpl extends Indicator {
|
|
|
80
81
|
mon.leave(worker);
|
|
81
82
|
}
|
|
82
83
|
static doCreate(hint, activationDelay, deactivationDelay, durationResolution) {
|
|
83
|
-
const
|
|
84
|
-
Mvcc.setHint(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
84
|
+
const ind = new IndicatorImpl();
|
|
85
|
+
Mvcc.setHint(ind, hint);
|
|
86
|
+
ind.internals.activationDelay = activationDelay;
|
|
87
|
+
ind.internals.deactivationDelay = deactivationDelay;
|
|
88
|
+
ind.internals.durationResolution = durationResolution;
|
|
89
|
+
return ind;
|
|
89
90
|
}
|
|
90
91
|
static activate(mon, delay) {
|
|
91
92
|
const active = mon.counter > 0;
|
|
@@ -102,7 +103,7 @@ export class IndicatorImpl extends Indicator {
|
|
|
102
103
|
}
|
|
103
104
|
if (delay >= 0) {
|
|
104
105
|
if (mon.internals.activationTimeout === undefined)
|
|
105
|
-
mon.internals.activationTimeout = setTimeout(() => Transaction.run({ hint: "Indicator.activate",
|
|
106
|
+
mon.internals.activationTimeout = setTimeout(() => Transaction.run({ hint: "Indicator.activate", isolation: Isolation.disjoinFromOuterAndInnerTransactions }, IndicatorImpl.activate, mon, -1), delay);
|
|
106
107
|
}
|
|
107
108
|
else if (active)
|
|
108
109
|
mon.isBusy = true;
|
|
@@ -110,7 +111,7 @@ export class IndicatorImpl extends Indicator {
|
|
|
110
111
|
static deactivate(mon, delay) {
|
|
111
112
|
if (delay >= 0) {
|
|
112
113
|
clearTimeout(mon.internals.deactivationTimeout);
|
|
113
|
-
mon.internals.deactivationTimeout = setTimeout(() => Transaction.run({ hint: "Indicator.deactivate",
|
|
114
|
+
mon.internals.deactivationTimeout = setTimeout(() => Transaction.run({ hint: "Indicator.deactivate", isolation: Isolation.disjoinFromOuterAndInnerTransactions }, IndicatorImpl.deactivate, mon, -1), delay);
|
|
114
115
|
}
|
|
115
116
|
else if (mon.counter <= 0) {
|
|
116
117
|
mon.isBusy = false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ObservableObject } from "./Mvcc.js";
|
|
2
|
-
import { ObjectHandle,
|
|
2
|
+
import { ObjectHandle, ObjectVersion, PatchSet } from "./Data.js";
|
|
3
3
|
export type Saver = (patch: PatchSet) => Promise<void>;
|
|
4
4
|
export declare abstract class Journal extends ObservableObject {
|
|
5
5
|
abstract capacity: number;
|
|
@@ -28,7 +28,7 @@ export declare class JournalImpl extends Journal {
|
|
|
28
28
|
saved(patch: PatchSet): void;
|
|
29
29
|
undo(count?: number): void;
|
|
30
30
|
redo(count?: number): void;
|
|
31
|
-
static buildPatch(hint: string, items: Map<ObjectHandle,
|
|
31
|
+
static buildPatch(hint: string, items: Map<ObjectHandle, ObjectVersion>): PatchSet;
|
|
32
32
|
static applyPatch(patch: PatchSet, undoing: boolean): void;
|
|
33
33
|
mergePatchToUnsaved(patch: PatchSet, undoing: boolean): void;
|
|
34
34
|
}
|