@nymphjs/nymph 1.0.0-beta.6 → 1.0.0-beta.60
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/CHANGELOG.md +273 -0
- package/README.md +13 -21
- package/dist/Entity.d.ts +269 -7
- package/dist/Entity.js +431 -89
- package/dist/Entity.js.map +1 -1
- package/dist/Entity.test.js +38 -16
- package/dist/Entity.test.js.map +1 -1
- package/dist/Entity.types.d.ts +225 -19
- package/dist/Nymph.d.ts +423 -11
- package/dist/Nymph.js +649 -156
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +31 -7
- package/dist/Nymph.types.js +2 -1
- package/dist/Nymph.types.js.map +1 -1
- package/dist/conf/d.d.ts +26 -0
- package/dist/conf/defaults.js +22 -0
- package/dist/conf/defaults.js.map +1 -1
- package/dist/driver/NymphDriver.d.ts +111 -36
- package/dist/driver/NymphDriver.js +169 -68
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/testArtifacts.d.ts +1 -1
- package/dist/driver/testArtifacts.js +285 -18
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/errors/EntityInvalidDataError.d.ts +6 -0
- package/dist/errors/EntityInvalidDataError.js +6 -0
- package/dist/errors/EntityInvalidDataError.js.map +1 -1
- package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
- package/dist/errors/EntityUniqueConstraintError.js +11 -0
- package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
- package/dist/errors/InvalidStateError.d.ts +3 -0
- package/dist/errors/InvalidStateError.js +11 -0
- package/dist/errors/InvalidStateError.js.map +1 -0
- package/dist/errors/QueryFailedError.js.map +1 -1
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/testArtifacts.d.ts +17 -5
- package/dist/testArtifacts.js +23 -19
- package/dist/testArtifacts.js.map +1 -1
- package/dist/testMocks.d.ts +15 -10
- package/dist/testMocks.js +34 -11
- package/dist/testMocks.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +21 -5
- package/dist/utils.js.map +1 -1
- package/package.json +16 -14
- package/src/Entity.test.ts +30 -10
- package/src/Entity.ts +406 -135
- package/src/Entity.types.ts +32 -66
- package/src/Nymph.ts +626 -196
- package/src/Nymph.types.ts +97 -26
- package/src/conf/d.ts +8 -0
- package/src/conf/defaults.ts +24 -0
- package/src/driver/NymphDriver.ts +187 -243
- package/src/driver/testArtifacts.ts +327 -146
- package/src/errors/EntityUniqueConstraintError.ts +6 -0
- package/src/errors/InvalidStateError.ts +6 -0
- package/src/errors/index.ts +4 -0
- package/src/nymphJoiProps.ts +2 -2
- package/src/testArtifacts.ts +18 -19
- package/src/testMocks.ts +64 -32
- package/src/utils.ts +22 -8
- package/tsconfig.json +1 -1
- package/typedoc.json +4 -0
package/src/Entity.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { difference, intersection, isEqual } from 'lodash';
|
|
2
2
|
|
|
3
3
|
import type Nymph from './Nymph';
|
|
4
|
-
import {
|
|
4
|
+
import type { Options } from './Nymph.types';
|
|
5
|
+
import type {
|
|
5
6
|
ACProperties,
|
|
6
7
|
EntityConstructor,
|
|
7
8
|
EntityData,
|
|
@@ -11,13 +12,25 @@ import {
|
|
|
11
12
|
EntityReference,
|
|
12
13
|
SerializedEntityData,
|
|
13
14
|
} from './Entity.types';
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
EntityConflictError,
|
|
17
|
+
EntityIsSleepingReferenceError,
|
|
18
|
+
InvalidParametersError,
|
|
19
|
+
InvalidStateError,
|
|
20
|
+
} from './errors';
|
|
15
21
|
import {
|
|
16
22
|
entitiesToReferences,
|
|
17
23
|
referencesToEntities,
|
|
18
24
|
uniqueStrings,
|
|
19
25
|
} from './utils';
|
|
20
26
|
|
|
27
|
+
export type EntityDataType<T> = T extends Entity<infer DataType>
|
|
28
|
+
? DataType
|
|
29
|
+
: never;
|
|
30
|
+
|
|
31
|
+
export type EntityInstanceType<T extends EntityConstructor> =
|
|
32
|
+
T extends new () => infer E ? E & EntityDataType<E> : never;
|
|
33
|
+
|
|
21
34
|
/**
|
|
22
35
|
* Database abstraction object.
|
|
23
36
|
*
|
|
@@ -45,9 +58,9 @@ import {
|
|
|
45
58
|
*
|
|
46
59
|
* Some notes about $equals() and $is(), the replacements for "==":
|
|
47
60
|
*
|
|
48
|
-
* The == operator will likely not give you the result you want, since
|
|
49
|
-
*
|
|
50
|
-
*
|
|
61
|
+
* The == operator will likely not give you the result you want, since two
|
|
62
|
+
* instances of the same entity will fail that check, even though they represent
|
|
63
|
+
* the same data in the database.
|
|
51
64
|
*
|
|
52
65
|
* $equals() performs a more strict comparison of the entity to another. Use
|
|
53
66
|
* $equals() instead of the == operator when you want to check both the entities
|
|
@@ -56,8 +69,7 @@ import {
|
|
|
56
69
|
*
|
|
57
70
|
* - They must be entities.
|
|
58
71
|
* - They must have equal GUIDs, or both must have no GUID.
|
|
59
|
-
* -
|
|
60
|
-
* - Their data must be equal.
|
|
72
|
+
* - Their data and tags must be equal.
|
|
61
73
|
*
|
|
62
74
|
* $is() performs a less strict comparison of the entity to another. Use $is()
|
|
63
75
|
* instead of the == operator when the entity's data may have been changed, but
|
|
@@ -66,7 +78,7 @@ import {
|
|
|
66
78
|
*
|
|
67
79
|
* - They must be entities.
|
|
68
80
|
* - They must have equal GUIDs, or both must have no GUID.
|
|
69
|
-
* - If they have no GUIDs, their data must be equal.
|
|
81
|
+
* - If they have no GUIDs, their data and tags must be equal.
|
|
70
82
|
*
|
|
71
83
|
* Some notes about saving entities in other entity's properties:
|
|
72
84
|
*
|
|
@@ -137,6 +149,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
137
149
|
* The reference to use to wake.
|
|
138
150
|
*/
|
|
139
151
|
protected $sleepingReference: EntityReference | null = null;
|
|
152
|
+
/**
|
|
153
|
+
* A promise that resolved when the entity's data is wake.
|
|
154
|
+
*/
|
|
155
|
+
protected $wakePromise: Promise<Entity<T>> | null = null;
|
|
140
156
|
/**
|
|
141
157
|
* Properties that will not be serialized into JSON with toJSON(). This
|
|
142
158
|
* can be considered a denylist, because these properties will not be set
|
|
@@ -146,6 +162,18 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
146
162
|
* also listed in searchRestrictedData.
|
|
147
163
|
*/
|
|
148
164
|
protected $privateData: string[] = [];
|
|
165
|
+
/**
|
|
166
|
+
* Whether this entity should publish changes to PubSub servers.
|
|
167
|
+
*/
|
|
168
|
+
public static pubSubEnabled = true;
|
|
169
|
+
/**
|
|
170
|
+
* Whether this entity should be accessible on the frontend through the REST
|
|
171
|
+
* server.
|
|
172
|
+
*
|
|
173
|
+
* If this is false, any request from the client that attempts to use this
|
|
174
|
+
* entity will fail.
|
|
175
|
+
*/
|
|
176
|
+
public static restEnabled = true;
|
|
149
177
|
/**
|
|
150
178
|
* Properties that will not be searchable from the frontend. If the frontend
|
|
151
179
|
* includes any of these properties in any of their clauses, they will be
|
|
@@ -157,8 +185,20 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
157
185
|
* be visible on the frontend, unlike $privateData, but any changes to them
|
|
158
186
|
* that come from the frontend will be ignored.
|
|
159
187
|
*
|
|
160
|
-
* In addition to what's listed here, the
|
|
161
|
-
* be
|
|
188
|
+
* In addition to what's listed here, all of the access control properties
|
|
189
|
+
* will be included when Tilmeld is being used. These are:
|
|
190
|
+
*
|
|
191
|
+
* - acUser
|
|
192
|
+
* - acGroup
|
|
193
|
+
* - acOther
|
|
194
|
+
* - acRead
|
|
195
|
+
* - acWrite
|
|
196
|
+
* - acFull
|
|
197
|
+
* - user
|
|
198
|
+
* - group
|
|
199
|
+
*
|
|
200
|
+
* You should modify these through client enabled methods or the $save method
|
|
201
|
+
* instead, for safety.
|
|
162
202
|
*/
|
|
163
203
|
protected $protectedData: string[] = [];
|
|
164
204
|
/**
|
|
@@ -199,26 +239,33 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
199
239
|
private $originalAcValues: ACProperties | null = null;
|
|
200
240
|
|
|
201
241
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
242
|
+
* Alter the options for a query for this entity.
|
|
243
|
+
*
|
|
244
|
+
* @param options The current options.
|
|
245
|
+
* @returns The altered options.
|
|
204
246
|
*/
|
|
205
|
-
|
|
247
|
+
static alterOptions?<T extends Options>(options: T): T;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Initialize an entity.
|
|
251
|
+
*/
|
|
252
|
+
public constructor(..._rest: any[]) {
|
|
206
253
|
this.$nymph = (this.constructor as EntityConstructor).nymph;
|
|
207
254
|
this.$dataHandler = {
|
|
208
255
|
has: (data: EntityData, name: string) => {
|
|
209
|
-
this.$
|
|
256
|
+
this.$check();
|
|
210
257
|
|
|
211
258
|
return name in data || name in this.$sdata;
|
|
212
259
|
},
|
|
213
260
|
|
|
214
261
|
get: (data: EntityData, name: string) => {
|
|
215
|
-
this.$
|
|
262
|
+
this.$check();
|
|
216
263
|
|
|
217
264
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
218
265
|
data[name] = referencesToEntities(
|
|
219
266
|
JSON.parse(this.$sdata[name]),
|
|
220
267
|
this.$nymph,
|
|
221
|
-
this.$skipAc
|
|
268
|
+
this.$skipAc,
|
|
222
269
|
);
|
|
223
270
|
delete this.$sdata[name];
|
|
224
271
|
}
|
|
@@ -229,7 +276,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
229
276
|
},
|
|
230
277
|
|
|
231
278
|
set: (data: EntityData, name: string, value: any) => {
|
|
232
|
-
this.$
|
|
279
|
+
this.$check();
|
|
233
280
|
|
|
234
281
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
235
282
|
delete this.$sdata[name];
|
|
@@ -239,7 +286,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
239
286
|
},
|
|
240
287
|
|
|
241
288
|
deleteProperty: (data: EntityData, name: string) => {
|
|
242
|
-
this.$
|
|
289
|
+
this.$check();
|
|
243
290
|
|
|
244
291
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
245
292
|
return delete this.$sdata[name];
|
|
@@ -253,9 +300,9 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
253
300
|
defineProperty: (
|
|
254
301
|
data: EntityData,
|
|
255
302
|
name: string,
|
|
256
|
-
descriptor: PropertyDescriptor
|
|
303
|
+
descriptor: PropertyDescriptor,
|
|
257
304
|
) => {
|
|
258
|
-
this.$
|
|
305
|
+
this.$check();
|
|
259
306
|
|
|
260
307
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
261
308
|
delete this.$sdata[name];
|
|
@@ -265,13 +312,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
265
312
|
},
|
|
266
313
|
|
|
267
314
|
getOwnPropertyDescriptor: (data: EntityData, name: string) => {
|
|
268
|
-
this.$
|
|
315
|
+
this.$check();
|
|
269
316
|
|
|
270
317
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
271
318
|
data[name] = referencesToEntities(
|
|
272
319
|
JSON.parse(this.$sdata[name]),
|
|
273
320
|
this.$nymph,
|
|
274
|
-
this.$skipAc
|
|
321
|
+
this.$skipAc,
|
|
275
322
|
);
|
|
276
323
|
delete this.$sdata[name];
|
|
277
324
|
}
|
|
@@ -279,10 +326,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
279
326
|
},
|
|
280
327
|
|
|
281
328
|
ownKeys: (data: EntityData) => {
|
|
282
|
-
this.$
|
|
329
|
+
this.$check();
|
|
283
330
|
|
|
284
331
|
return Object.getOwnPropertyNames(data).concat(
|
|
285
|
-
Object.getOwnPropertyNames(this.$sdata)
|
|
332
|
+
Object.getOwnPropertyNames(this.$sdata),
|
|
286
333
|
);
|
|
287
334
|
},
|
|
288
335
|
};
|
|
@@ -291,20 +338,6 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
291
338
|
|
|
292
339
|
this.$data = new Proxy(this.$dataStore, this.$dataHandler);
|
|
293
340
|
|
|
294
|
-
if (guid != null) {
|
|
295
|
-
const entity = this.$nymph.driver.getEntitySync(
|
|
296
|
-
{ class: this.constructor as EntityConstructor },
|
|
297
|
-
{ type: '&', guid }
|
|
298
|
-
);
|
|
299
|
-
if (entity) {
|
|
300
|
-
this.guid = entity.guid;
|
|
301
|
-
this.tags = entity.tags;
|
|
302
|
-
this.cdate = entity.cdate;
|
|
303
|
-
this.mdate = entity.mdate;
|
|
304
|
-
this.$putData(entity.$getData(), entity.$getSData());
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
341
|
return new Proxy(this, {
|
|
309
342
|
has: (entity: Entity, name: string) => {
|
|
310
343
|
if (
|
|
@@ -315,7 +348,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
315
348
|
return name in entity;
|
|
316
349
|
}
|
|
317
350
|
|
|
318
|
-
this.$
|
|
351
|
+
this.$check();
|
|
319
352
|
return name in entity.$data;
|
|
320
353
|
},
|
|
321
354
|
|
|
@@ -326,12 +359,12 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
326
359
|
name.substring(0, 1) === '$'
|
|
327
360
|
) {
|
|
328
361
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
329
|
-
this.$
|
|
362
|
+
this.$check();
|
|
330
363
|
}
|
|
331
364
|
return (entity as any)[name];
|
|
332
365
|
}
|
|
333
366
|
|
|
334
|
-
this.$
|
|
367
|
+
this.$check();
|
|
335
368
|
if (name in entity.$data) {
|
|
336
369
|
return entity.$data[name];
|
|
337
370
|
}
|
|
@@ -345,11 +378,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
345
378
|
name.substring(0, 1) === '$'
|
|
346
379
|
) {
|
|
347
380
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
348
|
-
this.$
|
|
381
|
+
this.$check();
|
|
349
382
|
}
|
|
350
383
|
(entity as any)[name] = value;
|
|
351
384
|
} else {
|
|
352
|
-
this.$
|
|
385
|
+
this.$check();
|
|
353
386
|
(entity.$data as any)[name] = value;
|
|
354
387
|
}
|
|
355
388
|
return true;
|
|
@@ -359,7 +392,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
359
392
|
if (name in entity) {
|
|
360
393
|
return delete (entity as any)[name];
|
|
361
394
|
} else if (name in entity.$data) {
|
|
362
|
-
this.$
|
|
395
|
+
this.$check();
|
|
363
396
|
return delete entity.$data[name];
|
|
364
397
|
}
|
|
365
398
|
return true;
|
|
@@ -372,7 +405,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
372
405
|
defineProperty: (
|
|
373
406
|
entity: Entity,
|
|
374
407
|
name: string,
|
|
375
|
-
descriptor: PropertyDescriptor
|
|
408
|
+
descriptor: PropertyDescriptor,
|
|
376
409
|
) => {
|
|
377
410
|
if (
|
|
378
411
|
typeof name !== 'string' ||
|
|
@@ -380,11 +413,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
380
413
|
name.substring(0, 1) === '$'
|
|
381
414
|
) {
|
|
382
415
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
383
|
-
this.$
|
|
416
|
+
this.$check();
|
|
384
417
|
}
|
|
385
418
|
Object.defineProperty(entity, name, descriptor);
|
|
386
419
|
} else {
|
|
387
|
-
this.$
|
|
420
|
+
this.$check();
|
|
388
421
|
Object.defineProperty(entity.$data, name, descriptor);
|
|
389
422
|
}
|
|
390
423
|
return true;
|
|
@@ -397,48 +430,126 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
397
430
|
name.substring(0, 1) === '$'
|
|
398
431
|
) {
|
|
399
432
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
400
|
-
this.$
|
|
433
|
+
this.$check();
|
|
401
434
|
}
|
|
402
435
|
return Object.getOwnPropertyDescriptor(entity, name);
|
|
403
436
|
} else {
|
|
404
|
-
this.$
|
|
437
|
+
this.$check();
|
|
405
438
|
return Object.getOwnPropertyDescriptor(entity.$data, name);
|
|
406
439
|
}
|
|
407
440
|
},
|
|
408
441
|
|
|
409
442
|
ownKeys: (entity: Entity) => {
|
|
410
|
-
this.$
|
|
443
|
+
this.$check();
|
|
411
444
|
return Object.getOwnPropertyNames(entity).concat(
|
|
412
|
-
Object.getOwnPropertyNames(entity.$data)
|
|
445
|
+
Object.getOwnPropertyNames(entity.$data),
|
|
413
446
|
);
|
|
414
447
|
},
|
|
415
448
|
}) as Entity<T>;
|
|
416
449
|
}
|
|
417
450
|
|
|
418
|
-
|
|
451
|
+
/**
|
|
452
|
+
* Create or retrieve a new entity instance.
|
|
453
|
+
*
|
|
454
|
+
* Note that this will always return an entity, even if the GUID is not found.
|
|
455
|
+
*
|
|
456
|
+
* @param guid An optional GUID to retrieve.
|
|
457
|
+
*/
|
|
458
|
+
public static async factory<E extends Entity>(
|
|
459
|
+
this: {
|
|
460
|
+
new (): E;
|
|
461
|
+
},
|
|
462
|
+
guid?: string,
|
|
463
|
+
): Promise<E & EntityDataType<E>> {
|
|
419
464
|
const entity = new this();
|
|
420
465
|
if (guid != null) {
|
|
421
|
-
const entity = await
|
|
466
|
+
const entity = await (
|
|
467
|
+
this as unknown as EntityConstructor
|
|
468
|
+
).nymph.getEntity(
|
|
422
469
|
{
|
|
423
|
-
class: this as
|
|
470
|
+
class: this as unknown as EntityConstructor,
|
|
424
471
|
},
|
|
425
|
-
{ type: '&', guid }
|
|
472
|
+
{ type: '&', guid },
|
|
426
473
|
);
|
|
427
474
|
if (entity != null) {
|
|
428
|
-
return entity
|
|
475
|
+
return entity as E & EntityDataType<E>;
|
|
429
476
|
}
|
|
430
477
|
}
|
|
431
|
-
return entity
|
|
478
|
+
return entity as E & EntityDataType<E>;
|
|
432
479
|
}
|
|
433
480
|
|
|
434
|
-
|
|
435
|
-
|
|
481
|
+
/**
|
|
482
|
+
* Create a new entity instance.
|
|
483
|
+
*/
|
|
484
|
+
public static factorySync<E extends Entity>(this: {
|
|
485
|
+
new (): E;
|
|
486
|
+
}): E & EntityDataType<E> {
|
|
487
|
+
return new this() as E & EntityDataType<E>;
|
|
436
488
|
}
|
|
437
489
|
|
|
438
|
-
|
|
490
|
+
/**
|
|
491
|
+
* Create a new sleeping reference instance.
|
|
492
|
+
*
|
|
493
|
+
* Sleeping references won't retrieve their data from the database until they
|
|
494
|
+
* are readied with `$wake()` or a parent's `$wakeAll()`.
|
|
495
|
+
*
|
|
496
|
+
* @param reference The Nymph Entity Reference to use to wake.
|
|
497
|
+
* @returns The new instance.
|
|
498
|
+
*/
|
|
499
|
+
public static factoryReference<E extends Entity>(
|
|
500
|
+
this: {
|
|
501
|
+
new (): E;
|
|
502
|
+
},
|
|
503
|
+
reference: EntityReference,
|
|
504
|
+
): E & EntityDataType<E> {
|
|
439
505
|
const entity = new this();
|
|
440
506
|
entity.$referenceSleep(reference);
|
|
441
|
-
return entity
|
|
507
|
+
return entity as E & EntityDataType<E>;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Get an array of strings that **must** be unique across the current etype.
|
|
512
|
+
*
|
|
513
|
+
* When you try to save another entity with any of the same unique strings,
|
|
514
|
+
* Nymph will throw an error.
|
|
515
|
+
*
|
|
516
|
+
* The default implementation of this static method instantiates the entity,
|
|
517
|
+
* assigns all of the given data, then calls `$getUniques` and returns its
|
|
518
|
+
* output. This can have a performance impact if a lot of extra processing
|
|
519
|
+
* happens during any of these steps. You can override this method to
|
|
520
|
+
* calculate the unique strings faster, but you must return the same strings
|
|
521
|
+
* that would be returned by `$getUniques`.
|
|
522
|
+
*
|
|
523
|
+
* @returns Resolves to an array of entity's unique constraint strings.
|
|
524
|
+
*/
|
|
525
|
+
public static async getUniques({
|
|
526
|
+
guid,
|
|
527
|
+
cdate,
|
|
528
|
+
mdate,
|
|
529
|
+
tags,
|
|
530
|
+
data,
|
|
531
|
+
sdata,
|
|
532
|
+
}: {
|
|
533
|
+
guid?: string;
|
|
534
|
+
cdate?: number;
|
|
535
|
+
mdate?: number;
|
|
536
|
+
tags: string[];
|
|
537
|
+
data: EntityData;
|
|
538
|
+
sdata?: SerializedEntityData;
|
|
539
|
+
}) {
|
|
540
|
+
const entity = new this();
|
|
541
|
+
if (guid != null) {
|
|
542
|
+
entity.guid = guid;
|
|
543
|
+
}
|
|
544
|
+
if (cdate != null) {
|
|
545
|
+
entity.cdate = cdate;
|
|
546
|
+
}
|
|
547
|
+
if (mdate != null) {
|
|
548
|
+
entity.mdate = mdate;
|
|
549
|
+
}
|
|
550
|
+
entity.tags = tags;
|
|
551
|
+
entity.$putData(data, sdata);
|
|
552
|
+
return await entity.$getUniques();
|
|
442
553
|
}
|
|
443
554
|
|
|
444
555
|
public toJSON() {
|
|
@@ -463,7 +574,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
463
574
|
}
|
|
464
575
|
|
|
465
576
|
public $addTag(...tags: string[]) {
|
|
466
|
-
this.$
|
|
577
|
+
this.$check();
|
|
467
578
|
|
|
468
579
|
if (tags.length < 1) {
|
|
469
580
|
return;
|
|
@@ -472,7 +583,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
472
583
|
}
|
|
473
584
|
|
|
474
585
|
public $arraySearch(array: any[], strict = false) {
|
|
475
|
-
this.$
|
|
586
|
+
this.$check();
|
|
476
587
|
|
|
477
588
|
if (!Array.isArray(array)) {
|
|
478
589
|
return -1;
|
|
@@ -487,7 +598,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
487
598
|
}
|
|
488
599
|
|
|
489
600
|
public $clearCache() {
|
|
490
|
-
this.$
|
|
601
|
+
this.$check();
|
|
491
602
|
|
|
492
603
|
this.$putData(this.$getData(), this.$getSData());
|
|
493
604
|
}
|
|
@@ -497,13 +608,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
497
608
|
}
|
|
498
609
|
|
|
499
610
|
public async $delete(): Promise<boolean> {
|
|
500
|
-
this.$
|
|
611
|
+
this.$check();
|
|
501
612
|
|
|
502
613
|
return await this.$nymph.deleteEntity(this);
|
|
503
614
|
}
|
|
504
615
|
|
|
505
616
|
public $equals(object: any) {
|
|
506
|
-
this.$
|
|
617
|
+
this.$check();
|
|
507
618
|
|
|
508
619
|
if (!(object instanceof Entity)) {
|
|
509
620
|
return false;
|
|
@@ -513,22 +624,24 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
513
624
|
return false;
|
|
514
625
|
}
|
|
515
626
|
}
|
|
516
|
-
if (object.constructor !== this.constructor) {
|
|
517
|
-
return false;
|
|
518
|
-
}
|
|
519
627
|
if (object.cdate !== this.cdate) {
|
|
520
628
|
return false;
|
|
521
629
|
}
|
|
522
630
|
if (object.mdate !== this.mdate) {
|
|
523
631
|
return false;
|
|
524
632
|
}
|
|
633
|
+
const obTags = [...object.tags].sort();
|
|
634
|
+
const myTags = [...this.tags].sort();
|
|
635
|
+
if (!isEqual(obTags, myTags)) {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
525
638
|
const obData = object.$getData(true);
|
|
526
639
|
const myData = this.$getData(true);
|
|
527
640
|
return isEqual(obData, myData);
|
|
528
641
|
}
|
|
529
642
|
|
|
530
643
|
public $getData(includeSData = false) {
|
|
531
|
-
this.$
|
|
644
|
+
this.$check();
|
|
532
645
|
|
|
533
646
|
if (includeSData) {
|
|
534
647
|
// Access all the serialized properties to initialize them.
|
|
@@ -540,30 +653,57 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
540
653
|
}
|
|
541
654
|
|
|
542
655
|
public $getSData() {
|
|
543
|
-
this.$
|
|
656
|
+
this.$check();
|
|
544
657
|
|
|
545
658
|
return this.$sdata;
|
|
546
659
|
}
|
|
547
660
|
|
|
548
|
-
public $
|
|
549
|
-
|
|
661
|
+
public async $getUniques(): Promise<string[]> {
|
|
662
|
+
return [];
|
|
663
|
+
}
|
|
550
664
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
665
|
+
public $getOriginalAcValues(): ACProperties {
|
|
666
|
+
this.$check();
|
|
667
|
+
|
|
668
|
+
return this.$originalAcValues ?? this.$getCurrentAcValues();
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
public $getCurrentAcValues(): ACProperties {
|
|
672
|
+
this.$check();
|
|
673
|
+
|
|
674
|
+
return {
|
|
675
|
+
user: this.$getAcUid(),
|
|
676
|
+
group: this.$getAcGid(),
|
|
677
|
+
acUser: this.$data.acUser ?? null,
|
|
678
|
+
acGroup: this.$data.acGroup ?? null,
|
|
679
|
+
acOther: this.$data.acOther ?? null,
|
|
680
|
+
acRead: this.$getAcReadIds(),
|
|
681
|
+
acWrite: this.$getAcWriteIds(),
|
|
682
|
+
acFull: this.$getAcFullIds(),
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
public $getAcUid() {
|
|
687
|
+
return (this.$data.user?.guid ?? null) as string | null;
|
|
688
|
+
}
|
|
689
|
+
public $getAcGid() {
|
|
690
|
+
return (this.$data.group?.guid ?? null) as string | null;
|
|
691
|
+
}
|
|
692
|
+
public $getAcReadIds() {
|
|
693
|
+
return (this.$data.acRead?.map((entity: EntityInterface) => entity.guid) ??
|
|
694
|
+
null) as (string | null)[] | null;
|
|
695
|
+
}
|
|
696
|
+
public $getAcWriteIds() {
|
|
697
|
+
return (this.$data.acWrite?.map((entity: EntityInterface) => entity.guid) ??
|
|
698
|
+
null) as (string | null)[] | null;
|
|
699
|
+
}
|
|
700
|
+
public $getAcFullIds() {
|
|
701
|
+
return (this.$data.acFull?.map((entity: EntityInterface) => entity.guid) ??
|
|
702
|
+
null) as (string | null)[] | null;
|
|
563
703
|
}
|
|
564
704
|
|
|
565
705
|
public $getValidatable() {
|
|
566
|
-
this.$
|
|
706
|
+
this.$check();
|
|
567
707
|
|
|
568
708
|
// Access all the serialized properties to initialize them.
|
|
569
709
|
for (const key in this.$sdata) {
|
|
@@ -579,13 +719,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
579
719
|
}
|
|
580
720
|
|
|
581
721
|
public $getTags() {
|
|
582
|
-
this.$
|
|
722
|
+
this.$check();
|
|
583
723
|
|
|
584
724
|
return this.tags;
|
|
585
725
|
}
|
|
586
726
|
|
|
587
727
|
public $hasTag(...tags: string[]) {
|
|
588
|
-
this.$
|
|
728
|
+
this.$check();
|
|
589
729
|
|
|
590
730
|
if (!tags.length) {
|
|
591
731
|
return false;
|
|
@@ -611,10 +751,15 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
611
751
|
return this.guid === object.guid;
|
|
612
752
|
}
|
|
613
753
|
|
|
614
|
-
this.$
|
|
754
|
+
this.$check();
|
|
615
755
|
if (typeof object.$getData !== 'function') {
|
|
616
756
|
return false;
|
|
617
757
|
} else {
|
|
758
|
+
const obTags = [...object.tags].sort();
|
|
759
|
+
const myTags = [...this.tags].sort();
|
|
760
|
+
if (!isEqual(obTags, myTags)) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
618
763
|
const obData = object.$getData(true);
|
|
619
764
|
const myData = this.$getData(true);
|
|
620
765
|
return isEqual(obData, myData);
|
|
@@ -622,12 +767,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
622
767
|
}
|
|
623
768
|
|
|
624
769
|
public $jsonAcceptData(input: EntityJson, allowConflict = false) {
|
|
625
|
-
|
|
626
|
-
this.$referenceWake();
|
|
770
|
+
this.$check();
|
|
627
771
|
|
|
628
772
|
if (this.guid != input.guid) {
|
|
629
773
|
throw new EntityConflictError(
|
|
630
|
-
'Tried to accept JSON input for the wrong entity.'
|
|
774
|
+
'Tried to accept JSON input for the wrong entity.',
|
|
631
775
|
);
|
|
632
776
|
}
|
|
633
777
|
|
|
@@ -665,12 +809,27 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
665
809
|
|
|
666
810
|
const protectedData: EntityData = {};
|
|
667
811
|
const protectedProps = [...this.$protectedData];
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
protectedProps.push('
|
|
673
|
-
protectedProps.push('
|
|
812
|
+
if (this.$nymph.tilmeld) {
|
|
813
|
+
protectedProps.push('acUser');
|
|
814
|
+
protectedProps.push('acGroup');
|
|
815
|
+
protectedProps.push('acOther');
|
|
816
|
+
protectedProps.push('acRead');
|
|
817
|
+
protectedProps.push('acWrite');
|
|
818
|
+
protectedProps.push('acFull');
|
|
819
|
+
if (
|
|
820
|
+
((this.constructor as EntityConstructor).class !== 'User' &&
|
|
821
|
+
(this.constructor as EntityConstructor).class !== 'Group') ||
|
|
822
|
+
!(this.$nymph.tilmeld as any).currentUser ||
|
|
823
|
+
(!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
824
|
+
'tilmeld/admin',
|
|
825
|
+
) &&
|
|
826
|
+
!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
827
|
+
'system/admin',
|
|
828
|
+
))
|
|
829
|
+
) {
|
|
830
|
+
protectedProps.push('user');
|
|
831
|
+
protectedProps.push('group');
|
|
832
|
+
}
|
|
674
833
|
}
|
|
675
834
|
for (const name of protectedProps) {
|
|
676
835
|
if (name in this.$data) {
|
|
@@ -703,11 +862,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
703
862
|
}
|
|
704
863
|
|
|
705
864
|
public $jsonAcceptPatch(patch: EntityPatch, allowConflict = false) {
|
|
706
|
-
this.$
|
|
865
|
+
this.$check();
|
|
707
866
|
|
|
708
867
|
if (this.guid != patch.guid) {
|
|
709
868
|
throw new EntityConflictError(
|
|
710
|
-
'Tried to accept JSON patch for the wrong entity.'
|
|
869
|
+
'Tried to accept JSON patch for the wrong entity.',
|
|
711
870
|
);
|
|
712
871
|
}
|
|
713
872
|
|
|
@@ -719,11 +878,35 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
719
878
|
}
|
|
720
879
|
this.mdate = patch.mdate;
|
|
721
880
|
|
|
881
|
+
const protectedProps = [...this.$protectedData];
|
|
882
|
+
if (this.$nymph.tilmeld) {
|
|
883
|
+
protectedProps.push('acUser');
|
|
884
|
+
protectedProps.push('acGroup');
|
|
885
|
+
protectedProps.push('acOther');
|
|
886
|
+
protectedProps.push('acRead');
|
|
887
|
+
protectedProps.push('acWrite');
|
|
888
|
+
protectedProps.push('acFull');
|
|
889
|
+
if (
|
|
890
|
+
((this.constructor as EntityConstructor).class !== 'User' &&
|
|
891
|
+
(this.constructor as EntityConstructor).class !== 'Group') ||
|
|
892
|
+
!(this.$nymph.tilmeld as any).currentUser ||
|
|
893
|
+
(!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
894
|
+
'tilmeld/admin',
|
|
895
|
+
) &&
|
|
896
|
+
!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
897
|
+
'system/admin',
|
|
898
|
+
))
|
|
899
|
+
) {
|
|
900
|
+
protectedProps.push('user');
|
|
901
|
+
protectedProps.push('group');
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
722
905
|
for (const name in patch.set) {
|
|
723
906
|
if (
|
|
724
907
|
(this.$allowlistData != null &&
|
|
725
908
|
this.$allowlistData.indexOf(name) === -1) ||
|
|
726
|
-
|
|
909
|
+
protectedProps.indexOf(name) !== -1 ||
|
|
727
910
|
this.$privateData.indexOf(name) !== -1
|
|
728
911
|
) {
|
|
729
912
|
continue;
|
|
@@ -731,7 +914,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
731
914
|
(this.$data as any)[name] = referencesToEntities(
|
|
732
915
|
patch.set[name],
|
|
733
916
|
this.$nymph,
|
|
734
|
-
this.$skipAc
|
|
917
|
+
this.$skipAc,
|
|
735
918
|
);
|
|
736
919
|
}
|
|
737
920
|
|
|
@@ -739,7 +922,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
739
922
|
if (
|
|
740
923
|
(this.$allowlistData != null &&
|
|
741
924
|
this.$allowlistData.indexOf(name) === -1) ||
|
|
742
|
-
|
|
925
|
+
protectedProps.indexOf(name) !== -1 ||
|
|
743
926
|
this.$privateData.indexOf(name) !== -1
|
|
744
927
|
) {
|
|
745
928
|
continue;
|
|
@@ -771,7 +954,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
771
954
|
}
|
|
772
955
|
|
|
773
956
|
public $putData(data: EntityData, sdata?: SerializedEntityData) {
|
|
774
|
-
this.$
|
|
957
|
+
this.$check();
|
|
775
958
|
|
|
776
959
|
const mySdata = sdata ?? this.$getSData();
|
|
777
960
|
for (const name in data) {
|
|
@@ -784,13 +967,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
784
967
|
(this.$dataStore as any)[name] = referencesToEntities(
|
|
785
968
|
data[name],
|
|
786
969
|
this.$nymph,
|
|
787
|
-
this.$skipAc
|
|
970
|
+
this.$skipAc,
|
|
788
971
|
);
|
|
789
972
|
}
|
|
790
973
|
this.$sdata = mySdata;
|
|
791
974
|
// Set original AC values if not set..
|
|
792
975
|
if (this.$originalAcValues == null) {
|
|
793
|
-
this.$originalAcValues = this.$
|
|
976
|
+
this.$originalAcValues = this.$getCurrentAcValues();
|
|
794
977
|
}
|
|
795
978
|
}
|
|
796
979
|
|
|
@@ -807,14 +990,14 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
807
990
|
) {
|
|
808
991
|
throw new InvalidParametersError(
|
|
809
992
|
'referenceSleep expects parameter 1 to be a valid Nymph entity ' +
|
|
810
|
-
'reference.'
|
|
993
|
+
'reference.',
|
|
811
994
|
);
|
|
812
995
|
}
|
|
813
996
|
const thisClass: string = (this.constructor as any).class;
|
|
814
997
|
if (reference[2] !== thisClass) {
|
|
815
998
|
throw new InvalidParametersError(
|
|
816
999
|
'referenceSleep can only be called with an entity reference of the ' +
|
|
817
|
-
`same class. Given class: ${reference[2]}; this class: ${thisClass}
|
|
1000
|
+
`same class. Given class: ${reference[2]}; this class: ${thisClass}.`,
|
|
818
1001
|
);
|
|
819
1002
|
}
|
|
820
1003
|
this.$isASleepingReference = true;
|
|
@@ -822,49 +1005,137 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
822
1005
|
this.$sleepingReference = reference;
|
|
823
1006
|
}
|
|
824
1007
|
|
|
1008
|
+
/**
|
|
1009
|
+
* Check if this is a sleeping reference and throw an error if so.
|
|
1010
|
+
*/
|
|
1011
|
+
protected $check() {
|
|
1012
|
+
if (this.$isASleepingReference || this.$sleepingReference != null) {
|
|
1013
|
+
throw new EntityIsSleepingReferenceError(
|
|
1014
|
+
'This entity is in a sleeping reference state. You must use .$wake() to wake it.',
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* Check if this is a sleeping reference.
|
|
1021
|
+
*/
|
|
1022
|
+
public $asleep() {
|
|
1023
|
+
return this.$isASleepingReference || this.$sleepingReference != null;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
825
1026
|
/**
|
|
826
1027
|
* Wake from a sleeping reference.
|
|
827
|
-
*
|
|
828
|
-
* @returns True on success, false on failure.
|
|
829
1028
|
*/
|
|
830
|
-
|
|
1029
|
+
public $wake() {
|
|
831
1030
|
if (!this.$isASleepingReference || this.$sleepingReference == null) {
|
|
832
|
-
|
|
1031
|
+
this.$wakePromise = null;
|
|
1032
|
+
return Promise.resolve(this);
|
|
833
1033
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
skipAc: this.$skipAc,
|
|
839
|
-
},
|
|
840
|
-
{ type: '&', guid: this.$sleepingReference[1] }
|
|
841
|
-
);
|
|
842
|
-
if (entity == null) {
|
|
843
|
-
return false;
|
|
1034
|
+
if (this.$sleepingReference?.[1] == null) {
|
|
1035
|
+
throw new InvalidStateError(
|
|
1036
|
+
'Tried to wake a sleeping reference with no GUID.',
|
|
1037
|
+
);
|
|
844
1038
|
}
|
|
845
|
-
this.$
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1039
|
+
if (!this.$wakePromise) {
|
|
1040
|
+
const EntityClass = this.$nymph.getEntityClass(
|
|
1041
|
+
this.$sleepingReference[2],
|
|
1042
|
+
);
|
|
1043
|
+
this.$wakePromise = this.$nymph
|
|
1044
|
+
.getEntity(
|
|
1045
|
+
{
|
|
1046
|
+
class: EntityClass,
|
|
1047
|
+
skipAc: this.$skipAc,
|
|
1048
|
+
},
|
|
1049
|
+
{ type: '&', guid: this.$sleepingReference[1] },
|
|
1050
|
+
)
|
|
1051
|
+
.then((entity) => {
|
|
1052
|
+
if (entity == null || entity.guid == null) {
|
|
1053
|
+
return Promise.reject(
|
|
1054
|
+
new InvalidStateError(
|
|
1055
|
+
'The sleeping reference could not be retrieved.',
|
|
1056
|
+
),
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
this.$isASleepingReference = false;
|
|
1060
|
+
this.$sleepingReference = null;
|
|
1061
|
+
this.guid = entity.guid;
|
|
1062
|
+
this.tags = entity.tags;
|
|
1063
|
+
this.cdate = entity.cdate;
|
|
1064
|
+
this.mdate = entity.mdate;
|
|
1065
|
+
this.$putData(entity.$getData(), entity.$getSData());
|
|
1066
|
+
|
|
1067
|
+
return this;
|
|
1068
|
+
})
|
|
1069
|
+
.finally(() => {
|
|
1070
|
+
this.$wakePromise = null;
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
return this.$wakePromise;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
public $wakeAll(level?: number) {
|
|
1077
|
+
return new Promise((resolve, reject) => {
|
|
1078
|
+
// Run this once this entity is wake.
|
|
1079
|
+
const wakeProps = () => {
|
|
1080
|
+
let newLevel;
|
|
1081
|
+
// If level is undefined, keep going forever, otherwise, stop once we've
|
|
1082
|
+
// gone deep enough.
|
|
1083
|
+
if (level !== undefined) {
|
|
1084
|
+
newLevel = level - 1;
|
|
1085
|
+
}
|
|
1086
|
+
if (newLevel !== undefined && newLevel < 0) {
|
|
1087
|
+
resolve(this);
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const promises = [];
|
|
1091
|
+
// Go through data looking for entities to wake.
|
|
1092
|
+
for (let [key, value] of Object.entries(this.$data)) {
|
|
1093
|
+
if (value instanceof Entity && value.$isASleepingReference) {
|
|
1094
|
+
promises.push(value.$wakeAll(newLevel));
|
|
1095
|
+
} else if (Array.isArray(value)) {
|
|
1096
|
+
for (let i = 0; i < value.length; i++) {
|
|
1097
|
+
if (
|
|
1098
|
+
value[i] instanceof Entity &&
|
|
1099
|
+
value[i].$isASleepingReference
|
|
1100
|
+
) {
|
|
1101
|
+
promises.push(value[i].$wakeAll(newLevel));
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (promises.length) {
|
|
1107
|
+
Promise.all(promises).then(
|
|
1108
|
+
() => resolve(this),
|
|
1109
|
+
(errObj) => reject(errObj),
|
|
1110
|
+
);
|
|
1111
|
+
} else {
|
|
1112
|
+
resolve(this);
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
|
|
1116
|
+
if (this.$isASleepingReference) {
|
|
1117
|
+
this.$wake().then(wakeProps, (errObj) => reject(errObj));
|
|
1118
|
+
} else {
|
|
1119
|
+
wakeProps();
|
|
1120
|
+
}
|
|
1121
|
+
}) as Promise<Entity<T>>;
|
|
853
1122
|
}
|
|
854
1123
|
|
|
855
1124
|
public async $refresh() {
|
|
856
|
-
this.$
|
|
1125
|
+
await this.$wake();
|
|
857
1126
|
|
|
858
1127
|
if (this.guid == null) {
|
|
859
1128
|
return false;
|
|
860
1129
|
}
|
|
861
1130
|
const refresh = await this.$nymph.getEntity(
|
|
862
1131
|
{
|
|
863
|
-
class: this.
|
|
1132
|
+
class: this.$nymph.getEntityClass(
|
|
1133
|
+
this.constructor as EntityConstructor,
|
|
1134
|
+
),
|
|
864
1135
|
skipCache: true,
|
|
865
1136
|
skipAc: this.$skipAc,
|
|
866
1137
|
},
|
|
867
|
-
{ type: '&', guid: this.guid }
|
|
1138
|
+
{ type: '&', guid: this.guid },
|
|
868
1139
|
);
|
|
869
1140
|
if (refresh == null) {
|
|
870
1141
|
return 0;
|
|
@@ -877,13 +1148,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
877
1148
|
}
|
|
878
1149
|
|
|
879
1150
|
public $removeTag(...tags: string[]) {
|
|
880
|
-
this.$
|
|
1151
|
+
this.$check();
|
|
881
1152
|
|
|
882
1153
|
this.tags = difference(this.tags, tags);
|
|
883
1154
|
}
|
|
884
1155
|
|
|
885
1156
|
public async $save(): Promise<boolean> {
|
|
886
|
-
this.$
|
|
1157
|
+
await this.$wake();
|
|
887
1158
|
|
|
888
1159
|
return await this.$nymph.saveEntity(this);
|
|
889
1160
|
}
|