@prestizni-software/client-dem 0.4.101 → 0.4.103
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.
|
@@ -2,25 +2,17 @@ import "reflect-metadata";
|
|
|
2
2
|
import _ from "lodash";
|
|
3
3
|
import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UPDATE, globalCache, } from "./CommonTypes.js";
|
|
4
4
|
import { ObjectId } from "bson";
|
|
5
|
-
import { stringSimilarity } from "string-similarity-js";
|
|
6
5
|
export class AutoUpdatedClientObject {
|
|
7
|
-
//From server type for overlapping keys
|
|
8
6
|
entry;
|
|
9
7
|
preLoad;
|
|
10
8
|
registerSocket;
|
|
11
9
|
readyLoggers;
|
|
12
10
|
loadFromDB(a) { }
|
|
13
11
|
setValue_(a, b) { }
|
|
14
|
-
//-*--
|
|
15
12
|
socket;
|
|
16
13
|
data;
|
|
17
14
|
isServer = false;
|
|
18
|
-
loggers
|
|
19
|
-
info: () => { },
|
|
20
|
-
debug: () => { },
|
|
21
|
-
error: () => { },
|
|
22
|
-
warn: () => { },
|
|
23
|
-
};
|
|
15
|
+
loggers;
|
|
24
16
|
isLoading = true;
|
|
25
17
|
isLoadingReferences = true;
|
|
26
18
|
checkedMissingRefs = false;
|
|
@@ -42,9 +34,7 @@ export class AutoUpdatedClientObject {
|
|
|
42
34
|
}
|
|
43
35
|
}
|
|
44
36
|
catch (error) {
|
|
45
|
-
this.loggers.error("Error loading references");
|
|
46
|
-
this.loggers.error(error.message);
|
|
47
|
-
this.loggers.error(error.stack);
|
|
37
|
+
this.loggers.error("Error loading references: " + error.message);
|
|
48
38
|
}
|
|
49
39
|
this.isLoadingReferences = false;
|
|
50
40
|
return;
|
|
@@ -60,9 +50,7 @@ export class AutoUpdatedClientObject {
|
|
|
60
50
|
}
|
|
61
51
|
catch (error) {
|
|
62
52
|
this.isLoadingReferences = false;
|
|
63
|
-
this.loggers.error("Error loading references");
|
|
64
|
-
this.loggers.error(error.message);
|
|
65
|
-
this.loggers.error(error.stack);
|
|
53
|
+
this.loggers.error("Error loading references: " + error.message);
|
|
66
54
|
}
|
|
67
55
|
};
|
|
68
56
|
/** @deprecated Use loadReferencesAsync instead */
|
|
@@ -74,7 +62,6 @@ export class AutoUpdatedClientObject {
|
|
|
74
62
|
!loggers ||
|
|
75
63
|
!className ||
|
|
76
64
|
!parentManager ||
|
|
77
|
-
!callback ||
|
|
78
65
|
!emitter) {
|
|
79
66
|
this.classParam = classParam;
|
|
80
67
|
this.socket = socket;
|
|
@@ -91,16 +78,13 @@ export class AutoUpdatedClientObject {
|
|
|
91
78
|
!loggers &&
|
|
92
79
|
!className &&
|
|
93
80
|
!parentManager &&
|
|
94
|
-
!callback &&
|
|
95
81
|
!emitter)
|
|
96
82
|
return;
|
|
97
83
|
else
|
|
98
84
|
throw new Error("Missing arguments???");
|
|
99
85
|
}
|
|
100
86
|
this.classParam = classParam;
|
|
101
|
-
|
|
102
|
-
processIsRefProperties(data, this, undefined, [], loggers);
|
|
103
|
-
}
|
|
87
|
+
this.socket = socket;
|
|
104
88
|
this.isServer = isServer;
|
|
105
89
|
this.emitter = emitter;
|
|
106
90
|
this.isLoadingReferences = true;
|
|
@@ -109,53 +93,19 @@ export class AutoUpdatedClientObject {
|
|
|
109
93
|
this.className = className;
|
|
110
94
|
this.properties = Reflect.getMetadata("props", classParam.prototype);
|
|
111
95
|
this.callbacks = callback;
|
|
112
|
-
this.loggers
|
|
113
|
-
this.className
|
|
114
|
-
|
|
115
|
-
(this.data?._id ?? "not loaded")
|
|
116
|
-
"
|
|
117
|
-
|
|
118
|
-
this.loggers.info = (s) => loggers.info("[DEM - " +
|
|
119
|
-
this.className +
|
|
120
|
-
": " +
|
|
121
|
-
(this.data?._id ?? "not loaded") +
|
|
122
|
-
"] " +
|
|
123
|
-
s);
|
|
124
|
-
this.loggers.error = (s) => loggers.error("[DEM - " +
|
|
125
|
-
this.className +
|
|
126
|
-
": " +
|
|
127
|
-
(this.data?._id ?? "not loaded") +
|
|
128
|
-
"] " +
|
|
129
|
-
s);
|
|
130
|
-
this.loggers.warn = (s) => loggers.warn("[DEM - " +
|
|
131
|
-
this.className +
|
|
132
|
-
": " +
|
|
133
|
-
(this.data?._id ?? "not loaded") +
|
|
134
|
-
"] " +
|
|
135
|
-
s);
|
|
136
|
-
for (const prop of this.properties) {
|
|
137
|
-
if (typeof prop !== "string")
|
|
138
|
-
throw new Error("Property '" + prop.toString() + "' is not a string");
|
|
139
|
-
if (prop.includes("."))
|
|
140
|
-
throw new Error("Property '" +
|
|
141
|
-
prop.toString() +
|
|
142
|
-
"' constain the illegal character '.'");
|
|
143
|
-
}
|
|
144
|
-
this.socket = socket;
|
|
96
|
+
this.loggers = {
|
|
97
|
+
debug: (s) => loggers.debug(`[DEM - ${this.className}: ${this.data?._id ?? "not loaded"}] ${s}`),
|
|
98
|
+
info: (s) => loggers.info(`[DEM - ${this.className}: ${this.data?._id ?? "not loaded"}] ${s}`),
|
|
99
|
+
warn: (s) => loggers.warn(`[DEM - ${this.className}: ${this.data?._id ?? "not loaded"}] ${s}`),
|
|
100
|
+
error: (s) => loggers.error(`[DEM - ${this.className}: ${this.data?._id ?? "not loaded"}] ${s}`),
|
|
101
|
+
};
|
|
145
102
|
if (typeof data === "string") {
|
|
103
|
+
this.data = { _id: data };
|
|
146
104
|
if (this.isServer) {
|
|
147
105
|
this.isLoading = false;
|
|
148
|
-
this.
|
|
106
|
+
this.generateSettersAndGetters();
|
|
149
107
|
return;
|
|
150
108
|
}
|
|
151
|
-
if (!data || data === "" || data === "undefined") {
|
|
152
|
-
this.loggers.error("Cannot create a new AutoUpdatedClientClass with an empty string for ID. Data typeof: " +
|
|
153
|
-
typeof data +
|
|
154
|
-
" Data: " +
|
|
155
|
-
data);
|
|
156
|
-
throw new Error("Cannot create a new AutoUpdatedClientClass with an empty string for ID.");
|
|
157
|
-
}
|
|
158
|
-
this.loggers.debug("Getting new object from server " + this.className + " - " + data);
|
|
159
109
|
this.socket.emit(EVENT_GET + this.className + data, null, (res) => {
|
|
160
110
|
if (!res.success) {
|
|
161
111
|
this.isLoading = false;
|
|
@@ -169,38 +119,24 @@ export class AutoUpdatedClientObject {
|
|
|
169
119
|
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID);
|
|
170
120
|
this.openSockets();
|
|
171
121
|
});
|
|
172
|
-
this.data = { _id: data };
|
|
173
122
|
}
|
|
174
123
|
else {
|
|
175
124
|
this.isLoading = true;
|
|
176
125
|
this.data = data;
|
|
177
|
-
const
|
|
178
|
-
for (const key of this.properties) {
|
|
179
|
-
if (typeof key !== "string")
|
|
180
|
-
throw new Error("Only string keys allowed. Not this shit: " + String(key));
|
|
181
|
-
dataKeys.splice(dataKeys.indexOf(key), 1);
|
|
126
|
+
for (const key of this.properties || []) {
|
|
182
127
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
183
|
-
if (isRef) {
|
|
128
|
+
if (isRef && this.data[key]) {
|
|
184
129
|
if (Array.isArray(this.data[key])) {
|
|
185
130
|
this.data[key] = this.data[key].map((obj) => obj._id?.toString() ?? obj?.toString());
|
|
186
131
|
}
|
|
187
132
|
else {
|
|
188
|
-
this.data[key] =
|
|
189
|
-
this.data[key]?._id?.toString() ??
|
|
190
|
-
this.data[key]?.toString();
|
|
133
|
+
this.data[key] = this.data[key]?._id?.toString() ?? this.data[key]?.toString();
|
|
191
134
|
}
|
|
192
135
|
}
|
|
193
136
|
}
|
|
194
|
-
if (
|
|
195
|
-
dataKeys.splice(dataKeys.indexOf("__v"), 1);
|
|
196
|
-
if (dataKeys.length > 0)
|
|
197
|
-
this.loggers.warn((dataKeys.length > 1 ? "Properties " : "Property ") +
|
|
198
|
-
dataKeys.join(", ") +
|
|
199
|
-
(dataKeys.length > 1 ? " were " : " was ") +
|
|
200
|
-
"unexpected. These properties are not known by the class. Please check your level of skill issue. Known properties are:\n" +
|
|
201
|
-
this.properties.join("\n"));
|
|
202
|
-
if ((!this.data._id || this.data._id === "") && !this.isServer)
|
|
137
|
+
if ((!this.data._id || this.data._id === "") && !this.isServer) {
|
|
203
138
|
this.handleNewObject(data);
|
|
139
|
+
}
|
|
204
140
|
else {
|
|
205
141
|
this.isLoading = false;
|
|
206
142
|
if (!this.isServer)
|
|
@@ -214,9 +150,8 @@ export class AutoUpdatedClientObject {
|
|
|
214
150
|
return;
|
|
215
151
|
await new Promise((resolve, reject) => {
|
|
216
152
|
this.emitter.once(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, (failed, reason) => {
|
|
217
|
-
if (failed)
|
|
153
|
+
if (failed)
|
|
218
154
|
reject(new Error(reason));
|
|
219
|
-
}
|
|
220
155
|
else
|
|
221
156
|
resolve();
|
|
222
157
|
});
|
|
@@ -224,31 +159,6 @@ export class AutoUpdatedClientObject {
|
|
|
224
159
|
}
|
|
225
160
|
handleNewObject(data) {
|
|
226
161
|
this.isLoading = true;
|
|
227
|
-
if (!this.className)
|
|
228
|
-
throw new Error("Cannot create a new AutoUpdatedClientClass without a class name.");
|
|
229
|
-
this.loggers.debug(this.className + " - Requesting new object creation on server");
|
|
230
|
-
if (this.isServer)
|
|
231
|
-
for (const key of this.properties) {
|
|
232
|
-
if (typeof key !== "string")
|
|
233
|
-
continue;
|
|
234
|
-
let pointer = getMetadataRecursive("refsTo", this, key);
|
|
235
|
-
if (pointer) {
|
|
236
|
-
pointer = pointer.split(":");
|
|
237
|
-
if (pointer.length != 2)
|
|
238
|
-
throw new Error("population ref incorrectly defined. Sould be 'ParentClass:PropName.Path'");
|
|
239
|
-
const temp = data[key];
|
|
240
|
-
delete data[key];
|
|
241
|
-
if (temp)
|
|
242
|
-
this.toChangeOnParents.push({ key: key, value: temp });
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
try {
|
|
246
|
-
data = _.cloneDeep(data);
|
|
247
|
-
}
|
|
248
|
-
catch (error) {
|
|
249
|
-
this.loggers.error("Most likely cycled object: " + error.message);
|
|
250
|
-
this.loggers.error(error.stack);
|
|
251
|
-
}
|
|
252
162
|
this.socket.emit(EVENT_NEW + this.className, data, (res) => {
|
|
253
163
|
if (!res.success) {
|
|
254
164
|
this.isLoading = false;
|
|
@@ -259,7 +169,6 @@ export class AutoUpdatedClientObject {
|
|
|
259
169
|
this.data = res.data;
|
|
260
170
|
this.generateSettersAndGetters();
|
|
261
171
|
this.isLoading = false;
|
|
262
|
-
this.loggers.debug("Created new object: " + this.data._id);
|
|
263
172
|
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID);
|
|
264
173
|
if (!this.isServer)
|
|
265
174
|
this.openSockets();
|
|
@@ -286,70 +195,75 @@ export class AutoUpdatedClientObject {
|
|
|
286
195
|
const res = await this.handleUpdateRequest(update);
|
|
287
196
|
if (ack && typeof ack === "function")
|
|
288
197
|
ack(res);
|
|
289
|
-
return res;
|
|
290
198
|
});
|
|
291
199
|
}
|
|
292
200
|
async handleUpdateRequest(update) {
|
|
293
201
|
try {
|
|
294
202
|
await this.setValue__(update.key, update.value, true);
|
|
295
|
-
this.loggers.debug(`Applied patch ${update.key} set to ${JSON.stringify(update.value)}`);
|
|
296
|
-
// Return success with the applied patch
|
|
297
203
|
if (this.isLoaded)
|
|
298
204
|
this.callbacks.update(this, update.key);
|
|
299
205
|
return { success: true, data: undefined, message: "" };
|
|
300
206
|
}
|
|
301
207
|
catch (error) {
|
|
302
|
-
this.loggers.error(`[${this.data._id}] Error applying patch: `
|
|
303
|
-
|
|
304
|
-
"\n" +
|
|
305
|
-
error.stack);
|
|
306
|
-
return {
|
|
307
|
-
success: false,
|
|
308
|
-
message: "Error applying update: " + error.message,
|
|
309
|
-
};
|
|
208
|
+
this.loggers.error(`[${this.data._id}] Error applying patch: ${error.message}`);
|
|
209
|
+
return { success: false, message: "Error applying update: " + error.message };
|
|
310
210
|
}
|
|
311
211
|
}
|
|
312
|
-
__gettersGenerated = false;
|
|
313
212
|
generateSettersAndGetters() {
|
|
314
|
-
if (this.
|
|
213
|
+
if (!this.properties)
|
|
315
214
|
return;
|
|
316
|
-
this.__gettersGenerated = true;
|
|
317
215
|
for (const key of this.properties) {
|
|
318
216
|
if (typeof key !== "string")
|
|
319
217
|
continue;
|
|
320
|
-
const k = key;
|
|
321
218
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
322
|
-
if
|
|
323
|
-
|
|
219
|
+
// Delete the property if it exists on the instance to ensure the getter sticks.
|
|
220
|
+
delete this[key];
|
|
324
221
|
Object.defineProperty(this, key, {
|
|
325
222
|
get: () => {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
.filter(Boolean);
|
|
331
|
-
return filtered;
|
|
223
|
+
const val = this.data ? this.data[key] : undefined;
|
|
224
|
+
if (isRef && val) {
|
|
225
|
+
if (Array.isArray(val)) {
|
|
226
|
+
return val.map((id) => this.findReference(id, key)).filter(Boolean);
|
|
332
227
|
}
|
|
333
228
|
else {
|
|
334
|
-
|
|
335
|
-
return result;
|
|
229
|
+
return this.findReference(val, key);
|
|
336
230
|
}
|
|
337
231
|
}
|
|
338
|
-
|
|
339
|
-
return this.data[k];
|
|
232
|
+
return val;
|
|
340
233
|
},
|
|
341
234
|
enumerable: true,
|
|
342
235
|
configurable: true,
|
|
343
236
|
});
|
|
344
237
|
}
|
|
345
238
|
}
|
|
239
|
+
getValue(key_) {
|
|
240
|
+
const key = key_;
|
|
241
|
+
const parts = key.split(".");
|
|
242
|
+
let value = this;
|
|
243
|
+
for (const part of parts) {
|
|
244
|
+
if (value === undefined || value === null)
|
|
245
|
+
return undefined;
|
|
246
|
+
const nextValue = value[part];
|
|
247
|
+
if (nextValue !== undefined) {
|
|
248
|
+
value = nextValue;
|
|
249
|
+
}
|
|
250
|
+
else if (value.data && value.data[part] !== undefined) {
|
|
251
|
+
value = value.data[part];
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return value;
|
|
258
|
+
}
|
|
346
259
|
findReference(id, key) {
|
|
347
|
-
if (
|
|
348
|
-
return
|
|
260
|
+
if (!id)
|
|
261
|
+
return undefined;
|
|
262
|
+
const idStr = id.toString();
|
|
349
263
|
if (this.parentManager.cache.references[key])
|
|
350
|
-
return this.parentManager.cache.references[key].getObject(
|
|
264
|
+
return this.parentManager.cache.references[key].getObject(idStr);
|
|
351
265
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
352
|
-
const result = manager.getObject(
|
|
266
|
+
const result = manager.getObject(idStr);
|
|
353
267
|
if (result) {
|
|
354
268
|
this.parentManager.cache.references[key] = manager;
|
|
355
269
|
return result;
|
|
@@ -358,326 +272,80 @@ export class AutoUpdatedClientObject {
|
|
|
358
272
|
return undefined;
|
|
359
273
|
}
|
|
360
274
|
async setValue(key, val) {
|
|
361
|
-
|
|
362
|
-
return result;
|
|
275
|
+
return await this.setValue__(key, val);
|
|
363
276
|
}
|
|
364
277
|
async setValue__(key, val, silent = false, noGet = false, noUpdate = false) {
|
|
365
|
-
let message = "Setting value " + key + " of " + this.className + " to ";
|
|
366
|
-
const isRef = getMetadataRecursive("isRef", this, key);
|
|
367
|
-
if (isRef)
|
|
368
|
-
val = Array.isArray(val)
|
|
369
|
-
? val.map((v) => {
|
|
370
|
-
return v._id?.toString() ?? v;
|
|
371
|
-
})
|
|
372
|
-
: (val?._id ?? val);
|
|
373
278
|
try {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (
|
|
387
|
-
val = val.extractedData._id;
|
|
388
|
-
if (Array.isArray(val))
|
|
389
|
-
val = val.map((v) => v instanceof AutoUpdatedClientObject ? v.extractedData._id : v);
|
|
390
|
-
let originalVal = this.getValue(key);
|
|
391
|
-
if (Array.isArray(originalVal)) {
|
|
392
|
-
originalVal = originalVal.map((v) => v instanceof AutoUpdatedClientObject ? v.extractedData._id : v);
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
originalVal =
|
|
396
|
-
originalVal instanceof AutoUpdatedClientObject
|
|
397
|
-
? originalVal.extractedData._id
|
|
398
|
-
: originalVal;
|
|
399
|
-
}
|
|
400
|
-
if ((Array.isArray(originalVal) &&
|
|
401
|
-
Array.isArray(val) &&
|
|
402
|
-
originalVal.length === val.length &&
|
|
403
|
-
!originalVal.some((v) => !val.includes(v))) ||
|
|
404
|
-
(Array.isArray(originalVal) &&
|
|
405
|
-
!Array.isArray(val) &&
|
|
406
|
-
originalVal.includes(val)) ||
|
|
407
|
-
(!Array.isArray(originalVal) &&
|
|
408
|
-
!Array.isArray(val) &&
|
|
409
|
-
originalVal === val)) {
|
|
279
|
+
const isRef = getMetadataRecursive("isRef", this, key);
|
|
280
|
+
let valueToStore = val;
|
|
281
|
+
if (isRef) {
|
|
282
|
+
valueToStore = Array.isArray(val)
|
|
283
|
+
? val.map((v) => v._id?.toString() ?? v.toString())
|
|
284
|
+
: (val?._id ?? val?.toString() ?? val);
|
|
285
|
+
}
|
|
286
|
+
// Optimization: skip if value hasn't changed
|
|
287
|
+
const currentVal = this.getValue(key);
|
|
288
|
+
const currentValId = Array.isArray(currentVal)
|
|
289
|
+
? currentVal.map(v => v._id?.toString() ?? v.toString())
|
|
290
|
+
: (currentVal?._id ?? currentVal?.toString());
|
|
291
|
+
if (_.isEqual(currentValId, valueToStore))
|
|
410
292
|
return { success: true, msg: "" };
|
|
411
|
-
}
|
|
412
293
|
const path = key.split(".");
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
catch (error) {
|
|
424
|
-
message +=
|
|
425
|
-
"\n Error: likely undefined property on path: " +
|
|
426
|
-
path +
|
|
427
|
-
" on index: " +
|
|
428
|
-
i +
|
|
429
|
-
" with error: " +
|
|
430
|
-
error.message;
|
|
431
|
-
}
|
|
432
|
-
if (!temp) {
|
|
433
|
-
message +=
|
|
434
|
-
"\nLikely undefined property " +
|
|
435
|
-
path[i] +
|
|
436
|
-
" on path: " +
|
|
437
|
-
path +
|
|
438
|
-
" at index: " +
|
|
439
|
-
i;
|
|
440
|
-
this.loggers.warn("Failed to set value for " + this.className + "\n" + message);
|
|
441
|
-
return {
|
|
442
|
-
success: false,
|
|
443
|
-
msg: message,
|
|
444
|
-
};
|
|
294
|
+
if (path.length > 1) {
|
|
295
|
+
// Deep path handling for references
|
|
296
|
+
let obj = this.data;
|
|
297
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
298
|
+
if (typeof obj[path[i]] === 'string' || ObjectId.isValid(obj[path[i]])) {
|
|
299
|
+
const ref = await this.resolveReference(obj[path[i]].toString());
|
|
300
|
+
if (!ref)
|
|
301
|
+
throw new Error("Could not resolve reference on path: " + key);
|
|
302
|
+
return await ref.setValue(path.slice(i + 1).join("."), val);
|
|
445
303
|
}
|
|
446
|
-
lastClass = temp;
|
|
447
|
-
lastPath = path.slice(i + 1).join(".");
|
|
448
|
-
const res = await lastClass.setValue(lastPath, val);
|
|
449
|
-
if (!noUpdate)
|
|
450
|
-
await this.onUpdate(noUpdate);
|
|
451
|
-
return res;
|
|
452
|
-
}
|
|
453
|
-
else
|
|
454
304
|
obj = obj[path[i]];
|
|
455
|
-
}
|
|
456
|
-
if (lastClass !== this) {
|
|
457
|
-
message +=
|
|
458
|
-
"\n What the actual fuckity fuck error on path: " +
|
|
459
|
-
path +
|
|
460
|
-
" on index: " +
|
|
461
|
-
(path.length - 1);
|
|
462
|
-
this.loggers.error("Failed to set value for " + this.className + "\n" + message);
|
|
463
|
-
return {
|
|
464
|
-
success: false,
|
|
465
|
-
msg: message,
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
if (!this.properties.includes(lastPath) && !lastPath.includes(".")) {
|
|
469
|
-
let nearest = "";
|
|
470
|
-
for (const prop of this.properties) {
|
|
471
|
-
if (typeof prop !== "string")
|
|
472
|
-
continue;
|
|
473
|
-
if (stringSimilarity(lastPath, prop) > 0 &&
|
|
474
|
-
stringSimilarity(lastPath, prop) > stringSimilarity(nearest, prop)) {
|
|
475
|
-
nearest = prop;
|
|
476
|
-
}
|
|
477
305
|
}
|
|
478
|
-
throw new Error(`Property ${lastPath} not found in class ${this.className}, did you mean ${nearest ?? "--No similar prop found--"}?`);
|
|
479
306
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
if (!parentObj) {
|
|
488
|
-
message +=
|
|
489
|
-
"\n Failed to set value for " +
|
|
490
|
-
this.className +
|
|
491
|
-
" parent not found";
|
|
492
|
-
this.loggers.error(message);
|
|
493
|
-
return { success: false, msg: message };
|
|
494
|
-
}
|
|
495
|
-
if (parentObj.getValue(isPopulated[1]) &&
|
|
496
|
-
!Array.isArray(parentObj.getValue(isPopulated[1]))) {
|
|
497
|
-
message +=
|
|
498
|
-
"\nThis is a 1:1 relationship and the parent already has a parent with the ID: " +
|
|
499
|
-
(parentObj.getValue(isPopulated[1])._id?.toString() ??
|
|
500
|
-
parentObj.getValue(isPopulated[1]).toString()) +
|
|
501
|
-
this.loggers.error(message);
|
|
502
|
-
return { success: false, msg: message };
|
|
503
|
-
}
|
|
504
|
-
let res;
|
|
505
|
-
if (this.isServer) {
|
|
506
|
-
const value = parentObj.getValue(isPopulated[1]);
|
|
507
|
-
if (Array.isArray(value)) {
|
|
508
|
-
if (value
|
|
509
|
-
.map((v) => v._id?.toString() ?? v.toString())
|
|
510
|
-
.includes(this.data._id.toString()))
|
|
511
|
-
return {
|
|
512
|
-
success: true,
|
|
513
|
-
msg: message + "\nValue already set",
|
|
514
|
-
};
|
|
515
|
-
res = await parentObj.setValue__(isPopulated[1], value.concat(this.data._id.toString()), false, false, true);
|
|
516
|
-
}
|
|
517
|
-
else {
|
|
518
|
-
if ((value?._id?.toString() ?? value?.toString()) ===
|
|
519
|
-
this.data._id.toString())
|
|
520
|
-
return {
|
|
521
|
-
success: true,
|
|
522
|
-
msg: message + "\nValue already set",
|
|
523
|
-
};
|
|
524
|
-
res = await parentObj.setValue__(isPopulated[1], this.data._id.toString(), false, false, true);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
const value = parentObj.getValue(isPopulated[1]);
|
|
529
|
-
if (Array.isArray(value)
|
|
530
|
-
? value
|
|
531
|
-
.map((v) => v._id?.toString() ?? v.toString())
|
|
532
|
-
.includes(this.data._id.toString())
|
|
533
|
-
: (value._id?.toString() ?? value.toString()) ===
|
|
534
|
-
this.data._id.toString())
|
|
535
|
-
return { success: true, msg: message + "\nValue already set" };
|
|
536
|
-
({ res, val } = await this.preInnerSetValue(noGet, key, val, lastPath, silent, noUpdate));
|
|
537
|
-
}
|
|
538
|
-
success = res.success;
|
|
539
|
-
message +=
|
|
540
|
-
"\nReport from inner setValue function: " +
|
|
541
|
-
res.msg.split("\n").join("\n ");
|
|
542
|
-
}
|
|
543
|
-
else {
|
|
544
|
-
const originalParenValue = this.getValue(key).getValue(isPopulated[1]);
|
|
545
|
-
if (!originalParenValue ||
|
|
546
|
-
(Array.isArray(originalParenValue) &&
|
|
547
|
-
!originalParenValue.some((v) => (v._id?.toString() ?? v.toString()) === this._id.toString()))) {
|
|
548
|
-
message += "\n Value already set";
|
|
549
|
-
return { success: true, msg: message };
|
|
550
|
-
}
|
|
551
|
-
const parentObj = this.parentManager.managers[isPopulated[0]].getObject(originalVal);
|
|
552
|
-
if (!parentObj) {
|
|
553
|
-
message +=
|
|
554
|
-
"\n Failed to set value for " +
|
|
555
|
-
this.className +
|
|
556
|
-
" parent not found";
|
|
557
|
-
this.loggers.error(message);
|
|
558
|
-
return { success: false, msg: message };
|
|
559
|
-
}
|
|
560
|
-
let res;
|
|
561
|
-
if (Array.isArray(originalParenValue)) {
|
|
562
|
-
res = await parentObj.setValue__(isPopulated[1], originalParenValue
|
|
563
|
-
.map((v) => v._id?.toString() ?? v.toString())
|
|
564
|
-
.filter((v) => v !== this._id.toString()));
|
|
565
|
-
}
|
|
566
|
-
else {
|
|
567
|
-
res = await parentObj.setValue__(isPopulated[1], null);
|
|
568
|
-
}
|
|
569
|
-
success = res.success;
|
|
570
|
-
message +=
|
|
571
|
-
"\nReport from inner setValue function: " +
|
|
572
|
-
res.msg.split("\n").join("\n ");
|
|
573
|
-
}
|
|
307
|
+
const res = await this.setValueInternal(key, valueToStore, silent, noUpdate);
|
|
308
|
+
if (res.success) {
|
|
309
|
+
// Apply update to this.data (handling deep paths)
|
|
310
|
+
const pathArr = key.split(".");
|
|
311
|
+
let obj = this.data;
|
|
312
|
+
for (let i = 0; i < pathArr.length - 1; i++) {
|
|
313
|
+
obj = obj[pathArr[i]];
|
|
574
314
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
? val.map((v) => new ObjectId(v))
|
|
582
|
-
: new ObjectId(val);
|
|
583
|
-
let res;
|
|
584
|
-
({ res, val } = await this.preInnerSetValue(noGet, key, val, lastPath, silent, noUpdate));
|
|
585
|
-
if (res.success) {
|
|
586
|
-
const originalValue = obj[path.at(-1)];
|
|
587
|
-
if (!Array.isArray(val) && Array.isArray(originalValue)) {
|
|
588
|
-
if (!originalValue.includes(val))
|
|
589
|
-
originalValue.push(val);
|
|
590
|
-
val = originalValue;
|
|
591
|
-
}
|
|
592
|
-
else
|
|
593
|
-
obj[path.at(-1)] = val;
|
|
594
|
-
}
|
|
595
|
-
success = res.success;
|
|
596
|
-
message += "\nReport from inner setValue function: \n " + res.msg;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
catch (error) {
|
|
600
|
-
success = false;
|
|
601
|
-
message += "\nError from inner setValue function: \n " + error.message;
|
|
602
|
-
message += error.stack;
|
|
315
|
+
obj[pathArr[pathArr.length - 1]] = valueToStore;
|
|
316
|
+
await this.findAndLoadReferences(key, valueToStore);
|
|
317
|
+
if (isRef && this.parentManager.isLoaded)
|
|
318
|
+
await this.contactChildren();
|
|
319
|
+
if (this.isLoaded)
|
|
320
|
+
this.callbacks.update(this, key);
|
|
603
321
|
}
|
|
604
|
-
|
|
605
|
-
this.loggers.warn("Failed to set value for " + this.className + "\n" + message);
|
|
606
|
-
return { success: false, msg: message };
|
|
607
|
-
}
|
|
608
|
-
const pathArr = lastPath.split(".");
|
|
609
|
-
if (pathArr.length === 1) {
|
|
610
|
-
this.data[key] = val;
|
|
611
|
-
}
|
|
612
|
-
else {
|
|
613
|
-
const last = pathArr.splice(-1, 1);
|
|
614
|
-
let ref = this;
|
|
615
|
-
for (const p of pathArr) {
|
|
616
|
-
ref = ref[p];
|
|
617
|
-
}
|
|
618
|
-
ref[last.at(-1)] = val;
|
|
619
|
-
}
|
|
620
|
-
if (!noUpdate)
|
|
621
|
-
await this.onUpdate(noUpdate);
|
|
622
|
-
await this.findAndLoadReferences(lastPath, val);
|
|
623
|
-
const isRef = getMetadataRecursive("isRef", this, path.at(-1));
|
|
624
|
-
if (isRef && this.parentManager.isLoaded) {
|
|
625
|
-
await this.contactChildren();
|
|
626
|
-
}
|
|
627
|
-
if (this.isLoaded)
|
|
628
|
-
this.callbacks.update(this, key);
|
|
629
|
-
return {
|
|
630
|
-
success: true,
|
|
631
|
-
msg: "Successfully set " + key + " to " + val,
|
|
632
|
-
};
|
|
322
|
+
return res;
|
|
633
323
|
}
|
|
634
324
|
catch (error) {
|
|
635
|
-
this.loggers.error(
|
|
636
|
-
|
|
637
|
-
"\n" +
|
|
638
|
-
message +
|
|
639
|
-
"\n Random error here: " +
|
|
640
|
-
error.message +
|
|
641
|
-
"\n" +
|
|
642
|
-
error.stack);
|
|
643
|
-
this.loggers.error(error);
|
|
644
|
-
return {
|
|
645
|
-
success: false,
|
|
646
|
-
msg: message +
|
|
647
|
-
"\n Random error here: " +
|
|
648
|
-
error.message +
|
|
649
|
-
"\n" +
|
|
650
|
-
error.stack,
|
|
651
|
-
};
|
|
325
|
+
this.loggers.error(`Error setting value ${key}: ${error.message}`);
|
|
326
|
+
return { success: false, msg: error.message };
|
|
652
327
|
}
|
|
653
328
|
}
|
|
654
|
-
async
|
|
655
|
-
if (
|
|
656
|
-
|
|
657
|
-
this.getValue(key) &&
|
|
658
|
-
Array.isArray(this.getValue(key)) &&
|
|
659
|
-
!Array.isArray(val)) {
|
|
660
|
-
val = [
|
|
661
|
-
...new Set(this.getValue(key)
|
|
662
|
-
.concat(val)
|
|
663
|
-
.map((v) => v?._id?.toString() ?? new ObjectId(v))
|
|
664
|
-
.filter(Boolean)),
|
|
665
|
-
];
|
|
329
|
+
async setValueInternal(key, value, silent = false, noUpdate = false) {
|
|
330
|
+
if (silent) {
|
|
331
|
+
return { success: true, msg: "Silent" };
|
|
666
332
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
333
|
+
return new Promise((resolve) => {
|
|
334
|
+
this.socket.emit(EVENT_UPDATE + this.className + this.data._id, { _id: this.data._id.toString(), key, value }, (res) => {
|
|
335
|
+
resolve({ success: res.success, msg: res.message ?? (res.success ? "Success" : "Error") });
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
makeUpdate(key, value) {
|
|
340
|
+
return { _id: this.data._id.toString(), key, value };
|
|
341
|
+
}
|
|
342
|
+
async resolveReference(id) {
|
|
343
|
+
for (const manager of Object.values(this.parentManager.managers)) {
|
|
344
|
+
const obj = manager.getObject(id);
|
|
345
|
+
if (obj)
|
|
346
|
+
return obj;
|
|
679
347
|
}
|
|
680
|
-
return
|
|
348
|
+
return null;
|
|
681
349
|
}
|
|
682
350
|
async findAndLoadReferences(lastPath, value) {
|
|
683
351
|
const isRef = getMetadataRecursive("isRef", this, lastPath);
|
|
@@ -691,121 +359,21 @@ export class AutoUpdatedClientObject {
|
|
|
691
359
|
if (result)
|
|
692
360
|
break;
|
|
693
361
|
}
|
|
694
|
-
if (!result) {
|
|
695
|
-
for (const manager of Object.values(this.parentManager.managers)) {
|
|
696
|
-
try {
|
|
697
|
-
result = await manager.handleGetMissingObject(id?.toString());
|
|
698
|
-
if (result)
|
|
699
|
-
break;
|
|
700
|
-
}
|
|
701
|
-
catch (error) {
|
|
702
|
-
const _ = error;
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
if (!result) {
|
|
706
|
-
this.loggers.warn("Failed to update childerns parent for " +
|
|
707
|
-
this.className +
|
|
708
|
-
" updating " +
|
|
709
|
-
id +
|
|
710
|
-
"'s parent to " +
|
|
711
|
-
this.data._id);
|
|
712
|
-
continue;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
362
|
if (result && typeof result.loadMissingReferences === "function") {
|
|
716
363
|
await result.loadMissingReferences();
|
|
717
364
|
}
|
|
718
|
-
else if (result) {
|
|
719
|
-
this.loggers.warn(`Object in reference resolution is missing loadMissingReferences function. Type: ${typeof result}, ID: ${result._id ?? result}`);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
getValue(key_) {
|
|
725
|
-
const key = key_;
|
|
726
|
-
if (!key.includes(".")) {
|
|
727
|
-
let val = this[key];
|
|
728
|
-
val ??= this.data[key];
|
|
729
|
-
return val;
|
|
730
|
-
}
|
|
731
|
-
let value;
|
|
732
|
-
const parts = key.split(".");
|
|
733
|
-
for (const part of parts) {
|
|
734
|
-
try {
|
|
735
|
-
if (value !== undefined && value !== null) {
|
|
736
|
-
value = value[part];
|
|
737
|
-
}
|
|
738
|
-
else {
|
|
739
|
-
value = this[part];
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
catch (error) {
|
|
743
|
-
this.loggers.error(`Error getting value for ${this.className} on key ${key} at index ${part}: ${error.message}`);
|
|
744
|
-
return undefined;
|
|
745
365
|
}
|
|
746
366
|
}
|
|
747
|
-
return value;
|
|
748
|
-
}
|
|
749
|
-
async setValueInternal(key, value, silent = false, noUpdate = false) {
|
|
750
|
-
const update = this.makeUpdate(key, value);
|
|
751
|
-
const promise = new Promise((resolve) => {
|
|
752
|
-
if (silent) {
|
|
753
|
-
if (noUpdate)
|
|
754
|
-
return resolve({ success: true, msg: "Success - no update" });
|
|
755
|
-
return this.onUpdate(true).then(() => {
|
|
756
|
-
if (this.isLoaded)
|
|
757
|
-
this.callbacks.update(this, key);
|
|
758
|
-
return resolve({ success: true, msg: "Success - silent" });
|
|
759
|
-
});
|
|
760
|
-
}
|
|
761
|
-
try {
|
|
762
|
-
this.socket.emit(EVENT_UPDATE + this.className + this.data._id, update, async (res) => {
|
|
763
|
-
if (!res.success) {
|
|
764
|
-
this.loggers.error("Error sending update: " + res.message);
|
|
765
|
-
resolve({ success: false, msg: res.message });
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
768
|
-
if (!noUpdate)
|
|
769
|
-
await this.onUpdate(noUpdate);
|
|
770
|
-
resolve({
|
|
771
|
-
success: res.success,
|
|
772
|
-
msg: res.message ?? "Success",
|
|
773
|
-
});
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
catch (error) {
|
|
777
|
-
this.loggers.error("Error sending update:" + error.message);
|
|
778
|
-
this.loggers.error(error.stack);
|
|
779
|
-
resolve({ success: false, msg: error.message });
|
|
780
|
-
}
|
|
781
|
-
});
|
|
782
|
-
return promise;
|
|
783
367
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
this.loggers.error("Probably missing the fucking identifier ['_id'] again: " +
|
|
791
|
-
error.message);
|
|
792
|
-
throw error;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
async onUpdate(_) {
|
|
796
|
-
return;
|
|
797
|
-
}
|
|
798
|
-
// return a properly typed AutoUpdatedClientClass (or null)
|
|
799
|
-
// inside AutoUpdatedClientClass
|
|
800
|
-
async resolveReference(id) {
|
|
801
|
-
if (!this.parentManager)
|
|
802
|
-
throw new Error("No Manager");
|
|
803
|
-
for (const manager of Object.values(this.parentManager.managers)) {
|
|
804
|
-
const data = manager.getObject(id);
|
|
805
|
-
if (data)
|
|
806
|
-
return data;
|
|
368
|
+
async wipeSelf() {
|
|
369
|
+
if (this.data.Wiped)
|
|
370
|
+
return;
|
|
371
|
+
const _id = this.data._id.toString();
|
|
372
|
+
for (const key of Object.keys(this.data)) {
|
|
373
|
+
delete this.data[key];
|
|
807
374
|
}
|
|
808
|
-
|
|
375
|
+
this.data = { Wiped: true };
|
|
376
|
+
this.loggers.info(`[${_id}] ${this.className} object wiped`);
|
|
809
377
|
}
|
|
810
378
|
async loadForceReferences(obj = this.data, proto = this, alreadySeen = []) {
|
|
811
379
|
const props = Reflect.getMetadata("props", proto) || [];
|
|
@@ -814,307 +382,144 @@ export class AutoUpdatedClientObject {
|
|
|
814
382
|
continue;
|
|
815
383
|
const isRef = Reflect.getMetadata("isRef", proto, key);
|
|
816
384
|
const pointer = Reflect.getMetadata("refsTo", proto, key);
|
|
817
|
-
if (pointer &&
|
|
818
|
-
obj === this.data &&
|
|
819
|
-
obj[key] &&
|
|
820
|
-
!alreadySeen.includes(obj))
|
|
385
|
+
if (pointer && obj === this.data && obj[key] && !alreadySeen.includes(obj)) {
|
|
821
386
|
await this.createdWithParent(pointer.split(":"), obj[key]);
|
|
387
|
+
}
|
|
822
388
|
if (obj[key] && !alreadySeen.includes(obj[key]))
|
|
823
389
|
alreadySeen.push(obj[key]);
|
|
824
|
-
if (isRef)
|
|
390
|
+
if (isRef)
|
|
825
391
|
await this.handleLoad(obj, key, alreadySeen);
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
const nestedProto = Object.getPrototypeOf(val);
|
|
834
|
-
if (nestedProto && !alreadySeen.includes(val)) {
|
|
835
|
-
alreadySeen.push(val);
|
|
836
|
-
await this.loadForceReferences(val, nestedProto, alreadySeen);
|
|
392
|
+
const val = obj[key];
|
|
393
|
+
if (val && typeof val === "object") {
|
|
394
|
+
const nestedProto = Object.getPrototypeOf(val);
|
|
395
|
+
if (nestedProto && !alreadySeen.includes(val)) {
|
|
396
|
+
alreadySeen.push(val);
|
|
397
|
+
await this.loadForceReferences(val, nestedProto, alreadySeen);
|
|
398
|
+
}
|
|
837
399
|
}
|
|
838
400
|
}
|
|
839
401
|
}
|
|
840
402
|
async handleLoad(obj, key, alreadySeen) {
|
|
841
|
-
if (!this.parentManager)
|
|
842
|
-
throw new Error("No manager");
|
|
843
403
|
const refIds = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
|
|
844
404
|
for (const refId of refIds) {
|
|
845
405
|
if (refId) {
|
|
846
406
|
const idStr = refId.toString();
|
|
847
|
-
|
|
848
|
-
if (
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
407
|
+
let result = globalCache.objects[idStr]?.object;
|
|
408
|
+
if (!result) {
|
|
409
|
+
for (const manager of Object.values(this.parentManager.managers)) {
|
|
410
|
+
result = manager.getObject(idStr);
|
|
411
|
+
if (result)
|
|
412
|
+
break;
|
|
853
413
|
}
|
|
854
|
-
continue;
|
|
855
414
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
alreadySeen.push(idStr);
|
|
860
|
-
await result.loadForceReferences(undefined, undefined, alreadySeen);
|
|
861
|
-
break;
|
|
862
|
-
}
|
|
415
|
+
if (result && !alreadySeen.includes(idStr)) {
|
|
416
|
+
alreadySeen.push(idStr);
|
|
417
|
+
await result.loadForceReferences(undefined, undefined, alreadySeen);
|
|
863
418
|
}
|
|
864
419
|
}
|
|
865
420
|
}
|
|
866
421
|
}
|
|
867
422
|
async createdWithParent(pointer, parent) {
|
|
868
|
-
if (pointer.length !== 2)
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
this.className +
|
|
873
|
-
", poiter must be 'className:pathToParentProperty'");
|
|
874
|
-
}
|
|
875
|
-
if (!parent)
|
|
876
|
-
throw new Error("Invalid pointer: " +
|
|
877
|
-
JSON.stringify(pointer) +
|
|
878
|
-
" for " +
|
|
879
|
-
this.className +
|
|
880
|
-
", parent is null");
|
|
881
|
-
const obj = this.parentManager.managers[pointer[0]]?.getObject(parent._id?.toString() ?? parent.toString());
|
|
423
|
+
if (pointer.length !== 2)
|
|
424
|
+
return;
|
|
425
|
+
const parentId = parent._id?.toString() ?? parent.toString();
|
|
426
|
+
const obj = this.parentManager.managers[pointer[0]]?.getObject(parentId);
|
|
882
427
|
if (!obj)
|
|
883
428
|
return;
|
|
884
429
|
const val = obj.getValue(pointer[1]);
|
|
430
|
+
const myId = this.data._id.toString();
|
|
885
431
|
if (Array.isArray(val)) {
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
await obj.setValue__(pointer[1], filtred, true, false, true);
|
|
890
|
-
this.loggers.warn("Array value changed from " +
|
|
891
|
-
originalLength +
|
|
892
|
-
" to " +
|
|
893
|
-
filtred.length +
|
|
894
|
-
" - some values were undefined");
|
|
432
|
+
const ids = val.map(v => v._id?.toString() ?? v.toString());
|
|
433
|
+
if (!ids.includes(myId)) {
|
|
434
|
+
await obj.setValue__(pointer[1], [...val, myId], true, false, true);
|
|
895
435
|
}
|
|
896
|
-
|
|
436
|
+
else {
|
|
897
437
|
await obj.contactChildren();
|
|
898
|
-
|
|
899
|
-
await obj.setValue__(pointer[1], [
|
|
900
|
-
...new Set([...filtred, this.data._id]),
|
|
901
|
-
], true, false, true);
|
|
438
|
+
}
|
|
902
439
|
}
|
|
903
|
-
else if (val?.toString()
|
|
440
|
+
else if ((val?._id?.toString() ?? val?.toString()) === myId) {
|
|
904
441
|
await obj.contactChildren();
|
|
905
|
-
|
|
906
|
-
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
await obj.setValue__(pointer[1], myId, true, false, true);
|
|
445
|
+
}
|
|
907
446
|
}
|
|
908
447
|
async destroy(once = false) {
|
|
909
|
-
if (!once)
|
|
448
|
+
if (!once)
|
|
910
449
|
return await this.parentManager.deleteObject(this.data._id);
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if (!res.success) {
|
|
915
|
-
this.loggers.error("Error deleting object from database - " +
|
|
916
|
-
this.className +
|
|
917
|
-
" - " +
|
|
918
|
-
this.data._id);
|
|
919
|
-
this.loggers.error(res.message);
|
|
920
|
-
resolve({
|
|
921
|
-
success: false,
|
|
922
|
-
message: res.message,
|
|
923
|
-
});
|
|
924
|
-
return;
|
|
925
|
-
}
|
|
926
|
-
resolve({
|
|
927
|
-
success: true,
|
|
928
|
-
message: "Deleted",
|
|
929
|
-
});
|
|
450
|
+
return new Promise((resolve) => {
|
|
451
|
+
this.socket.emit(EVENT_DELETE + this.className, this.data._id, (res) => {
|
|
452
|
+
resolve({ success: res.success, message: res.message ?? "" });
|
|
930
453
|
});
|
|
931
454
|
});
|
|
932
|
-
return res;
|
|
933
455
|
}
|
|
934
456
|
async checkForMissingRefs() {
|
|
935
457
|
for (const prop of this.properties) {
|
|
936
|
-
|
|
458
|
+
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
937
459
|
if (pointer) {
|
|
938
|
-
|
|
939
|
-
if (
|
|
940
|
-
|
|
941
|
-
await this.findMissingObjectReference(prop, pointer);
|
|
460
|
+
const parts = pointer.split(":");
|
|
461
|
+
if (parts.length === 2)
|
|
462
|
+
await this.findMissingObjectReference(prop, parts);
|
|
942
463
|
}
|
|
943
464
|
}
|
|
944
465
|
}
|
|
945
466
|
async findMissingObjectReference(prop, pointer) {
|
|
946
|
-
if (this.checkedMissingRefs
|
|
467
|
+
if (this.checkedMissingRefs)
|
|
947
468
|
return;
|
|
948
469
|
this.checkedMissingRefs = true;
|
|
949
470
|
const ac = this.parentManager.managers[pointer[0]];
|
|
950
471
|
if (!ac)
|
|
951
|
-
|
|
472
|
+
return;
|
|
952
473
|
const targetId = this.data._id.toString();
|
|
953
|
-
const pointerKey = pointer[1];
|
|
954
|
-
const isNested = pointerKey.includes(".");
|
|
955
|
-
const pathParts = isNested ? pointerKey.split(".") : [];
|
|
956
474
|
const allObjects = Object.values(ac.objects);
|
|
957
|
-
const pendingObjects = allObjects.filter(obj => !obj.isLoaded);
|
|
958
|
-
if (pendingObjects.length > 0) {
|
|
959
|
-
await Promise.all(pendingObjects.map(obj => obj.waitForPreloaded()));
|
|
960
|
-
}
|
|
961
475
|
for (const obj of allObjects) {
|
|
962
|
-
if (!obj.isLoaded)
|
|
476
|
+
if (!obj.isLoaded)
|
|
963
477
|
await obj.waitForPreloaded();
|
|
964
|
-
|
|
965
|
-
let val;
|
|
966
|
-
if (isNested) {
|
|
967
|
-
val = obj;
|
|
968
|
-
for (const element of pathParts) {
|
|
969
|
-
if (!val)
|
|
970
|
-
break;
|
|
971
|
-
val = val[element] ?? val.data?.[element];
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
val = obj[pointerKey] ?? obj.data?.[pointerKey];
|
|
976
|
-
}
|
|
478
|
+
const val = obj.getValue(pointer[1]);
|
|
977
479
|
if (!val)
|
|
978
480
|
continue;
|
|
979
|
-
|
|
980
|
-
if (
|
|
981
|
-
for (let i = 0; i < val.length; i++) {
|
|
982
|
-
const item = val[i];
|
|
983
|
-
if (!item)
|
|
984
|
-
continue;
|
|
985
|
-
const idStr = item._id ? item._id.toString() : item.toString();
|
|
986
|
-
if (idStr === targetId) {
|
|
987
|
-
found = true;
|
|
988
|
-
break;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
const idStr = val._id ? val._id.toString() : val.toString();
|
|
994
|
-
found = (idStr === targetId);
|
|
995
|
-
}
|
|
996
|
-
if (found) {
|
|
481
|
+
const ids = Array.isArray(val) ? val.map(v => v._id?.toString() ?? v.toString()) : [val._id?.toString() ?? val.toString()];
|
|
482
|
+
if (ids.includes(targetId)) {
|
|
997
483
|
this.data[prop] = obj._id;
|
|
998
484
|
return;
|
|
999
485
|
}
|
|
1000
486
|
}
|
|
1001
487
|
}
|
|
1002
|
-
async wipeSelf() {
|
|
1003
|
-
if (this.data.Wiped)
|
|
1004
|
-
return;
|
|
1005
|
-
const _id = this.data._id.toString();
|
|
1006
|
-
for (const key of Object.keys(this.data)) {
|
|
1007
|
-
delete this.data[key];
|
|
1008
|
-
}
|
|
1009
|
-
this.data = { Wiped: true };
|
|
1010
|
-
this.loggers.info(`[${_id}] ${this.className} object wiped`);
|
|
1011
|
-
}
|
|
1012
488
|
async contactChildren() {
|
|
1013
|
-
let childsManager = null;
|
|
1014
|
-
const findMissingObjectWithoutKnownManager = async (o) => {
|
|
1015
|
-
if (o instanceof AutoUpdatedClientObject)
|
|
1016
|
-
return o;
|
|
1017
|
-
if (childsManager)
|
|
1018
|
-
try {
|
|
1019
|
-
return await childsManager.handleGetMissingObject(o._id?.toString() ?? o.toString());
|
|
1020
|
-
}
|
|
1021
|
-
catch (error) {
|
|
1022
|
-
this.loggers.error("This should fucking not happen wtffffff");
|
|
1023
|
-
this.loggers.error(error.message);
|
|
1024
|
-
childsManager = null;
|
|
1025
|
-
}
|
|
1026
|
-
else {
|
|
1027
|
-
for (const manager of Object.values(this.parentManager.managers)) {
|
|
1028
|
-
try {
|
|
1029
|
-
const newO = await manager.handleGetMissingObject(o._id?.toString() ?? o.toString());
|
|
1030
|
-
childsManager = manager;
|
|
1031
|
-
return newO;
|
|
1032
|
-
}
|
|
1033
|
-
catch (e) {
|
|
1034
|
-
const _ = e;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
return undefined;
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
489
|
for (const prop of this.properties) {
|
|
1041
|
-
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
1042
490
|
const isRef = getMetadataRecursive("isRef", this, prop.toString());
|
|
491
|
+
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
1043
492
|
if (!isRef || pointer)
|
|
1044
493
|
continue;
|
|
1045
|
-
|
|
1046
|
-
if (!obj || (Array.isArray(obj) && obj.length == 0)) {
|
|
1047
|
-
obj = this.getValueInternal(prop);
|
|
1048
|
-
try {
|
|
1049
|
-
if (Array.isArray(obj))
|
|
1050
|
-
obj = await Promise.all(obj.map(findMissingObjectWithoutKnownManager));
|
|
1051
|
-
else
|
|
1052
|
-
obj = await findMissingObjectWithoutKnownManager(obj);
|
|
1053
|
-
}
|
|
1054
|
-
catch (error) {
|
|
1055
|
-
const _ = error;
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
494
|
+
const obj = this.getValue(prop);
|
|
1058
495
|
if (!obj)
|
|
1059
496
|
continue;
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
await child.loadMissingReferences();
|
|
1065
|
-
}
|
|
1066
|
-
else if (child) {
|
|
1067
|
-
this.loggers.warn(`Object in property ${prop.toString()} is missing loadMissingReferences function. Type: ${typeof child}, ID: ${child._id ?? child}`);
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
catch (error) {
|
|
1071
|
-
this.loggers.error(error.message);
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
else {
|
|
1076
|
-
if (obj && typeof obj.loadMissingReferences === "function") {
|
|
1077
|
-
await obj.loadMissingReferences();
|
|
1078
|
-
}
|
|
1079
|
-
else if (obj) {
|
|
1080
|
-
this.loggers.warn(`Object in property ${prop.toString()} is missing loadMissingReferences function. Type: ${typeof obj}, ID: ${obj._id ?? obj}`);
|
|
497
|
+
const children = Array.isArray(obj) ? obj : [obj];
|
|
498
|
+
for (const child of children) {
|
|
499
|
+
if (child && typeof child.loadMissingReferences === "function") {
|
|
500
|
+
await child.loadMissingReferences();
|
|
1081
501
|
}
|
|
1082
502
|
}
|
|
1083
503
|
}
|
|
1084
504
|
}
|
|
1085
|
-
getValueInternal(key) {
|
|
1086
|
-
const keys = key.toString().split(".");
|
|
1087
|
-
let value = this.data;
|
|
1088
|
-
for (const k of keys) {
|
|
1089
|
-
value = value[k];
|
|
1090
|
-
}
|
|
1091
|
-
return value;
|
|
1092
|
-
}
|
|
1093
505
|
}
|
|
1094
|
-
export function processIsRefProperties(instance, target, prefix
|
|
506
|
+
export function processIsRefProperties(instance, target, prefix, allProps, newData, loggers) {
|
|
1095
507
|
const props = Reflect.getMetadata("props", target) || [];
|
|
1096
508
|
for (const prop of props) {
|
|
1097
509
|
const path = prefix ? `${prefix}.${prop}` : prop;
|
|
1098
510
|
allProps.push(path);
|
|
1099
|
-
newData[prop] = ObjectId.isValid(instance[prop])
|
|
1100
|
-
? instance[prop]?.toString()
|
|
1101
|
-
: instance[prop];
|
|
511
|
+
newData[prop] = ObjectId.isValid(instance[prop]) ? instance[prop]?.toString() : instance[prop];
|
|
1102
512
|
if (Reflect.getMetadata("isRef", target, prop)) {
|
|
1103
513
|
if (Array.isArray(instance[prop]))
|
|
1104
|
-
newData[prop] = instance[prop]
|
|
1105
|
-
.map((item) => item?._id?.toString() ?? item?.toString() ?? undefined)
|
|
1106
|
-
.filter(Boolean);
|
|
514
|
+
newData[prop] = instance[prop].map((item) => item?._id?.toString() ?? item?.toString()).filter(Boolean);
|
|
1107
515
|
else
|
|
1108
|
-
newData[prop] =
|
|
1109
|
-
instance[prop]?._id?.toString() ??
|
|
1110
|
-
instance[prop]?.toString() ??
|
|
1111
|
-
undefined;
|
|
516
|
+
newData[prop] = instance[prop]?._id?.toString() ?? instance[prop]?.toString();
|
|
1112
517
|
}
|
|
1113
518
|
const type = Reflect.getMetadata("design:type", target, prop);
|
|
1114
519
|
if (type?.prototype) {
|
|
1115
520
|
const nestedProps = Reflect.getMetadata("props", type.prototype);
|
|
1116
521
|
if (nestedProps && instance[prop]) {
|
|
1117
|
-
newData[prop] = processIsRefProperties(instance[prop], type.prototype, path, allProps,
|
|
522
|
+
newData[prop] = processIsRefProperties(instance[prop], type.prototype, path, allProps, {}, loggers).newData;
|
|
1118
523
|
}
|
|
1119
524
|
}
|
|
1120
525
|
}
|