vona-module-test-vona 5.0.39 → 5.0.41

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.
Files changed (118) hide show
  1. package/dist/.metadata/index.d.ts +12 -1
  2. package/dist/index.js +239 -128
  3. package/dist/service/order.d.ts +4 -0
  4. package/dist/service/post.d.ts +2 -0
  5. package/package.json +4 -2
  6. package/src/.metadata/index.ts +1741 -0
  7. package/src/.metadata/this.ts +2 -0
  8. package/src/bean/aop.regExp.ts +30 -0
  9. package/src/bean/aop.simple.ts +58 -0
  10. package/src/bean/aopMethod.test.ts +42 -0
  11. package/src/bean/bean.testCtx.ts +55 -0
  12. package/src/bean/broadcast.test.ts +22 -0
  13. package/src/bean/cacheMem.test.ts +7 -0
  14. package/src/bean/cacheRedis.post.ts +10 -0
  15. package/src/bean/cacheRedis.test.ts +7 -0
  16. package/src/bean/event.helloEcho.ts +8 -0
  17. package/src/bean/eventListener.helloEcho.ts +21 -0
  18. package/src/bean/meta.version.ts +81 -0
  19. package/src/bean/queue.test.ts +18 -0
  20. package/src/bean/schedule.test.ts +12 -0
  21. package/src/bean/schedule.test3.ts +12 -0
  22. package/src/bean/summerCache.test.ts +29 -0
  23. package/src/config/config.ts +5 -0
  24. package/src/config/locale/en-us.ts +19 -0
  25. package/src/config/locale/zh-cn.ts +17 -0
  26. package/src/controller/bean.ts +95 -0
  27. package/src/controller/cacheMem.ts +63 -0
  28. package/src/controller/cacheRedis.ts +55 -0
  29. package/src/controller/dtoTest.ts +63 -0
  30. package/src/controller/guardPassport.ts +25 -0
  31. package/src/controller/onion.ts +92 -0
  32. package/src/controller/passport.ts +48 -0
  33. package/src/controller/performAction.ts +18 -0
  34. package/src/controller/queue.ts +25 -0
  35. package/src/controller/summer.ts +125 -0
  36. package/src/controller/tail.ts +32 -0
  37. package/src/controller/transaction.ts +29 -0
  38. package/src/controller/upload.ts +57 -0
  39. package/src/dto/categoryTree.ts +8 -0
  40. package/src/dto/orderCreate.ts +10 -0
  41. package/src/dto/orderResult.ts +9 -0
  42. package/src/dto/orderUpdate.ts +9 -0
  43. package/src/dto/postCreate.ts +9 -0
  44. package/src/dto/profile.ts +14 -0
  45. package/src/dto/roleLazy.ts +15 -0
  46. package/src/dto/user.ts +19 -0
  47. package/src/dto/userCreate.ts +8 -0
  48. package/src/dto/userLazy.ts +18 -0
  49. package/src/dto/userUpdate.ts +8 -0
  50. package/src/entity/category.ts +14 -0
  51. package/src/entity/order.ts +18 -0
  52. package/src/entity/post.ts +17 -0
  53. package/src/entity/postContent.ts +14 -0
  54. package/src/entity/product.ts +24 -0
  55. package/src/entity/role.ts +11 -0
  56. package/src/entity/roleUser.ts +14 -0
  57. package/src/entity/test.ts +18 -0
  58. package/src/entity/user.ts +17 -0
  59. package/src/index.ts +1 -0
  60. package/src/model/category.ts +17 -0
  61. package/src/model/categoryChain.ts +16 -0
  62. package/src/model/order.ts +26 -0
  63. package/src/model/orderStats.ts +27 -0
  64. package/src/model/post.ts +16 -0
  65. package/src/model/postContent.ts +17 -0
  66. package/src/model/product.ts +8 -0
  67. package/src/model/role.ts +15 -0
  68. package/src/model/roleUser.ts +8 -0
  69. package/src/model/test.ts +8 -0
  70. package/src/model/testDynamicTable.ts +21 -0
  71. package/src/model/user.ts +21 -0
  72. package/src/model/userStats.ts +15 -0
  73. package/src/model/userStatsGroup.ts +15 -0
  74. package/src/service/aopMethod.ts +38 -0
  75. package/src/service/caching.ts +75 -0
  76. package/src/service/order.ts +65 -0
  77. package/src/service/post.ts +219 -0
  78. package/src/service/test.ts +9 -0
  79. package/src/service/testApp.ts +13 -0
  80. package/src/service/testClass.ts +15 -0
  81. package/src/service/testData.ts +67 -0
  82. package/src/service/transaction.ts +20 -0
  83. package/test/aopMethod.test.ts +21 -0
  84. package/test/authSimple.test.ts +45 -0
  85. package/test/bean.test.ts +16 -0
  86. package/test/broadcast.test.ts +17 -0
  87. package/test/cache/cacheMem.test.ts +10 -0
  88. package/test/cache/cacheRedis.test.ts +10 -0
  89. package/test/cache/caching.test.ts +58 -0
  90. package/test/cache/summer.test.ts +10 -0
  91. package/test/database/database.test.ts +127 -0
  92. package/test/database/dtoAggregate.test.ts +44 -0
  93. package/test/database/dtoGet.test.ts +61 -0
  94. package/test/database/dtoGroup.test.ts +44 -0
  95. package/test/database/dtoLazy.test.ts +45 -0
  96. package/test/database/dtoMutate.test.ts +56 -0
  97. package/test/database/modelAggregate.test.ts +197 -0
  98. package/test/database/modelCache.test.ts +37 -0
  99. package/test/database/modelGeneral.test.ts +18 -0
  100. package/test/database/modelGroup.test.ts +211 -0
  101. package/test/database/modelRelations.test.ts +203 -0
  102. package/test/database/modelRelationsJoins.test.ts +39 -0
  103. package/test/database/modelRelationsMutate.test.ts +354 -0
  104. package/test/database/modelWhere.test.ts +138 -0
  105. package/test/database/orm.test.ts +22 -0
  106. package/test/database/transaction.test.ts +142 -0
  107. package/test/event.test.ts +14 -0
  108. package/test/guardPassport.test.ts +44 -0
  109. package/test/jwt.test.ts +27 -0
  110. package/test/locale.test.ts +51 -0
  111. package/test/passport.test.ts +57 -0
  112. package/test/queue.test.ts +11 -0
  113. package/test/tail.test.ts +21 -0
  114. package/test/upload.test.ts +58 -0
  115. package/test/utils/cabloyUtils.test.ts +22 -0
  116. package/test/utils/celjs.test.ts +26 -0
  117. package/test/utils/mappedTypes.test.ts +65 -0
  118. package/test/utils/performAction.test.ts +28 -0
@@ -0,0 +1,55 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import assert from 'node:assert';
3
+ import { sleep } from '@cabloy/utils';
4
+ import { BeanBase, retry } from 'vona';
5
+ import { Api } from 'vona-module-a-openapi';
6
+ import { Passport } from 'vona-module-a-user';
7
+ import { Controller, Web } from 'vona-module-a-web';
8
+
9
+ export interface IControllerOptionsCacheRedis extends IDecoratorControllerOptions {}
10
+
11
+ @Controller<IControllerOptionsCacheRedis>({ path: 'cacheRedis', meta: { mode: 'test' } })
12
+ @Api.exclude()
13
+ @Passport.public()
14
+ export class ControllerCacheRedis extends BeanBase {
15
+ @Web.post()
16
+ async redis() {
17
+ let res;
18
+ let value;
19
+
20
+ // getset
21
+ value = await this.scope.cacheRedis.test.getset('zhen.nann');
22
+ assert.equal(value, undefined);
23
+
24
+ value = await this.scope.cacheRedis.test.getset('zhennann');
25
+ assert.equal(value, 'zhen.nann');
26
+
27
+ // has
28
+ res = await this.scope.cacheRedis.test.has();
29
+ assert.equal(res, true);
30
+
31
+ // get
32
+ value = await this.scope.cacheRedis.test.get();
33
+ assert.equal(value, 'zhennann');
34
+
35
+ // del
36
+ await this.scope.cacheRedis.test.del();
37
+ res = await this.scope.cacheRedis.test.has();
38
+ assert.equal(res, false);
39
+
40
+ // set again
41
+ await this.scope.cacheRedis.test.set('zhennann'); // will be expired after 1s
42
+
43
+ // get
44
+ value = await this.scope.cacheRedis.test.get();
45
+ assert.equal(value, 'zhennann');
46
+
47
+ // peek after timeout
48
+ await sleep(900);
49
+ await retry({ retries: 3 }, async () => {
50
+ await sleep(100);
51
+ value = await this.scope.cacheRedis.test.peek();
52
+ assert.equal(value, undefined);
53
+ });
54
+ }
55
+ }
@@ -0,0 +1,63 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import { BeanBase } from 'vona';
3
+ import { Api, Arg, v } from 'vona-module-a-openapi';
4
+ import { $Dto, TableIdentity } from 'vona-module-a-orm';
5
+ import { Controller, Web } from 'vona-module-a-web';
6
+ import { DtoCategoryTree } from '../dto/categoryTree.ts';
7
+ import { DtoUserCreate } from '../dto/userCreate.ts';
8
+ import { DtoUserLazy } from '../dto/userLazy.ts';
9
+ import { DtoUserUpdate } from '../dto/userUpdate.ts';
10
+
11
+ export interface IControllerOptionsDtoTest extends IDecoratorControllerOptions {}
12
+
13
+ @Controller<IControllerOptionsDtoTest>('dtoTest', { meta: { mode: ['test', 'dev'] } })
14
+ export class ControllerDtoTest extends BeanBase {
15
+ @Web.get('getUserLazy')
16
+ getUserLazy(): DtoUserLazy {
17
+ return {} as any;
18
+ }
19
+
20
+ @Web.get('getUserDynamic')
21
+ @Api.body($Dto.get('test-vona:post'))
22
+ getPostDynamic() {
23
+ }
24
+
25
+ @Web.get('getUserStats')
26
+ @Api.body($Dto.get('test-vona:userStats'))
27
+ getUserStats() {
28
+ }
29
+
30
+ @Web.get('getUserStatsGroup')
31
+ @Api.body($Dto.get('test-vona:userStatsGroup'))
32
+ getUserStatsGroup() {
33
+ }
34
+
35
+ @Web.post('createUser')
36
+ createUser(
37
+ @Arg.body(v.object(DtoUserCreate)) user: DtoUserCreate,
38
+ ) {
39
+ return this.scope.model.user.insert(user);
40
+ }
41
+
42
+ @Web.patch('updateUser/:id')
43
+ updateUser(
44
+ @Arg.param('id') id: TableIdentity,
45
+ @Arg.body(v.object(DtoUserUpdate)) user: DtoUserUpdate,
46
+ ) {
47
+ return this.scope.model.user.update(user, { where: { id } });
48
+ }
49
+
50
+ @Web.get('getCategoryTree')
51
+ @Api.body(v.array($Dto.get('test-vona:category', { columns: ['id', 'name'] })))
52
+ async getCategoryTree() {
53
+ const items = await this.scope.model.category.select({ columns: ['id', 'name'] });
54
+ return items;
55
+ }
56
+
57
+ @Web.get('getCategoryTree2')
58
+ @Api.body(v.array(DtoCategoryTree))
59
+ async getCategoryTree2() {
60
+ const items = await this.scope.model.category.select({ columns: ['id', 'name'] });
61
+ return items;
62
+ }
63
+ }
@@ -0,0 +1,25 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import { BeanBase } from 'vona';
3
+ import { Passport } from 'vona-module-a-user';
4
+ import { Controller, Web } from 'vona-module-a-web';
5
+
6
+ export interface IControllerOptionsGuardPassport extends IDecoratorControllerOptions {}
7
+
8
+ @Controller<IControllerOptionsGuardPassport>('guardPassport')
9
+ export class ControllerGuardPassport extends BeanBase {
10
+ @Web.get('testUserName')
11
+ @Passport.userName({ name: 'admin' })
12
+ testUserName() {}
13
+
14
+ @Web.get('testUserNameFail')
15
+ @Passport.userName({ name: 'admin-none' as any })
16
+ testUserNameFail() {}
17
+
18
+ @Web.get('testRoleName')
19
+ @Passport.roleName({ name: 'admin' })
20
+ testRoleName() {}
21
+
22
+ @Web.get('testRoleNameFail')
23
+ @Passport.roleName({ name: 'admin-none' as any })
24
+ testRoleNameFail() {}
25
+ }
@@ -0,0 +1,92 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import { BeanBase } from 'vona';
3
+ import { Aspect } from 'vona-module-a-aspect';
4
+ import { Core } from 'vona-module-a-core';
5
+ import { Api, Arg, v } from 'vona-module-a-openapi';
6
+ import { Database } from 'vona-module-a-orm';
7
+ import { Passport } from 'vona-module-a-user';
8
+ import { Controller, Web } from 'vona-module-a-web';
9
+ import { z } from 'zod';
10
+ import { $locale } from '../.metadata/index.ts';
11
+ import { DtoUser } from '../dto/user.ts';
12
+
13
+ export interface IControllerOptionsOnion extends IDecoratorControllerOptions {}
14
+
15
+ @Controller<IControllerOptionsOnion>({ path: 'onion', tags: ['Onion'], meta: { mode: ['dev', 'test'] } })
16
+ export class ControllerOnion extends BeanBase {
17
+ @Web.get('/')
18
+ @Aspect.aopMethod('a-orm:transaction', { enable: true, meta: { mode: 'dev' } })
19
+ @Aspect.guardGlobal('a-user:passport', { public: true })
20
+ index() {
21
+ return this.ctx.db.inTransaction;
22
+ // return 'Hello Vona';
23
+ }
24
+
25
+ @Web.post('//echo')
26
+ @Aspect.guardGlobal('a-user:passport', { public: true })
27
+ @Aspect.middlewareGlobal('a-core:gate', { gate: { mode: 'dev' } })
28
+ @Core.gate({ gate: { mode: 'dev' } })
29
+ @Aspect.aopMethod('a-orm:transaction', { isolationLevel: 'SERIALIZABLE', readOnly: true })
30
+ @Database.transaction({ isolationLevel: 'READ_COMMITTED', readOnly: false })
31
+ @Api.body(v.optional(), z.string())
32
+ echo(
33
+ @Arg.query('id', v.default(0), z.number()) id: number,
34
+ temp: string,
35
+ @Arg.query('name', z.number().optional()) name: string,
36
+ @Arg.body(v.title($locale('User')), z.object({ id: z.number().openapi({ title: $locale('UserId') }) }))
37
+ _user: DtoUser,
38
+ ): string | undefined {
39
+ return `echo: ${id}:${temp}:${name}`;
40
+ }
41
+
42
+ @Web.post('echo2/:userId/:userName')
43
+ // @Aspect.middlewareGlobal('a-core:gate', { gate: { mode: 'dev' } })
44
+ @Aspect.guardGlobal('a-user:passport', { public: true })
45
+ // echo2(@Arg.query(v.object(DtoUser, { passthrough: false, strict: false })) book: Partial<DtoUser>) {
46
+ echo2(
47
+ @Arg.param('userId', v.title($locale('UserId')), v.example('example:1')) _userId: number,
48
+ @Arg.param('userName', v.title($locale('UserId')), v.example('example:1')) _userName: string,
49
+ @Arg.query(DtoUser) _user: DtoUser,
50
+ @Arg.body(v.title($locale('User')), z.object({ id: z.number().openapi({ title: $locale('UserId') }) }))
51
+ user: DtoUser,
52
+ ): DtoUser {
53
+ // const ctx = this.app.currentContext;
54
+ // this.$logger.silly(ctx === this.ctx);
55
+ return user;
56
+ }
57
+
58
+ @Web.get('echo3/:userId')
59
+ @Aspect.guardGlobal('a-user:passport', { public: true })
60
+ echo3(
61
+ @Arg.param('userId') _userId: number,
62
+ @Arg.query('id', v.optional()) id: number,
63
+ @Arg.headers('Accept', v.title($locale('UserId'))) accept: string,
64
+ ) {
65
+ this.$logger.silly(this.ctx.path);
66
+ // const ctx = this.app.currentContext;
67
+ // this.$logger.silly(ctx === this.ctx);
68
+ return `${id}:${accept}`;
69
+ }
70
+
71
+ @Web.post('echo4')
72
+ @Aspect.guardGlobal('a-user:passport', { public: true })
73
+ @Aspect.filterGlobal('a-error:error', { enable: true, logs: { 422: true } })
74
+ @Api.body(v.array(DtoUser))
75
+ echo4(@Arg.body(v.optional(), v.array(), v.object(DtoUser)) users: DtoUser[]): DtoUser[] {
76
+ return users;
77
+ }
78
+
79
+ @Web.get('echo5')
80
+ @Passport.public()
81
+ echo5(@Arg.query('ids', v.default([1]), v.array(Number, { separator: '-' })) ids: number[]) {
82
+ // const ctx = this.app.currentContext;
83
+ // this.$logger.silly(ctx === this.ctx);
84
+ return ids;
85
+ }
86
+
87
+ @Web.get('echo6')
88
+ @Passport.admin()
89
+ echo6() {
90
+ return this.bean.passport.isAuthenticated;
91
+ }
92
+ }
@@ -0,0 +1,48 @@
1
+ import type { IJwtToken } from 'vona-module-a-jwt';
2
+ import type { IUserBase, IUserNameRecord } from 'vona-module-a-user';
3
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
4
+ import assert from 'node:assert';
5
+ import { BeanBase } from 'vona';
6
+ import { DtoJwtToken } from 'vona-module-a-jwt';
7
+ import { Api, Arg, v } from 'vona-module-a-openapi';
8
+ import { $getUserName, Passport } from 'vona-module-a-user';
9
+ import { Controller, Web } from 'vona-module-a-web';
10
+
11
+ export interface IControllerOptionsPassport extends IDecoratorControllerOptions {}
12
+
13
+ @Controller<IControllerOptionsPassport>({ path: 'passport', meta: { mode: 'test' } })
14
+ @Api.exclude()
15
+ export class ControllerPassport extends BeanBase {
16
+ @Web.get('echo/:name')
17
+ @Passport.public()
18
+ echo(@Arg.param('name') name: string, @Arg.user() user: IUserBase) {
19
+ assert.equal(name, 'admin');
20
+ assert.equal($getUserName(user), 'admin');
21
+ return { name, user };
22
+ }
23
+
24
+ @Web.post('login')
25
+ @Api.body(v.object(DtoJwtToken))
26
+ @Passport.public()
27
+ async login(@Arg.body('name') name: string): Promise<IJwtToken> {
28
+ const jwt = await this.bean.passport.signinMock(name as keyof IUserNameRecord);
29
+ return jwt;
30
+ }
31
+
32
+ @Web.get('isAuthenticated')
33
+ isAuthenticated(): boolean {
34
+ return this.bean.passport.isAuthenticated;
35
+ }
36
+
37
+ @Web.post('refresh')
38
+ @Api.body(v.object(DtoJwtToken))
39
+ @Passport.public()
40
+ async refresh(@Arg.body('refreshToken') refreshToken: string): Promise<IJwtToken> {
41
+ return await this.bean.passport.refreshAuthToken(refreshToken);
42
+ }
43
+
44
+ @Web.post('logout')
45
+ async logout() {
46
+ return await this.bean.passport.signout();
47
+ }
48
+ }
@@ -0,0 +1,18 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import { BeanBase } from 'vona';
3
+ import { Api, Arg } from 'vona-module-a-openapi';
4
+ import { Passport } from 'vona-module-a-user';
5
+ import { Controller, Web } from 'vona-module-a-web';
6
+
7
+ export interface IControllerOptionsPerformAction extends IDecoratorControllerOptions {}
8
+
9
+ @Controller<IControllerOptionsPerformAction>({ path: 'performAction', meta: { mode: 'test' } })
10
+ @Api.exclude()
11
+ export class ControllerPerformAction extends BeanBase {
12
+ @Web.post('echo')
13
+ @Passport.public()
14
+ echo(@Arg.body('id') id: number) {
15
+ const url = this.scope.util.combineApiPath('performAction/echo');
16
+ return { id, url };
17
+ }
18
+ }
@@ -0,0 +1,25 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import assert from 'node:assert';
3
+ import { BeanBase } from 'vona';
4
+ import { Api } from 'vona-module-a-openapi';
5
+ import { Passport } from 'vona-module-a-user';
6
+ import { Controller, Web } from 'vona-module-a-web';
7
+
8
+ export interface IControllerOptionsQueue extends IDecoratorControllerOptions {}
9
+
10
+ @Controller<IControllerOptionsQueue>({ path: 'queue', meta: { mode: 'test' } })
11
+ @Api.exclude()
12
+ export class ControllerQueue extends BeanBase {
13
+ @Web.post('pushAsync')
14
+ @Passport.public()
15
+ async pushAsync() {
16
+ const res = await this.scope.queue.test.pushAsync({ a: 1, b: 2 });
17
+ assert.equal(res, 3);
18
+ }
19
+
20
+ @Web.post('push')
21
+ @Passport.public()
22
+ push() {
23
+ this.scope.queue.test.push({ a: 1, b: 2 });
24
+ }
25
+ }
@@ -0,0 +1,125 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import type { SummerCacheTest, TSummerCacheTestData } from '../bean/summerCache.test.ts';
3
+ import assert from 'node:assert';
4
+ import { sleep } from '@cabloy/utils';
5
+ import { BeanBase, retry } from 'vona';
6
+ import { Api } from 'vona-module-a-openapi';
7
+ import { Passport } from 'vona-module-a-user';
8
+ import { Controller, Web } from 'vona-module-a-web';
9
+ import { __ThisModule__ } from '../.metadata/this.ts';
10
+
11
+ export interface IControllerOptionsSummer extends IDecoratorControllerOptions {}
12
+
13
+ @Controller<IControllerOptionsSummer>({ path: 'summer', meta: { mode: 'test' } })
14
+ @Api.exclude()
15
+ export class ControllerSummer extends BeanBase {
16
+ @Web.post()
17
+ @Passport.public()
18
+ async test() {
19
+ // name
20
+ const name = 'test';
21
+ const key1 = { id: 1 };
22
+ const key2 = { id: 2 };
23
+ const key3 = { id: 3 };
24
+
25
+ // getCache
26
+ const cache = this.scope.summerCache.test;
27
+ assert.equal(!!cache, true);
28
+ let cacheOtherModule = this.$scope.testVona.summerCache.test;
29
+ assert.equal(cache, cacheOtherModule);
30
+ cacheOtherModule = this.bean.summer.cache(`${__ThisModule__}.summerCache.${name}`) as SummerCacheTest;
31
+ assert.equal(cache, cacheOtherModule);
32
+
33
+ let value: TSummerCacheTestData | null | undefined;
34
+ let values: Array<TSummerCacheTestData | null | undefined>;
35
+
36
+ // get: peek
37
+ value = await cache.peek(key1);
38
+ assert.equal(value, undefined);
39
+
40
+ // get
41
+ value = await cache.get(key1);
42
+ assert.equal(value?.id, key1.id);
43
+
44
+ // get: peek
45
+ value = await cache.peek(key1);
46
+ assert.equal(value?.id, key1.id);
47
+ value = await cache.peek(key1, { mode: 'mem' });
48
+ assert.equal(value?.id, key1.id);
49
+ value = await cache.peek(key1, { mode: 'redis' });
50
+ assert.equal(value?.id, key1.id);
51
+
52
+ // get: peek sleep for mem stale
53
+ await sleep(900);
54
+
55
+ // get: peek again
56
+ value = await cache.peek(key1, { mode: 'redis' });
57
+ assert.equal(value?.id, key1.id);
58
+ await retry({ retries: 3 }, async () => {
59
+ await sleep(100);
60
+ value = await cache.peek(key1, { mode: 'mem' });
61
+ assert.equal(value, undefined);
62
+ });
63
+
64
+ // get: peek sleep for redis stale
65
+ await sleep(1900);
66
+
67
+ // get: peek again
68
+ await retry({ retries: 3 }, async () => {
69
+ await sleep(100);
70
+ value = await cache.peek(key1, { mode: 'redis' });
71
+ assert.equal(value, undefined);
72
+ });
73
+ value = await cache.peek(key1, { mode: 'mem' });
74
+ assert.equal(value, undefined);
75
+
76
+ // mget
77
+ // mem cache graph: key1
78
+ value = await cache.get(key1);
79
+ assert.equal(value?.id, key1.id);
80
+ // mem cache graph: key2 key3
81
+ values = await cache.mget([key1, key2, key3]); // todo: maybe has bug
82
+ assert.equal(values[0]?.id, key1.id); // todo: maybe has bug
83
+ assert.equal(values[1]?.id, key2.id);
84
+ assert.equal(values[2]?.id, key3.id);
85
+ // mem cache graph: key3 key1
86
+ values = await cache.mget([key1, key2, key3]);
87
+ assert.equal(values[0]?.id, key1.id);
88
+ assert.equal(values[1]?.id, key2.id);
89
+ assert.equal(values[2]?.id, key3.id);
90
+
91
+ // mget: peek
92
+ value = await cache.peek(key2, { mode: 'redis' });
93
+ assert.equal(value?.id, key2.id);
94
+ value = await cache.peek(key2, { mode: 'mem' });
95
+ assert.equal(value, undefined);
96
+
97
+ // del
98
+ await cache.del(key1);
99
+ await cache.del(key2);
100
+
101
+ // mdel
102
+ await cache.mdel([key1, key2, key3]);
103
+
104
+ // mdel: peek
105
+ value = await cache.peek(key3, { mode: 'redis' });
106
+ assert.equal(value, undefined);
107
+ value = await cache.peek(key3, { mode: 'mem' });
108
+ assert.equal(value, undefined);
109
+
110
+ // clear
111
+ values = await cache.mget([key1, key2, key3]);
112
+ assert.equal(values[2]?.id, key3.id);
113
+ value = await cache.peek(key3, { mode: 'redis' });
114
+ assert.equal(value?.id, key3.id);
115
+ value = await cache.peek(key3, { mode: 'mem' });
116
+ assert.equal(value?.id, key3.id);
117
+
118
+ await cache.clear();
119
+
120
+ value = await cache.peek(key3, { mode: 'redis' });
121
+ assert.equal(value, undefined);
122
+ value = await cache.peek(key3, { mode: 'mem' });
123
+ assert.equal(value, undefined);
124
+ }
125
+ }
@@ -0,0 +1,32 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import assert from 'node:assert';
3
+ import { BeanBase, cast } from 'vona';
4
+ import { Api } from 'vona-module-a-openapi';
5
+ import { Passport } from 'vona-module-a-user';
6
+ import { Controller, Web } from 'vona-module-a-web';
7
+
8
+ export interface IControllerOptionsTail extends IDecoratorControllerOptions {}
9
+
10
+ @Controller<IControllerOptionsTail>({ path: 'tail', meta: { mode: 'test' } })
11
+ @Api.exclude()
12
+ export class ControllerTail extends BeanBase {
13
+ @Web.post()
14
+ @Passport.public()
15
+ tail() {
16
+ // 1
17
+ cast(this.ctx)._tail_test = 1;
18
+
19
+ // tail
20
+ this.ctx.db.commit(() => {
21
+ assert.equal(cast(this.ctx)._tail_test_als_caller, undefined);
22
+ assert.equal(cast(this.ctx)._tail_test, 2);
23
+ this.ctx.db.commit(() => {
24
+ assert.equal(cast(this.ctx)._tail_test, 3);
25
+ });
26
+ cast(this.ctx)._tail_test = 3;
27
+ });
28
+
29
+ // 2
30
+ cast(this.ctx)._tail_test = 2;
31
+ }
32
+ }
@@ -0,0 +1,29 @@
1
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
2
+ import { BeanBase } from 'vona';
3
+ import { Api, Arg } from 'vona-module-a-openapi';
4
+ import { Database } from 'vona-module-a-orm';
5
+ import { Passport } from 'vona-module-a-user';
6
+ import { Controller, Web } from 'vona-module-a-web';
7
+
8
+ const tableNameFail = '__tempTransactionFail';
9
+ const tableNameSuccess = '__tempTransactionSuccess';
10
+ export interface IControllerOptionsTransaction extends IDecoratorControllerOptions {}
11
+
12
+ @Controller<IControllerOptionsTransaction>({ path: 'transaction', meta: { mode: 'test' } })
13
+ @Api.exclude()
14
+ export class ControllerTransaction extends BeanBase {
15
+ @Web.post('fail')
16
+ @Database.transaction()
17
+ @Passport.public()
18
+ async fail(@Arg.body() item: object) {
19
+ await this.bean.model.update(`${tableNameFail}` as any, item);
20
+ await this.bean.model.update(`${tableNameFail}error` as any, item);
21
+ }
22
+
23
+ @Web.post('success')
24
+ @Database.transaction()
25
+ @Passport.public()
26
+ async success(@Arg.body() item: object) {
27
+ await this.bean.model.update(tableNameSuccess as any, item);
28
+ }
29
+ }
@@ -0,0 +1,57 @@
1
+ import type { IUploadField, IUploadFile } from 'vona-module-a-upload';
2
+ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
3
+ import assert from 'node:assert';
4
+ import { BeanBase } from 'vona';
5
+ import { Aspect } from 'vona-module-a-aspect';
6
+ import { Api, Arg, v } from 'vona-module-a-openapi';
7
+ import { SymbolUploadValue } from 'vona-module-a-upload';
8
+ import { Passport } from 'vona-module-a-user';
9
+ import { Controller, Web } from 'vona-module-a-web';
10
+ import { z } from 'zod';
11
+
12
+ export interface IControllerOptionsUpload extends IDecoratorControllerOptions {}
13
+
14
+ @Controller<IControllerOptionsUpload>({ path: 'upload', meta: { mode: ['test', 'dev'] } })
15
+ export class ControllerUpload extends BeanBase {
16
+ @Web.post('fields')
17
+ @Passport.public()
18
+ @Aspect.interceptor('a-upload:upload')
19
+ @Api.contentType('application/json')
20
+ fields(
21
+ @Arg.fields() fields: IUploadField[],
22
+ @Arg.fields('checkes', v.array(z.string())) checkes: string[],
23
+ @Arg.field('name', v.default('zhennann'), v.title('your name')) name: string,
24
+ ) {
25
+ assert.equal(fields.find(item => item.name === 'name')?.value, 'zhennann');
26
+ assert.equal(checkes.length > 0, true);
27
+ assert.equal(name, 'zhennann');
28
+ return this.ctx[SymbolUploadValue];
29
+ }
30
+
31
+ @Web.post('file')
32
+ @Passport.public()
33
+ @Aspect.interceptor('a-upload:upload')
34
+ @Api.contentType('application/json')
35
+ file(@Arg.field('name', v.default('zhennann')) name: string, @Arg.file('welcome') file: IUploadFile) {
36
+ assert.equal(name, 'zhennann');
37
+ assert.equal(file.name, 'welcome');
38
+ return this.ctx[SymbolUploadValue];
39
+ }
40
+
41
+ @Web.post('files')
42
+ @Passport.public()
43
+ @Aspect.interceptor('a-upload:upload')
44
+ @Api.contentType('application/json')
45
+ files(
46
+ @Arg.files(v.title('more files')) files: IUploadFile[],
47
+ @Arg.files('images', v.title('images')) images: IUploadFile[],
48
+ @Arg.file('welcome1', v.title('single file')) file1: IUploadFile,
49
+ @Arg.file('welcome2')file2: IUploadFile,
50
+ ) {
51
+ assert.equal(files.find(item => item.name === 'welcome1')?.name, 'welcome1');
52
+ assert.equal(images.find(item => item.name === 'images')?.name, 'images');
53
+ assert.equal(file1.name, 'welcome1');
54
+ assert.equal(file2.name, 'welcome2');
55
+ return this.ctx[SymbolUploadValue];
56
+ }
57
+ }
@@ -0,0 +1,8 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { $Dto } from 'vona-module-a-orm';
3
+ import { Dto } from 'vona-module-a-web';
4
+
5
+ export interface IDtoOptionsCategoryTree extends IDecoratorDtoOptions {}
6
+
7
+ @Dto<IDtoOptionsCategoryTree>()
8
+ export class DtoCategoryTree extends $Dto.get('test-vona:category', { columns: ['id', 'name'] }) {}
@@ -0,0 +1,10 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { $Dto } from 'vona-module-a-orm';
3
+ import { Dto } from 'vona-module-a-web';
4
+ import { ModelOrder } from '../model/order.ts';
5
+
6
+ export interface IDtoOptionsOrderCreate extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsOrderCreate>()
9
+ export class DtoOrderCreate
10
+ extends $Dto.create(() => ModelOrder, { columns: ['orderNo', 'remark'] }) {}
@@ -0,0 +1,9 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { $Dto } from 'vona-module-a-orm';
3
+ import { Dto } from 'vona-module-a-web';
4
+ import { ModelOrder } from '../model/order.ts';
5
+
6
+ export interface IDtoOptionsOrderResult extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsOrderResult>()
9
+ export class DtoOrderResult extends $Dto.get(() => ModelOrder) {}
@@ -0,0 +1,9 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { $Dto } from 'vona-module-a-orm';
3
+ import { Dto } from 'vona-module-a-web';
4
+ import { ModelOrder } from '../model/order.ts';
5
+
6
+ export interface IDtoOptionsOrderUpdate extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsOrderUpdate>()
9
+ export class DtoOrderUpdate extends $Dto.update(() => ModelOrder, { columns: ['orderNo', 'remark'] }) {}
@@ -0,0 +1,9 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { $Dto } from 'vona-module-a-orm';
3
+ import { Dto } from 'vona-module-a-web';
4
+ import { ModelPost } from '../model/post.ts';
5
+
6
+ export interface IDtoOptionsPostCreate extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsPostCreate>({ independent: true })
9
+ export class DtoPostCreate extends $Dto.create(() => ModelPost) {}
@@ -0,0 +1,14 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { Api, v } from 'vona-module-a-openapi';
3
+ import { Dto } from 'vona-module-a-web';
4
+
5
+ export interface IDtoOptionsProfile extends IDecoratorDtoOptions {}
6
+
7
+ @Dto<IDtoOptionsProfile>()
8
+ export class DtoProfile {
9
+ @Api.field()
10
+ id: number;
11
+
12
+ @Api.field(v.email())
13
+ email: string;
14
+ }
@@ -0,0 +1,15 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { Api, v } from 'vona-module-a-openapi';
3
+ import { Dto } from 'vona-module-a-web';
4
+ import { DtoUserLazy } from './userLazy.ts';
5
+
6
+ export interface IDtoOptionsRoleLazy extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsRoleLazy>()
9
+ export class DtoRoleLazy {
10
+ @Api.field()
11
+ name: string;
12
+
13
+ @Api.field(v.optional(), v.array(v.lazy(() => DtoUserLazy)))
14
+ users?: DtoUserLazy[];
15
+ }