@nymphjs/server 1.0.0-beta.1 → 1.0.0-beta.100
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 +435 -0
- package/README.md +79 -7
- package/dist/HttpError.d.ts +5 -0
- package/dist/HttpError.js +11 -0
- package/dist/HttpError.js.map +1 -0
- package/dist/cache.test.js +17 -21
- package/dist/cache.test.js.map +1 -1
- package/dist/createServer.d.ts +17 -0
- package/dist/createServer.js +907 -0
- package/dist/createServer.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +5 -715
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +203 -61
- package/dist/index.test.js.map +1 -1
- package/dist/statusDescriptions.d.ts +6 -0
- package/dist/statusDescriptions.js +69 -0
- package/dist/statusDescriptions.js.map +1 -0
- package/dist/testArtifacts.d.ts +59 -7
- package/dist/testArtifacts.js +174 -72
- package/dist/testArtifacts.js.map +1 -1
- package/jest.config.js +11 -2
- package/package.json +20 -20
- package/src/HttpError.ts +12 -0
- package/src/cache.test.ts +10 -7
- package/src/createServer.ts +981 -0
- package/src/index.test.ts +208 -31
- package/src/index.ts +5 -793
- package/src/statusDescriptions.ts +68 -0
- package/src/testArtifacts.ts +189 -42
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/src/index.test.ts
CHANGED
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import SQLite3Driver from '@nymphjs/driver-sqlite3';
|
|
3
3
|
import { Nymph as NymphServer } from '@nymphjs/nymph';
|
|
4
|
-
import { Nymph } from '@nymphjs/client
|
|
5
|
-
import { Entity } from '@nymphjs/client';
|
|
4
|
+
import { Nymph, Entity, HttpError } from '@nymphjs/client';
|
|
6
5
|
|
|
7
|
-
import createServer from './index';
|
|
8
|
-
import {
|
|
6
|
+
import createServer from './index.js';
|
|
7
|
+
import {
|
|
8
|
+
EmployeeModel as EmployeeModelClass,
|
|
9
|
+
Employee as EmployeeClass,
|
|
10
|
+
RestrictedModel as RestrictedModelClass,
|
|
11
|
+
Restricted as RestrictedClass,
|
|
12
|
+
EmployeeData,
|
|
13
|
+
} from './testArtifacts.js';
|
|
9
14
|
|
|
10
15
|
const sqliteConfig = {
|
|
11
16
|
filename: ':memory:',
|
|
12
17
|
};
|
|
13
18
|
|
|
14
19
|
const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
|
|
15
|
-
nymphServer.addEntityClass(
|
|
20
|
+
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
|
|
21
|
+
const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
|
|
16
22
|
|
|
17
23
|
const app = express();
|
|
18
24
|
app.use('/test', createServer(nymphServer));
|
|
19
25
|
const server = app.listen(5080);
|
|
20
26
|
|
|
27
|
+
const REST_URL = 'http://localhost:5080/test/';
|
|
21
28
|
const nymph = new Nymph({
|
|
22
|
-
restUrl:
|
|
29
|
+
restUrl: REST_URL,
|
|
23
30
|
});
|
|
24
|
-
nymph.addEntityClass(
|
|
31
|
+
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
32
|
+
const Restricted = nymph.addEntityClass(RestrictedClass);
|
|
25
33
|
|
|
26
34
|
describe('Nymph REST Server and Client', () => {
|
|
27
35
|
async function createJane() {
|
|
@@ -126,7 +134,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
126
134
|
{
|
|
127
135
|
type: '&',
|
|
128
136
|
ref: ['subordinates', jane],
|
|
129
|
-
}
|
|
137
|
+
},
|
|
130
138
|
);
|
|
131
139
|
|
|
132
140
|
expect(checkSteve?.guid).toEqual(steve.guid);
|
|
@@ -139,7 +147,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
139
147
|
'subordinates',
|
|
140
148
|
[{ class: Employee }, { type: '&', guid: jane.guid }],
|
|
141
149
|
],
|
|
142
|
-
}
|
|
150
|
+
},
|
|
143
151
|
);
|
|
144
152
|
|
|
145
153
|
expect(checkSteveQref?.guid).toEqual(steve.guid);
|
|
@@ -153,7 +161,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
153
161
|
expect(entity.$hasTag('test', 'test2')).toEqual(true);
|
|
154
162
|
entity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
|
|
155
163
|
expect(entity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(
|
|
156
|
-
true
|
|
164
|
+
true,
|
|
157
165
|
);
|
|
158
166
|
entity.$removeTag('test2');
|
|
159
167
|
expect(!entity.$hasTag('test2')).toEqual(true);
|
|
@@ -175,10 +183,10 @@ describe('Nymph REST Server and Client', () => {
|
|
|
175
183
|
'nymph_entity_reference',
|
|
176
184
|
jane.guid,
|
|
177
185
|
'Employee',
|
|
178
|
-
]);
|
|
179
|
-
await entity.$
|
|
186
|
+
]) as EmployeeClass & EmployeeData;
|
|
187
|
+
await entity.$wake();
|
|
180
188
|
|
|
181
|
-
expect(
|
|
189
|
+
expect(entity?.name).toEqual('Jane Doe');
|
|
182
190
|
});
|
|
183
191
|
|
|
184
192
|
it('change an entity', async () => {
|
|
@@ -229,13 +237,51 @@ describe('Nymph REST Server and Client', () => {
|
|
|
229
237
|
{
|
|
230
238
|
type: '&',
|
|
231
239
|
equal: ['name', 'Jane Doe'],
|
|
232
|
-
}
|
|
240
|
+
},
|
|
233
241
|
);
|
|
234
242
|
|
|
235
243
|
expect(jane).not.toBeNull();
|
|
236
244
|
expect(jane?.guid).not.toBeNull();
|
|
237
245
|
});
|
|
238
246
|
|
|
247
|
+
it('try to get a non-existent entity', async () => {
|
|
248
|
+
let error = { status: 200 };
|
|
249
|
+
try {
|
|
250
|
+
await nymph.getEntity(
|
|
251
|
+
{
|
|
252
|
+
class: Employee,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: '&',
|
|
256
|
+
equal: ['name', 'Non Existent'],
|
|
257
|
+
},
|
|
258
|
+
);
|
|
259
|
+
} catch (e: any) {
|
|
260
|
+
error = e;
|
|
261
|
+
}
|
|
262
|
+
expect(error.status).toEqual(404);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('try to get a non-existent entity without error', async () => {
|
|
266
|
+
const nymph = new Nymph({
|
|
267
|
+
restUrl: REST_URL,
|
|
268
|
+
returnNullOnNotFound: true,
|
|
269
|
+
});
|
|
270
|
+
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
271
|
+
|
|
272
|
+
const nonexistent = await nymph.getEntity(
|
|
273
|
+
{
|
|
274
|
+
class: Employee,
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: '&',
|
|
278
|
+
equal: ['name', 'Non Existent'],
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(nonexistent).toBeNull();
|
|
283
|
+
});
|
|
284
|
+
|
|
239
285
|
it('get entities', async () => {
|
|
240
286
|
for (let i = 0; i < 4; i++) {
|
|
241
287
|
await createJane();
|
|
@@ -249,7 +295,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
249
295
|
{
|
|
250
296
|
type: '&',
|
|
251
297
|
tag: ['employee'],
|
|
252
|
-
}
|
|
298
|
+
},
|
|
253
299
|
);
|
|
254
300
|
|
|
255
301
|
expect(entities.length).toEqual(4);
|
|
@@ -275,13 +321,13 @@ describe('Nymph REST Server and Client', () => {
|
|
|
275
321
|
|
|
276
322
|
const resultSelectors = await nymph.getEntities(
|
|
277
323
|
{ class: Employee },
|
|
278
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
324
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
279
325
|
);
|
|
280
326
|
|
|
281
327
|
// Testing count return with selectors...
|
|
282
328
|
const resultSelectorsCount = await nymph.getEntities(
|
|
283
329
|
{ class: Employee, return: 'count' },
|
|
284
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
330
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
285
331
|
);
|
|
286
332
|
expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
|
|
287
333
|
expect(resultSelectorsCount).toEqual(resultSelectors.length);
|
|
@@ -304,7 +350,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
304
350
|
// Testing empty count...
|
|
305
351
|
const resultSelectorsEmpty = await nymph.getEntities(
|
|
306
352
|
{ class: Employee, return: 'count' },
|
|
307
|
-
{ type: '&', tag: 'pickle' }
|
|
353
|
+
{ type: '&', tag: 'pickle' },
|
|
308
354
|
);
|
|
309
355
|
expect(resultSelectorsEmpty).toEqual(0);
|
|
310
356
|
});
|
|
@@ -323,7 +369,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
323
369
|
{
|
|
324
370
|
type: '&',
|
|
325
371
|
tag: 'employee',
|
|
326
|
-
}
|
|
372
|
+
},
|
|
327
373
|
);
|
|
328
374
|
|
|
329
375
|
expect(entities.length).toEqual(4);
|
|
@@ -349,7 +395,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
349
395
|
{
|
|
350
396
|
type: '&',
|
|
351
397
|
like: ['name', '%Jane%'],
|
|
352
|
-
}
|
|
398
|
+
},
|
|
353
399
|
);
|
|
354
400
|
|
|
355
401
|
expect(entities.length).toEqual(4);
|
|
@@ -375,7 +421,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
375
421
|
type: '|',
|
|
376
422
|
like: ['name', '%Jane%'],
|
|
377
423
|
},
|
|
378
|
-
}
|
|
424
|
+
},
|
|
379
425
|
);
|
|
380
426
|
|
|
381
427
|
expect(entities.length).toEqual(4);
|
|
@@ -410,7 +456,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
410
456
|
},
|
|
411
457
|
],
|
|
412
458
|
},
|
|
413
|
-
}
|
|
459
|
+
},
|
|
414
460
|
);
|
|
415
461
|
|
|
416
462
|
expect(entities.length).toEqual(4);
|
|
@@ -435,7 +481,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
435
481
|
{
|
|
436
482
|
type: '&',
|
|
437
483
|
guid,
|
|
438
|
-
}
|
|
484
|
+
},
|
|
439
485
|
);
|
|
440
486
|
|
|
441
487
|
expect(check.length).toEqual(0);
|
|
@@ -458,7 +504,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
458
504
|
{
|
|
459
505
|
type: '|',
|
|
460
506
|
guid: guids,
|
|
461
|
-
}
|
|
507
|
+
},
|
|
462
508
|
);
|
|
463
509
|
|
|
464
510
|
expect(check.length).toEqual(0);
|
|
@@ -475,7 +521,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
475
521
|
error = e;
|
|
476
522
|
}
|
|
477
523
|
expect(error.message).toEqual(
|
|
478
|
-
"Can't use Entity class directly from the front end."
|
|
524
|
+
"Can't use Entity class directly from the front end.",
|
|
479
525
|
);
|
|
480
526
|
});
|
|
481
527
|
|
|
@@ -490,32 +536,103 @@ describe('Nymph REST Server and Client', () => {
|
|
|
490
536
|
});
|
|
491
537
|
|
|
492
538
|
it('handle server side static error', async () => {
|
|
493
|
-
let error = { error: { name: '' } };
|
|
539
|
+
let error = { status: 0, error: { name: '' } };
|
|
494
540
|
try {
|
|
495
541
|
await Employee.throwErrorStatic();
|
|
496
542
|
} catch (e: any) {
|
|
497
543
|
error = e;
|
|
498
544
|
}
|
|
545
|
+
expect(error.status).toEqual(500);
|
|
546
|
+
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it('handle server side static iterator error', async () => {
|
|
550
|
+
let error: any = { status: 0, error: { name: '' } };
|
|
551
|
+
const data = await Employee.throwErrorStaticIterable();
|
|
552
|
+
|
|
553
|
+
let count = 0;
|
|
554
|
+
for await (let value of data) {
|
|
555
|
+
count++;
|
|
556
|
+
if (value instanceof Error) {
|
|
557
|
+
error = value;
|
|
558
|
+
} else {
|
|
559
|
+
expect(value).toEqual(count);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
expect(count).toEqual(2);
|
|
564
|
+
expect(error.status).toEqual(500);
|
|
499
565
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
500
566
|
});
|
|
501
567
|
|
|
502
568
|
it('handle server side error', async () => {
|
|
503
569
|
const jane = await createJane();
|
|
504
570
|
|
|
505
|
-
let error = { error: { name: '' } };
|
|
571
|
+
let error = { status: 0, error: { name: '' } };
|
|
506
572
|
try {
|
|
507
573
|
await jane.$throwError();
|
|
508
574
|
} catch (e: any) {
|
|
509
575
|
error = e;
|
|
510
576
|
}
|
|
577
|
+
expect(error.status).toEqual(500);
|
|
511
578
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
512
579
|
});
|
|
513
580
|
|
|
581
|
+
it('handle server side HTTP error', async () => {
|
|
582
|
+
const jane = await createJane();
|
|
583
|
+
|
|
584
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
585
|
+
try {
|
|
586
|
+
await jane.$throwHttpError();
|
|
587
|
+
} catch (e: any) {
|
|
588
|
+
error = e;
|
|
589
|
+
}
|
|
590
|
+
expect(error.status).toEqual(501);
|
|
591
|
+
expect(error.statusText).toEqual('Not Implemented');
|
|
592
|
+
expect(error.message).toEqual('A 501 HTTP error.');
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it('handle server side custom HTTP error', async () => {
|
|
596
|
+
const jane = await createJane();
|
|
597
|
+
|
|
598
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
599
|
+
try {
|
|
600
|
+
await jane.$throwHttpErrorWithDescription();
|
|
601
|
+
} catch (e: any) {
|
|
602
|
+
error = e;
|
|
603
|
+
}
|
|
604
|
+
expect(error.status).toEqual(512);
|
|
605
|
+
expect(error.statusText).toEqual('Some Error');
|
|
606
|
+
expect(error.message).toEqual('A 512 HTTP error.');
|
|
607
|
+
});
|
|
608
|
+
|
|
514
609
|
it('call a server side static method', async () => {
|
|
515
610
|
const data = await Employee.testStatic(5);
|
|
516
611
|
expect(data).toEqual(10);
|
|
517
612
|
});
|
|
518
613
|
|
|
614
|
+
it('call a server side static iterator method', async () => {
|
|
615
|
+
const data = await Employee.testStaticIterable(5);
|
|
616
|
+
|
|
617
|
+
let count = 0;
|
|
618
|
+
for await (let value of data) {
|
|
619
|
+
count++;
|
|
620
|
+
expect(value).toEqual(5 + count);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
expect(count).toEqual(3);
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
it('aborts a server side static iterator method', async () => {
|
|
627
|
+
const data = await Employee.testStaticIterableAbort();
|
|
628
|
+
data.abortController.abort();
|
|
629
|
+
|
|
630
|
+
// Wait 1 second to ensure server receives abort signal.
|
|
631
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
632
|
+
|
|
633
|
+
expect(true).toBeTruthy();
|
|
634
|
+
});
|
|
635
|
+
|
|
519
636
|
it('call a stateless server side method', async () => {
|
|
520
637
|
const jane = await createJane();
|
|
521
638
|
|
|
@@ -544,7 +661,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
544
661
|
{
|
|
545
662
|
class: Employee,
|
|
546
663
|
},
|
|
547
|
-
jane1.guid
|
|
664
|
+
jane1.guid,
|
|
548
665
|
);
|
|
549
666
|
if (jane1 == null || jane2 == null) {
|
|
550
667
|
throw new Error('Entity is null.');
|
|
@@ -570,7 +687,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
570
687
|
{
|
|
571
688
|
class: Employee,
|
|
572
689
|
},
|
|
573
|
-
first.guid
|
|
690
|
+
first.guid,
|
|
574
691
|
);
|
|
575
692
|
|
|
576
693
|
if (second == null || second.guid == null) {
|
|
@@ -602,7 +719,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
602
719
|
{
|
|
603
720
|
class: Employee,
|
|
604
721
|
},
|
|
605
|
-
first.guid
|
|
722
|
+
first.guid,
|
|
606
723
|
);
|
|
607
724
|
|
|
608
725
|
if (second == null || second.guid == null) {
|
|
@@ -625,7 +742,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
625
742
|
{
|
|
626
743
|
type: '&',
|
|
627
744
|
'!guid': first.guid,
|
|
628
|
-
}
|
|
745
|
+
},
|
|
629
746
|
);
|
|
630
747
|
|
|
631
748
|
if (third == null || third.guid == null) {
|
|
@@ -635,6 +752,66 @@ describe('Nymph REST Server and Client', () => {
|
|
|
635
752
|
expect(first.$is(third)).toEqual(false);
|
|
636
753
|
});
|
|
637
754
|
|
|
755
|
+
it("doesn't allow creation of a restricted entity class", async () => {
|
|
756
|
+
const attempt = await Restricted.factory();
|
|
757
|
+
attempt.name = 'Jane Doe';
|
|
758
|
+
|
|
759
|
+
let error = null;
|
|
760
|
+
|
|
761
|
+
try {
|
|
762
|
+
await attempt.$save();
|
|
763
|
+
} catch (e: any) {
|
|
764
|
+
error = e;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
768
|
+
expect(error.status).toEqual(403);
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
it("doesn't allow search of a restricted entity class", async () => {
|
|
772
|
+
let error = null;
|
|
773
|
+
|
|
774
|
+
try {
|
|
775
|
+
await nymph.getEntity({
|
|
776
|
+
class: Restricted,
|
|
777
|
+
});
|
|
778
|
+
} catch (e: any) {
|
|
779
|
+
error = e;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
783
|
+
expect(error.status).toEqual(403);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
it("doesn't allow methods of a restricted entity class", async () => {
|
|
787
|
+
const attempt = await Restricted.factory();
|
|
788
|
+
attempt.name = 'Jane Doe';
|
|
789
|
+
|
|
790
|
+
let error = null;
|
|
791
|
+
|
|
792
|
+
try {
|
|
793
|
+
await attempt.$testMethod(1);
|
|
794
|
+
} catch (e: any) {
|
|
795
|
+
error = e;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
799
|
+
expect(error.status).toEqual(403);
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it("doesn't allow static methods of a restricted entity class", async () => {
|
|
803
|
+
let error = null;
|
|
804
|
+
|
|
805
|
+
try {
|
|
806
|
+
await Restricted.testStatic(1);
|
|
807
|
+
} catch (e: any) {
|
|
808
|
+
error = e;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
812
|
+
expect(error.status).toEqual(403);
|
|
813
|
+
});
|
|
814
|
+
|
|
638
815
|
it('get a new UID', async () => {
|
|
639
816
|
const uidValue = await nymph.newUID('employee');
|
|
640
817
|
expect(typeof uidValue).toEqual('number');
|