@nymphjs/client 1.0.0-beta.13 → 1.0.0-beta.131
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 +552 -0
- package/README.md +12 -8
- package/asyncitertest.js +53 -0
- package/dist/Entity.d.ts +158 -0
- package/dist/Entity.js +643 -0
- package/dist/Entity.js.map +1 -0
- package/dist/Entity.types.d.ts +216 -0
- package/dist/Entity.types.js +2 -0
- package/{lib → dist}/EntityWeakCache.d.ts +1 -1
- package/{lib → dist}/EntityWeakCache.js +5 -9
- package/dist/EntityWeakCache.js.map +1 -0
- package/{lib → dist}/HttpRequester.d.ts +18 -4
- package/dist/HttpRequester.js +365 -0
- package/dist/HttpRequester.js.map +1 -0
- package/{lib → dist}/Nymph.d.ts +48 -11
- package/{lib → dist}/Nymph.js +172 -56
- package/dist/Nymph.js.map +1 -0
- package/dist/Nymph.types.d.ts +227 -0
- package/dist/Nymph.types.js +45 -0
- package/dist/Nymph.types.js.map +1 -0
- package/{lib → dist}/PubSub.d.ts +16 -10
- package/{lib → dist}/PubSub.js +207 -135
- package/dist/PubSub.js.map +1 -0
- package/{lib → dist}/PubSub.types.d.ts +19 -6
- package/dist/PubSub.types.js +2 -0
- package/{lib → dist}/entityRefresh.d.ts +1 -1
- package/{lib → dist}/entityRefresh.js +21 -13
- package/dist/entityRefresh.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/{lib → dist}/utils.d.ts +2 -1
- package/dist/utils.js +145 -0
- package/dist/utils.js.map +1 -0
- package/jest.config.js +31 -5
- package/package.json +36 -32
- package/src/Entity.ts +361 -247
- package/src/Entity.types.ts +37 -57
- package/src/EntityWeakCache.ts +8 -6
- package/src/HttpRequester.ts +268 -31
- package/src/Nymph.ts +203 -96
- package/src/Nymph.types.ts +98 -2
- package/src/PubSub.ts +264 -181
- package/src/PubSub.types.ts +33 -19
- package/src/entityRefresh.ts +6 -6
- package/src/index.ts +10 -10
- package/src/utils.ts +67 -14
- package/tsconfig.json +7 -4
- package/typedoc.json +4 -0
- package/dist/index.js.LICENSE.txt +0 -8
- package/lib/Entity.d.ts +0 -51
- package/lib/Entity.js +0 -500
- package/lib/Entity.js.map +0 -1
- package/lib/Entity.types.d.ts +0 -65
- package/lib/Entity.types.js +0 -3
- package/lib/EntityWeakCache.js.map +0 -1
- package/lib/HttpRequester.js +0 -190
- package/lib/HttpRequester.js.map +0 -1
- package/lib/Nymph.js.map +0 -1
- package/lib/Nymph.types.d.ts +0 -98
- package/lib/Nymph.types.js +0 -3
- package/lib/Nymph.types.js.map +0 -1
- package/lib/PubSub.js.map +0 -1
- package/lib/PubSub.types.js +0 -3
- package/lib/entityRefresh.js.map +0 -1
- package/lib/index.d.ts +0 -13
- package/lib/index.js +0 -34
- package/lib/index.js.map +0 -1
- package/lib/utils.js +0 -86
- package/lib/utils.js.map +0 -1
- package/webpack.config.js +0 -28
- /package/{lib → dist}/Entity.types.js.map +0 -0
- /package/{lib → dist}/PubSub.types.js.map +0 -0
package/src/Entity.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { difference, isEqual } from 'lodash';
|
|
1
|
+
import { difference, isEqual } from 'lodash-es';
|
|
2
2
|
|
|
3
|
-
import type Nymph from './Nymph';
|
|
3
|
+
import type Nymph from './Nymph.js';
|
|
4
4
|
import {
|
|
5
5
|
EntityConstructor,
|
|
6
6
|
EntityData,
|
|
@@ -8,21 +8,25 @@ import {
|
|
|
8
8
|
EntityJson,
|
|
9
9
|
EntityPatch,
|
|
10
10
|
EntityReference,
|
|
11
|
-
} from './Entity.types';
|
|
11
|
+
} from './Entity.types.js';
|
|
12
12
|
import {
|
|
13
13
|
uniqueStrings,
|
|
14
14
|
entitiesToReferences,
|
|
15
15
|
referencesToEntities,
|
|
16
16
|
sortObj,
|
|
17
|
-
|
|
17
|
+
entityConstructorsToClassNames,
|
|
18
|
+
classNamesToEntityConstructors,
|
|
19
|
+
} from './utils.js';
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'You must use .$ready() to wake it.';
|
|
21
|
+
export type EntityDataType<T> =
|
|
22
|
+
T extends Entity<infer DataType> ? DataType : never;
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
export type EntityInstanceType<T extends EntityConstructor> =
|
|
25
|
+
T extends new () => infer E ? E & EntityDataType<E> : never;
|
|
26
|
+
|
|
27
|
+
export default class Entity<
|
|
28
|
+
T extends EntityData = EntityData,
|
|
29
|
+
> implements EntityInterface {
|
|
26
30
|
/**
|
|
27
31
|
* The instance of Nymph to use for queries.
|
|
28
32
|
*/
|
|
@@ -84,29 +88,26 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
84
88
|
*/
|
|
85
89
|
protected $sleepingReference: EntityReference | null = null;
|
|
86
90
|
/**
|
|
87
|
-
* A promise that resolved when the entity's data is
|
|
91
|
+
* A promise that resolved when the entity's data is wake.
|
|
88
92
|
*/
|
|
89
|
-
protected $
|
|
93
|
+
protected $wakePromise: Promise<Entity<T>> | null = null;
|
|
90
94
|
|
|
91
95
|
/**
|
|
92
|
-
*
|
|
93
|
-
* @param guid The ID of the entity to load, undefined for a new entity.
|
|
96
|
+
* Initialize an entity.
|
|
94
97
|
*/
|
|
95
|
-
public constructor(
|
|
98
|
+
public constructor(..._rest: any[]) {
|
|
96
99
|
this.$nymph = (this.constructor as EntityConstructor).nymph;
|
|
97
100
|
this.$dataHandler = {
|
|
98
101
|
has: (data: EntityData, name: string) => {
|
|
99
|
-
if (typeof name !== 'symbol'
|
|
100
|
-
|
|
101
|
-
return false;
|
|
102
|
+
if (typeof name !== 'symbol') {
|
|
103
|
+
this.$check();
|
|
102
104
|
}
|
|
103
105
|
return name in data;
|
|
104
106
|
},
|
|
105
107
|
|
|
106
108
|
get: (data: EntityData, name: string) => {
|
|
107
|
-
if (typeof name !== 'symbol'
|
|
108
|
-
|
|
109
|
-
return undefined;
|
|
109
|
+
if (typeof name !== 'symbol') {
|
|
110
|
+
this.$check();
|
|
110
111
|
}
|
|
111
112
|
if (data.hasOwnProperty(name)) {
|
|
112
113
|
return data[name];
|
|
@@ -115,9 +116,8 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
115
116
|
},
|
|
116
117
|
|
|
117
118
|
set: (data: EntityData, name: string, value: any) => {
|
|
118
|
-
if (typeof name !== 'symbol'
|
|
119
|
-
|
|
120
|
-
return false;
|
|
119
|
+
if (typeof name !== 'symbol') {
|
|
120
|
+
this.$check();
|
|
121
121
|
}
|
|
122
122
|
if (typeof name !== 'symbol') {
|
|
123
123
|
this.$dirty[name] = true;
|
|
@@ -127,11 +127,8 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
127
127
|
},
|
|
128
128
|
|
|
129
129
|
deleteProperty: (data: EntityData, name: string) => {
|
|
130
|
-
if (typeof name !== 'symbol'
|
|
131
|
-
|
|
132
|
-
`Tried to delete data on a sleeping reference: ${name}`
|
|
133
|
-
);
|
|
134
|
-
return false;
|
|
130
|
+
if (typeof name !== 'symbol') {
|
|
131
|
+
this.$check();
|
|
135
132
|
}
|
|
136
133
|
if (data.hasOwnProperty(name)) {
|
|
137
134
|
this.$dirty[name] = true;
|
|
@@ -143,13 +140,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
143
140
|
defineProperty: (
|
|
144
141
|
data: EntityData,
|
|
145
142
|
name: string,
|
|
146
|
-
descriptor: PropertyDescriptor
|
|
143
|
+
descriptor: PropertyDescriptor,
|
|
147
144
|
) => {
|
|
148
|
-
if (typeof name !== 'symbol'
|
|
149
|
-
|
|
150
|
-
`Tried to define data on a sleeping reference: ${name}`
|
|
151
|
-
);
|
|
152
|
-
return false;
|
|
145
|
+
if (typeof name !== 'symbol') {
|
|
146
|
+
this.$check();
|
|
153
147
|
}
|
|
154
148
|
if (typeof name !== 'symbol') {
|
|
155
149
|
this.$dirty[name] = true;
|
|
@@ -159,173 +153,258 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
159
153
|
},
|
|
160
154
|
|
|
161
155
|
getOwnPropertyDescriptor: (data: EntityData, name: string) => {
|
|
162
|
-
if (typeof name !== 'symbol'
|
|
163
|
-
|
|
164
|
-
`Tried to get property descriptor on a sleeping reference: ${name}`
|
|
165
|
-
);
|
|
166
|
-
return undefined;
|
|
156
|
+
if (typeof name !== 'symbol') {
|
|
157
|
+
this.$check();
|
|
167
158
|
}
|
|
168
159
|
return Object.getOwnPropertyDescriptor(data, name);
|
|
169
160
|
},
|
|
170
161
|
|
|
171
162
|
ownKeys: (data: EntityData) => {
|
|
172
|
-
|
|
173
|
-
console.error(`Tried to enumerate data on a sleeping reference.`);
|
|
174
|
-
return undefined;
|
|
175
|
-
}
|
|
163
|
+
this.$check();
|
|
176
164
|
return Object.getOwnPropertyNames(data);
|
|
177
165
|
},
|
|
178
166
|
};
|
|
179
167
|
this.$dataStore = {} as T;
|
|
180
168
|
this.$data = new Proxy(this.$dataStore, this.$dataHandler);
|
|
181
169
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.$isASleepingReference = true;
|
|
185
|
-
this.$sleepingReference = [
|
|
186
|
-
'nymph_entity_reference',
|
|
187
|
-
this.guid,
|
|
188
|
-
(this.constructor as EntityConstructor).class,
|
|
189
|
-
];
|
|
190
|
-
this.$ready();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return new Proxy(this, {
|
|
194
|
-
has(entity: Entity, name: string) {
|
|
195
|
-
if (
|
|
196
|
-
typeof name !== 'string' ||
|
|
197
|
-
name in entity ||
|
|
198
|
-
name.substring(0, 1) === '$'
|
|
199
|
-
) {
|
|
200
|
-
return name in entity;
|
|
201
|
-
}
|
|
202
|
-
return name in entity.$data;
|
|
203
|
-
},
|
|
204
|
-
|
|
205
|
-
get(entity: Entity, name: string) {
|
|
206
|
-
if (
|
|
207
|
-
typeof name !== 'string' ||
|
|
208
|
-
name in entity ||
|
|
209
|
-
name.substring(0, 1) === '$'
|
|
210
|
-
) {
|
|
211
|
-
return (entity as EntityInterface)[name];
|
|
212
|
-
}
|
|
213
|
-
if (name in entity.$data) {
|
|
214
|
-
return entity.$data[name];
|
|
215
|
-
}
|
|
216
|
-
return undefined;
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
set(entity: Entity, name: string, value: any) {
|
|
220
|
-
if (
|
|
221
|
-
typeof name !== 'string' ||
|
|
222
|
-
name in entity ||
|
|
223
|
-
name.substring(0, 1) === '$'
|
|
224
|
-
) {
|
|
225
|
-
(entity as EntityInterface)[name] = value;
|
|
226
|
-
} else {
|
|
227
|
-
entity.$data[name] = value;
|
|
228
|
-
}
|
|
229
|
-
return true;
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
deleteProperty(entity: Entity, name: string) {
|
|
233
|
-
if (name in entity) {
|
|
234
|
-
return delete (entity as EntityInterface)[name];
|
|
235
|
-
} else if (name in entity.$data) {
|
|
236
|
-
return delete entity.$data[name];
|
|
237
|
-
}
|
|
238
|
-
return true;
|
|
239
|
-
},
|
|
170
|
+
return this.$proxy();
|
|
171
|
+
}
|
|
240
172
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
173
|
+
private $existingProxy?: this & T;
|
|
174
|
+
protected $proxy() {
|
|
175
|
+
if (this.$existingProxy == null) {
|
|
176
|
+
this.$existingProxy = new Proxy(this, {
|
|
177
|
+
has: (entity: this, name: string) => {
|
|
178
|
+
if (
|
|
179
|
+
typeof name !== 'string' ||
|
|
180
|
+
name in entity ||
|
|
181
|
+
name.substring(0, 1) === '$'
|
|
182
|
+
) {
|
|
183
|
+
return name in entity;
|
|
184
|
+
}
|
|
244
185
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
},
|
|
186
|
+
this.$check();
|
|
187
|
+
return name in entity.$data;
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
get: (entity: this, name: string) => {
|
|
191
|
+
if (
|
|
192
|
+
typeof name !== 'string' ||
|
|
193
|
+
name in entity ||
|
|
194
|
+
name.substring(0, 1) === '$'
|
|
195
|
+
) {
|
|
196
|
+
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
197
|
+
this.$check();
|
|
198
|
+
}
|
|
199
|
+
return (entity as any)[name];
|
|
200
|
+
}
|
|
261
201
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
202
|
+
this.$check();
|
|
203
|
+
if (name in entity.$data) {
|
|
204
|
+
return entity.$data[name];
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
set: (entity: this, name: string, value: any) => {
|
|
210
|
+
if (
|
|
211
|
+
typeof name !== 'string' ||
|
|
212
|
+
name in entity ||
|
|
213
|
+
name.substring(0, 1) === '$'
|
|
214
|
+
) {
|
|
215
|
+
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
216
|
+
this.$check();
|
|
217
|
+
}
|
|
218
|
+
(entity as any)[name] = value;
|
|
219
|
+
} else {
|
|
220
|
+
this.$check();
|
|
221
|
+
(entity.$data as any)[name] = value;
|
|
222
|
+
}
|
|
223
|
+
return true;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
deleteProperty: (entity: this, name: string) => {
|
|
227
|
+
if (name in entity) {
|
|
228
|
+
return delete (entity as any)[name];
|
|
229
|
+
} else if (name in entity.$data) {
|
|
230
|
+
this.$check();
|
|
231
|
+
return delete entity.$data[name];
|
|
232
|
+
}
|
|
233
|
+
return true;
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
getPrototypeOf: (entity: this) => {
|
|
237
|
+
return entity.constructor.prototype;
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
defineProperty: (
|
|
241
|
+
entity: this,
|
|
242
|
+
name: string,
|
|
243
|
+
descriptor: PropertyDescriptor,
|
|
244
|
+
) => {
|
|
245
|
+
if (
|
|
246
|
+
typeof name !== 'string' ||
|
|
247
|
+
name in entity ||
|
|
248
|
+
name.substring(0, 1) === '$'
|
|
249
|
+
) {
|
|
250
|
+
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
251
|
+
this.$check();
|
|
252
|
+
}
|
|
253
|
+
Object.defineProperty(entity, name, descriptor);
|
|
254
|
+
} else {
|
|
255
|
+
this.$check();
|
|
256
|
+
Object.defineProperty(entity.$data, name, descriptor);
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
getOwnPropertyDescriptor: (entity: this, name: string) => {
|
|
262
|
+
if (
|
|
263
|
+
typeof name !== 'string' ||
|
|
264
|
+
name in entity ||
|
|
265
|
+
name.substring(0, 1) === '$'
|
|
266
|
+
) {
|
|
267
|
+
if (name === 'tags' || name === 'cdate' || name === 'mdate') {
|
|
268
|
+
this.$check();
|
|
269
|
+
}
|
|
270
|
+
return Object.getOwnPropertyDescriptor(entity, name);
|
|
271
|
+
} else {
|
|
272
|
+
this.$check();
|
|
273
|
+
return Object.getOwnPropertyDescriptor(entity.$data, name);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
273
276
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
Object.getOwnPropertyNames(entity
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
277
|
+
ownKeys: (entity: this) => {
|
|
278
|
+
this.$check();
|
|
279
|
+
return Object.getOwnPropertyNames(entity).concat(
|
|
280
|
+
Object.getOwnPropertyNames(entity.$data),
|
|
281
|
+
);
|
|
282
|
+
},
|
|
283
|
+
}) as this & T;
|
|
284
|
+
}
|
|
285
|
+
return this.$existingProxy;
|
|
280
286
|
}
|
|
281
287
|
|
|
282
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Create or retrieve a new entity instance.
|
|
290
|
+
*
|
|
291
|
+
* Note that this will always return an entity, even if the GUID is not found.
|
|
292
|
+
*
|
|
293
|
+
* @param guid An optional GUID to retrieve.
|
|
294
|
+
*/
|
|
295
|
+
public static async factory<E extends Entity>(
|
|
296
|
+
this: {
|
|
297
|
+
new (): E;
|
|
298
|
+
},
|
|
299
|
+
guid?: string,
|
|
300
|
+
): Promise<E & EntityDataType<E>> {
|
|
283
301
|
const cacheEntity = (
|
|
284
|
-
guid
|
|
302
|
+
guid
|
|
303
|
+
? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
|
|
304
|
+
this as unknown as EntityConstructor,
|
|
305
|
+
guid,
|
|
306
|
+
)
|
|
307
|
+
: null
|
|
285
308
|
) as Entity | null;
|
|
286
|
-
|
|
309
|
+
if (cacheEntity) {
|
|
310
|
+
return cacheEntity as E & EntityDataType<E>;
|
|
311
|
+
}
|
|
312
|
+
const entity = new this();
|
|
287
313
|
if (guid != null) {
|
|
288
|
-
|
|
314
|
+
entity.guid = guid;
|
|
315
|
+
entity.$isASleepingReference = true;
|
|
316
|
+
entity.$sleepingReference = [
|
|
317
|
+
'nymph_entity_reference',
|
|
318
|
+
guid,
|
|
319
|
+
(this as unknown as EntityConstructor).class,
|
|
320
|
+
];
|
|
321
|
+
await entity.$wake();
|
|
289
322
|
}
|
|
290
|
-
return entity
|
|
323
|
+
return entity as E & EntityDataType<E>;
|
|
291
324
|
}
|
|
292
325
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
326
|
+
/**
|
|
327
|
+
* Create a new entity instance.
|
|
328
|
+
*/
|
|
329
|
+
public static factorySync<E extends Entity>(this: {
|
|
330
|
+
new (): E;
|
|
331
|
+
}): E & EntityDataType<E> {
|
|
332
|
+
return new this() as E & EntityDataType<E>;
|
|
298
333
|
}
|
|
299
334
|
|
|
300
|
-
|
|
335
|
+
/**
|
|
336
|
+
* Create a new sleeping reference instance.
|
|
337
|
+
*
|
|
338
|
+
* Sleeping references won't retrieve their data from the server until they
|
|
339
|
+
* are readied with `$wake()` or a parent's `$wakeAll()`.
|
|
340
|
+
*
|
|
341
|
+
* @param reference The Nymph Entity Reference to use to wake.
|
|
342
|
+
* @returns The new instance.
|
|
343
|
+
*/
|
|
344
|
+
public static factoryReference<E extends Entity>(
|
|
345
|
+
this: {
|
|
346
|
+
new (): E;
|
|
347
|
+
},
|
|
348
|
+
reference: EntityReference,
|
|
349
|
+
): E & EntityDataType<E> {
|
|
301
350
|
const cacheEntity = (
|
|
302
|
-
reference[1]
|
|
351
|
+
reference[1]
|
|
352
|
+
? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
|
|
353
|
+
this as unknown as EntityConstructor,
|
|
354
|
+
reference[1],
|
|
355
|
+
)
|
|
356
|
+
: null
|
|
303
357
|
) as Entity | null;
|
|
304
358
|
|
|
305
359
|
const entity = cacheEntity || new this();
|
|
306
360
|
if (!cacheEntity) {
|
|
307
361
|
entity.$referenceSleep(reference);
|
|
308
362
|
}
|
|
309
|
-
return entity
|
|
363
|
+
return entity as E & EntityDataType<E>;
|
|
310
364
|
}
|
|
311
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Call a static method on the server version of this entity.
|
|
368
|
+
*
|
|
369
|
+
* @param method The name of the method.
|
|
370
|
+
* @param params The parameters to call the method with.
|
|
371
|
+
* @returns The value that the method on the server returned.
|
|
372
|
+
*/
|
|
312
373
|
public static async serverCallStatic(method: string, params: Iterable<any>) {
|
|
313
374
|
const data = await this.nymph.serverCallStatic(
|
|
314
375
|
this.class,
|
|
315
376
|
method,
|
|
316
377
|
// Turn the params into a real array, in case an arguments object was
|
|
317
378
|
// passed.
|
|
318
|
-
Array.prototype.slice.call(params)
|
|
379
|
+
Array.prototype.slice.call(params),
|
|
319
380
|
);
|
|
320
381
|
return data.return;
|
|
321
382
|
}
|
|
322
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Call a static iterator method on the server version of this entity.
|
|
386
|
+
*
|
|
387
|
+
* @param method The name of the method.
|
|
388
|
+
* @param params The parameters to call the method with.
|
|
389
|
+
* @returns An iterator that iterates over values that the method on the server yields.
|
|
390
|
+
*/
|
|
391
|
+
public static async serverCallStaticIterator(
|
|
392
|
+
method: string,
|
|
393
|
+
params: Iterable<any>,
|
|
394
|
+
) {
|
|
395
|
+
return await this.nymph.serverCallStaticIterator(
|
|
396
|
+
this.class,
|
|
397
|
+
method,
|
|
398
|
+
// Turn the params into a real array, in case an arguments object was
|
|
399
|
+
// passed.
|
|
400
|
+
Array.prototype.slice.call(params),
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
323
404
|
public toJSON() {
|
|
324
|
-
|
|
325
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
326
|
-
}
|
|
405
|
+
this.$check();
|
|
327
406
|
const obj: EntityJson = {
|
|
328
|
-
class: (this.constructor
|
|
407
|
+
class: entityConstructorsToClassNames(this.constructor),
|
|
329
408
|
guid: this.guid,
|
|
330
409
|
cdate: this.cdate,
|
|
331
410
|
mdate: this.mdate,
|
|
@@ -333,14 +412,16 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
333
412
|
data: {},
|
|
334
413
|
};
|
|
335
414
|
for (let [key, value] of Object.entries(this.$dataStore)) {
|
|
336
|
-
obj.data[key] =
|
|
415
|
+
obj.data[key] = entityConstructorsToClassNames(
|
|
416
|
+
entitiesToReferences(value),
|
|
417
|
+
);
|
|
337
418
|
}
|
|
338
419
|
return obj;
|
|
339
420
|
}
|
|
340
421
|
|
|
341
422
|
public $init(entityJson: EntityJson | null) {
|
|
342
423
|
if (entityJson == null) {
|
|
343
|
-
return this;
|
|
424
|
+
return this.$proxy();
|
|
344
425
|
}
|
|
345
426
|
|
|
346
427
|
this.$isASleepingReference = false;
|
|
@@ -355,23 +436,27 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
355
436
|
this.$dataStore = Object.entries(entityJson.data)
|
|
356
437
|
.map(([key, value]) => {
|
|
357
438
|
this.$dirty[key] = false;
|
|
358
|
-
return {
|
|
439
|
+
return {
|
|
440
|
+
key,
|
|
441
|
+
value: classNamesToEntityConstructors(
|
|
442
|
+
this.$nymph,
|
|
443
|
+
referencesToEntities(value, this.$nymph),
|
|
444
|
+
),
|
|
445
|
+
};
|
|
359
446
|
})
|
|
360
447
|
.reduce(
|
|
361
448
|
(obj, { key, value }) => Object.assign(obj, { [key]: value }),
|
|
362
|
-
{}
|
|
449
|
+
{},
|
|
363
450
|
) as T;
|
|
364
451
|
this.$data = new Proxy(this.$dataStore, this.$dataHandler);
|
|
365
452
|
|
|
366
453
|
this.$nymph.setEntityToCache(this.constructor as EntityConstructor, this);
|
|
367
454
|
|
|
368
|
-
return this
|
|
455
|
+
return this.$proxy();
|
|
369
456
|
}
|
|
370
457
|
|
|
371
458
|
public $addTag(...tags: string[]) {
|
|
372
|
-
|
|
373
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
374
|
-
}
|
|
459
|
+
this.$check();
|
|
375
460
|
|
|
376
461
|
if (tags.length < 1) {
|
|
377
462
|
return;
|
|
@@ -380,9 +465,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
380
465
|
}
|
|
381
466
|
|
|
382
467
|
public $arraySearch(array: any[], strict = false) {
|
|
383
|
-
|
|
384
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
385
|
-
}
|
|
468
|
+
this.$check();
|
|
386
469
|
|
|
387
470
|
if (!Array.isArray(array)) {
|
|
388
471
|
return -1;
|
|
@@ -396,20 +479,18 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
396
479
|
return -1;
|
|
397
480
|
}
|
|
398
481
|
|
|
399
|
-
public async $delete(): Promise<
|
|
400
|
-
|
|
401
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
402
|
-
}
|
|
482
|
+
public async $delete(): Promise<void> {
|
|
483
|
+
this.$check();
|
|
403
484
|
|
|
404
485
|
const guid = this.guid;
|
|
405
486
|
|
|
406
|
-
|
|
487
|
+
if ((await this.$nymph.deleteEntity(this)) !== guid) {
|
|
488
|
+
throw new Error('Failed to delete entity.');
|
|
489
|
+
}
|
|
407
490
|
}
|
|
408
491
|
|
|
409
492
|
public $equals(object: any) {
|
|
410
|
-
|
|
411
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
412
|
-
}
|
|
493
|
+
this.$check();
|
|
413
494
|
|
|
414
495
|
if (!(object instanceof Entity)) {
|
|
415
496
|
return false;
|
|
@@ -435,23 +516,21 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
435
516
|
}
|
|
436
517
|
|
|
437
518
|
public $getPatch(): EntityPatch {
|
|
438
|
-
|
|
439
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
440
|
-
}
|
|
519
|
+
this.$check();
|
|
441
520
|
if (this.guid == null) {
|
|
442
521
|
throw new InvalidStateError(
|
|
443
|
-
"You can't make a patch from an unsaved entity."
|
|
522
|
+
"You can't make a patch from an unsaved entity.",
|
|
444
523
|
);
|
|
445
524
|
}
|
|
446
525
|
const patch: EntityPatch = {
|
|
447
526
|
guid: this.guid,
|
|
448
527
|
mdate: this.mdate,
|
|
449
|
-
class: (this.constructor
|
|
528
|
+
class: entityConstructorsToClassNames(this.constructor),
|
|
450
529
|
addTags: this.tags.filter(
|
|
451
|
-
(tag) => this.$originalTags.indexOf(tag) === -1
|
|
530
|
+
(tag) => this.$originalTags.indexOf(tag) === -1,
|
|
452
531
|
),
|
|
453
532
|
removeTags: this.$originalTags.filter(
|
|
454
|
-
(tag) => this.tags.indexOf(tag) === -1
|
|
533
|
+
(tag) => this.tags.indexOf(tag) === -1,
|
|
455
534
|
),
|
|
456
535
|
unset: [],
|
|
457
536
|
set: {},
|
|
@@ -460,7 +539,9 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
460
539
|
for (let [key, dirty] of Object.entries(this.$dirty)) {
|
|
461
540
|
if (dirty) {
|
|
462
541
|
if (key in this.$data) {
|
|
463
|
-
patch.set[key] =
|
|
542
|
+
patch.set[key] = entityConstructorsToClassNames(
|
|
543
|
+
entitiesToReferences(this.$data[key]),
|
|
544
|
+
);
|
|
464
545
|
} else {
|
|
465
546
|
patch.unset.push(key);
|
|
466
547
|
}
|
|
@@ -471,9 +552,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
471
552
|
}
|
|
472
553
|
|
|
473
554
|
public $hasTag(...tags: string[]) {
|
|
474
|
-
|
|
475
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
476
|
-
}
|
|
555
|
+
this.$check();
|
|
477
556
|
|
|
478
557
|
if (!tags.length) {
|
|
479
558
|
return false;
|
|
@@ -486,14 +565,16 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
486
565
|
return true;
|
|
487
566
|
}
|
|
488
567
|
|
|
568
|
+
public $isDirty(property: string) {
|
|
569
|
+
return property in this.$dirty ? this.$dirty[property] : null;
|
|
570
|
+
}
|
|
571
|
+
|
|
489
572
|
public $inArray(array: any[], strict = false) {
|
|
490
573
|
return this.$arraySearch(array, strict) !== -1;
|
|
491
574
|
}
|
|
492
575
|
|
|
493
576
|
public $is(object: any) {
|
|
494
|
-
|
|
495
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
496
|
-
}
|
|
577
|
+
this.$check();
|
|
497
578
|
|
|
498
579
|
if (!(object instanceof Entity)) {
|
|
499
580
|
return false;
|
|
@@ -514,31 +595,52 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
514
595
|
}
|
|
515
596
|
|
|
516
597
|
public async $patch() {
|
|
517
|
-
|
|
518
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
519
|
-
}
|
|
598
|
+
this.$check();
|
|
520
599
|
|
|
521
600
|
const mdate = this.mdate;
|
|
522
601
|
|
|
523
602
|
await this.$nymph.patchEntity(this);
|
|
524
|
-
|
|
603
|
+
if (mdate === this.mdate) {
|
|
604
|
+
throw new Error('Failed to patch entity.');
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Check if this is a sleeping reference and throw an error if so.
|
|
610
|
+
*/
|
|
611
|
+
protected $check() {
|
|
612
|
+
if (this.$asleep()) {
|
|
613
|
+
throw new EntityIsSleepingReferenceError(
|
|
614
|
+
'This entity is in a sleeping reference state. You must use .$wake() to wake it.',
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Check if this is a sleeping reference.
|
|
621
|
+
*/
|
|
622
|
+
public $asleep() {
|
|
623
|
+
return this.$isASleepingReference || this.$sleepingReference != null;
|
|
525
624
|
}
|
|
526
625
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
626
|
+
/**
|
|
627
|
+
* Wake from a sleeping reference.
|
|
628
|
+
*/
|
|
629
|
+
public $wake() {
|
|
630
|
+
if (!this.$asleep()) {
|
|
631
|
+
this.$wakePromise = null;
|
|
632
|
+
return Promise.resolve(this.$proxy());
|
|
531
633
|
}
|
|
532
634
|
if (this.$sleepingReference?.[1] == null) {
|
|
533
635
|
throw new InvalidStateError(
|
|
534
|
-
'Tried to
|
|
636
|
+
'Tried to wake a sleeping reference with no GUID.',
|
|
535
637
|
);
|
|
536
638
|
}
|
|
537
|
-
if (!this.$
|
|
538
|
-
this.$
|
|
639
|
+
if (!this.$wakePromise) {
|
|
640
|
+
this.$wakePromise = this.$nymph
|
|
539
641
|
.getEntityData(
|
|
540
642
|
{ class: this.constructor as EntityConstructor },
|
|
541
|
-
{ type: '&', guid: this.$sleepingReference[1] }
|
|
643
|
+
{ type: '&', guid: this.$sleepingReference[1] },
|
|
542
644
|
)
|
|
543
645
|
.then((data) => {
|
|
544
646
|
if (data == null) {
|
|
@@ -548,56 +650,69 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
548
650
|
return this.$init(data);
|
|
549
651
|
})
|
|
550
652
|
.finally(() => {
|
|
551
|
-
this.$
|
|
653
|
+
this.$wakePromise = null;
|
|
552
654
|
});
|
|
553
655
|
}
|
|
554
|
-
return this.$
|
|
656
|
+
return this.$wakePromise;
|
|
555
657
|
}
|
|
556
658
|
|
|
557
|
-
public $
|
|
659
|
+
public $wakeAll(level?: number) {
|
|
558
660
|
return new Promise((resolve, reject) => {
|
|
559
|
-
// Run this once this entity is
|
|
560
|
-
const
|
|
561
|
-
let newLevel;
|
|
661
|
+
// Run this once this entity is awake.
|
|
662
|
+
const wakeProps = () => {
|
|
663
|
+
let newLevel: number | undefined;
|
|
562
664
|
// If level is undefined, keep going forever, otherwise, stop once we've
|
|
563
665
|
// gone deep enough.
|
|
564
666
|
if (level !== undefined) {
|
|
565
667
|
newLevel = level - 1;
|
|
566
668
|
}
|
|
567
669
|
if (newLevel !== undefined && newLevel < 0) {
|
|
568
|
-
resolve(this);
|
|
670
|
+
resolve(this.$proxy());
|
|
569
671
|
return;
|
|
570
672
|
}
|
|
571
|
-
const promises = [];
|
|
572
|
-
// Go through data looking for entities to
|
|
573
|
-
|
|
574
|
-
if (
|
|
575
|
-
|
|
576
|
-
} else if (
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
673
|
+
const promises: Promise<any>[] = [];
|
|
674
|
+
// Go through data looking for entities to wake.
|
|
675
|
+
const walkData = (data: any) => {
|
|
676
|
+
if (data == null) {
|
|
677
|
+
return;
|
|
678
|
+
} else if (
|
|
679
|
+
typeof data === 'function' &&
|
|
680
|
+
data.prototype instanceof Entity
|
|
681
|
+
) {
|
|
682
|
+
// Ignore this, it is an entity class.
|
|
683
|
+
return;
|
|
684
|
+
} else if (data instanceof Entity) {
|
|
685
|
+
// Wake it up.
|
|
686
|
+
if (data.$isASleepingReference) {
|
|
687
|
+
promises.push(data.$wakeAll(newLevel));
|
|
688
|
+
}
|
|
689
|
+
} else if (Array.isArray(data)) {
|
|
690
|
+
// Recurse into lower arrays.
|
|
691
|
+
for (let i = 0; i < data.length; i++) {
|
|
692
|
+
walkData(data[i]);
|
|
693
|
+
}
|
|
694
|
+
} else if (data instanceof Object) {
|
|
695
|
+
// Recurse into objects.
|
|
696
|
+
for (let [key, value] of Object.entries(data)) {
|
|
697
|
+
walkData(value);
|
|
584
698
|
}
|
|
585
699
|
}
|
|
586
|
-
}
|
|
700
|
+
};
|
|
701
|
+
walkData(this.$data);
|
|
587
702
|
if (promises.length) {
|
|
588
703
|
Promise.all(promises).then(
|
|
589
|
-
() => resolve(this),
|
|
590
|
-
(errObj) => reject(errObj)
|
|
704
|
+
() => resolve(this.$proxy()),
|
|
705
|
+
(errObj) => reject(errObj),
|
|
591
706
|
);
|
|
592
707
|
} else {
|
|
593
|
-
resolve(this);
|
|
708
|
+
resolve(this.$proxy());
|
|
594
709
|
}
|
|
595
710
|
};
|
|
596
711
|
|
|
597
|
-
if (this.$
|
|
598
|
-
this.$
|
|
712
|
+
if (this.$asleep()) {
|
|
713
|
+
this.$wake().then(wakeProps, (errObj) => reject(errObj));
|
|
599
714
|
} else {
|
|
600
|
-
|
|
715
|
+
wakeProps();
|
|
601
716
|
}
|
|
602
717
|
}) as Promise<Entity<T>>;
|
|
603
718
|
}
|
|
@@ -609,8 +724,8 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
609
724
|
}
|
|
610
725
|
|
|
611
726
|
public async $refresh() {
|
|
612
|
-
if (this.$
|
|
613
|
-
await this.$
|
|
727
|
+
if (this.$asleep()) {
|
|
728
|
+
await this.$wake();
|
|
614
729
|
return true;
|
|
615
730
|
}
|
|
616
731
|
|
|
@@ -624,37 +739,36 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
624
739
|
{
|
|
625
740
|
type: '&',
|
|
626
741
|
guid: this.guid,
|
|
627
|
-
}
|
|
742
|
+
},
|
|
628
743
|
);
|
|
744
|
+
if (data == null) {
|
|
745
|
+
throw new Error("The entity's data could not be refreshed.");
|
|
746
|
+
}
|
|
629
747
|
this.$init(data);
|
|
630
|
-
return
|
|
748
|
+
return true;
|
|
631
749
|
}
|
|
632
750
|
|
|
633
751
|
public $removeTag(...tags: string[]) {
|
|
634
|
-
|
|
635
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
636
|
-
}
|
|
752
|
+
this.$check();
|
|
637
753
|
|
|
638
754
|
this.tags = difference(this.tags, tags);
|
|
639
755
|
}
|
|
640
756
|
|
|
641
757
|
public async $save() {
|
|
642
|
-
|
|
643
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
644
|
-
}
|
|
758
|
+
this.$check();
|
|
645
759
|
|
|
646
760
|
await this.$nymph.saveEntity(this);
|
|
647
|
-
|
|
761
|
+
if (!this.guid) {
|
|
762
|
+
throw new Error('Failed to save entity.');
|
|
763
|
+
}
|
|
648
764
|
}
|
|
649
765
|
|
|
650
766
|
public async $serverCall(
|
|
651
767
|
method: string,
|
|
652
768
|
params: Iterable<any>,
|
|
653
|
-
stateless = false
|
|
769
|
+
stateless = false,
|
|
654
770
|
) {
|
|
655
|
-
|
|
656
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
657
|
-
}
|
|
771
|
+
this.$check();
|
|
658
772
|
// Turn the params into a real array, in case an arguments object was
|
|
659
773
|
// passed.
|
|
660
774
|
const paramArray = Array.prototype.slice.call(params);
|
|
@@ -662,7 +776,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
662
776
|
this,
|
|
663
777
|
method,
|
|
664
778
|
paramArray,
|
|
665
|
-
stateless
|
|
779
|
+
stateless,
|
|
666
780
|
);
|
|
667
781
|
if (!stateless && data.entity) {
|
|
668
782
|
this.$init(data.entity);
|
|
@@ -670,13 +784,13 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
670
784
|
return data.return;
|
|
671
785
|
}
|
|
672
786
|
|
|
673
|
-
public $toReference()
|
|
674
|
-
if (this.$isASleepingReference && this.$sleepingReference) {
|
|
787
|
+
public $toReference() {
|
|
788
|
+
if (this.$isASleepingReference && this.$sleepingReference != null) {
|
|
675
789
|
return this.$sleepingReference;
|
|
676
790
|
}
|
|
677
791
|
|
|
678
792
|
if (this.guid == null) {
|
|
679
|
-
return this
|
|
793
|
+
return this.$proxy();
|
|
680
794
|
}
|
|
681
795
|
return [
|
|
682
796
|
'nymph_entity_reference',
|