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