@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.
- package/dist/AutoUpdateManagerClass.d.ts +3 -3
- package/dist/AutoUpdateManagerClass.js +2 -4
- package/dist/AutoUpdateManagerClass.js.map +1 -1
- package/dist/AutoUpdateServerManagerClass.d.ts +3 -3
- package/dist/AutoUpdateServerManagerClass.js +37 -33
- package/dist/AutoUpdateServerManagerClass.js.map +1 -1
- package/dist/AutoUpdatedClientObjectClass.d.ts +15 -15
- package/dist/AutoUpdatedClientObjectClass.js +229 -783
- package/dist/AutoUpdatedClientObjectClass.js.map +1 -1
- package/dist/AutoUpdatedServerObjectClass.d.ts +4 -3
- package/dist/AutoUpdatedServerObjectClass.js +29 -4
- package/dist/AutoUpdatedServerObjectClass.js.map +1 -1
- package/dist/CommonTypes.d.ts +2 -2
- package/dist/CommonTypes.js +3 -3
- package/dist/CommonTypes.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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;
|
|
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.
|
|
104
|
+
this.generateSettersAndGetters();
|
|
149
105
|
return;
|
|
150
106
|
}
|
|
151
|
-
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
317
|
-
const k = key;
|
|
224
|
+
continue;
|
|
318
225
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
319
226
|
Object.defineProperty(this, key, {
|
|
320
227
|
get: () => {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
330
|
-
return result;
|
|
234
|
+
return this.findReference(val, key);
|
|
331
235
|
}
|
|
332
236
|
}
|
|
333
|
-
|
|
334
|
-
|
|
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 (
|
|
343
|
-
return
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
if (
|
|
384
|
-
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
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
|
-
|
|
591
|
-
message += "\nReport from inner setValue function: \n " + res.msg;
|
|
316
|
+
obj = obj[currentKey];
|
|
592
317
|
}
|
|
593
318
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
|
|
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(
|
|
631
|
-
|
|
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
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
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
|
|
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
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
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
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
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
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
|
871
|
-
|
|
872
|
-
|
|
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()
|
|
888
|
-
await obj.
|
|
889
|
-
|
|
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
|
-
|
|
897
|
-
|
|
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
|
-
|
|
476
|
+
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
921
477
|
if (pointer) {
|
|
922
|
-
|
|
923
|
-
if (
|
|
924
|
-
|
|
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
|
|
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
|
-
|
|
490
|
+
return;
|
|
936
491
|
const targetId = this.data._id.toString();
|
|
937
|
-
const
|
|
938
|
-
const
|
|
939
|
-
|
|
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
|
-
|
|
963
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
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
|
-
|
|
522
|
+
this.generateSettersAndGetters();
|
|
1075
523
|
}
|
|
1076
524
|
}
|
|
1077
|
-
export function processIsRefProperties(instance, target, prefix
|
|
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()
|
|
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,
|
|
546
|
+
newData[prop] = processIsRefProperties(instance[prop], type.prototype, path, allProps, {}, loggers).newData;
|
|
1101
547
|
}
|
|
1102
548
|
}
|
|
1103
549
|
}
|