@prestizni-software/client-dem 0.5.7 → 0.5.9
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/dist/AutoUpdateClientManagerClass.d.ts +28 -22
- package/dist/AutoUpdateClientManagerClass.js +249 -155
- package/dist/AutoUpdateClientManagerClass.js.map +1 -1
- package/dist/AutoUpdateManagerClass.d.ts +19 -18
- package/dist/AutoUpdateManagerClass.js +15 -28
- package/dist/AutoUpdateManagerClass.js.map +1 -1
- package/dist/AutoUpdatedClientObjectClass.d.ts +38 -42
- package/dist/AutoUpdatedClientObjectClass.js +197 -278
- package/dist/AutoUpdatedClientObjectClass.js.map +1 -1
- package/dist/CommonTypes.d.ts +48 -41
- package/dist/CommonTypes.js +0 -2
- package/dist/CommonTypes.js.map +1 -1
- package/dist/client.d.ts +5 -1
- package/dist/client.js +5 -10
- package/dist/client.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import _ from "lodash";
|
|
3
|
-
import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UPDATE, globalCache, } from "./CommonTypes
|
|
3
|
+
import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UPDATE, globalCache, } from "./CommonTypes";
|
|
4
4
|
import { ObjectId } from "bson";
|
|
5
5
|
export class AutoUpdatedClientObject {
|
|
6
6
|
entry;
|
|
7
7
|
preLoad;
|
|
8
8
|
registerSocket;
|
|
9
9
|
readyLoggers;
|
|
10
|
-
loadFromDB(a) {
|
|
11
|
-
|
|
12
|
-
}
|
|
10
|
+
loadFromDB(a) { }
|
|
11
|
+
setValue_(a, b) { }
|
|
13
12
|
socket;
|
|
14
13
|
data;
|
|
15
14
|
isServer = false;
|
|
16
15
|
loggers;
|
|
17
16
|
isLoading = true;
|
|
17
|
+
loadError;
|
|
18
18
|
isLoadingReferences = true;
|
|
19
19
|
checkedMissingRefs = false;
|
|
20
|
-
isDestroyed = false;
|
|
21
20
|
emitter;
|
|
22
21
|
properties;
|
|
23
22
|
classParam;
|
|
@@ -26,7 +25,6 @@ export class AutoUpdatedClientObject {
|
|
|
26
25
|
EmitterID = new ObjectId().toHexString();
|
|
27
26
|
toChangeOnParents = [];
|
|
28
27
|
callbacks;
|
|
29
|
-
preloadTimers = new Set();
|
|
30
28
|
loadReferencesAsync = async () => {
|
|
31
29
|
try {
|
|
32
30
|
if (!this.isLoaded) {
|
|
@@ -35,14 +33,11 @@ export class AutoUpdatedClientObject {
|
|
|
35
33
|
this.generateSettersAndGetters();
|
|
36
34
|
await this.loadForceReferences();
|
|
37
35
|
for (const thing of this.toChangeOnParents) {
|
|
38
|
-
await this.
|
|
39
|
-
silent: true,
|
|
40
|
-
isParentUpdate: true,
|
|
41
|
-
});
|
|
36
|
+
await this.setValue__(thing.key, thing.value, true, false, false, true);
|
|
42
37
|
}
|
|
43
38
|
}
|
|
44
39
|
catch (error) {
|
|
45
|
-
|
|
40
|
+
this.loggers.error?.("Error loading references: " + error.message);
|
|
46
41
|
}
|
|
47
42
|
finally {
|
|
48
43
|
this.isLoadingReferences = false;
|
|
@@ -66,8 +61,18 @@ export class AutoUpdatedClientObject {
|
|
|
66
61
|
this.parentManager = parentManager;
|
|
67
62
|
this.callbacks = callback;
|
|
68
63
|
this.emitter = emitter;
|
|
69
|
-
this.properties =
|
|
70
|
-
|
|
64
|
+
this.properties = undefined;
|
|
65
|
+
if (!classParam &&
|
|
66
|
+
!socket &&
|
|
67
|
+
!data &&
|
|
68
|
+
!loggers &&
|
|
69
|
+
!className &&
|
|
70
|
+
!parentManager &&
|
|
71
|
+
!callback &&
|
|
72
|
+
!emitter)
|
|
73
|
+
return;
|
|
74
|
+
else
|
|
75
|
+
throw new Error("Missing arguments???");
|
|
71
76
|
}
|
|
72
77
|
this.classParam = classParam;
|
|
73
78
|
this.socket = socket;
|
|
@@ -78,126 +83,95 @@ export class AutoUpdatedClientObject {
|
|
|
78
83
|
this.parentManager = parentManager;
|
|
79
84
|
this.className = className;
|
|
80
85
|
const allProps = new Set();
|
|
81
|
-
let
|
|
82
|
-
while (
|
|
83
|
-
const props = Reflect.getOwnMetadata("props",
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
proto = Object.getPrototypeOf(proto);
|
|
86
|
+
let proto_ = classParam.prototype;
|
|
87
|
+
while (proto_ && proto_ !== Object.prototype) {
|
|
88
|
+
const props = Reflect.getOwnMetadata("props", proto_) || [];
|
|
89
|
+
for (const p of props)
|
|
90
|
+
allProps.add(p);
|
|
91
|
+
proto_ = Object.getPrototypeOf(proto_);
|
|
89
92
|
}
|
|
90
93
|
this.properties = Array.from(allProps);
|
|
91
|
-
this.callbacks = callback
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
this.callbacks = callback;
|
|
95
|
+
this.loggers = {
|
|
96
|
+
debug: (s) => loggers.debug?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
97
|
+
info: (s) => loggers.info?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
98
|
+
warn: (s) => loggers.warn?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
99
|
+
error: (s) => loggers.error?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
96
100
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
if (typeof data === "string") {
|
|
102
|
+
this.data = { _id: data };
|
|
103
|
+
if (this.isServer) {
|
|
104
|
+
this.isLoading = false;
|
|
105
|
+
this.generateSettersAndGetters();
|
|
106
|
+
return;
|
|
103
107
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
debug: (s) => loggers.debug?.(`[${this.className}: ${currentId}] ${s}`),
|
|
107
|
-
info: (s) => loggers.info?.(`[${this.className}: ${currentId}] ${s}`),
|
|
108
|
-
warn: (s) => loggers.warn?.(`[${this.className}: ${currentId}] ${s}`),
|
|
109
|
-
error: (s) => loggers.error?.(`[${this.className}: ${currentId}] ${s}`),
|
|
110
|
-
};
|
|
111
|
-
if (typeof data === "string") {
|
|
112
|
-
if (this.isServer) {
|
|
108
|
+
this.socket.emit(EVENT_GET + this.className + data, null, (res) => {
|
|
109
|
+
if (!res.success) {
|
|
113
110
|
this.isLoading = false;
|
|
114
|
-
this.
|
|
115
|
-
this.
|
|
111
|
+
this.loadError = res.message;
|
|
112
|
+
this.loggers.error?.("Could not load data from server: " + res.message);
|
|
113
|
+
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, true, res.message);
|
|
116
114
|
return;
|
|
117
115
|
}
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
const currentDataRec = this.data;
|
|
136
|
-
for (const key of this.properties) {
|
|
137
|
-
const isRef = getMetadataRecursive("isRef", this, key);
|
|
138
|
-
if (isRef && currentDataRec[key]) {
|
|
139
|
-
if (Array.isArray(currentDataRec[key])) {
|
|
140
|
-
currentDataRec[key] = currentDataRec[key].map((obj) => obj._id?.toString() ?? obj?.toString());
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
currentDataRec[key] =
|
|
144
|
-
currentDataRec[key]?._id?.toString() ??
|
|
145
|
-
currentDataRec[key]?.toString();
|
|
146
|
-
}
|
|
116
|
+
this.data = res.data;
|
|
117
|
+
this.generateSettersAndGetters();
|
|
118
|
+
this.isLoading = false;
|
|
119
|
+
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID);
|
|
120
|
+
this.openSockets();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
this.isLoading = true;
|
|
125
|
+
this.data = data;
|
|
126
|
+
for (const key of this.properties || []) {
|
|
127
|
+
const isRef = getMetadataRecursive("isRef", this, key);
|
|
128
|
+
if (isRef && this.data[key]) {
|
|
129
|
+
if (Array.isArray(this.data[key])) {
|
|
130
|
+
this.data[key] = this.data[key].map((obj) => obj._id?.toString() ?? obj?.toString());
|
|
147
131
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.handleNewObject(this.data);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
this.isLoading = false;
|
|
156
|
-
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID);
|
|
157
|
-
if (!this.isServer) {
|
|
158
|
-
this.openSockets();
|
|
159
|
-
this.onUpdate();
|
|
132
|
+
else {
|
|
133
|
+
this.data[key] =
|
|
134
|
+
this.data[key]?._id?.toString() ??
|
|
135
|
+
this.data[key]?.toString();
|
|
160
136
|
}
|
|
161
137
|
}
|
|
162
138
|
}
|
|
163
|
-
this.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
139
|
+
if ((!this.data._id || this.data._id === "") &&
|
|
140
|
+
!this.isServer) {
|
|
141
|
+
this.handleNewObject(data);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
this.isLoading = false;
|
|
145
|
+
if (!this.isServer)
|
|
146
|
+
this.openSockets();
|
|
171
147
|
}
|
|
172
148
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
149
|
+
this.generateSettersAndGetters();
|
|
150
|
+
Promise.resolve().then(() => {
|
|
151
|
+
this.generateSettersAndGetters();
|
|
152
|
+
});
|
|
177
153
|
}
|
|
178
154
|
async waitForPreloaded() {
|
|
155
|
+
if (this.loadError)
|
|
156
|
+
throw new Error(this.loadError);
|
|
179
157
|
if (this.isLoaded)
|
|
180
158
|
return;
|
|
181
|
-
|
|
182
|
-
|
|
159
|
+
await new Promise((resolve, reject) => {
|
|
160
|
+
this.emitter.once(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, (failed, reason) => {
|
|
183
161
|
if (failed)
|
|
184
162
|
reject(new Error(reason));
|
|
185
163
|
else
|
|
186
164
|
resolve();
|
|
187
|
-
};
|
|
188
|
-
this.emitter.once(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, onPreloaded);
|
|
165
|
+
});
|
|
189
166
|
});
|
|
190
167
|
}
|
|
191
168
|
handleNewObject(data) {
|
|
192
169
|
this.isLoading = true;
|
|
193
|
-
if (!this.socket || typeof this.socket.emit !== "function") {
|
|
194
|
-
this.isLoading = false;
|
|
195
|
-
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, true, "Socket not available");
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
170
|
this.socket.emit(EVENT_NEW + this.className, data, (res) => {
|
|
199
171
|
if (!res.success) {
|
|
200
172
|
this.isLoading = false;
|
|
173
|
+
this.loadError = res.message;
|
|
174
|
+
this.loggers.error?.("Could not create data on server: " + res.message);
|
|
201
175
|
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, true, res.message);
|
|
202
176
|
return;
|
|
203
177
|
}
|
|
@@ -211,13 +185,13 @@ export class AutoUpdatedClientObject {
|
|
|
211
185
|
}
|
|
212
186
|
get extractedData() {
|
|
213
187
|
const extracted = processIsRefProperties(this.data, this, null, [], {}, this.loggers).newData;
|
|
214
|
-
return extracted;
|
|
188
|
+
return _.cloneDeep(extracted);
|
|
215
189
|
}
|
|
216
190
|
get isLoaded() {
|
|
217
191
|
return !this.isLoading;
|
|
218
192
|
}
|
|
219
193
|
async isPreLoadedAsync() {
|
|
220
|
-
await this.
|
|
194
|
+
await this.loadShit();
|
|
221
195
|
return true;
|
|
222
196
|
}
|
|
223
197
|
async loadMissingReferences() {
|
|
@@ -225,30 +199,24 @@ export class AutoUpdatedClientObject {
|
|
|
225
199
|
this.generateSettersAndGetters();
|
|
226
200
|
}
|
|
227
201
|
openSockets() {
|
|
228
|
-
const
|
|
229
|
-
const id = dataRec["_id"];
|
|
230
|
-
if (!id || !this.socket || typeof this.socket.on !== "function")
|
|
231
|
-
return;
|
|
202
|
+
const id = this.data?._id ?? this._id;
|
|
232
203
|
const event = EVENT_UPDATE + this.className + id.toString();
|
|
233
204
|
this.socket.on(event, async (update, ack) => {
|
|
234
205
|
const res = await this.handleUpdateRequest(update);
|
|
235
|
-
if (ack)
|
|
206
|
+
if (ack && typeof ack === "function")
|
|
236
207
|
ack(res);
|
|
237
208
|
return res;
|
|
238
209
|
});
|
|
239
210
|
}
|
|
240
211
|
async handleUpdateRequest(update) {
|
|
241
212
|
try {
|
|
242
|
-
await this.
|
|
243
|
-
silent: true,
|
|
244
|
-
});
|
|
213
|
+
await this.setValue__(update.key, update.value, true);
|
|
245
214
|
if (this.isLoaded)
|
|
246
215
|
this.callbacks.update(this, update.key);
|
|
247
216
|
return { success: true, data: undefined, message: "" };
|
|
248
217
|
}
|
|
249
218
|
catch (error) {
|
|
250
|
-
|
|
251
|
-
this.loggers.error?.(`[${dataRec["_id"]?.toString()}] Error applying patch: ${error.message}`);
|
|
219
|
+
this.loggers.error?.(`[${this.data._id}] Error applying patch: ${error.message}`);
|
|
252
220
|
return {
|
|
253
221
|
success: false,
|
|
254
222
|
message: "Error applying update: " + error.message,
|
|
@@ -262,10 +230,14 @@ export class AutoUpdatedClientObject {
|
|
|
262
230
|
if (typeof key !== "string")
|
|
263
231
|
continue;
|
|
264
232
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
233
|
+
delete this[key];
|
|
265
234
|
Object.defineProperty(this, key, {
|
|
266
235
|
get: () => {
|
|
267
|
-
|
|
268
|
-
|
|
236
|
+
if (!this.data)
|
|
237
|
+
return undefined;
|
|
238
|
+
let val = this.data[key];
|
|
239
|
+
if (val === null)
|
|
240
|
+
val = undefined;
|
|
269
241
|
if (isRef && val) {
|
|
270
242
|
if (Array.isArray(val)) {
|
|
271
243
|
return val
|
|
@@ -289,31 +261,43 @@ export class AutoUpdatedClientObject {
|
|
|
289
261
|
}
|
|
290
262
|
getValue(key_) {
|
|
291
263
|
const key = key_;
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
264
|
+
const parts = key.split(".");
|
|
265
|
+
let value = this;
|
|
266
|
+
for (const part of parts) {
|
|
267
|
+
if (value === undefined || value === null)
|
|
268
|
+
return undefined;
|
|
269
|
+
const nextValue = value[part];
|
|
270
|
+
if (nextValue !== undefined) {
|
|
271
|
+
value = nextValue;
|
|
272
|
+
}
|
|
273
|
+
else if (value.data && value.data[part] !== undefined) {
|
|
274
|
+
value = value.data[part];
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return value;
|
|
298
281
|
}
|
|
299
282
|
findReference(id, key) {
|
|
300
|
-
if (!id
|
|
283
|
+
if (!id)
|
|
301
284
|
return undefined;
|
|
302
285
|
const idStr = id.toString();
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return cacheRec[key].getObject(idStr);
|
|
286
|
+
if (this.parentManager.cache.references[key])
|
|
287
|
+
return this.parentManager.cache.references[key].getObject(idStr);
|
|
306
288
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
307
289
|
const result = manager.getObject(idStr);
|
|
308
290
|
if (result) {
|
|
309
|
-
|
|
291
|
+
this.parentManager.cache.references[key] = manager;
|
|
310
292
|
return result;
|
|
311
293
|
}
|
|
312
294
|
}
|
|
313
295
|
return undefined;
|
|
314
296
|
}
|
|
315
|
-
async setValue(key, val
|
|
316
|
-
|
|
297
|
+
async setValue(key, val) {
|
|
298
|
+
return await this.setValue__(key, val);
|
|
299
|
+
}
|
|
300
|
+
async setValue__(key, val, silent = false, noGet = false, noUpdate = false, isParentUpdate = false) {
|
|
317
301
|
try {
|
|
318
302
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
319
303
|
const pointer = getMetadataRecursive("refsTo", this, key);
|
|
@@ -324,18 +308,39 @@ export class AutoUpdatedClientObject {
|
|
|
324
308
|
if (isRef) {
|
|
325
309
|
valueToStore = Array.isArray(val)
|
|
326
310
|
? val.map((v) => v._id?.toString() ?? v.toString())
|
|
327
|
-
:
|
|
311
|
+
: val?._id ?? val?.toString() ?? val;
|
|
328
312
|
}
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
|
|
313
|
+
const currentVal = this.getValue(key);
|
|
314
|
+
const currentValId = Array.isArray(currentVal)
|
|
315
|
+
? currentVal.map((v) => v._id?.toString() ?? v.toString())
|
|
316
|
+
: currentVal?._id ?? currentVal?.toString();
|
|
317
|
+
if (_.isEqual(currentValId, valueToStore))
|
|
332
318
|
return { success: true, msg: "Successfully set " + key + " to " + val };
|
|
319
|
+
const path = key.split(".");
|
|
320
|
+
if (path.length > 1) {
|
|
321
|
+
let obj = this.data;
|
|
322
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
323
|
+
const currentKey = path[i];
|
|
324
|
+
if (typeof obj[currentKey] === "string" ||
|
|
325
|
+
ObjectId.isValid(obj[currentKey])) {
|
|
326
|
+
const ref = await this.resolveReference(obj[currentKey].toString());
|
|
327
|
+
if (!ref)
|
|
328
|
+
throw new Error("Could not resolve reference on path: " + key);
|
|
329
|
+
return await ref.setValue(path.slice(i + 1).join("."), val);
|
|
330
|
+
}
|
|
331
|
+
obj = obj[currentKey];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
333
334
|
const res = await this.setValueInternal(key, valueToStore, silent, noUpdate);
|
|
334
335
|
if (res.success) {
|
|
335
|
-
|
|
336
|
-
|
|
336
|
+
const pathArr = key.split(".");
|
|
337
|
+
let obj = this.data;
|
|
338
|
+
for (let i = 0; i < pathArr.length - 1; i++) {
|
|
339
|
+
obj = obj[pathArr[i]];
|
|
340
|
+
}
|
|
341
|
+
obj[pathArr[pathArr.length - 1]] = valueToStore;
|
|
337
342
|
await this.findAndLoadReferences(key, valueToStore);
|
|
338
|
-
if (isRef && this.parentManager
|
|
343
|
+
if (isRef && this.parentManager.isLoaded)
|
|
339
344
|
await this.contactChildren();
|
|
340
345
|
if (this.isLoaded)
|
|
341
346
|
this.callbacks.update(this, key);
|
|
@@ -351,17 +356,11 @@ export class AutoUpdatedClientObject {
|
|
|
351
356
|
}
|
|
352
357
|
}
|
|
353
358
|
async setValueInternal(key, value, silent = false, noUpdate = false) {
|
|
354
|
-
if (silent
|
|
355
|
-
return { success: true, msg: "Silent
|
|
359
|
+
if (silent)
|
|
360
|
+
return { success: true, msg: "Silent" };
|
|
356
361
|
return new Promise((resolve) => {
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
if (!id)
|
|
360
|
-
return resolve({ success: false, msg: "Missing _id" });
|
|
361
|
-
if (!this.socket || typeof this.socket.emit !== "function") {
|
|
362
|
-
return resolve({ success: false, msg: "Socket not available" });
|
|
363
|
-
}
|
|
364
|
-
this.socket.emit(EVENT_UPDATE + this.className + id.toString(), { _id: id.toString(), key, value }, (res) => {
|
|
362
|
+
const id = this.data?._id ?? this._id;
|
|
363
|
+
this.socket.emit(EVENT_UPDATE + this.className + id, { _id: id.toString(), key, value }, (res) => {
|
|
365
364
|
resolve({
|
|
366
365
|
success: res.success,
|
|
367
366
|
msg: res.message ?? (res.success ? "Success" : "Error"),
|
|
@@ -370,17 +369,14 @@ export class AutoUpdatedClientObject {
|
|
|
370
369
|
});
|
|
371
370
|
}
|
|
372
371
|
makeUpdate(key, value) {
|
|
373
|
-
const
|
|
374
|
-
const id = dataRec ? dataRec["_id"] : undefined;
|
|
372
|
+
const id = this.data?._id ?? this._id;
|
|
375
373
|
if (!id) {
|
|
376
374
|
this.loggers.error?.(`Probably missing the identifier ['_id'] again: ${key} = ${value}`);
|
|
377
375
|
throw new Error(`Cannot make update for ${this.className} because _id is missing.`);
|
|
378
376
|
}
|
|
379
|
-
return { _id: id, key, value };
|
|
377
|
+
return { _id: id.toString(), key, value };
|
|
380
378
|
}
|
|
381
379
|
async resolveReference(id) {
|
|
382
|
-
if (!this.parentManager)
|
|
383
|
-
return null;
|
|
384
380
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
385
381
|
const obj = manager.getObject(id);
|
|
386
382
|
if (obj)
|
|
@@ -390,7 +386,7 @@ export class AutoUpdatedClientObject {
|
|
|
390
386
|
}
|
|
391
387
|
async findAndLoadReferences(lastPath, value) {
|
|
392
388
|
const isRef = getMetadataRecursive("isRef", this, lastPath);
|
|
393
|
-
if (isRef
|
|
389
|
+
if (isRef) {
|
|
394
390
|
for (const id of Array.isArray(value) ? value : [value]) {
|
|
395
391
|
if (!id)
|
|
396
392
|
continue;
|
|
@@ -407,60 +403,48 @@ export class AutoUpdatedClientObject {
|
|
|
407
403
|
}
|
|
408
404
|
}
|
|
409
405
|
async wipeSelf() {
|
|
410
|
-
|
|
411
|
-
if (!dataRec || dataRec["Wiped"])
|
|
406
|
+
if (this.data.Wiped)
|
|
412
407
|
return;
|
|
413
|
-
const id =
|
|
408
|
+
const id = this.data?._id ?? this._id;
|
|
414
409
|
const _id = id ? id.toString() : "unknown";
|
|
415
|
-
for (const key of Object.keys(
|
|
416
|
-
delete
|
|
410
|
+
for (const key of Object.keys(this.data)) {
|
|
411
|
+
delete this.data[key];
|
|
417
412
|
}
|
|
418
|
-
|
|
413
|
+
this.data = { Wiped: true };
|
|
419
414
|
this.loggers.info?.(`[${_id}] ${this.className} object wiped`);
|
|
420
415
|
}
|
|
416
|
+
destroyImmediate() {
|
|
417
|
+
this.wipeSelf();
|
|
418
|
+
}
|
|
421
419
|
async loadForceReferences(obj = this.data, proto = this, alreadySeen = []) {
|
|
422
|
-
if (!obj)
|
|
423
|
-
return;
|
|
424
|
-
if (obj === this.data) {
|
|
425
|
-
const dataRec = this.data;
|
|
426
|
-
const myId = dataRec["_id"]?.toString();
|
|
427
|
-
if (myId && !alreadySeen.includes(myId))
|
|
428
|
-
alreadySeen.push(myId);
|
|
429
|
-
}
|
|
430
420
|
const props = Reflect.getMetadata("props", proto) || [];
|
|
431
421
|
for (const key of props) {
|
|
422
|
+
if (typeof key !== "string")
|
|
423
|
+
continue;
|
|
432
424
|
const isRef = Reflect.getMetadata("isRef", proto, key);
|
|
433
425
|
const pointer = Reflect.getMetadata("refsTo", proto, key);
|
|
434
|
-
const objRec = obj;
|
|
435
426
|
if (pointer &&
|
|
436
427
|
obj === this.data &&
|
|
437
|
-
|
|
438
|
-
!alreadySeen.includes(
|
|
439
|
-
await this.createdWithParent(pointer.split(":"),
|
|
428
|
+
obj[key] &&
|
|
429
|
+
!alreadySeen.includes(obj)) {
|
|
430
|
+
await this.createdWithParent(pointer.split(":"), obj[key]);
|
|
440
431
|
}
|
|
441
|
-
if (
|
|
442
|
-
alreadySeen.push(
|
|
432
|
+
if (obj[key] && !alreadySeen.includes(obj[key]))
|
|
433
|
+
alreadySeen.push(obj[key]);
|
|
443
434
|
if (isRef)
|
|
444
435
|
await this.handleLoad(obj, key, alreadySeen);
|
|
445
|
-
const val =
|
|
436
|
+
const val = obj[key];
|
|
446
437
|
if (val && typeof val === "object") {
|
|
447
438
|
const nestedProto = Object.getPrototypeOf(val);
|
|
448
|
-
if (nestedProto &&
|
|
449
|
-
|
|
450
|
-
!alreadySeen.includes(JSON.stringify(val))) {
|
|
451
|
-
alreadySeen.push(JSON.stringify(val));
|
|
439
|
+
if (nestedProto && !alreadySeen.includes(val)) {
|
|
440
|
+
alreadySeen.push(val);
|
|
452
441
|
await this.loadForceReferences(val, nestedProto, alreadySeen);
|
|
453
442
|
}
|
|
454
443
|
}
|
|
455
444
|
}
|
|
456
445
|
}
|
|
457
446
|
async handleLoad(obj, key, alreadySeen) {
|
|
458
|
-
|
|
459
|
-
return;
|
|
460
|
-
const objRec = obj;
|
|
461
|
-
const refIds = Array.isArray(objRec[key])
|
|
462
|
-
? objRec[key]
|
|
463
|
-
: [objRec[key]];
|
|
447
|
+
const refIds = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
|
|
464
448
|
for (const refId of refIds) {
|
|
465
449
|
if (refId) {
|
|
466
450
|
const idStr = refId.toString();
|
|
@@ -479,82 +463,38 @@ export class AutoUpdatedClientObject {
|
|
|
479
463
|
}
|
|
480
464
|
}
|
|
481
465
|
}
|
|
482
|
-
async onUpdate(noUpdate = false) {
|
|
483
|
-
if (noUpdate)
|
|
484
|
-
return;
|
|
485
|
-
try {
|
|
486
|
-
await this.callbacks?.onUpdate?.(this, (key, val) => {
|
|
487
|
-
return this.setValue(key, val, {
|
|
488
|
-
silent: false,
|
|
489
|
-
noGet: true,
|
|
490
|
-
noUpdate: true,
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
catch (error) {
|
|
495
|
-
this.loggers.error(`[onUpdate] ${error}`);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
466
|
async createdWithParent(pointer, parent) {
|
|
499
|
-
if (pointer.length !== 2
|
|
467
|
+
if (pointer.length !== 2)
|
|
500
468
|
return;
|
|
501
469
|
const parentId = parent._id?.toString() ?? parent.toString();
|
|
502
|
-
const
|
|
503
|
-
if (!ac)
|
|
504
|
-
return;
|
|
505
|
-
const obj = ac.getObject(parentId);
|
|
470
|
+
const obj = this.parentManager.managers[pointer[0]]?.getObject(parentId);
|
|
506
471
|
if (!obj)
|
|
507
472
|
return;
|
|
508
473
|
const val = obj.getValue(pointer[1]);
|
|
509
|
-
const
|
|
510
|
-
const myId = dataRec["_id"]?.toString();
|
|
511
|
-
if (!myId)
|
|
512
|
-
return;
|
|
474
|
+
const myId = this.data._id.toString();
|
|
513
475
|
if (Array.isArray(val)) {
|
|
514
476
|
const ids = val.map((v) => v._id?.toString() ?? v.toString());
|
|
515
477
|
if (!ids.includes(myId)) {
|
|
516
|
-
await obj.
|
|
478
|
+
await obj.setValue__(pointer[1], [...val, myId], true, false, false, true);
|
|
517
479
|
}
|
|
518
480
|
}
|
|
519
481
|
else if ((val?._id?.toString() ?? val?.toString()) !== myId) {
|
|
520
|
-
await obj.
|
|
521
|
-
silent: true,
|
|
522
|
-
isParentUpdate: true,
|
|
523
|
-
});
|
|
482
|
+
await obj.setValue__(pointer[1], myId, true, false, false, true);
|
|
524
483
|
}
|
|
525
484
|
}
|
|
526
485
|
async destroy(once = false) {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
this.preloadTimers.clear();
|
|
531
|
-
const dataRec = this.data;
|
|
532
|
-
const id = dataRec ? dataRec["_id"] : undefined;
|
|
533
|
-
if (!id)
|
|
534
|
-
return { success: false, message: "Missing _id" };
|
|
535
|
-
if (!once && this.parentManager)
|
|
536
|
-
return await this.parentManager.deleteObject(id);
|
|
486
|
+
if (!once)
|
|
487
|
+
return await this.parentManager.deleteObject(this.data._id);
|
|
537
488
|
return new Promise((resolve) => {
|
|
538
|
-
|
|
539
|
-
return resolve({ success: false, message: "Socket not available" });
|
|
540
|
-
}
|
|
541
|
-
this.socket.emit(EVENT_DELETE + this.className, id.toString(), (res) => {
|
|
489
|
+
this.socket.emit(EVENT_DELETE + this.className, this.data._id, (res) => {
|
|
542
490
|
resolve({ success: res.success, message: res.message ?? "" });
|
|
543
491
|
});
|
|
544
492
|
});
|
|
545
493
|
}
|
|
546
|
-
destroyImmediate() {
|
|
547
|
-
this.isDestroyed = true;
|
|
548
|
-
for (const timer of this.preloadTimers) {
|
|
549
|
-
clearTimeout(timer);
|
|
550
|
-
}
|
|
551
|
-
this.preloadTimers.clear();
|
|
552
|
-
this.isLoading = false;
|
|
553
|
-
}
|
|
554
494
|
async checkForMissingRefs() {
|
|
555
495
|
for (const prop of this.properties) {
|
|
556
496
|
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
557
|
-
if (
|
|
497
|
+
if (pointer) {
|
|
558
498
|
const parts = pointer.split(":");
|
|
559
499
|
if (parts.length === 2)
|
|
560
500
|
await this.findMissingObjectReference(prop, parts);
|
|
@@ -562,18 +502,13 @@ export class AutoUpdatedClientObject {
|
|
|
562
502
|
}
|
|
563
503
|
}
|
|
564
504
|
async findMissingObjectReference(prop, pointer) {
|
|
565
|
-
if (this.checkedMissingRefs
|
|
505
|
+
if (this.checkedMissingRefs)
|
|
566
506
|
return;
|
|
567
507
|
this.checkedMissingRefs = true;
|
|
568
508
|
const ac = this.parentManager.managers[pointer[0]];
|
|
569
509
|
if (!ac)
|
|
570
510
|
return;
|
|
571
|
-
const
|
|
572
|
-
const targetId = dataRec
|
|
573
|
-
? dataRec["_id"]?.toString()
|
|
574
|
-
: undefined;
|
|
575
|
-
if (!targetId)
|
|
576
|
-
return;
|
|
511
|
+
const targetId = this.data._id.toString();
|
|
577
512
|
const allObjects = Object.values(ac.objects);
|
|
578
513
|
for (const obj of allObjects) {
|
|
579
514
|
if (!obj.isLoaded)
|
|
@@ -585,46 +520,30 @@ export class AutoUpdatedClientObject {
|
|
|
585
520
|
? val.map((v) => v._id?.toString() ?? v.toString())
|
|
586
521
|
: [val._id?.toString() ?? val.toString()];
|
|
587
522
|
if (ids.includes(targetId)) {
|
|
588
|
-
|
|
523
|
+
this.data[prop] = obj._id;
|
|
589
524
|
return;
|
|
590
525
|
}
|
|
591
526
|
}
|
|
592
527
|
}
|
|
593
|
-
async resolveReferences() {
|
|
594
|
-
await this.loadMissingReferences();
|
|
595
|
-
await this.contactChildren();
|
|
596
|
-
}
|
|
597
528
|
async contactChildren() {
|
|
598
|
-
if (!this.parentManager)
|
|
599
|
-
return;
|
|
600
529
|
for (const prop of this.properties) {
|
|
601
530
|
const isRef = getMetadataRecursive("isRef", this, prop.toString());
|
|
602
531
|
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
603
532
|
if (!isRef || pointer)
|
|
604
533
|
continue;
|
|
605
|
-
const
|
|
606
|
-
if (!
|
|
534
|
+
const obj = this.getValue(prop);
|
|
535
|
+
if (!obj)
|
|
607
536
|
continue;
|
|
608
|
-
const
|
|
609
|
-
for (const
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
let childObj = item;
|
|
613
|
-
if (typeof item === "string" || item instanceof ObjectId) {
|
|
614
|
-
const idStr = item.toString();
|
|
615
|
-
for (const manager of Object.values(this.parentManager.managers)) {
|
|
616
|
-
childObj = manager.getObject(idStr);
|
|
617
|
-
if (childObj)
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
if (childObj &&
|
|
622
|
-
typeof childObj.loadMissingReferences === "function") {
|
|
623
|
-
await childObj.loadMissingReferences();
|
|
537
|
+
const children = Array.isArray(obj) ? obj : [obj];
|
|
538
|
+
for (const child of children) {
|
|
539
|
+
if (child && typeof child.loadMissingReferences === "function") {
|
|
540
|
+
await child.loadMissingReferences();
|
|
624
541
|
}
|
|
625
542
|
}
|
|
626
543
|
}
|
|
627
|
-
|
|
544
|
+
}
|
|
545
|
+
async onUpdate() {
|
|
546
|
+
// Placeholder for server-side override
|
|
628
547
|
}
|
|
629
548
|
}
|
|
630
549
|
export function processIsRefProperties(instance, target, prefix, allProps, newData, loggers) {
|
|
@@ -632,8 +551,6 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
632
551
|
for (const prop of props) {
|
|
633
552
|
const path = prefix ? `${prefix}.${prop}` : prop;
|
|
634
553
|
allProps.push(path);
|
|
635
|
-
if (!instance)
|
|
636
|
-
continue;
|
|
637
554
|
newData[prop] = ObjectId.isValid(instance[prop])
|
|
638
555
|
? instance[prop]?.toString()
|
|
639
556
|
: instance[prop];
|
|
@@ -648,16 +565,18 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
648
565
|
}
|
|
649
566
|
const type = Reflect.getMetadata("design:type", target, prop);
|
|
650
567
|
if (type?.prototype) {
|
|
651
|
-
|
|
568
|
+
const nestedProps = Reflect.getMetadata("props", type.prototype);
|
|
569
|
+
if (nestedProps && instance[prop]) {
|
|
570
|
+
newData[prop] = processIsRefProperties(instance[prop], type.prototype, path, allProps, {}, loggers).newData;
|
|
571
|
+
}
|
|
652
572
|
}
|
|
653
573
|
}
|
|
654
574
|
return { allProps, newData };
|
|
655
575
|
}
|
|
656
|
-
export function getMetadataRecursive(metaKey,
|
|
657
|
-
let proto = target;
|
|
576
|
+
export function getMetadataRecursive(metaKey, proto, prop) {
|
|
658
577
|
while (proto) {
|
|
659
578
|
const meta = Reflect.getMetadata(metaKey, proto, prop);
|
|
660
|
-
if (meta
|
|
579
|
+
if (meta)
|
|
661
580
|
return meta;
|
|
662
581
|
proto = Object.getPrototypeOf(proto);
|
|
663
582
|
}
|