oak-db 1.0.0

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.
@@ -0,0 +1,771 @@
1
+ import assert from 'assert';
2
+ import { UniversalContext } from 'oak-domain/lib/store/UniversalContext';
3
+ import { v4 } from 'uuid';
4
+ import { MysqlStore } from '../src/MySQL/store';
5
+ import { EntityDict, storageSchema } from './test-app-domain';
6
+
7
+ describe('test mysqlstore', function() {
8
+ this.timeout(100000);
9
+ let store: MysqlStore<EntityDict, UniversalContext<EntityDict>>;
10
+
11
+ before(async () => {
12
+ store = new MysqlStore(storageSchema, {
13
+ host: 'localhost',
14
+ database: 'oakdb',
15
+ user: 'root',
16
+ password: '',
17
+ charset: 'utf8mb4_general_ci',
18
+ connectionLimit: 20,
19
+ });
20
+ store.connect();
21
+ await store.initialize(true);
22
+ });
23
+
24
+ it('test insert', async () => {
25
+ const context = new UniversalContext(store);
26
+ await store.operate('user', {
27
+ action: 'create',
28
+ data: [
29
+ {
30
+ id: v4(),
31
+ name: 'xc',
32
+ nickname: 'xc',
33
+ },
34
+ {
35
+ id: v4(),
36
+ name: 'zz',
37
+ nickname: 'zzz',
38
+ }
39
+ ]
40
+ }, context);
41
+ });
42
+
43
+ it('test cascade insert', async () => {
44
+ const context = new UniversalContext(store);
45
+ await store.operate('user', {
46
+ action: 'create',
47
+ data: {
48
+ id: v4(),
49
+ name: 'xxxc',
50
+ nickname: 'ddd',
51
+ token$player: [{
52
+ action: 'create',
53
+ data: {
54
+ id: v4(),
55
+ env: {
56
+ type: 'web',
57
+ },
58
+ applicationId: v4(),
59
+ userId: v4(),
60
+ entity: 'mobile',
61
+ entityId: v4(),
62
+ }
63
+ }]
64
+ }
65
+ }, context);
66
+ });
67
+
68
+ it('test update', async () => {
69
+ const context = new UniversalContext(store);
70
+ const tokenId = v4();
71
+ await store.operate('user', {
72
+ action: 'create',
73
+ data: {
74
+ id: v4(),
75
+ name: 'xxxc',
76
+ nickname: 'ddd',
77
+ token$player: [{
78
+ action: 'create',
79
+ data: {
80
+ id: tokenId,
81
+ env: {
82
+ type: 'web',
83
+ },
84
+ applicationId: v4(),
85
+ userId: v4(),
86
+ entity: 'mobile',
87
+ entityId: v4(),
88
+ }
89
+ }]
90
+ }
91
+ }, context);
92
+ await store.operate('token', {
93
+ action: 'update',
94
+ filter: {
95
+ id: tokenId,
96
+ },
97
+ data: {
98
+ player: {
99
+ action: 'activate',
100
+ data: {
101
+ name: 'xcxcxc0903'
102
+ },
103
+ }
104
+ }
105
+ }, context);
106
+ });
107
+
108
+ it('test delete', async () => {
109
+ const context = new UniversalContext(store);
110
+ const tokenId = v4();
111
+ await store.operate('user', {
112
+ action: 'create',
113
+ data: {
114
+ id: v4(),
115
+ name: 'xxxc',
116
+ nickname: 'ddd',
117
+ token$player: [{
118
+ action: 'create',
119
+ data: {
120
+ id: tokenId,
121
+ env: {
122
+ type: 'web',
123
+ },
124
+ applicationId: v4(),
125
+ userId: v4(),
126
+ entity: 'mobile',
127
+ entityId: v4(),
128
+ }
129
+ }]
130
+ }
131
+ }, context);
132
+ await store.operate('token', {
133
+ action: 'remove',
134
+ filter: {
135
+ id: tokenId,
136
+ },
137
+ data: {
138
+ player: {
139
+ action: 'update',
140
+ data: {
141
+ name: 'xcxcxc0902'
142
+ },
143
+ }
144
+ }
145
+ }, context);
146
+ });
147
+
148
+
149
+ it('test delete2', async () => {
150
+ // 这个例子暂在mysql上过不去,先放着吧
151
+ const context = new UniversalContext(store);
152
+ const tokenId = v4();
153
+ await store.operate('user', {
154
+ action: 'create',
155
+ data: {
156
+ id: v4(),
157
+ name: 'xxxc',
158
+ nickname: 'ddd',
159
+ token$player: [{
160
+ action: 'create',
161
+ data: {
162
+ id: tokenId,
163
+ env: {
164
+ type: 'web',
165
+ },
166
+ applicationId: v4(),
167
+ userId: v4(),
168
+ entity: 'mobile',
169
+ entityId: v4(),
170
+ }
171
+ }]
172
+ }
173
+ }, context);
174
+ await store.operate('user', {
175
+ action: 'remove',
176
+ filter: {
177
+ id: tokenId,
178
+ },
179
+ data: {
180
+ ref: {
181
+ action: 'remove',
182
+ data: {},
183
+ }
184
+ },
185
+ }, context);
186
+ });
187
+
188
+ it('[1.1]子查询', async () => {
189
+ const context = new UniversalContext(store);
190
+
191
+ await store.operate('user', {
192
+ action: 'create',
193
+ data: {
194
+ id: v4(),
195
+ name: 'xc',
196
+ nickname: 'xc',
197
+ }
198
+ }, context);
199
+
200
+ /**
201
+ * 这个子查询没有跨结点的表达式,所以应该可以提前计算子查询的值
202
+ * 这个可以跟一下store.ts中translateAttribute函数里$in的分支代码
203
+ * by Xc
204
+ */
205
+ process.env.NODE_ENV = 'development';
206
+ const rows = await store.select('user', {
207
+ data: {
208
+ id: 1,
209
+ name: 1,
210
+ nickname: 1,
211
+ },
212
+ filter: {
213
+ id: {
214
+ $in: {
215
+ entity: 'token',
216
+ data: {
217
+ userId: 1,
218
+ },
219
+ filter: {
220
+ entity: 'mobile',
221
+ }
222
+ },
223
+ }
224
+ },
225
+ }, context);
226
+ process.env.NODE_ENV = undefined;
227
+ // console.log(rows);
228
+ assert(rows.result.length === 0);
229
+ });
230
+
231
+ it('[1.2]行内属性上的表达式', async () => {
232
+ const context = new UniversalContext(store);
233
+
234
+ const id = v4();
235
+ await store.operate('user', {
236
+ action: 'create',
237
+ data: {
238
+ id,
239
+ name: 'xc',
240
+ nickname: 'xc',
241
+ }
242
+ }, context);
243
+
244
+ process.env.NODE_ENV = 'development';
245
+ const { result: users } = await store.select('user', {
246
+ data: {
247
+ id: 1,
248
+ name: 1,
249
+ nickname: 1,
250
+ },
251
+ filter: {
252
+ // '#id': 'node-123',
253
+ $expr: {
254
+ $eq: [{
255
+ '#attr': 'name',
256
+ }, {
257
+ "#attr": 'nickname',
258
+ }]
259
+ },
260
+ id,
261
+ },
262
+ }, context);
263
+ process.env.NODE_ENV = undefined;
264
+
265
+ assert(users.length === 1);
266
+ });
267
+
268
+ it('[1.3]跨filter结点的表达式', async () => {
269
+ const context = new UniversalContext(store);
270
+
271
+ const id1 = v4();
272
+ const id2 = v4();
273
+ await store.operate('application', {
274
+ action: 'create',
275
+ data: [{
276
+ id: id1,
277
+ name: 'test',
278
+ description: 'ttttt',
279
+ type: 'web',
280
+ config: {
281
+ type: 'web',
282
+ domain: 'http://www.tt.com',
283
+ },
284
+ system: {
285
+ action: 'create',
286
+ data: {
287
+ id: 'bbb',
288
+ name: 'systest',
289
+ description: 'aaaaa',
290
+ config: {},
291
+ }
292
+ }
293
+ }, {
294
+ id: id2,
295
+ name: 'test2',
296
+ description: 'ttttt2',
297
+ type: 'web',
298
+ config: {
299
+ type: 'web',
300
+ domain: 'http://www.tt.com',
301
+ },
302
+ system: {
303
+ action: 'create',
304
+ data: {
305
+ id: 'ccc',
306
+ name: 'test2',
307
+ description: 'aaaaa2',
308
+ config: {},
309
+ }
310
+ }
311
+ }]
312
+ }, context);
313
+
314
+ const { result: applications } = await store.select('application', {
315
+ data: {
316
+ id: 1,
317
+ name: 1,
318
+ systemId: 1,
319
+ system: {
320
+ id: 1,
321
+ name: 1,
322
+ }
323
+ },
324
+ filter: {
325
+ $expr: {
326
+ $startsWith: [
327
+ {
328
+ "#refAttr": 'name',
329
+ "#refId": 'node-1',
330
+ },
331
+ {
332
+ "#attr": 'name',
333
+ }
334
+ ]
335
+ },
336
+ system: {
337
+ "#id": 'node-1',
338
+ },
339
+ id: id2,
340
+ },
341
+ sorter: [
342
+ {
343
+ $attr: {
344
+ system: {
345
+ name: 1,
346
+ }
347
+ },
348
+ $direction: 'asc',
349
+ }
350
+ ]
351
+ }, context);
352
+ console.log(applications);
353
+ assert(applications.length === 1 && applications[0].id === id2);
354
+ });
355
+
356
+
357
+ it('[1.4]跨filter子查询的表达式', async () => {
358
+ const context = new UniversalContext(store);
359
+
360
+ await store.operate('application', {
361
+ action: 'create',
362
+ data: [{
363
+ id: 'aaa',
364
+ name: 'test',
365
+ description: 'ttttt',
366
+ type: 'web',
367
+ config: {
368
+ type: 'web',
369
+ domain: 'http://www.tt.com',
370
+ },
371
+ system: {
372
+ action: 'create',
373
+ data: {
374
+ id: 'bbb',
375
+ name: 'systest',
376
+ description: 'aaaaa',
377
+ config: {},
378
+ }
379
+ }
380
+ }, {
381
+ id: 'aaa2',
382
+ name: 'test2',
383
+ description: 'ttttt2',
384
+ type: 'web',
385
+ config: {
386
+ type: 'web',
387
+ domain: 'http://www.tt.com',
388
+ },
389
+ system: {
390
+ action: 'create',
391
+ data: {
392
+ id: 'ccc',
393
+ name: 'test2',
394
+ description: 'aaaaa2',
395
+ config: {},
396
+ }
397
+ }
398
+ }]
399
+ }, context);
400
+
401
+ process.env.NODE_ENV = 'development';
402
+ let systems = await store.select('system', {
403
+ data: {
404
+ id: 1,
405
+ name: 1,
406
+ },
407
+ filter: {
408
+ "#id": 'node-1',
409
+ id: {
410
+ $nin: {
411
+ entity: 'application',
412
+ data: {
413
+ systemId: 1,
414
+ },
415
+ filter: {
416
+ $expr: {
417
+ $eq: [
418
+ {
419
+ "#attr": 'name',
420
+ },
421
+ {
422
+ '#refId': 'node-1',
423
+ "#refAttr": 'name',
424
+ }
425
+ ]
426
+ },
427
+ '#id': 'node-2',
428
+ }
429
+ },
430
+ }
431
+ },
432
+ sorter: [
433
+ {
434
+ $attr: {
435
+ name: 1,
436
+ },
437
+ $direction: 'asc',
438
+ }
439
+ ]
440
+ }, context);
441
+ assert(systems.result.length === 1 && systems.result[0].id === 'bbb');
442
+ systems = await store.select('system', {
443
+ data: {
444
+ id: 1,
445
+ name: 1,
446
+ },
447
+ filter: {
448
+ "#id": 'node-1',
449
+ id: {
450
+ $in: {
451
+ entity: 'application',
452
+ data: {
453
+ systemId: 1,
454
+ },
455
+ filter: {
456
+ $expr: {
457
+ $eq: [
458
+ {
459
+ "#attr": 'name',
460
+ },
461
+ {
462
+ '#refId': 'node-1',
463
+ "#refAttr": 'name',
464
+ }
465
+ ]
466
+ },
467
+ }
468
+ },
469
+ }
470
+ },
471
+ sorter: [
472
+ {
473
+ $attr: {
474
+ name: 1,
475
+ },
476
+ $direction: 'asc',
477
+ }
478
+ ]
479
+ }, context);
480
+ process.env.NODE_ENV = undefined;
481
+ assert(systems.result.length === 1 && systems.result[0].id === 'ccc');
482
+ });
483
+
484
+ it('[1.5]projection中的跨结点表达式', async () => {
485
+ const context = new UniversalContext(store);
486
+
487
+ await store.operate('application', {
488
+ action: 'create',
489
+ data: [{
490
+ id: 'aaa',
491
+ name: 'test',
492
+ description: 'ttttt',
493
+ type: 'web',
494
+ config: {
495
+ type: 'web',
496
+ domain: 'http://www.tt.com',
497
+ },
498
+ system: {
499
+ action: 'create',
500
+ data: {
501
+ id: 'bbb',
502
+ name: 'systest',
503
+ description: 'aaaaa',
504
+ config: {},
505
+ }
506
+ }
507
+ }, {
508
+ id: 'aaa2',
509
+ name: 'test2',
510
+ description: 'ttttt2',
511
+ type: 'web',
512
+ config: {
513
+ type: 'web',
514
+ domain: 'http://www.tt.com',
515
+ },
516
+ system: {
517
+ action: 'create',
518
+ data: {
519
+ id: 'ccc',
520
+ name: 'test2',
521
+ description: 'aaaaa2',
522
+ config: {},
523
+ }
524
+ }
525
+ }]
526
+ }, context);
527
+
528
+ let applications = await store.select('application', {
529
+ data: {
530
+ "#id": 'node-1',
531
+ id: 1,
532
+ name: 1,
533
+ system: {
534
+ id: 1,
535
+ name: 1,
536
+ $expr: {
537
+ $eq: [
538
+ {
539
+ "#attr": 'name',
540
+ },
541
+ {
542
+ '#refId': 'node-1',
543
+ "#refAttr": 'name',
544
+ }
545
+ ]
546
+ },
547
+ }
548
+ },
549
+ }, context);
550
+ // console.log(applications);
551
+ assert(applications.result.length === 2);
552
+ applications.result.forEach(
553
+ (app) => {
554
+ assert(app.id === 'aaa' && app.system!.$expr === false
555
+ || app.id === 'aaa2' && app.system!.$expr === true);
556
+ }
557
+ );
558
+
559
+ const applications2 = await store.select('application', {
560
+ data: {
561
+ $expr: {
562
+ $eq: [
563
+ {
564
+ "#attr": 'name',
565
+ },
566
+ {
567
+ '#refId': 'node-1',
568
+ "#refAttr": 'name',
569
+ }
570
+ ]
571
+ },
572
+ id: 1,
573
+ name: 1,
574
+ system: {
575
+ "#id": 'node-1',
576
+ id: 1,
577
+ name: 1,
578
+ }
579
+ },
580
+ }, context);
581
+ console.log(applications2);
582
+ // assert(applications.length === 2);
583
+ applications2.result.forEach(
584
+ (app) => {
585
+ assert(app.id === 'aaa' && app.$expr === false
586
+ || app.id === 'aaa2' && app.$expr === true);
587
+ }
588
+ );
589
+ });
590
+
591
+ // 这个貌似目前支持不了 by Xc
592
+ it('[1.6]projection中的一对多跨结点表达式', async () => {
593
+ const context = new UniversalContext(store);
594
+
595
+ await store.operate('system', {
596
+ action: 'create',
597
+ data: {
598
+ id: 'bbb',
599
+ name: 'test2',
600
+ description: 'aaaaa',
601
+ config: {},
602
+ application$system: [{
603
+ action: 'create',
604
+ data: [
605
+ {
606
+ id: 'aaa',
607
+ name: 'test',
608
+ description: 'ttttt',
609
+ type: 'web',
610
+ config: {
611
+ type: 'web',
612
+ domain: 'http://www.tt.com',
613
+ },
614
+ },
615
+ {
616
+
617
+ id: 'aaa2',
618
+ name: 'test2',
619
+ description: 'ttttt2',
620
+ type: 'wechatMp',
621
+ config: {
622
+ type: 'web',
623
+ domain: 'http://www.tt.com',
624
+ },
625
+ }
626
+ ]
627
+ }]
628
+ }
629
+ }, context);
630
+
631
+ const systems = await store.select('system', {
632
+ data: {
633
+ "#id": 'node-1',
634
+ id: 1,
635
+ name: 1,
636
+ application$system: {
637
+ $entity: 'application',
638
+ data: {
639
+ id: 1,
640
+ name: 1,
641
+ $expr: {
642
+ $eq: [
643
+ {
644
+ "#attr": 'name',
645
+ },
646
+ {
647
+ '#refId': 'node-1',
648
+ "#refAttr": 'name',
649
+ }
650
+ ]
651
+ },
652
+ $expr2: {
653
+ '#refId': 'node-1',
654
+ "#refAttr": 'id',
655
+ }
656
+ }
657
+ },
658
+ },
659
+ }, context);
660
+ // console.log(systems);
661
+ assert(systems.result.length === 1);
662
+ const [ system ] = systems.result;
663
+ const { application$system: applications } = system;
664
+ assert(applications!.length === 2);
665
+ applications!.forEach(
666
+ (ele) => {
667
+ assert(ele.id === 'aaa' && ele.$expr === false && ele.$expr2 === 'bbb'
668
+ || ele.id === 'aaa2' && ele.$expr === true && ele.$expr2 === 'bbb');
669
+ }
670
+ );
671
+ });
672
+
673
+ it('[1.7]事务性测试', async () => {
674
+ const context = new UniversalContext(store);
675
+
676
+ await store.operate('system', {
677
+ action: 'create',
678
+ data: {
679
+ id: 'bbb',
680
+ name: 'test2',
681
+ description: 'aaaaa',
682
+ config: {},
683
+ application$system: [{
684
+ action: 'create',
685
+ data: [
686
+ {
687
+ id: 'aaa',
688
+ name: 'test',
689
+ description: 'ttttt',
690
+ type: 'web',
691
+ config: {
692
+ type: 'web',
693
+ domain: 'http://www.tt.com',
694
+ },
695
+ },
696
+ {
697
+
698
+ id: 'aaa2',
699
+ name: 'test2',
700
+ description: 'ttttt2',
701
+ type: 'wechatMp',
702
+ config: {
703
+ type: 'web',
704
+ domain: 'http://www.tt.com',
705
+ },
706
+ }
707
+ ]
708
+ }]
709
+ }
710
+ }, context);
711
+
712
+ await context.begin();
713
+ const systems = await store.select('system', {
714
+ data: {
715
+ id: 1,
716
+ name: 1,
717
+ application$system: {
718
+ $entity: 'application',
719
+ data: {
720
+ id: 1,
721
+ name: 1,
722
+ }
723
+ },
724
+ },
725
+ }, context);
726
+ assert(systems.result.length === 1 && systems.result[0].application$system!.length === 2);
727
+
728
+ await store.operate('application', {
729
+ action: 'remove',
730
+ data: {},
731
+ filter: {
732
+ id: 'aaa',
733
+ }
734
+ }, context);
735
+
736
+ const systems2 = await store.select('system', {
737
+ data: {
738
+ id: 1,
739
+ name: 1,
740
+ application$system: {
741
+ $entity: 'application',
742
+ data: {
743
+ id: 1,
744
+ name: 1,
745
+ }
746
+ },
747
+ },
748
+ }, context);
749
+ assert(systems2.result.length === 1 && systems2.result[0].application$system!.length === 1);
750
+ await context.rollback();
751
+
752
+ const systems3 = await store.select('system', {
753
+ data: {
754
+ id: 1,
755
+ name: 1,
756
+ application$system: {
757
+ $entity: 'application',
758
+ data: {
759
+ id: 1,
760
+ name: 1,
761
+ }
762
+ },
763
+ },
764
+ }, context);
765
+ assert(systems3.result.length === 1 && systems3.result[0].application$system!.length === 2);
766
+ });
767
+
768
+ after(() => {
769
+ store.disconnect();
770
+ });
771
+ });