@prestizni-software/server-dem 0.4.87 → 0.4.89

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