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.
- package/dist/.metadata/index.d.ts +12 -1
- package/dist/index.js +239 -128
- package/dist/service/order.d.ts +4 -0
- package/dist/service/post.d.ts +2 -0
- package/package.json +4 -2
- package/src/.metadata/index.ts +1741 -0
- package/src/.metadata/this.ts +2 -0
- package/src/bean/aop.regExp.ts +30 -0
- package/src/bean/aop.simple.ts +58 -0
- package/src/bean/aopMethod.test.ts +42 -0
- package/src/bean/bean.testCtx.ts +55 -0
- package/src/bean/broadcast.test.ts +22 -0
- package/src/bean/cacheMem.test.ts +7 -0
- package/src/bean/cacheRedis.post.ts +10 -0
- package/src/bean/cacheRedis.test.ts +7 -0
- package/src/bean/event.helloEcho.ts +8 -0
- package/src/bean/eventListener.helloEcho.ts +21 -0
- package/src/bean/meta.version.ts +81 -0
- package/src/bean/queue.test.ts +18 -0
- package/src/bean/schedule.test.ts +12 -0
- package/src/bean/schedule.test3.ts +12 -0
- package/src/bean/summerCache.test.ts +29 -0
- package/src/config/config.ts +5 -0
- package/src/config/locale/en-us.ts +19 -0
- package/src/config/locale/zh-cn.ts +17 -0
- package/src/controller/bean.ts +95 -0
- package/src/controller/cacheMem.ts +63 -0
- package/src/controller/cacheRedis.ts +55 -0
- package/src/controller/dtoTest.ts +63 -0
- package/src/controller/guardPassport.ts +25 -0
- package/src/controller/onion.ts +92 -0
- package/src/controller/passport.ts +48 -0
- package/src/controller/performAction.ts +18 -0
- package/src/controller/queue.ts +25 -0
- package/src/controller/summer.ts +125 -0
- package/src/controller/tail.ts +32 -0
- package/src/controller/transaction.ts +29 -0
- package/src/controller/upload.ts +57 -0
- package/src/dto/categoryTree.ts +8 -0
- package/src/dto/orderCreate.ts +10 -0
- package/src/dto/orderResult.ts +9 -0
- package/src/dto/orderUpdate.ts +9 -0
- package/src/dto/postCreate.ts +9 -0
- package/src/dto/profile.ts +14 -0
- package/src/dto/roleLazy.ts +15 -0
- package/src/dto/user.ts +19 -0
- package/src/dto/userCreate.ts +8 -0
- package/src/dto/userLazy.ts +18 -0
- package/src/dto/userUpdate.ts +8 -0
- package/src/entity/category.ts +14 -0
- package/src/entity/order.ts +18 -0
- package/src/entity/post.ts +17 -0
- package/src/entity/postContent.ts +14 -0
- package/src/entity/product.ts +24 -0
- package/src/entity/role.ts +11 -0
- package/src/entity/roleUser.ts +14 -0
- package/src/entity/test.ts +18 -0
- package/src/entity/user.ts +17 -0
- package/src/index.ts +1 -0
- package/src/model/category.ts +17 -0
- package/src/model/categoryChain.ts +16 -0
- package/src/model/order.ts +26 -0
- package/src/model/orderStats.ts +27 -0
- package/src/model/post.ts +16 -0
- package/src/model/postContent.ts +17 -0
- package/src/model/product.ts +8 -0
- package/src/model/role.ts +15 -0
- package/src/model/roleUser.ts +8 -0
- package/src/model/test.ts +8 -0
- package/src/model/testDynamicTable.ts +21 -0
- package/src/model/user.ts +21 -0
- package/src/model/userStats.ts +15 -0
- package/src/model/userStatsGroup.ts +15 -0
- package/src/service/aopMethod.ts +38 -0
- package/src/service/caching.ts +75 -0
- package/src/service/order.ts +65 -0
- package/src/service/post.ts +219 -0
- package/src/service/test.ts +9 -0
- package/src/service/testApp.ts +13 -0
- package/src/service/testClass.ts +15 -0
- package/src/service/testData.ts +67 -0
- package/src/service/transaction.ts +20 -0
- package/test/aopMethod.test.ts +21 -0
- package/test/authSimple.test.ts +45 -0
- package/test/bean.test.ts +16 -0
- package/test/broadcast.test.ts +17 -0
- package/test/cache/cacheMem.test.ts +10 -0
- package/test/cache/cacheRedis.test.ts +10 -0
- package/test/cache/caching.test.ts +58 -0
- package/test/cache/summer.test.ts +10 -0
- package/test/database/database.test.ts +127 -0
- package/test/database/dtoAggregate.test.ts +44 -0
- package/test/database/dtoGet.test.ts +61 -0
- package/test/database/dtoGroup.test.ts +44 -0
- package/test/database/dtoLazy.test.ts +45 -0
- package/test/database/dtoMutate.test.ts +56 -0
- package/test/database/modelAggregate.test.ts +197 -0
- package/test/database/modelCache.test.ts +37 -0
- package/test/database/modelGeneral.test.ts +18 -0
- package/test/database/modelGroup.test.ts +211 -0
- package/test/database/modelRelations.test.ts +203 -0
- package/test/database/modelRelationsJoins.test.ts +39 -0
- package/test/database/modelRelationsMutate.test.ts +354 -0
- package/test/database/modelWhere.test.ts +138 -0
- package/test/database/orm.test.ts +22 -0
- package/test/database/transaction.test.ts +142 -0
- package/test/event.test.ts +14 -0
- package/test/guardPassport.test.ts +44 -0
- package/test/jwt.test.ts +27 -0
- package/test/locale.test.ts +51 -0
- package/test/passport.test.ts +57 -0
- package/test/queue.test.ts +11 -0
- package/test/tail.test.ts +21 -0
- package/test/upload.test.ts +58 -0
- package/test/utils/cabloyUtils.test.ts +22 -0
- package/test/utils/celjs.test.ts +26 -0
- package/test/utils/mappedTypes.test.ts +65 -0
- 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
|
+
}
|