@nymphjs/pubsub 1.0.0-beta.11 → 1.0.0-beta.111
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 +454 -0
- package/README.md +8 -8
- package/dist/PubSub.d.ts +77 -12
- package/dist/PubSub.js +467 -103
- package/dist/PubSub.js.map +1 -1
- package/dist/PubSub.test.js +394 -65
- package/dist/PubSub.test.js.map +1 -1
- package/dist/PubSub.types.d.ts +6 -1
- package/dist/PubSub.types.js +1 -2
- package/dist/conf/d.d.ts +23 -0
- package/dist/conf/d.js +1 -2
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +4 -4
- 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/createServer.d.ts +2 -2
- package/dist/createServer.js +14 -15
- package/dist/createServer.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +7 -27
- package/dist/index.js.map +1 -1
- package/jest.config.js +11 -2
- package/package.json +23 -23
- package/src/PubSub.test.ts +467 -101
- package/src/PubSub.ts +548 -286
- package/src/PubSub.types.ts +2 -1
- package/src/conf/defaults.ts +2 -2
- package/src/conf/index.ts +2 -2
- package/src/createServer.ts +8 -8
- package/src/index.ts +4 -4
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/dist/PubSub.test.js
CHANGED
|
@@ -1,39 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const server_1 = __importDefault(require("@nymphjs/server"));
|
|
11
|
-
const testArtifacts_js_1 = require("@nymphjs/server/dist/testArtifacts.js");
|
|
12
|
-
const index_1 = __importDefault(require("./index"));
|
|
13
|
-
const PubSub_1 = __importDefault(require("./PubSub"));
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import ws from 'websocket';
|
|
3
|
+
import SQLite3Driver from '@nymphjs/driver-sqlite3';
|
|
4
|
+
import { Nymph as NymphServer } from '@nymphjs/nymph';
|
|
5
|
+
import { Nymph, PubSub } from '@nymphjs/client';
|
|
6
|
+
import createRestServer from '@nymphjs/server';
|
|
7
|
+
import { EmployeeModel as EmployeeModelClass, Employee as EmployeeClass, RestrictedModel as RestrictedModelClass, Restricted as RestrictedClass, PubSubDisabledModel as PubSubDisabledModelClass, PubSubDisabled as PubSubDisabledClass, } from '@nymphjs/server/dist/testArtifacts.js';
|
|
8
|
+
import createServer from './index.js';
|
|
9
|
+
import PubSubServer from './PubSub.js';
|
|
14
10
|
const sqliteConfig = {
|
|
15
11
|
filename: ':memory:',
|
|
16
12
|
};
|
|
17
13
|
const pubSubConfig = {
|
|
18
14
|
originIsAllowed: () => true,
|
|
19
|
-
entries: ['ws://localhost:
|
|
15
|
+
entries: ['ws://localhost:5083/'],
|
|
20
16
|
logger: () => { },
|
|
21
17
|
};
|
|
22
|
-
const nymphServer = new
|
|
23
|
-
const EmployeeModel = nymphServer.addEntityClass(
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
18
|
+
const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
|
|
19
|
+
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
|
|
20
|
+
const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
|
|
21
|
+
const PubSubDisabledModel = nymphServer.addEntityClass(PubSubDisabledModelClass);
|
|
22
|
+
const removePublisher = PubSubServer.initPublisher(pubSubConfig, nymphServer);
|
|
23
|
+
const app = express();
|
|
24
|
+
app.use(createRestServer(nymphServer));
|
|
25
|
+
const server = app.listen(5082);
|
|
26
|
+
const pubsubServer = createServer(5083, pubSubConfig, nymphServer);
|
|
29
27
|
const nymphOptions = {
|
|
30
|
-
restUrl: 'http://localhost:
|
|
31
|
-
pubsubUrl: 'ws://localhost:
|
|
28
|
+
restUrl: 'http://localhost:5082/',
|
|
29
|
+
pubsubUrl: 'ws://localhost:5083/',
|
|
32
30
|
noConsole: true,
|
|
31
|
+
WebSocket: ws.w3cwebsocket,
|
|
33
32
|
};
|
|
34
|
-
const nymph = new
|
|
35
|
-
const pubsub = new
|
|
36
|
-
const Employee = nymph.addEntityClass(
|
|
33
|
+
const nymph = new Nymph(nymphOptions);
|
|
34
|
+
const pubsub = new PubSub(nymphOptions, nymph);
|
|
35
|
+
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
36
|
+
const Restricted = nymph.addEntityClass(RestrictedClass);
|
|
37
|
+
const PubSubDisabled = nymph.addEntityClass(PubSubDisabledClass);
|
|
37
38
|
describe('Nymph REST Server and Client', () => {
|
|
38
39
|
async function createJane() {
|
|
39
40
|
const jane = await Employee.factory();
|
|
@@ -95,7 +96,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
95
96
|
expect('added' in update && update.added).toEqual((await jane).guid);
|
|
96
97
|
expect('data' in update && update.data.guid).toEqual((await jane).guid);
|
|
97
98
|
subscription.unsubscribe();
|
|
98
|
-
resolve(
|
|
99
|
+
resolve();
|
|
99
100
|
}
|
|
100
101
|
else {
|
|
101
102
|
expect(update).toEqual([]);
|
|
@@ -105,6 +106,167 @@ describe('Nymph REST Server and Client', () => {
|
|
|
105
106
|
});
|
|
106
107
|
});
|
|
107
108
|
});
|
|
109
|
+
it('notified of new match only after transaction committed', async () => {
|
|
110
|
+
let guid;
|
|
111
|
+
let committed = false;
|
|
112
|
+
await new Promise((resolve) => {
|
|
113
|
+
let updated = false;
|
|
114
|
+
const subscription = pubsub.subscribeEntities({ class: Employee }, {
|
|
115
|
+
type: '&',
|
|
116
|
+
equal: ['name', 'Steve Transaction'],
|
|
117
|
+
})(async (update) => {
|
|
118
|
+
if (updated) {
|
|
119
|
+
if (committed) {
|
|
120
|
+
expect('added' in update && update.added).toEqual(guid);
|
|
121
|
+
expect('data' in update && update.data.guid).toEqual(guid);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
throw new Error('Update arrived before transaction committed.');
|
|
125
|
+
}
|
|
126
|
+
subscription.unsubscribe();
|
|
127
|
+
resolve();
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
expect(update).toEqual([]);
|
|
131
|
+
updated = true;
|
|
132
|
+
const tnymph = await nymphServer.startTransaction('steve');
|
|
133
|
+
const Employee = tnymph.getEntityClass(EmployeeModel);
|
|
134
|
+
const steve = await Employee.factory();
|
|
135
|
+
steve.name = 'Steve Transaction';
|
|
136
|
+
steve.current = true;
|
|
137
|
+
steve.salary = 8000000;
|
|
138
|
+
steve.startDate = Date.now();
|
|
139
|
+
steve.subordinates = [];
|
|
140
|
+
steve.title = 'Seniorer Person';
|
|
141
|
+
try {
|
|
142
|
+
await steve.$save();
|
|
143
|
+
guid = steve.guid;
|
|
144
|
+
await new Promise((res) => setTimeout(res, 1000));
|
|
145
|
+
committed = true;
|
|
146
|
+
await tnymph.commit('steve');
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
console.error('Error creating entity: ', e);
|
|
150
|
+
throw e;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
it('not notified of new match when transaction rolled back', async () => {
|
|
157
|
+
let guid;
|
|
158
|
+
await new Promise((resolve) => {
|
|
159
|
+
let updated = false;
|
|
160
|
+
const subscription = pubsub.subscribeEntities({ class: Employee }, {
|
|
161
|
+
type: '&',
|
|
162
|
+
equal: ['name', 'Steve Rollback'],
|
|
163
|
+
})(async (update) => {
|
|
164
|
+
if (updated) {
|
|
165
|
+
if ('added' in update && update.added === guid) {
|
|
166
|
+
throw new Error('Update arrived after transaction rolled back.');
|
|
167
|
+
}
|
|
168
|
+
throw new Error('Update arrived unrelated to transaction.');
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
expect(update).toEqual([]);
|
|
172
|
+
updated = true;
|
|
173
|
+
const tnymph = await nymphServer.startTransaction('steve');
|
|
174
|
+
const Employee = tnymph.getEntityClass(EmployeeModel);
|
|
175
|
+
const steve = await Employee.factory();
|
|
176
|
+
steve.name = 'Steve Rollback';
|
|
177
|
+
steve.current = true;
|
|
178
|
+
steve.salary = 8000000;
|
|
179
|
+
steve.startDate = Date.now();
|
|
180
|
+
steve.subordinates = [];
|
|
181
|
+
steve.title = 'Seniorer Person';
|
|
182
|
+
try {
|
|
183
|
+
await steve.$save();
|
|
184
|
+
guid = steve.guid;
|
|
185
|
+
await new Promise((res) => setTimeout(res, 600));
|
|
186
|
+
await tnymph.rollback('steve');
|
|
187
|
+
await new Promise((res) => setTimeout(res, 600));
|
|
188
|
+
subscription.unsubscribe();
|
|
189
|
+
resolve();
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
console.error('Error creating entity: ', e);
|
|
193
|
+
throw e;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
it('notified of new match after complex transactions committed', async () => {
|
|
200
|
+
let guid;
|
|
201
|
+
let committed = false;
|
|
202
|
+
await new Promise((resolve) => {
|
|
203
|
+
let updated = false;
|
|
204
|
+
const subscription = pubsub.subscribeEntities({ class: Employee }, {
|
|
205
|
+
type: '&',
|
|
206
|
+
equal: ['name', 'Steve Complex'],
|
|
207
|
+
})(async (update) => {
|
|
208
|
+
if (updated) {
|
|
209
|
+
if (committed) {
|
|
210
|
+
expect('added' in update && update.added).toEqual(guid);
|
|
211
|
+
expect('data' in update && update.data.guid).toEqual(guid);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
throw new Error('Update arrived before transaction committed.');
|
|
215
|
+
}
|
|
216
|
+
subscription.unsubscribe();
|
|
217
|
+
resolve();
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
expect(update).toEqual([]);
|
|
221
|
+
updated = true;
|
|
222
|
+
const tnymphTop = await nymphServer.startTransaction('steve-top');
|
|
223
|
+
// Start a transaction that ultimately gets rolled back.
|
|
224
|
+
const tnymphB = await tnymphTop.startTransaction('steve-b');
|
|
225
|
+
const EmployeeB = tnymphB.getEntityClass(EmployeeModel);
|
|
226
|
+
const badSteve = await EmployeeB.factory();
|
|
227
|
+
badSteve.name = 'Steve Complex';
|
|
228
|
+
badSteve.current = true;
|
|
229
|
+
badSteve.salary = 8000000;
|
|
230
|
+
badSteve.startDate = Date.now();
|
|
231
|
+
badSteve.subordinates = [];
|
|
232
|
+
badSteve.title = 'Seniorer Person';
|
|
233
|
+
try {
|
|
234
|
+
await badSteve.$save();
|
|
235
|
+
await new Promise((res) => setTimeout(res, 200));
|
|
236
|
+
await tnymphB.rollback('steve-b');
|
|
237
|
+
await new Promise((res) => setTimeout(res, 200));
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
console.error('Error creating entity: ', e);
|
|
241
|
+
throw e;
|
|
242
|
+
}
|
|
243
|
+
// Start a transaction that ultimately gets committed.
|
|
244
|
+
const tnymphA = await tnymphTop.startTransaction('steve-a');
|
|
245
|
+
const EmployeeA = tnymphA.getEntityClass(EmployeeModel);
|
|
246
|
+
const goodSteve = await EmployeeA.factory();
|
|
247
|
+
goodSteve.name = 'Steve Complex';
|
|
248
|
+
goodSteve.current = true;
|
|
249
|
+
goodSteve.salary = 8000000;
|
|
250
|
+
goodSteve.startDate = Date.now();
|
|
251
|
+
goodSteve.subordinates = [];
|
|
252
|
+
goodSteve.title = 'Seniorer Person';
|
|
253
|
+
try {
|
|
254
|
+
await goodSteve.$save();
|
|
255
|
+
guid = goodSteve.guid;
|
|
256
|
+
await new Promise((res) => setTimeout(res, 200));
|
|
257
|
+
await tnymphA.commit('steve-a');
|
|
258
|
+
await new Promise((res) => setTimeout(res, 400));
|
|
259
|
+
committed = true;
|
|
260
|
+
await tnymphTop.commit('steve-top');
|
|
261
|
+
}
|
|
262
|
+
catch (e) {
|
|
263
|
+
console.error('Error creating entity: ', e);
|
|
264
|
+
throw e;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|
|
108
270
|
it('notified of entity update', async () => {
|
|
109
271
|
let jane = await createJane();
|
|
110
272
|
let entities = [];
|
|
@@ -120,11 +282,12 @@ describe('Nymph REST Server and Client', () => {
|
|
|
120
282
|
pubsub.updateArray(entities, update);
|
|
121
283
|
if (mdate > 0 && (entities[0]?.mdate ?? -1) === mdate) {
|
|
122
284
|
subscription.unsubscribe();
|
|
123
|
-
resolve(
|
|
285
|
+
resolve();
|
|
124
286
|
}
|
|
125
287
|
else if (Array.isArray(update)) {
|
|
126
288
|
expect(update.length).toEqual(1);
|
|
127
289
|
expect(entities[0].salary).toEqual(8000000);
|
|
290
|
+
// Time for a raise!
|
|
128
291
|
jane.salary = (jane.salary ?? 0) + 1000000;
|
|
129
292
|
await jane.$save();
|
|
130
293
|
mdate = jane.mdate ?? 0;
|
|
@@ -151,11 +314,12 @@ describe('Nymph REST Server and Client', () => {
|
|
|
151
314
|
pubsub.updateArray(entities, update);
|
|
152
315
|
if (mdate > 0 && (entities[0]?.mdate ?? -1) === mdate) {
|
|
153
316
|
subscription.unsubscribe();
|
|
154
|
-
resolve(
|
|
317
|
+
resolve();
|
|
155
318
|
}
|
|
156
319
|
else if (Array.isArray(update)) {
|
|
157
320
|
expect(update.length).toEqual(1);
|
|
158
321
|
expect(entities[0].salary).toEqual(8000000);
|
|
322
|
+
// Time for a raise!
|
|
159
323
|
jane.salary = (jane.salary ?? 0) + 1000000;
|
|
160
324
|
await jane.$save();
|
|
161
325
|
mdate = jane.mdate ?? 0;
|
|
@@ -167,7 +331,14 @@ describe('Nymph REST Server and Client', () => {
|
|
|
167
331
|
it('notified of new match for qref query', async () => {
|
|
168
332
|
let [jane, john] = await createBossJane();
|
|
169
333
|
let entities = [];
|
|
170
|
-
|
|
334
|
+
// Create employees that matches qref to test when multiple things match.
|
|
335
|
+
let oldEmployee = await createJane();
|
|
336
|
+
oldEmployee.current = false;
|
|
337
|
+
await oldEmployee.$save();
|
|
338
|
+
let oldEmployee2 = await createJane();
|
|
339
|
+
oldEmployee2.current = false;
|
|
340
|
+
await oldEmployee2.$save();
|
|
341
|
+
expect(await new Promise((resolve) => {
|
|
171
342
|
if (jane.guid == null || john.guid == null) {
|
|
172
343
|
throw new Error('Entity is null.');
|
|
173
344
|
}
|
|
@@ -186,13 +357,100 @@ describe('Nymph REST Server and Client', () => {
|
|
|
186
357
|
}
|
|
187
358
|
else if (Array.isArray(update)) {
|
|
188
359
|
expect(update.length).toEqual(0);
|
|
360
|
+
// John gets fired.
|
|
189
361
|
john.current = false;
|
|
190
362
|
await john.$save();
|
|
191
363
|
}
|
|
192
364
|
});
|
|
193
|
-
});
|
|
365
|
+
})).toEqual(true);
|
|
194
366
|
expect(entities.length).toEqual(1);
|
|
195
367
|
});
|
|
368
|
+
it('notified of new match for qref query in transaction', async () => {
|
|
369
|
+
let entities = [];
|
|
370
|
+
const john = await EmployeeModel.factory();
|
|
371
|
+
john.name = 'John Der';
|
|
372
|
+
john.current = true;
|
|
373
|
+
john.salary = 8000000;
|
|
374
|
+
john.startDate = Date.now();
|
|
375
|
+
john.subordinates = [];
|
|
376
|
+
john.title = 'Junior Person';
|
|
377
|
+
try {
|
|
378
|
+
await john.$save();
|
|
379
|
+
}
|
|
380
|
+
catch (e) {
|
|
381
|
+
console.error('Error creating entity: ', e);
|
|
382
|
+
throw e;
|
|
383
|
+
}
|
|
384
|
+
const jane = await EmployeeModel.factory();
|
|
385
|
+
jane.name = 'Jane Doe';
|
|
386
|
+
jane.current = true;
|
|
387
|
+
jane.salary = 8000000;
|
|
388
|
+
jane.startDate = Date.now();
|
|
389
|
+
jane.subordinates = [john];
|
|
390
|
+
jane.title = 'Seniorer Person';
|
|
391
|
+
try {
|
|
392
|
+
await jane.$save();
|
|
393
|
+
}
|
|
394
|
+
catch (e) {
|
|
395
|
+
console.error('Error creating entity: ', e);
|
|
396
|
+
throw e;
|
|
397
|
+
}
|
|
398
|
+
async function createNewBoss() {
|
|
399
|
+
// Create employee that matches qref.
|
|
400
|
+
const tnymph = await nymphServer.startTransaction('qref-test');
|
|
401
|
+
const tnymphDeep = await tnymph.startTransaction('qref-deep-test');
|
|
402
|
+
const TEmployeeModel = tnymph.getEntityClass(EmployeeModel);
|
|
403
|
+
const newBoss = await TEmployeeModel.factory();
|
|
404
|
+
newBoss.name = 'Jill Doe';
|
|
405
|
+
newBoss.current = false;
|
|
406
|
+
newBoss.salary = 8000000;
|
|
407
|
+
newBoss.startDate = Date.now();
|
|
408
|
+
newBoss.subordinates = [john];
|
|
409
|
+
newBoss.title = 'Seniorer Person';
|
|
410
|
+
try {
|
|
411
|
+
await newBoss.$save();
|
|
412
|
+
}
|
|
413
|
+
catch (e) {
|
|
414
|
+
console.error('Error creating entity: ', e);
|
|
415
|
+
throw e;
|
|
416
|
+
}
|
|
417
|
+
newBoss.current = true;
|
|
418
|
+
try {
|
|
419
|
+
await newBoss.$save();
|
|
420
|
+
}
|
|
421
|
+
catch (e) {
|
|
422
|
+
console.error('Error creating entity: ', e);
|
|
423
|
+
throw e;
|
|
424
|
+
}
|
|
425
|
+
await tnymphDeep.commit('qref-deep-test');
|
|
426
|
+
await tnymph.commit('qref-test');
|
|
427
|
+
}
|
|
428
|
+
expect(await new Promise((resolve) => {
|
|
429
|
+
if (jane.guid == null || john.guid == null) {
|
|
430
|
+
throw new Error('Entity is null.');
|
|
431
|
+
}
|
|
432
|
+
const subscription = pubsub.subscribeEntities({ class: Employee }, {
|
|
433
|
+
type: '&',
|
|
434
|
+
truthy: 'current',
|
|
435
|
+
qref: [
|
|
436
|
+
'subordinates',
|
|
437
|
+
[{ class: Employee }, { type: '&', guid: john.guid }],
|
|
438
|
+
],
|
|
439
|
+
})(async (update) => {
|
|
440
|
+
pubsub.updateArray(entities, update);
|
|
441
|
+
if (Array.isArray(update)) {
|
|
442
|
+
expect(entities.length).toEqual(1);
|
|
443
|
+
await createNewBoss();
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
expect(entities.length).toEqual(2);
|
|
447
|
+
subscription.unsubscribe();
|
|
448
|
+
resolve(true);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
})).toEqual(true);
|
|
452
|
+
expect(entities.length).toEqual(2);
|
|
453
|
+
});
|
|
196
454
|
it('notified of removed match for qref query', async () => {
|
|
197
455
|
let [jane, john] = await createBossJane();
|
|
198
456
|
let entities = [];
|
|
@@ -211,10 +469,11 @@ describe('Nymph REST Server and Client', () => {
|
|
|
211
469
|
pubsub.updateArray(entities, update);
|
|
212
470
|
if (!entities.length) {
|
|
213
471
|
subscription.unsubscribe();
|
|
214
|
-
resolve(
|
|
472
|
+
resolve();
|
|
215
473
|
}
|
|
216
474
|
else if (Array.isArray(update)) {
|
|
217
475
|
expect(update.length).toEqual(1);
|
|
476
|
+
// John gets fired.
|
|
218
477
|
john.current = false;
|
|
219
478
|
await john.$save();
|
|
220
479
|
}
|
|
@@ -225,8 +484,10 @@ describe('Nymph REST Server and Client', () => {
|
|
|
225
484
|
it('receives correct number of updates', async () => {
|
|
226
485
|
let jane = await createJane();
|
|
227
486
|
let entities = [];
|
|
228
|
-
|
|
487
|
+
// Wait for change to propagate. (Only needed since we're not going across network.)
|
|
488
|
+
await new Promise((resolve) => setTimeout(() => resolve(), 10));
|
|
229
489
|
await new Promise((resolve) => {
|
|
490
|
+
// Should only receive 1 update, since we waited.
|
|
230
491
|
let updated = false;
|
|
231
492
|
if (jane.guid == null) {
|
|
232
493
|
throw new Error('Entity is null.');
|
|
@@ -238,12 +499,13 @@ describe('Nymph REST Server and Client', () => {
|
|
|
238
499
|
pubsub.updateArray(entities, update);
|
|
239
500
|
if (updated) {
|
|
240
501
|
subscription.unsubscribe();
|
|
241
|
-
resolve(
|
|
502
|
+
resolve();
|
|
242
503
|
}
|
|
243
504
|
else if (Array.isArray(update)) {
|
|
244
505
|
expect(update.length).toEqual(1);
|
|
245
506
|
expect(entities[0].salary).toEqual(8000000);
|
|
246
507
|
updated = true;
|
|
508
|
+
// Time for a raise!
|
|
247
509
|
jane.salary = (jane.salary ?? 0) + 1000000;
|
|
248
510
|
await jane.$save();
|
|
249
511
|
}
|
|
@@ -252,39 +514,39 @@ describe('Nymph REST Server and Client', () => {
|
|
|
252
514
|
expect(entities[0].salary).toEqual(9000000);
|
|
253
515
|
});
|
|
254
516
|
it('notified of entity delete', async () => {
|
|
255
|
-
let jane
|
|
517
|
+
let jane;
|
|
256
518
|
let entities = [];
|
|
257
|
-
|
|
258
|
-
let length = -1;
|
|
519
|
+
let removed = false;
|
|
259
520
|
await new Promise((resolve) => {
|
|
260
|
-
let updated = false;
|
|
261
|
-
if (jane.guid == null) {
|
|
262
|
-
throw new Error('Entity is null.');
|
|
263
|
-
}
|
|
264
521
|
const subscription = pubsub.subscribeEntities({ class: Employee }, {
|
|
265
522
|
type: '&',
|
|
266
523
|
equal: ['name', 'Jane Doe'],
|
|
267
524
|
})(async (update) => {
|
|
268
525
|
pubsub.updateArray(entities, update);
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
|
|
526
|
+
if (Array.isArray(update)) {
|
|
527
|
+
jane = await createJane();
|
|
528
|
+
if (jane.guid == null) {
|
|
529
|
+
throw new Error('Entity is null.');
|
|
530
|
+
}
|
|
272
531
|
}
|
|
273
|
-
else if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
532
|
+
else if ('added' in update) {
|
|
533
|
+
await entities.find((e) => e.guid === update.added)?.$delete();
|
|
534
|
+
}
|
|
535
|
+
else if ('removed' in update && update.removed === jane.guid) {
|
|
536
|
+
subscription.unsubscribe();
|
|
537
|
+
removed = true;
|
|
538
|
+
resolve();
|
|
278
539
|
}
|
|
279
540
|
});
|
|
280
541
|
});
|
|
281
|
-
expect(
|
|
542
|
+
expect(removed).toBeTruthy();
|
|
282
543
|
});
|
|
283
544
|
it('entire match is updated', async () => {
|
|
284
545
|
let jane;
|
|
285
546
|
let entities = [];
|
|
286
547
|
await createJane();
|
|
287
|
-
|
|
548
|
+
// Wait for change to propagate. (Only needed since we're not going across network.)
|
|
549
|
+
await new Promise((resolve) => setTimeout(() => resolve(), 10));
|
|
288
550
|
await new Promise((resolve) => {
|
|
289
551
|
let receivedRemove = false;
|
|
290
552
|
let receivedAdd = false;
|
|
@@ -302,7 +564,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
302
564
|
}
|
|
303
565
|
if (receivedAdd && receivedRemove) {
|
|
304
566
|
subscription.unsubscribe();
|
|
305
|
-
resolve(
|
|
567
|
+
resolve();
|
|
306
568
|
}
|
|
307
569
|
}
|
|
308
570
|
else if (Array.isArray(update)) {
|
|
@@ -319,9 +581,10 @@ describe('Nymph REST Server and Client', () => {
|
|
|
319
581
|
await new Promise(async (resolve) => {
|
|
320
582
|
let mdate = 0;
|
|
321
583
|
const subscription = pubsub.subscribeWith(jane, async () => {
|
|
584
|
+
expect(jane.guid).not.toBeNull();
|
|
322
585
|
if (mdate > 0 && (jane.mdate ?? -1) === mdate) {
|
|
323
586
|
subscription.unsubscribe();
|
|
324
|
-
resolve(
|
|
587
|
+
resolve();
|
|
325
588
|
}
|
|
326
589
|
});
|
|
327
590
|
if (jane.guid == null) {
|
|
@@ -330,18 +593,72 @@ describe('Nymph REST Server and Client', () => {
|
|
|
330
593
|
expect(jane.salary).toEqual(8000000);
|
|
331
594
|
const janeDupe = await Employee.factory(jane.guid);
|
|
332
595
|
expect(janeDupe.salary).toEqual(8000000);
|
|
596
|
+
// Time for a raise!
|
|
333
597
|
janeDupe.salary = (janeDupe.salary ?? 0) + 1000000;
|
|
334
598
|
await janeDupe.$save();
|
|
335
599
|
mdate = janeDupe.mdate ?? 0;
|
|
336
600
|
});
|
|
337
601
|
expect(jane.salary).toEqual(9000000);
|
|
338
602
|
});
|
|
603
|
+
it("doesn't allow subscription of a restricted entity class", async () => {
|
|
604
|
+
let receivedBadUpdate = false;
|
|
605
|
+
let error = null;
|
|
606
|
+
await new Promise((resolve) => {
|
|
607
|
+
pubsub.subscribeEntities({ class: Restricted }, {
|
|
608
|
+
type: '&',
|
|
609
|
+
equal: ['name', 'Jane Doe'],
|
|
610
|
+
})(async () => {
|
|
611
|
+
receivedBadUpdate = true;
|
|
612
|
+
resolve();
|
|
613
|
+
}, (e) => {
|
|
614
|
+
error = e;
|
|
615
|
+
resolve();
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
expect(receivedBadUpdate).toEqual(false);
|
|
619
|
+
expect(error).toEqual('Not accessible.');
|
|
620
|
+
});
|
|
621
|
+
it("doesn't notify of new pubsub disabled entity class", async () => {
|
|
622
|
+
let receivedBadUpdate = false;
|
|
623
|
+
await new Promise(async (resolve) => {
|
|
624
|
+
const subscription = await new Promise(async (resolve) => {
|
|
625
|
+
let updated = false;
|
|
626
|
+
const subscription = pubsub.subscribeEntities({
|
|
627
|
+
class: PubSubDisabled,
|
|
628
|
+
})(async (update) => {
|
|
629
|
+
if (updated) {
|
|
630
|
+
receivedBadUpdate = true;
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
expect(update).toEqual([]);
|
|
634
|
+
updated = true;
|
|
635
|
+
try {
|
|
636
|
+
const entity = await PubSubDisabled.factory();
|
|
637
|
+
entity.name = 'Someone';
|
|
638
|
+
if (!(await entity.$save())) {
|
|
639
|
+
throw new Error("Couldn't save.");
|
|
640
|
+
}
|
|
641
|
+
resolve(subscription);
|
|
642
|
+
}
|
|
643
|
+
catch (e) {
|
|
644
|
+
console.error('Error creating entity: ', e);
|
|
645
|
+
throw e;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
651
|
+
subscription.unsubscribe();
|
|
652
|
+
resolve();
|
|
653
|
+
});
|
|
654
|
+
expect(receivedBadUpdate).toEqual(false);
|
|
655
|
+
});
|
|
339
656
|
it('new uid', async () => {
|
|
340
657
|
await new Promise(async (resolve) => {
|
|
341
658
|
const subscription = pubsub.subscribeUID('testNewUID')(async (value) => {
|
|
342
659
|
expect(value).toEqual(directValue);
|
|
343
660
|
subscription.unsubscribe();
|
|
344
|
-
resolve(
|
|
661
|
+
resolve();
|
|
345
662
|
}, (err) => {
|
|
346
663
|
expect(err.status).toEqual(404);
|
|
347
664
|
});
|
|
@@ -362,7 +679,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
362
679
|
lastUpdate = value;
|
|
363
680
|
if (value == 100) {
|
|
364
681
|
subscription.unsubscribe();
|
|
365
|
-
resolve(
|
|
682
|
+
resolve();
|
|
366
683
|
}
|
|
367
684
|
}, (err) => {
|
|
368
685
|
expect(err.status).toEqual(404);
|
|
@@ -379,7 +696,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
379
696
|
const subscription = pubsub.subscribeUID('testSetUID')(async (value) => {
|
|
380
697
|
expect(value).toEqual(123);
|
|
381
698
|
subscription.unsubscribe();
|
|
382
|
-
resolve(
|
|
699
|
+
resolve();
|
|
383
700
|
}, (err) => {
|
|
384
701
|
expect(err.status).toEqual(404);
|
|
385
702
|
});
|
|
@@ -394,9 +711,9 @@ describe('Nymph REST Server and Client', () => {
|
|
|
394
711
|
expect(event).toEqual('renameUID');
|
|
395
712
|
expect(value).toEqual(null);
|
|
396
713
|
subscription.unsubscribe();
|
|
397
|
-
resolve(
|
|
714
|
+
resolve();
|
|
398
715
|
}
|
|
399
|
-
else {
|
|
716
|
+
else if (event === 'setUID') {
|
|
400
717
|
expect(value).toEqual(456);
|
|
401
718
|
updated = true;
|
|
402
719
|
}
|
|
@@ -413,7 +730,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
413
730
|
expect(event).toEqual('setUID');
|
|
414
731
|
expect(value).toEqual(456);
|
|
415
732
|
subscription.unsubscribe();
|
|
416
|
-
resolve(
|
|
733
|
+
resolve();
|
|
417
734
|
}, (err) => {
|
|
418
735
|
expect(err.status).toEqual(404);
|
|
419
736
|
});
|
|
@@ -429,28 +746,40 @@ describe('Nymph REST Server and Client', () => {
|
|
|
429
746
|
if (updated && event === 'deleteUID') {
|
|
430
747
|
expect(value).toEqual(null);
|
|
431
748
|
subscription.unsubscribe();
|
|
432
|
-
resolve(
|
|
749
|
+
resolve();
|
|
433
750
|
}
|
|
434
751
|
else {
|
|
435
752
|
expect(value).toEqual(789);
|
|
436
753
|
updated = true;
|
|
754
|
+
await nymph.deleteUID('testDeleteUID');
|
|
437
755
|
}
|
|
438
756
|
}, (err) => {
|
|
439
757
|
expect(err.status).toEqual(404);
|
|
440
758
|
});
|
|
441
|
-
await nymph.deleteUID('testDeleteUID');
|
|
442
759
|
});
|
|
443
760
|
});
|
|
761
|
+
beforeEach(async () => {
|
|
762
|
+
pubsub.connect();
|
|
763
|
+
while (!pubsub.isConnectionOpen()) {
|
|
764
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
765
|
+
}
|
|
766
|
+
});
|
|
444
767
|
afterAll(async () => {
|
|
768
|
+
// Don't publish anything after the tests.
|
|
769
|
+
removePublisher();
|
|
770
|
+
// Avoid jest open handle errors.
|
|
445
771
|
const closed = new Promise((resolve) => {
|
|
446
772
|
pubsub.on('disconnect', () => {
|
|
447
|
-
resolve(
|
|
773
|
+
resolve();
|
|
448
774
|
});
|
|
449
775
|
});
|
|
450
|
-
pubsub.close();
|
|
776
|
+
pubsub.close(); // close PubSub client.
|
|
451
777
|
await closed;
|
|
452
|
-
pubsubServer.close();
|
|
453
|
-
server.close();
|
|
778
|
+
pubsubServer.close(); // close PubSub server.
|
|
779
|
+
server.close(); // close REST server.
|
|
780
|
+
// Wait for the next event loop to prevent websocket importing something
|
|
781
|
+
// after jest teardown.
|
|
782
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
454
783
|
});
|
|
455
784
|
});
|
|
456
785
|
//# sourceMappingURL=PubSub.test.js.map
|