@nymphjs/nymph 1.0.0-beta.9 → 1.0.0-beta.90
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 +432 -0
- package/README.md +10 -20
- package/dist/Entity.d.ts +277 -10
- package/dist/Entity.js +543 -148
- package/dist/Entity.js.map +1 -1
- package/dist/Entity.test.js +53 -13
- package/dist/Entity.test.js.map +1 -1
- package/dist/Entity.types.d.ts +249 -23
- package/dist/Entity.types.js +1 -2
- package/dist/Nymph.d.ts +431 -12
- package/dist/Nymph.js +692 -180
- package/dist/Nymph.js.map +1 -1
- package/dist/Nymph.types.d.ts +65 -7
- package/dist/Nymph.types.js +3 -5
- package/dist/Nymph.types.js.map +1 -1
- package/dist/conf/d.d.ts +43 -0
- package/dist/conf/d.js +1 -2
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +26 -3
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +2 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/driver/NymphDriver.d.ts +137 -39
- package/dist/driver/NymphDriver.js +344 -194
- package/dist/driver/NymphDriver.js.map +1 -1
- package/dist/driver/index.d.ts +2 -2
- package/dist/driver/index.js +3 -23
- package/dist/driver/index.js.map +1 -1
- package/dist/driver/testArtifacts.d.ts +2 -2
- package/dist/driver/testArtifacts.js +557 -92
- package/dist/driver/testArtifacts.js.map +1 -1
- package/dist/errors/ClassNotAvailableError.js +1 -5
- package/dist/errors/ClassNotAvailableError.js.map +1 -1
- package/dist/errors/EntityConflictError.js +1 -5
- package/dist/errors/EntityConflictError.js.map +1 -1
- package/dist/errors/EntityInvalidDataError.d.ts +6 -0
- package/dist/errors/EntityInvalidDataError.js +8 -6
- package/dist/errors/EntityInvalidDataError.js.map +1 -1
- package/dist/errors/EntityIsSleepingReferenceError.js +1 -5
- package/dist/errors/EntityIsSleepingReferenceError.js.map +1 -1
- package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
- package/dist/errors/EntityUniqueConstraintError.js +7 -0
- package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
- package/dist/errors/InvalidParametersError.js +1 -5
- package/dist/errors/InvalidParametersError.js.map +1 -1
- package/dist/errors/InvalidStateError.d.ts +3 -0
- package/dist/errors/InvalidStateError.js +7 -0
- package/dist/errors/InvalidStateError.js.map +1 -0
- package/dist/errors/NotConfiguredError.js +1 -5
- package/dist/errors/NotConfiguredError.js.map +1 -1
- package/dist/errors/QueryFailedError.js +2 -5
- package/dist/errors/QueryFailedError.js.map +1 -1
- package/dist/errors/UnableToConnectError.js +1 -5
- package/dist/errors/UnableToConnectError.js.map +1 -1
- package/dist/errors/index.d.ts +10 -8
- package/dist/errors/index.js +10 -24
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +14 -34
- package/dist/index.js.map +1 -1
- package/dist/nymphJoiProps.js +10 -15
- package/dist/nymphJoiProps.js.map +1 -1
- package/dist/testArtifacts.d.ts +18 -6
- package/dist/testArtifacts.js +32 -37
- package/dist/testArtifacts.js.map +1 -1
- package/dist/testMocks.d.ts +15 -12
- package/dist/testMocks.js +40 -29
- package/dist/testMocks.js.map +1 -1
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +40 -29
- package/dist/utils.js.map +1 -1
- package/jest.config.js +11 -2
- package/package.json +22 -19
- package/src/Entity.test.ts +52 -7
- package/src/Entity.ts +458 -147
- package/src/Entity.types.ts +64 -74
- package/src/Nymph.ts +754 -321
- package/src/Nymph.types.ts +131 -26
- package/src/conf/d.ts +25 -0
- package/src/conf/defaults.ts +34 -1
- package/src/conf/index.ts +2 -2
- package/src/driver/NymphDriver.ts +362 -359
- package/src/driver/index.ts +2 -2
- package/src/driver/testArtifacts.ts +609 -185
- package/src/errors/EntityUniqueConstraintError.ts +6 -0
- package/src/errors/InvalidStateError.ts +6 -0
- package/src/errors/index.ts +12 -8
- package/src/index.ts +11 -11
- package/src/nymphJoiProps.ts +2 -2
- package/src/testArtifacts.ts +19 -20
- package/src/testMocks.ts +60 -35
- package/src/type/locutus.d.ts +3 -0
- package/src/utils.ts +39 -18
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/src/Entity.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { difference, intersection, isEqual } from 'lodash';
|
|
1
|
+
import { difference, intersection, isEqual } from 'lodash-es';
|
|
2
|
+
import { guid } from '@nymphjs/guid';
|
|
2
3
|
|
|
3
|
-
import type Nymph from './Nymph';
|
|
4
|
-
import {
|
|
4
|
+
import type Nymph from './Nymph.js';
|
|
5
|
+
import type { Options } from './Nymph.types.js';
|
|
6
|
+
import type {
|
|
5
7
|
ACProperties,
|
|
6
8
|
EntityConstructor,
|
|
7
9
|
EntityData,
|
|
@@ -10,13 +12,24 @@ import {
|
|
|
10
12
|
EntityPatch,
|
|
11
13
|
EntityReference,
|
|
12
14
|
SerializedEntityData,
|
|
13
|
-
} from './Entity.types';
|
|
14
|
-
import {
|
|
15
|
+
} from './Entity.types.js';
|
|
16
|
+
import {
|
|
17
|
+
EntityConflictError,
|
|
18
|
+
EntityIsSleepingReferenceError,
|
|
19
|
+
InvalidParametersError,
|
|
20
|
+
InvalidStateError,
|
|
21
|
+
} from './errors/index.js';
|
|
15
22
|
import {
|
|
16
23
|
entitiesToReferences,
|
|
17
24
|
referencesToEntities,
|
|
18
25
|
uniqueStrings,
|
|
19
|
-
} from './utils';
|
|
26
|
+
} from './utils.js';
|
|
27
|
+
|
|
28
|
+
export type EntityDataType<T> =
|
|
29
|
+
T extends Entity<infer DataType> ? DataType : never;
|
|
30
|
+
|
|
31
|
+
export type EntityInstanceType<T extends EntityConstructor> =
|
|
32
|
+
T extends new () => infer E ? E & EntityDataType<E> : never;
|
|
20
33
|
|
|
21
34
|
/**
|
|
22
35
|
* Database abstraction object.
|
|
@@ -136,6 +149,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
136
149
|
* The reference to use to wake.
|
|
137
150
|
*/
|
|
138
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;
|
|
139
156
|
/**
|
|
140
157
|
* Properties that will not be serialized into JSON with toJSON(). This
|
|
141
158
|
* can be considered a denylist, because these properties will not be set
|
|
@@ -145,6 +162,18 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
145
162
|
* also listed in searchRestrictedData.
|
|
146
163
|
*/
|
|
147
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;
|
|
148
177
|
/**
|
|
149
178
|
* Properties that will not be searchable from the frontend. If the frontend
|
|
150
179
|
* includes any of these properties in any of their clauses, they will be
|
|
@@ -156,8 +185,20 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
156
185
|
* be visible on the frontend, unlike $privateData, but any changes to them
|
|
157
186
|
* that come from the frontend will be ignored.
|
|
158
187
|
*
|
|
159
|
-
* In addition to what's listed here, the
|
|
160
|
-
* 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.
|
|
161
202
|
*/
|
|
162
203
|
protected $protectedData: string[] = [];
|
|
163
204
|
/**
|
|
@@ -196,28 +237,39 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
196
237
|
* The AC properties' values when the entity was loaded.
|
|
197
238
|
*/
|
|
198
239
|
private $originalAcValues: ACProperties | null = null;
|
|
240
|
+
/**
|
|
241
|
+
* This is used to hold a generated GUID for a new entity.
|
|
242
|
+
*/
|
|
243
|
+
private $guaranteedGUID: string | null = null;
|
|
199
244
|
|
|
200
245
|
/**
|
|
201
|
-
*
|
|
202
|
-
*
|
|
246
|
+
* Alter the options for a query for this entity.
|
|
247
|
+
*
|
|
248
|
+
* @param options The current options.
|
|
249
|
+
* @returns The altered options.
|
|
203
250
|
*/
|
|
204
|
-
|
|
251
|
+
static alterOptions?<T extends Options>(options: T): T;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Initialize an entity.
|
|
255
|
+
*/
|
|
256
|
+
public constructor(..._rest: any[]) {
|
|
205
257
|
this.$nymph = (this.constructor as EntityConstructor).nymph;
|
|
206
258
|
this.$dataHandler = {
|
|
207
259
|
has: (data: EntityData, name: string) => {
|
|
208
|
-
this.$
|
|
260
|
+
this.$check();
|
|
209
261
|
|
|
210
262
|
return name in data || name in this.$sdata;
|
|
211
263
|
},
|
|
212
264
|
|
|
213
265
|
get: (data: EntityData, name: string) => {
|
|
214
|
-
this.$
|
|
266
|
+
this.$check();
|
|
215
267
|
|
|
216
268
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
217
269
|
data[name] = referencesToEntities(
|
|
218
270
|
JSON.parse(this.$sdata[name]),
|
|
219
271
|
this.$nymph,
|
|
220
|
-
this.$skipAc
|
|
272
|
+
this.$skipAc,
|
|
221
273
|
);
|
|
222
274
|
delete this.$sdata[name];
|
|
223
275
|
}
|
|
@@ -228,7 +280,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
228
280
|
},
|
|
229
281
|
|
|
230
282
|
set: (data: EntityData, name: string, value: any) => {
|
|
231
|
-
this.$
|
|
283
|
+
this.$check();
|
|
232
284
|
|
|
233
285
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
234
286
|
delete this.$sdata[name];
|
|
@@ -238,7 +290,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
238
290
|
},
|
|
239
291
|
|
|
240
292
|
deleteProperty: (data: EntityData, name: string) => {
|
|
241
|
-
this.$
|
|
293
|
+
this.$check();
|
|
242
294
|
|
|
243
295
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
244
296
|
return delete this.$sdata[name];
|
|
@@ -252,9 +304,9 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
252
304
|
defineProperty: (
|
|
253
305
|
data: EntityData,
|
|
254
306
|
name: string,
|
|
255
|
-
descriptor: PropertyDescriptor
|
|
307
|
+
descriptor: PropertyDescriptor,
|
|
256
308
|
) => {
|
|
257
|
-
this.$
|
|
309
|
+
this.$check();
|
|
258
310
|
|
|
259
311
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
260
312
|
delete this.$sdata[name];
|
|
@@ -264,13 +316,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
264
316
|
},
|
|
265
317
|
|
|
266
318
|
getOwnPropertyDescriptor: (data: EntityData, name: string) => {
|
|
267
|
-
this.$
|
|
319
|
+
this.$check();
|
|
268
320
|
|
|
269
321
|
if (this.$sdata.hasOwnProperty(name)) {
|
|
270
322
|
data[name] = referencesToEntities(
|
|
271
323
|
JSON.parse(this.$sdata[name]),
|
|
272
324
|
this.$nymph,
|
|
273
|
-
this.$skipAc
|
|
325
|
+
this.$skipAc,
|
|
274
326
|
);
|
|
275
327
|
delete this.$sdata[name];
|
|
276
328
|
}
|
|
@@ -278,10 +330,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
278
330
|
},
|
|
279
331
|
|
|
280
332
|
ownKeys: (data: EntityData) => {
|
|
281
|
-
this.$
|
|
333
|
+
this.$check();
|
|
282
334
|
|
|
283
335
|
return Object.getOwnPropertyNames(data).concat(
|
|
284
|
-
Object.getOwnPropertyNames(this.$sdata)
|
|
336
|
+
Object.getOwnPropertyNames(this.$sdata),
|
|
285
337
|
);
|
|
286
338
|
},
|
|
287
339
|
};
|
|
@@ -290,20 +342,6 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
290
342
|
|
|
291
343
|
this.$data = new Proxy(this.$dataStore, this.$dataHandler);
|
|
292
344
|
|
|
293
|
-
if (guid != null) {
|
|
294
|
-
const entity = this.$nymph.driver.getEntitySync(
|
|
295
|
-
{ class: this.constructor as EntityConstructor },
|
|
296
|
-
{ type: '&', guid }
|
|
297
|
-
);
|
|
298
|
-
if (entity) {
|
|
299
|
-
this.guid = entity.guid;
|
|
300
|
-
this.tags = entity.tags;
|
|
301
|
-
this.cdate = entity.cdate;
|
|
302
|
-
this.mdate = entity.mdate;
|
|
303
|
-
this.$putData(entity.$getData(), entity.$getSData());
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
345
|
return new Proxy(this, {
|
|
308
346
|
has: (entity: Entity, name: string) => {
|
|
309
347
|
if (
|
|
@@ -314,7 +352,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
314
352
|
return name in entity;
|
|
315
353
|
}
|
|
316
354
|
|
|
317
|
-
this.$
|
|
355
|
+
this.$check();
|
|
318
356
|
return name in entity.$data;
|
|
319
357
|
},
|
|
320
358
|
|
|
@@ -325,12 +363,12 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
325
363
|
name.substring(0, 1) === '$'
|
|
326
364
|
) {
|
|
327
365
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
328
|
-
this.$
|
|
366
|
+
this.$check();
|
|
329
367
|
}
|
|
330
368
|
return (entity as any)[name];
|
|
331
369
|
}
|
|
332
370
|
|
|
333
|
-
this.$
|
|
371
|
+
this.$check();
|
|
334
372
|
if (name in entity.$data) {
|
|
335
373
|
return entity.$data[name];
|
|
336
374
|
}
|
|
@@ -344,11 +382,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
344
382
|
name.substring(0, 1) === '$'
|
|
345
383
|
) {
|
|
346
384
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
347
|
-
this.$
|
|
385
|
+
this.$check();
|
|
348
386
|
}
|
|
349
387
|
(entity as any)[name] = value;
|
|
350
388
|
} else {
|
|
351
|
-
this.$
|
|
389
|
+
this.$check();
|
|
352
390
|
(entity.$data as any)[name] = value;
|
|
353
391
|
}
|
|
354
392
|
return true;
|
|
@@ -358,7 +396,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
358
396
|
if (name in entity) {
|
|
359
397
|
return delete (entity as any)[name];
|
|
360
398
|
} else if (name in entity.$data) {
|
|
361
|
-
this.$
|
|
399
|
+
this.$check();
|
|
362
400
|
return delete entity.$data[name];
|
|
363
401
|
}
|
|
364
402
|
return true;
|
|
@@ -371,7 +409,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
371
409
|
defineProperty: (
|
|
372
410
|
entity: Entity,
|
|
373
411
|
name: string,
|
|
374
|
-
descriptor: PropertyDescriptor
|
|
412
|
+
descriptor: PropertyDescriptor,
|
|
375
413
|
) => {
|
|
376
414
|
if (
|
|
377
415
|
typeof name !== 'string' ||
|
|
@@ -379,11 +417,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
379
417
|
name.substring(0, 1) === '$'
|
|
380
418
|
) {
|
|
381
419
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
382
|
-
this.$
|
|
420
|
+
this.$check();
|
|
383
421
|
}
|
|
384
422
|
Object.defineProperty(entity, name, descriptor);
|
|
385
423
|
} else {
|
|
386
|
-
this.$
|
|
424
|
+
this.$check();
|
|
387
425
|
Object.defineProperty(entity.$data, name, descriptor);
|
|
388
426
|
}
|
|
389
427
|
return true;
|
|
@@ -396,48 +434,126 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
396
434
|
name.substring(0, 1) === '$'
|
|
397
435
|
) {
|
|
398
436
|
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
399
|
-
this.$
|
|
437
|
+
this.$check();
|
|
400
438
|
}
|
|
401
439
|
return Object.getOwnPropertyDescriptor(entity, name);
|
|
402
440
|
} else {
|
|
403
|
-
this.$
|
|
441
|
+
this.$check();
|
|
404
442
|
return Object.getOwnPropertyDescriptor(entity.$data, name);
|
|
405
443
|
}
|
|
406
444
|
},
|
|
407
445
|
|
|
408
446
|
ownKeys: (entity: Entity) => {
|
|
409
|
-
this.$
|
|
447
|
+
this.$check();
|
|
410
448
|
return Object.getOwnPropertyNames(entity).concat(
|
|
411
|
-
Object.getOwnPropertyNames(entity.$data)
|
|
449
|
+
Object.getOwnPropertyNames(entity.$data),
|
|
412
450
|
);
|
|
413
451
|
},
|
|
414
452
|
}) as Entity<T>;
|
|
415
453
|
}
|
|
416
454
|
|
|
417
|
-
|
|
455
|
+
/**
|
|
456
|
+
* Create or retrieve a new entity instance.
|
|
457
|
+
*
|
|
458
|
+
* Note that this will always return an entity, even if the GUID is not found.
|
|
459
|
+
*
|
|
460
|
+
* @param guid An optional GUID to retrieve.
|
|
461
|
+
*/
|
|
462
|
+
public static async factory<E extends Entity>(
|
|
463
|
+
this: {
|
|
464
|
+
new (): E;
|
|
465
|
+
},
|
|
466
|
+
guid?: string,
|
|
467
|
+
): Promise<E & EntityDataType<E>> {
|
|
418
468
|
const entity = new this();
|
|
419
469
|
if (guid != null) {
|
|
420
|
-
const entity = await
|
|
470
|
+
const entity = await (
|
|
471
|
+
this as unknown as EntityConstructor
|
|
472
|
+
).nymph.getEntity(
|
|
421
473
|
{
|
|
422
|
-
class: this as
|
|
474
|
+
class: this as unknown as EntityConstructor,
|
|
423
475
|
},
|
|
424
|
-
{ type: '&', guid }
|
|
476
|
+
{ type: '&', guid },
|
|
425
477
|
);
|
|
426
478
|
if (entity != null) {
|
|
427
|
-
return entity
|
|
479
|
+
return entity as E & EntityDataType<E>;
|
|
428
480
|
}
|
|
429
481
|
}
|
|
430
|
-
return entity
|
|
482
|
+
return entity as E & EntityDataType<E>;
|
|
431
483
|
}
|
|
432
484
|
|
|
433
|
-
|
|
434
|
-
|
|
485
|
+
/**
|
|
486
|
+
* Create a new entity instance.
|
|
487
|
+
*/
|
|
488
|
+
public static factorySync<E extends Entity>(this: {
|
|
489
|
+
new (): E;
|
|
490
|
+
}): E & EntityDataType<E> {
|
|
491
|
+
return new this() as E & EntityDataType<E>;
|
|
435
492
|
}
|
|
436
493
|
|
|
437
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Create a new sleeping reference instance.
|
|
496
|
+
*
|
|
497
|
+
* Sleeping references won't retrieve their data from the database until they
|
|
498
|
+
* are readied with `$wake()` or a parent's `$wakeAll()`.
|
|
499
|
+
*
|
|
500
|
+
* @param reference The Nymph Entity Reference to use to wake.
|
|
501
|
+
* @returns The new instance.
|
|
502
|
+
*/
|
|
503
|
+
public static factoryReference<E extends Entity>(
|
|
504
|
+
this: {
|
|
505
|
+
new (): E;
|
|
506
|
+
},
|
|
507
|
+
reference: EntityReference,
|
|
508
|
+
): E & EntityDataType<E> {
|
|
438
509
|
const entity = new this();
|
|
439
510
|
entity.$referenceSleep(reference);
|
|
440
|
-
return entity
|
|
511
|
+
return entity as E & EntityDataType<E>;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Get an array of strings that **must** be unique across the current etype.
|
|
516
|
+
*
|
|
517
|
+
* When you try to save another entity with any of the same unique strings,
|
|
518
|
+
* Nymph will throw an error.
|
|
519
|
+
*
|
|
520
|
+
* The default implementation of this static method instantiates the entity,
|
|
521
|
+
* assigns all of the given data, then calls `$getUniques` and returns its
|
|
522
|
+
* output. This can have a performance impact if a lot of extra processing
|
|
523
|
+
* happens during any of these steps. You can override this method to
|
|
524
|
+
* calculate the unique strings faster, but you must return the same strings
|
|
525
|
+
* that would be returned by `$getUniques`.
|
|
526
|
+
*
|
|
527
|
+
* @returns Resolves to an array of entity's unique constraint strings.
|
|
528
|
+
*/
|
|
529
|
+
public static async getUniques({
|
|
530
|
+
guid,
|
|
531
|
+
cdate,
|
|
532
|
+
mdate,
|
|
533
|
+
tags,
|
|
534
|
+
data,
|
|
535
|
+
sdata,
|
|
536
|
+
}: {
|
|
537
|
+
guid?: string;
|
|
538
|
+
cdate?: number;
|
|
539
|
+
mdate?: number;
|
|
540
|
+
tags: string[];
|
|
541
|
+
data: EntityData;
|
|
542
|
+
sdata?: SerializedEntityData;
|
|
543
|
+
}) {
|
|
544
|
+
const entity = new this();
|
|
545
|
+
if (guid != null) {
|
|
546
|
+
entity.guid = guid;
|
|
547
|
+
}
|
|
548
|
+
if (cdate != null) {
|
|
549
|
+
entity.cdate = cdate;
|
|
550
|
+
}
|
|
551
|
+
if (mdate != null) {
|
|
552
|
+
entity.mdate = mdate;
|
|
553
|
+
}
|
|
554
|
+
entity.tags = tags;
|
|
555
|
+
entity.$putData(data, sdata);
|
|
556
|
+
return await entity.$getUniques();
|
|
441
557
|
}
|
|
442
558
|
|
|
443
559
|
public toJSON() {
|
|
@@ -452,17 +568,29 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
452
568
|
tags: [...this.tags],
|
|
453
569
|
data: {},
|
|
454
570
|
};
|
|
455
|
-
const
|
|
456
|
-
|
|
571
|
+
for (const key of [
|
|
572
|
+
...Object.keys(this.$dataStore),
|
|
573
|
+
...Object.keys(this.$sdata),
|
|
574
|
+
]) {
|
|
457
575
|
if (this.$privateData.indexOf(key) === -1) {
|
|
458
|
-
obj.data[key] = entitiesToReferences(data[key]);
|
|
576
|
+
obj.data[key] = entitiesToReferences(this.$data[key], true);
|
|
459
577
|
}
|
|
460
578
|
}
|
|
461
579
|
return obj;
|
|
462
580
|
}
|
|
463
581
|
|
|
582
|
+
public $getGuaranteedGUID() {
|
|
583
|
+
if (this.guid !== null) {
|
|
584
|
+
return this.guid;
|
|
585
|
+
}
|
|
586
|
+
if (this.$guaranteedGUID == null) {
|
|
587
|
+
this.$guaranteedGUID = guid();
|
|
588
|
+
}
|
|
589
|
+
return this.$guaranteedGUID;
|
|
590
|
+
}
|
|
591
|
+
|
|
464
592
|
public $addTag(...tags: string[]) {
|
|
465
|
-
this.$
|
|
593
|
+
this.$check();
|
|
466
594
|
|
|
467
595
|
if (tags.length < 1) {
|
|
468
596
|
return;
|
|
@@ -471,7 +599,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
471
599
|
}
|
|
472
600
|
|
|
473
601
|
public $arraySearch(array: any[], strict = false) {
|
|
474
|
-
this.$
|
|
602
|
+
this.$check();
|
|
475
603
|
|
|
476
604
|
if (!Array.isArray(array)) {
|
|
477
605
|
return -1;
|
|
@@ -486,9 +614,9 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
486
614
|
}
|
|
487
615
|
|
|
488
616
|
public $clearCache() {
|
|
489
|
-
this.$
|
|
617
|
+
this.$check();
|
|
490
618
|
|
|
491
|
-
this.$putData(this.$getData(), this.$getSData());
|
|
619
|
+
this.$putData(this.$getData(false, true), this.$getSData());
|
|
492
620
|
}
|
|
493
621
|
|
|
494
622
|
public $getClientEnabledMethods() {
|
|
@@ -496,13 +624,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
496
624
|
}
|
|
497
625
|
|
|
498
626
|
public async $delete(): Promise<boolean> {
|
|
499
|
-
this.$
|
|
627
|
+
this.$check();
|
|
500
628
|
|
|
501
629
|
return await this.$nymph.deleteEntity(this);
|
|
502
630
|
}
|
|
503
631
|
|
|
504
632
|
public $equals(object: any) {
|
|
505
|
-
this.$
|
|
633
|
+
this.$check();
|
|
506
634
|
|
|
507
635
|
if (!(object instanceof Entity)) {
|
|
508
636
|
return false;
|
|
@@ -523,13 +651,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
523
651
|
if (!isEqual(obTags, myTags)) {
|
|
524
652
|
return false;
|
|
525
653
|
}
|
|
526
|
-
const obData = object.$getData(true);
|
|
527
|
-
const myData = this.$getData(true);
|
|
654
|
+
const obData = object.$getData(true, true);
|
|
655
|
+
const myData = this.$getData(true, true);
|
|
528
656
|
return isEqual(obData, myData);
|
|
529
657
|
}
|
|
530
658
|
|
|
531
|
-
public $getData(includeSData = false) {
|
|
532
|
-
this.$
|
|
659
|
+
public $getData(includeSData = false, referenceOnlyExisting?: boolean) {
|
|
660
|
+
this.$check();
|
|
533
661
|
|
|
534
662
|
if (includeSData) {
|
|
535
663
|
// Access all the serialized properties to initialize them.
|
|
@@ -537,34 +665,79 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
537
665
|
const _unused: any = (this as any)[key];
|
|
538
666
|
}
|
|
539
667
|
}
|
|
540
|
-
return entitiesToReferences({ ...this.$dataStore });
|
|
668
|
+
return entitiesToReferences({ ...this.$dataStore }, referenceOnlyExisting);
|
|
541
669
|
}
|
|
542
670
|
|
|
543
671
|
public $getSData() {
|
|
544
|
-
this.$
|
|
672
|
+
this.$check();
|
|
545
673
|
|
|
546
674
|
return this.$sdata;
|
|
547
675
|
}
|
|
548
676
|
|
|
549
|
-
public $
|
|
550
|
-
|
|
677
|
+
public async $getUniques(): Promise<string[]> {
|
|
678
|
+
return [];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
public $getOriginalAcValues(): ACProperties {
|
|
682
|
+
this.$check();
|
|
683
|
+
|
|
684
|
+
return this.$originalAcValues ?? this.$getCurrentAcValues();
|
|
685
|
+
}
|
|
551
686
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
687
|
+
public $getCurrentAcValues(): ACProperties {
|
|
688
|
+
this.$check();
|
|
689
|
+
|
|
690
|
+
return {
|
|
691
|
+
user: this.$getAcUid(),
|
|
692
|
+
group: this.$getAcGid(),
|
|
693
|
+
acUser: this.$data.acUser ?? null,
|
|
694
|
+
acGroup: this.$data.acGroup ?? null,
|
|
695
|
+
acOther: this.$data.acOther ?? null,
|
|
696
|
+
acRead: this.$getAcReadIds(),
|
|
697
|
+
acWrite: this.$getAcWriteIds(),
|
|
698
|
+
acFull: this.$getAcFullIds(),
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
public $getAcUid() {
|
|
703
|
+
if ('user' in this.$sdata) {
|
|
704
|
+
const userValue = JSON.parse(this.$sdata.user);
|
|
705
|
+
if (
|
|
706
|
+
Array.isArray(userValue) &&
|
|
707
|
+
userValue[0] === 'nymph_entity_reference'
|
|
708
|
+
) {
|
|
709
|
+
return userValue[1];
|
|
562
710
|
}
|
|
563
|
-
|
|
711
|
+
}
|
|
712
|
+
return (this.$data.user?.guid ?? null) as string | null;
|
|
713
|
+
}
|
|
714
|
+
public $getAcGid() {
|
|
715
|
+
if ('group' in this.$sdata) {
|
|
716
|
+
const groupValue = JSON.parse(this.$sdata.group);
|
|
717
|
+
if (
|
|
718
|
+
Array.isArray(groupValue) &&
|
|
719
|
+
groupValue[0] === 'nymph_entity_reference'
|
|
720
|
+
) {
|
|
721
|
+
return groupValue[1];
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return (this.$data.group?.guid ?? null) as string | null;
|
|
725
|
+
}
|
|
726
|
+
public $getAcReadIds() {
|
|
727
|
+
return (this.$data.acRead?.map((entity: EntityInterface) => entity.guid) ??
|
|
728
|
+
null) as (string | null)[] | null;
|
|
729
|
+
}
|
|
730
|
+
public $getAcWriteIds() {
|
|
731
|
+
return (this.$data.acWrite?.map((entity: EntityInterface) => entity.guid) ??
|
|
732
|
+
null) as (string | null)[] | null;
|
|
733
|
+
}
|
|
734
|
+
public $getAcFullIds() {
|
|
735
|
+
return (this.$data.acFull?.map((entity: EntityInterface) => entity.guid) ??
|
|
736
|
+
null) as (string | null)[] | null;
|
|
564
737
|
}
|
|
565
738
|
|
|
566
739
|
public $getValidatable() {
|
|
567
|
-
this.$
|
|
740
|
+
this.$check();
|
|
568
741
|
|
|
569
742
|
// Access all the serialized properties to initialize them.
|
|
570
743
|
for (const key in this.$sdata) {
|
|
@@ -580,13 +753,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
580
753
|
}
|
|
581
754
|
|
|
582
755
|
public $getTags() {
|
|
583
|
-
this.$
|
|
756
|
+
this.$check();
|
|
584
757
|
|
|
585
758
|
return this.tags;
|
|
586
759
|
}
|
|
587
760
|
|
|
588
761
|
public $hasTag(...tags: string[]) {
|
|
589
|
-
this.$
|
|
762
|
+
this.$check();
|
|
590
763
|
|
|
591
764
|
if (!tags.length) {
|
|
592
765
|
return false;
|
|
@@ -608,11 +781,15 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
608
781
|
return false;
|
|
609
782
|
}
|
|
610
783
|
|
|
611
|
-
if (this
|
|
784
|
+
if (this === object) {
|
|
785
|
+
return true;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (this.guid != null || object.guid != null) {
|
|
612
789
|
return this.guid === object.guid;
|
|
613
790
|
}
|
|
614
791
|
|
|
615
|
-
this.$
|
|
792
|
+
this.$check();
|
|
616
793
|
if (typeof object.$getData !== 'function') {
|
|
617
794
|
return false;
|
|
618
795
|
} else {
|
|
@@ -621,19 +798,18 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
621
798
|
if (!isEqual(obTags, myTags)) {
|
|
622
799
|
return false;
|
|
623
800
|
}
|
|
624
|
-
const obData = object.$getData(true);
|
|
625
|
-
const myData = this.$getData(true);
|
|
801
|
+
const obData = object.$getData(true, true);
|
|
802
|
+
const myData = this.$getData(true, true);
|
|
626
803
|
return isEqual(obData, myData);
|
|
627
804
|
}
|
|
628
805
|
}
|
|
629
806
|
|
|
630
807
|
public $jsonAcceptData(input: EntityJson, allowConflict = false) {
|
|
631
|
-
|
|
632
|
-
this.$referenceWake();
|
|
808
|
+
this.$check();
|
|
633
809
|
|
|
634
810
|
if (this.guid != input.guid) {
|
|
635
811
|
throw new EntityConflictError(
|
|
636
|
-
'Tried to accept JSON input for the wrong entity.'
|
|
812
|
+
'Tried to accept JSON input for the wrong entity.',
|
|
637
813
|
);
|
|
638
814
|
}
|
|
639
815
|
|
|
@@ -658,7 +834,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
658
834
|
this.$addTag(...protectedTags, ...tags);
|
|
659
835
|
|
|
660
836
|
// Accept the data.
|
|
661
|
-
const data = input.data;
|
|
837
|
+
const data = { ...input.data };
|
|
662
838
|
const privateData: EntityData = {};
|
|
663
839
|
for (const name of this.$privateData) {
|
|
664
840
|
if (name in this.$data) {
|
|
@@ -671,12 +847,27 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
671
847
|
|
|
672
848
|
const protectedData: EntityData = {};
|
|
673
849
|
const protectedProps = [...this.$protectedData];
|
|
674
|
-
if (
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
protectedProps.push('
|
|
679
|
-
protectedProps.push('
|
|
850
|
+
if (this.$nymph.tilmeld) {
|
|
851
|
+
protectedProps.push('acUser');
|
|
852
|
+
protectedProps.push('acGroup');
|
|
853
|
+
protectedProps.push('acOther');
|
|
854
|
+
protectedProps.push('acRead');
|
|
855
|
+
protectedProps.push('acWrite');
|
|
856
|
+
protectedProps.push('acFull');
|
|
857
|
+
if (
|
|
858
|
+
((this.constructor as EntityConstructor).class !== 'User' &&
|
|
859
|
+
(this.constructor as EntityConstructor).class !== 'Group') ||
|
|
860
|
+
!(this.$nymph.tilmeld as any).currentUser ||
|
|
861
|
+
(!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
862
|
+
'tilmeld/admin',
|
|
863
|
+
) &&
|
|
864
|
+
!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
865
|
+
'system/admin',
|
|
866
|
+
))
|
|
867
|
+
) {
|
|
868
|
+
protectedProps.push('user');
|
|
869
|
+
protectedProps.push('group');
|
|
870
|
+
}
|
|
680
871
|
}
|
|
681
872
|
for (const name of protectedProps) {
|
|
682
873
|
if (name in this.$data) {
|
|
@@ -689,7 +880,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
689
880
|
|
|
690
881
|
let nonAllowlistData: EntityData = {};
|
|
691
882
|
if (this.$allowlistData != null) {
|
|
692
|
-
nonAllowlistData = { ...this.$getData(true) };
|
|
883
|
+
nonAllowlistData = { ...this.$getData(true, true) };
|
|
693
884
|
for (const name of this.$allowlistData) {
|
|
694
885
|
delete nonAllowlistData[name];
|
|
695
886
|
}
|
|
@@ -709,11 +900,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
709
900
|
}
|
|
710
901
|
|
|
711
902
|
public $jsonAcceptPatch(patch: EntityPatch, allowConflict = false) {
|
|
712
|
-
this.$
|
|
903
|
+
this.$check();
|
|
713
904
|
|
|
714
905
|
if (this.guid != patch.guid) {
|
|
715
906
|
throw new EntityConflictError(
|
|
716
|
-
'Tried to accept JSON patch for the wrong entity.'
|
|
907
|
+
'Tried to accept JSON patch for the wrong entity.',
|
|
717
908
|
);
|
|
718
909
|
}
|
|
719
910
|
|
|
@@ -725,11 +916,35 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
725
916
|
}
|
|
726
917
|
this.mdate = patch.mdate;
|
|
727
918
|
|
|
919
|
+
const protectedProps = [...this.$protectedData];
|
|
920
|
+
if (this.$nymph.tilmeld) {
|
|
921
|
+
protectedProps.push('acUser');
|
|
922
|
+
protectedProps.push('acGroup');
|
|
923
|
+
protectedProps.push('acOther');
|
|
924
|
+
protectedProps.push('acRead');
|
|
925
|
+
protectedProps.push('acWrite');
|
|
926
|
+
protectedProps.push('acFull');
|
|
927
|
+
if (
|
|
928
|
+
((this.constructor as EntityConstructor).class !== 'User' &&
|
|
929
|
+
(this.constructor as EntityConstructor).class !== 'Group') ||
|
|
930
|
+
!(this.$nymph.tilmeld as any).currentUser ||
|
|
931
|
+
(!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
932
|
+
'tilmeld/admin',
|
|
933
|
+
) &&
|
|
934
|
+
!(this.$nymph.tilmeld as any).currentUser.abilities?.includes(
|
|
935
|
+
'system/admin',
|
|
936
|
+
))
|
|
937
|
+
) {
|
|
938
|
+
protectedProps.push('user');
|
|
939
|
+
protectedProps.push('group');
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
728
943
|
for (const name in patch.set) {
|
|
729
944
|
if (
|
|
730
945
|
(this.$allowlistData != null &&
|
|
731
946
|
this.$allowlistData.indexOf(name) === -1) ||
|
|
732
|
-
|
|
947
|
+
protectedProps.indexOf(name) !== -1 ||
|
|
733
948
|
this.$privateData.indexOf(name) !== -1
|
|
734
949
|
) {
|
|
735
950
|
continue;
|
|
@@ -737,7 +952,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
737
952
|
(this.$data as any)[name] = referencesToEntities(
|
|
738
953
|
patch.set[name],
|
|
739
954
|
this.$nymph,
|
|
740
|
-
this.$skipAc
|
|
955
|
+
this.$skipAc,
|
|
741
956
|
);
|
|
742
957
|
}
|
|
743
958
|
|
|
@@ -745,7 +960,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
745
960
|
if (
|
|
746
961
|
(this.$allowlistData != null &&
|
|
747
962
|
this.$allowlistData.indexOf(name) === -1) ||
|
|
748
|
-
|
|
963
|
+
protectedProps.indexOf(name) !== -1 ||
|
|
749
964
|
this.$privateData.indexOf(name) !== -1
|
|
750
965
|
) {
|
|
751
966
|
continue;
|
|
@@ -776,8 +991,12 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
776
991
|
}
|
|
777
992
|
}
|
|
778
993
|
|
|
779
|
-
public $putData(
|
|
780
|
-
|
|
994
|
+
public $putData(
|
|
995
|
+
data: EntityData,
|
|
996
|
+
sdata?: SerializedEntityData,
|
|
997
|
+
_source?: 'server',
|
|
998
|
+
) {
|
|
999
|
+
this.$check();
|
|
781
1000
|
|
|
782
1001
|
const mySdata = sdata ?? this.$getSData();
|
|
783
1002
|
for (const name in data) {
|
|
@@ -790,13 +1009,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
790
1009
|
(this.$dataStore as any)[name] = referencesToEntities(
|
|
791
1010
|
data[name],
|
|
792
1011
|
this.$nymph,
|
|
793
|
-
this.$skipAc
|
|
1012
|
+
this.$skipAc,
|
|
794
1013
|
);
|
|
795
1014
|
}
|
|
796
1015
|
this.$sdata = mySdata;
|
|
797
1016
|
// Set original AC values if not set..
|
|
798
1017
|
if (this.$originalAcValues == null) {
|
|
799
|
-
this.$originalAcValues = this.$
|
|
1018
|
+
this.$originalAcValues = this.$getCurrentAcValues();
|
|
800
1019
|
}
|
|
801
1020
|
}
|
|
802
1021
|
|
|
@@ -813,14 +1032,14 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
813
1032
|
) {
|
|
814
1033
|
throw new InvalidParametersError(
|
|
815
1034
|
'referenceSleep expects parameter 1 to be a valid Nymph entity ' +
|
|
816
|
-
'reference.'
|
|
1035
|
+
'reference.',
|
|
817
1036
|
);
|
|
818
1037
|
}
|
|
819
1038
|
const thisClass: string = (this.constructor as any).class;
|
|
820
1039
|
if (reference[2] !== thisClass) {
|
|
821
1040
|
throw new InvalidParametersError(
|
|
822
1041
|
'referenceSleep can only be called with an entity reference of the ' +
|
|
823
|
-
`same class. Given class: ${reference[2]}; this class: ${thisClass}
|
|
1042
|
+
`same class. Given class: ${reference[2]}; this class: ${thisClass}.`,
|
|
824
1043
|
);
|
|
825
1044
|
}
|
|
826
1045
|
this.$isASleepingReference = true;
|
|
@@ -828,49 +1047,141 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
828
1047
|
this.$sleepingReference = reference;
|
|
829
1048
|
}
|
|
830
1049
|
|
|
1050
|
+
/**
|
|
1051
|
+
* Check if this is a sleeping reference and throw an error if so.
|
|
1052
|
+
*/
|
|
1053
|
+
protected $check() {
|
|
1054
|
+
if (this.$isASleepingReference || this.$sleepingReference != null) {
|
|
1055
|
+
throw new EntityIsSleepingReferenceError(
|
|
1056
|
+
'This entity is in a sleeping reference state. You must use .$wake() to wake it.',
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Check if this is a sleeping reference.
|
|
1063
|
+
*/
|
|
1064
|
+
public $asleep() {
|
|
1065
|
+
return this.$isASleepingReference || this.$sleepingReference != null;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
831
1068
|
/**
|
|
832
1069
|
* Wake from a sleeping reference.
|
|
833
|
-
*
|
|
834
|
-
* @returns True on success, false on failure.
|
|
835
1070
|
*/
|
|
836
|
-
|
|
1071
|
+
public $wake() {
|
|
837
1072
|
if (!this.$isASleepingReference || this.$sleepingReference == null) {
|
|
838
|
-
|
|
1073
|
+
this.$wakePromise = null;
|
|
1074
|
+
return Promise.resolve(this);
|
|
839
1075
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
skipAc: this.$skipAc,
|
|
845
|
-
},
|
|
846
|
-
{ type: '&', guid: this.$sleepingReference[1] }
|
|
847
|
-
);
|
|
848
|
-
if (entity == null) {
|
|
849
|
-
return false;
|
|
1076
|
+
if (this.$sleepingReference?.[1] == null) {
|
|
1077
|
+
throw new InvalidStateError(
|
|
1078
|
+
'Tried to wake a sleeping reference with no GUID.',
|
|
1079
|
+
);
|
|
850
1080
|
}
|
|
851
|
-
this.$
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
1081
|
+
if (!this.$wakePromise) {
|
|
1082
|
+
const EntityClass = this.$nymph.getEntityClass(
|
|
1083
|
+
this.$sleepingReference[2],
|
|
1084
|
+
);
|
|
1085
|
+
this.$wakePromise = this.$nymph
|
|
1086
|
+
.getEntity(
|
|
1087
|
+
{
|
|
1088
|
+
class: EntityClass,
|
|
1089
|
+
skipAc: this.$skipAc,
|
|
1090
|
+
},
|
|
1091
|
+
{ type: '&', guid: this.$sleepingReference[1] },
|
|
1092
|
+
)
|
|
1093
|
+
.then((entity) => {
|
|
1094
|
+
if (entity == null || entity.guid == null) {
|
|
1095
|
+
return Promise.reject(
|
|
1096
|
+
new InvalidStateError(
|
|
1097
|
+
'The sleeping reference could not be retrieved.',
|
|
1098
|
+
),
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
this.$isASleepingReference = false;
|
|
1102
|
+
this.$sleepingReference = null;
|
|
1103
|
+
this.guid = entity.guid;
|
|
1104
|
+
this.tags = entity.tags;
|
|
1105
|
+
this.cdate = entity.cdate;
|
|
1106
|
+
this.mdate = entity.mdate;
|
|
1107
|
+
this.$putData(
|
|
1108
|
+
entity.$getData(false, true),
|
|
1109
|
+
entity.$getSData(),
|
|
1110
|
+
'server',
|
|
1111
|
+
);
|
|
1112
|
+
|
|
1113
|
+
return this;
|
|
1114
|
+
})
|
|
1115
|
+
.finally(() => {
|
|
1116
|
+
this.$wakePromise = null;
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
return this.$wakePromise;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
public $wakeAll(level?: number) {
|
|
1123
|
+
return new Promise((resolve, reject) => {
|
|
1124
|
+
// Run this once this entity is wake.
|
|
1125
|
+
const wakeProps = () => {
|
|
1126
|
+
let newLevel;
|
|
1127
|
+
// If level is undefined, keep going forever, otherwise, stop once we've
|
|
1128
|
+
// gone deep enough.
|
|
1129
|
+
if (level !== undefined) {
|
|
1130
|
+
newLevel = level - 1;
|
|
1131
|
+
}
|
|
1132
|
+
if (newLevel !== undefined && newLevel < 0) {
|
|
1133
|
+
resolve(this);
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
const promises = [];
|
|
1137
|
+
// Go through data looking for entities to wake.
|
|
1138
|
+
for (let [key, value] of Object.entries(this.$data)) {
|
|
1139
|
+
if (value instanceof Entity && value.$isASleepingReference) {
|
|
1140
|
+
promises.push(value.$wakeAll(newLevel));
|
|
1141
|
+
} else if (Array.isArray(value)) {
|
|
1142
|
+
for (let i = 0; i < value.length; i++) {
|
|
1143
|
+
if (
|
|
1144
|
+
value[i] instanceof Entity &&
|
|
1145
|
+
value[i].$isASleepingReference
|
|
1146
|
+
) {
|
|
1147
|
+
promises.push(value[i].$wakeAll(newLevel));
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (promises.length) {
|
|
1153
|
+
Promise.all(promises).then(
|
|
1154
|
+
() => resolve(this),
|
|
1155
|
+
(errObj) => reject(errObj),
|
|
1156
|
+
);
|
|
1157
|
+
} else {
|
|
1158
|
+
resolve(this);
|
|
1159
|
+
}
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
if (this.$isASleepingReference) {
|
|
1163
|
+
this.$wake().then(wakeProps, (errObj) => reject(errObj));
|
|
1164
|
+
} else {
|
|
1165
|
+
wakeProps();
|
|
1166
|
+
}
|
|
1167
|
+
}) as Promise<Entity<T>>;
|
|
859
1168
|
}
|
|
860
1169
|
|
|
861
1170
|
public async $refresh() {
|
|
862
|
-
this.$
|
|
1171
|
+
await this.$wake();
|
|
863
1172
|
|
|
864
1173
|
if (this.guid == null) {
|
|
865
1174
|
return false;
|
|
866
1175
|
}
|
|
867
1176
|
const refresh = await this.$nymph.getEntity(
|
|
868
1177
|
{
|
|
869
|
-
class: this.
|
|
1178
|
+
class: this.$nymph.getEntityClass(
|
|
1179
|
+
this.constructor as EntityConstructor,
|
|
1180
|
+
),
|
|
870
1181
|
skipCache: true,
|
|
871
1182
|
skipAc: this.$skipAc,
|
|
872
1183
|
},
|
|
873
|
-
{ type: '&', guid: this.guid }
|
|
1184
|
+
{ type: '&', guid: this.guid },
|
|
874
1185
|
);
|
|
875
1186
|
if (refresh == null) {
|
|
876
1187
|
return 0;
|
|
@@ -878,32 +1189,32 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
878
1189
|
this.tags = refresh.tags;
|
|
879
1190
|
this.cdate = refresh.cdate;
|
|
880
1191
|
this.mdate = refresh.mdate;
|
|
881
|
-
this.$putData(refresh.$getData(), refresh.$getSData());
|
|
1192
|
+
this.$putData(refresh.$getData(false, true), refresh.$getSData(), 'server');
|
|
882
1193
|
return true;
|
|
883
1194
|
}
|
|
884
1195
|
|
|
885
1196
|
public $removeTag(...tags: string[]) {
|
|
886
|
-
this.$
|
|
1197
|
+
this.$check();
|
|
887
1198
|
|
|
888
1199
|
this.tags = difference(this.tags, tags);
|
|
889
1200
|
}
|
|
890
1201
|
|
|
891
1202
|
public async $save(): Promise<boolean> {
|
|
892
|
-
this.$
|
|
1203
|
+
await this.$wake();
|
|
893
1204
|
|
|
894
1205
|
return await this.$nymph.saveEntity(this);
|
|
895
1206
|
}
|
|
896
1207
|
|
|
897
|
-
public $toReference() {
|
|
1208
|
+
public $toReference(existingOnly?: boolean) {
|
|
898
1209
|
if (this.$isASleepingReference && this.$sleepingReference != null) {
|
|
899
1210
|
return this.$sleepingReference;
|
|
900
1211
|
}
|
|
901
|
-
if (this.guid == null) {
|
|
1212
|
+
if (existingOnly && this.guid == null) {
|
|
902
1213
|
return this;
|
|
903
1214
|
}
|
|
904
1215
|
return [
|
|
905
1216
|
'nymph_entity_reference',
|
|
906
|
-
this
|
|
1217
|
+
this.$getGuaranteedGUID(),
|
|
907
1218
|
(this.constructor as any).class as string,
|
|
908
1219
|
] as EntityReference;
|
|
909
1220
|
}
|