vona-module-a-web 5.0.30 → 5.0.32
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/cli/filterTransform/boilerplate/{{sceneName}}.{{beanName}}.ts_ +10 -0
- package/dist/.metadata/index.d.ts +54 -8
- package/dist/bean/bean.router.d.ts +2 -3
- package/dist/bean/filterTransform.base.d.ts +8 -0
- package/dist/bean/filterTransform.dateRange.d.ts +8 -0
- package/dist/bean/hmr.controller.d.ts +6 -0
- package/dist/bean/pipe.filter.d.ts +17 -0
- package/dist/index.js +281 -231
- package/dist/lib/const.d.ts +4 -0
- package/dist/lib/decorator/arguments.d.ts +2 -3
- package/dist/lib/decorator/filterTransform.d.ts +2 -0
- package/dist/lib/decorator/index.d.ts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/main.d.ts +0 -1
- package/dist/types/filter.d.ts +26 -0
- package/dist/types/filterTransform.d.ts +41 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/router.d.ts +2 -4
- package/package.json +6 -1
- package/dist/bean/pipe.query.d.ts +0 -37
- package/dist/lib/decorator/response.d.ts +0 -1
- package/dist/lib/utils.d.ts +0 -6
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IDecoratorFilterTransformOptions, IFilterTransformWhere, IPipeOptionsFilterTransformInfo } from 'vona-module-a-web';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
import { FilterTransform } from 'vona-module-a-web';
|
|
4
|
+
|
|
5
|
+
export interface IFilterTransformOptions<%=argv.beanNameCapitalize%> extends IDecoratorFilterTransformOptions {}
|
|
6
|
+
|
|
7
|
+
@FilterTransform<IFilterTransformOptions<%=argv.beanNameCapitalize%>>()
|
|
8
|
+
export class FilterTransform<%=argv.beanNameCapitalize%> extends BeanBase implements IFilterTransformWhere {
|
|
9
|
+
async where(_info: IPipeOptionsFilterTransformInfo, _options: IFilterTransformOptions<%=argv.beanNameCapitalize%>): Promise<any | undefined> {}
|
|
10
|
+
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/** pipe: begin */
|
|
2
|
-
export * from '../bean/pipe.
|
|
2
|
+
export * from '../bean/pipe.filter.ts';
|
|
3
3
|
export * from '../bean/pipe.valid.ts';
|
|
4
|
-
import type {
|
|
4
|
+
import type { IPipeOptionsFilter } from '../bean/pipe.filter.ts';
|
|
5
5
|
import type { IPipeOptionsValid } from '../bean/pipe.valid.ts';
|
|
6
6
|
import 'vona-module-a-aspect';
|
|
7
7
|
declare module 'vona-module-a-aspect' {
|
|
8
8
|
interface IPipeRecordLocal {
|
|
9
|
-
'a-web:
|
|
9
|
+
'a-web:filter': IPipeOptionsFilter;
|
|
10
10
|
'a-web:valid': IPipeOptionsValid;
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
declare module 'vona-module-a-web' {
|
|
14
|
-
interface
|
|
14
|
+
interface PipeFilter {
|
|
15
15
|
}
|
|
16
|
-
interface
|
|
17
|
-
get $beanFullName(): 'a-web.pipe.
|
|
18
|
-
get $onionName(): 'a-web:
|
|
19
|
-
get $onionOptions():
|
|
16
|
+
interface PipeFilter {
|
|
17
|
+
get $beanFullName(): 'a-web.pipe.filter';
|
|
18
|
+
get $onionName(): 'a-web:filter';
|
|
19
|
+
get $onionOptions(): IPipeOptionsFilter;
|
|
20
20
|
}
|
|
21
21
|
interface PipeValid {
|
|
22
22
|
}
|
|
@@ -95,6 +95,52 @@ declare module 'vona-module-a-web' {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
/** startup: end */
|
|
98
|
+
/** filterTransform: begin */
|
|
99
|
+
export * from '../bean/filterTransform.base.ts';
|
|
100
|
+
export * from '../bean/filterTransform.dateRange.ts';
|
|
101
|
+
import type { IFilterTransformOptionsBase } from '../bean/filterTransform.base.ts';
|
|
102
|
+
import type { IFilterTransformOptionsDateRange } from '../bean/filterTransform.dateRange.ts';
|
|
103
|
+
import 'vona-module-a-web';
|
|
104
|
+
declare module 'vona-module-a-web' {
|
|
105
|
+
interface IFilterTransformRecord {
|
|
106
|
+
'a-web:base': IFilterTransformOptionsBase;
|
|
107
|
+
'a-web:dateRange': IFilterTransformOptionsDateRange;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
declare module 'vona-module-a-web' {
|
|
111
|
+
interface FilterTransformBase {
|
|
112
|
+
}
|
|
113
|
+
interface FilterTransformBase {
|
|
114
|
+
get $beanFullName(): 'a-web.filterTransform.base';
|
|
115
|
+
get $onionName(): 'a-web:base';
|
|
116
|
+
get $onionOptions(): IFilterTransformOptionsBase;
|
|
117
|
+
}
|
|
118
|
+
interface FilterTransformDateRange {
|
|
119
|
+
}
|
|
120
|
+
interface FilterTransformDateRange {
|
|
121
|
+
get $beanFullName(): 'a-web.filterTransform.dateRange';
|
|
122
|
+
get $onionName(): 'a-web:dateRange';
|
|
123
|
+
get $onionOptions(): IFilterTransformOptionsDateRange;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** filterTransform: end */
|
|
127
|
+
/** hmr: begin */
|
|
128
|
+
export * from '../bean/hmr.controller.ts';
|
|
129
|
+
import 'vona';
|
|
130
|
+
declare module 'vona' {
|
|
131
|
+
interface IHmrRecord {
|
|
132
|
+
'a-web:controller': never;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
declare module 'vona-module-a-web' {
|
|
136
|
+
interface HmrController {
|
|
137
|
+
}
|
|
138
|
+
interface HmrController {
|
|
139
|
+
get $beanFullName(): 'a-web.hmr.controller';
|
|
140
|
+
get $onionName(): 'a-web:controller';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** hmr: end */
|
|
98
144
|
/** config: begin */
|
|
99
145
|
export * from '../config/config.ts';
|
|
100
146
|
import type { config } from '../config/config.ts';
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type { Constructable, VonaContext } from 'vona';
|
|
2
1
|
import * as ModuleInfo from '@cabloy/module-info';
|
|
3
2
|
import Router from 'find-my-way';
|
|
4
3
|
import { BeanBase } from 'vona';
|
|
5
4
|
export declare class BeanRouter extends BeanBase {
|
|
6
|
-
|
|
5
|
+
reRegisterController(beanFullName: string): void;
|
|
6
|
+
registerController(beanFullName: string): void;
|
|
7
7
|
register(method: Router.HTTPMethod, moduleName: ModuleInfo.IModuleInfo | string, path: string | undefined, simplify: boolean, fn: Router.Handler<Router.HTTPVersion.V1>): void;
|
|
8
8
|
unRegister(method: Router.HTTPMethod, moduleName: ModuleInfo.IModuleInfo | string, path: string | undefined, simplify: boolean): void;
|
|
9
9
|
findByPath(method: Router.HTTPMethod, moduleName: ModuleInfo.IModuleInfo | string, path: string | undefined, simplify: boolean): any;
|
|
10
10
|
private _registerControllerAction;
|
|
11
|
-
_registerComposeMiddlewares(ctx: VonaContext): (context: any, next?: any) => any;
|
|
12
11
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IDecoratorFilterTransformOptions, IFilterTransformWhere, IPipeOptionsFilterTransformInfo } from '../types/filterTransform.ts';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
export interface IFilterTransformOptionsBase extends IDecoratorFilterTransformOptions {
|
|
4
|
+
test: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare class FilterTransformBase extends BeanBase implements IFilterTransformWhere {
|
|
7
|
+
where(info: IPipeOptionsFilterTransformInfo, _options: IFilterTransformOptionsBase): Promise<any | undefined>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IDecoratorFilterTransformOptions, IFilterTransformWhere, IPipeOptionsFilterTransformInfo } from '../types/filterTransform.ts';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
export interface IFilterTransformOptionsDateRange extends IDecoratorFilterTransformOptions {
|
|
4
|
+
separator: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class FilterTransformDateRange extends BeanBase implements IFilterTransformWhere {
|
|
7
|
+
where(info: IPipeOptionsFilterTransformInfo, options: IFilterTransformOptionsDateRange): Promise<any | undefined>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IDecoratorBeanOptionsBase } from 'vona';
|
|
2
|
+
import type { IHmrReload } from 'vona-module-a-hmr';
|
|
3
|
+
import { BeanBase } from 'vona';
|
|
4
|
+
export declare class HmrController extends BeanBase implements IHmrReload {
|
|
5
|
+
reload(beanOptions: IDecoratorBeanOptionsBase): Promise<void>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, IPipeTransform } from 'vona-module-a-aspect';
|
|
2
|
+
import type { RouteHandlerArgumentMeta } from 'vona-module-a-openapi';
|
|
3
|
+
import type { ValidatorOptions } from 'vona-module-a-validation';
|
|
4
|
+
import { BeanBase } from 'vona';
|
|
5
|
+
export type TypePipeFilterData = unknown;
|
|
6
|
+
export type TypePipeFilterResult = TypePipeFilterData;
|
|
7
|
+
export interface IPipeOptionsFilter extends IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, ValidatorOptions {
|
|
8
|
+
}
|
|
9
|
+
export declare class PipeFilter extends BeanBase implements IPipeTransform<TypePipeFilterData, TypePipeFilterResult> {
|
|
10
|
+
transform(value: TypePipeFilterData, metadata: RouteHandlerArgumentMeta, options: IPipeOptionsFilter): Promise<TypePipeFilterResult>;
|
|
11
|
+
private _transform;
|
|
12
|
+
private _transformSystem;
|
|
13
|
+
private _transformOrders;
|
|
14
|
+
private _transformField;
|
|
15
|
+
private _transformFields;
|
|
16
|
+
}
|
|
17
|
+
export declare const ArgFilterPro: (options?: Partial<IPipeOptionsFilter> | undefined) => any;
|
package/dist/index.js
CHANGED
|
@@ -1,44 +1,45 @@
|
|
|
1
|
-
import { BeanInfo, BeanBase, cast, appMetadata, appResource, deepExtend, compose, BeanSimple, BeanScopeBase
|
|
2
|
-
import { isNil,
|
|
1
|
+
import { BeanInfo, BeanBase, cast, beanFullNameFromOnionName, appMetadata, appResource, deepExtend, compose, createBeanDecorator, BeanSimple, BeanScopeBase } from 'vona';
|
|
2
|
+
import { isNil, isNilOrEmptyString } from '@cabloy/utils';
|
|
3
3
|
import { ZodMetadata } from '@cabloy/zod-openapi';
|
|
4
|
-
import { Pipe, createArgumentPipe, setArgumentPipe } from 'vona-module-a-aspect';
|
|
5
|
-
import * as ModuleInfo from '@cabloy/module-info';
|
|
4
|
+
import { Pipe, createArgumentPipe, SymbolCacheComposeGuards, SymbolCacheComposeInterceptors, SymbolCacheComposePipes, SymbolCacheComposeMiddlewares, clearCacheComposesRouter, SymbolCacheComposeMiddlewareSystems, setArgumentPipe } from 'vona-module-a-aspect';
|
|
6
5
|
import { Bean, Service, Scope } from 'vona-module-a-bean';
|
|
7
6
|
import { SymbolUseOnionOptions } from 'vona-module-a-onion';
|
|
8
|
-
import { SymbolRouteHandlersArgumentsValue, SymbolRouteHandlersArgumentsMeta, makeSchemaLikes, $schema, mergeFieldsOpenapiMetadata } from 'vona-module-a-
|
|
7
|
+
import { SymbolRouteHandlersArgumentsValue, SymbolRouteHandlersArgumentsMeta, makeSchemaLikes, $schema, SymbolOpenApiOptions, mergeFieldsOpenapiMetadata } from 'vona-module-a-openapiutils';
|
|
9
8
|
import { SymbolUploadValue } from 'vona-module-a-upload';
|
|
10
9
|
import http from 'node:http';
|
|
11
10
|
import { Startup } from 'vona-module-a-startup';
|
|
11
|
+
import { DateTime } from 'luxon';
|
|
12
|
+
import 'vona-module-a-web';
|
|
13
|
+
import { Hmr } from 'vona-module-a-hmr';
|
|
12
14
|
import Router from 'find-my-way';
|
|
13
15
|
import { SymbolRouterMiddleware } from 'vona-module-a-executor';
|
|
14
16
|
import { z } from 'zod';
|
|
15
|
-
import { SymbolOpenApiOptions } from 'vona-module-a-openapiutils';
|
|
16
17
|
|
|
17
|
-
var _dec$
|
|
18
|
+
var _dec$8, _dec2$8, _class$8;
|
|
18
19
|
const __FieldsSystem = ['columns', 'where', 'orders', 'pageNo', 'pageSize'];
|
|
19
|
-
let
|
|
20
|
+
let PipeFilter = (_dec$8 = Pipe({
|
|
20
21
|
// ValidatorOptions
|
|
21
22
|
disableErrorMessages: false,
|
|
22
23
|
errorHttpStatusCode: 400,
|
|
23
24
|
loose: false,
|
|
24
25
|
strict: false
|
|
25
|
-
}), _dec2$
|
|
26
|
+
}), _dec2$8 = BeanInfo({
|
|
26
27
|
module: "a-web"
|
|
27
|
-
}), _dec$
|
|
28
|
+
}), _dec$8(_class$8 = _dec2$8(_class$8 = class PipeFilter extends BeanBase {
|
|
28
29
|
async transform(value, metadata, options) {
|
|
29
|
-
if (!options.schema) throw new Error(`should specify the schema of
|
|
30
|
+
if (!options.schema) throw new Error(`should specify the schema of pipeFilter: ${metadata.controller.name}.${metadata.method}#${metadata.index}`);
|
|
30
31
|
// validateSchema
|
|
31
32
|
value = await this.bean.validator.validateSchema(options.schema, value, options, metadata.field);
|
|
32
33
|
// transform
|
|
33
|
-
value = this._transform(value, options);
|
|
34
|
+
value = await this._transform(value, options);
|
|
34
35
|
// ok
|
|
35
36
|
return value;
|
|
36
37
|
}
|
|
37
|
-
_transform(value, options) {
|
|
38
|
+
async _transform(value, options) {
|
|
38
39
|
// 1. system: columns/where/orders/pageNo/pageSize
|
|
39
40
|
const params = this._transformSystem(value);
|
|
40
41
|
// 2. fields
|
|
41
|
-
this._transformFields(params, value, options);
|
|
42
|
+
await this._transformFields(params, value, options);
|
|
42
43
|
// 3. system: orders
|
|
43
44
|
this._transformOrders(params, options);
|
|
44
45
|
// ok
|
|
@@ -76,41 +77,43 @@ let PipeQuery = (_dec$5 = Pipe({
|
|
|
76
77
|
if (!params.orders) return;
|
|
77
78
|
// openapi
|
|
78
79
|
const openapi = ZodMetadata.getOpenapiMetadata(options.schema);
|
|
79
|
-
const table = openapi?.
|
|
80
|
+
const table = openapi?.filter?.table;
|
|
80
81
|
// loop
|
|
81
82
|
for (const order of params.orders) {
|
|
82
83
|
const field = order[0];
|
|
83
84
|
if (field.includes('.')) continue;
|
|
84
85
|
let tableCurrent = table;
|
|
85
86
|
let fieldCurrent = field;
|
|
86
|
-
const fieldSchema = ZodMetadata.
|
|
87
|
+
const fieldSchema = ZodMetadata.getFieldSchema(options.schema, field);
|
|
87
88
|
if (fieldSchema) {
|
|
88
89
|
const openapi = ZodMetadata.getOpenapiMetadata(fieldSchema);
|
|
89
|
-
if (openapi?.
|
|
90
|
-
tableCurrent = openapi?.
|
|
90
|
+
if (openapi?.filter?.table) {
|
|
91
|
+
tableCurrent = openapi?.filter?.table;
|
|
91
92
|
}
|
|
92
|
-
if (openapi?.
|
|
93
|
-
fieldCurrent = openapi?.
|
|
93
|
+
if (openapi?.filter?.originalName) {
|
|
94
|
+
fieldCurrent = openapi?.filter?.originalName;
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
cast(order)[0] = tableCurrent ? `${tableCurrent}.${fieldCurrent}` : fieldCurrent;
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
|
-
_transformField(key, fieldValue, params, value, options) {
|
|
100
|
+
async _transformField(key, fieldValue, params, value, options) {
|
|
101
|
+
if (isNilOrEmptyString(fieldValue)) return;
|
|
100
102
|
if (__FieldsSystem.includes(key)) return;
|
|
101
|
-
const fieldSchema = ZodMetadata.
|
|
103
|
+
const fieldSchema = ZodMetadata.getFieldSchema(options.schema, key);
|
|
102
104
|
if (!fieldSchema) return;
|
|
105
|
+
const fieldSchemaInner = ZodMetadata.unwrapChained(fieldSchema);
|
|
103
106
|
// openapi
|
|
104
107
|
const openapi = ZodMetadata.getOpenapiMetadata(fieldSchema);
|
|
105
108
|
// name
|
|
106
|
-
const originalName = openapi?.
|
|
109
|
+
const originalName = openapi?.filter?.originalName ?? key;
|
|
107
110
|
let fullName;
|
|
108
111
|
// joins
|
|
109
112
|
let joinInfo;
|
|
110
|
-
if (openapi?.
|
|
111
|
-
const joinType = openapi.
|
|
112
|
-
const joinTable = openapi.
|
|
113
|
-
const joinOn = openapi.
|
|
113
|
+
if (openapi?.filter?.joinOn) {
|
|
114
|
+
const joinType = openapi.filter.joinType ?? 'innerJoin';
|
|
115
|
+
const joinTable = openapi.filter.table;
|
|
116
|
+
const joinOn = openapi.filter.joinOn;
|
|
114
117
|
joinInfo = [joinType, joinTable, joinOn];
|
|
115
118
|
fullName = `${joinTable}.${originalName}`;
|
|
116
119
|
} else {
|
|
@@ -118,8 +121,19 @@ let PipeQuery = (_dec$5 = Pipe({
|
|
|
118
121
|
}
|
|
119
122
|
// check where
|
|
120
123
|
if (Object.prototype.hasOwnProperty.call(params.where, fullName)) return;
|
|
121
|
-
//
|
|
122
|
-
const
|
|
124
|
+
// filter transform
|
|
125
|
+
const [transformName, transformOptions] = openapi?.filter?.transform ?? ['a-web:base', undefined];
|
|
126
|
+
const transformOptions2 = this.bean.onion.filterTransform.getOnionOptionsDynamic(transformName, transformOptions);
|
|
127
|
+
// execute
|
|
128
|
+
const beanFullName = beanFullNameFromOnionName(transformName, 'filterTransform');
|
|
129
|
+
const beanInstance = this.bean._getBean(beanFullName);
|
|
130
|
+
if (!beanInstance) {
|
|
131
|
+
throw new Error(`filterTransform bean not found: ${beanFullName}`);
|
|
132
|
+
}
|
|
133
|
+
if (!beanInstance.where) {
|
|
134
|
+
throw new Error(`filterTransform.where not found: ${beanFullName}`);
|
|
135
|
+
}
|
|
136
|
+
const info = {
|
|
123
137
|
params,
|
|
124
138
|
query: value,
|
|
125
139
|
options,
|
|
@@ -127,82 +141,42 @@ let PipeQuery = (_dec$5 = Pipe({
|
|
|
127
141
|
fullName,
|
|
128
142
|
key,
|
|
129
143
|
value: fieldValue,
|
|
144
|
+
type: fieldSchemaInner.type,
|
|
130
145
|
schema: fieldSchema,
|
|
131
146
|
openapi
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (resTransform
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
params.joins.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (resTransform === true) return;
|
|
144
|
-
// default transform
|
|
145
|
-
let op = openapi?.query?.op;
|
|
146
|
-
if (!op) {
|
|
147
|
-
const typeName = fieldSchema.type;
|
|
148
|
-
if (typeName === 'string') {
|
|
149
|
-
op = '_includesI_';
|
|
150
|
-
} else {
|
|
151
|
-
op = '_eq_';
|
|
147
|
+
};
|
|
148
|
+
const resTransform = await beanInstance.where(info, transformOptions2);
|
|
149
|
+
if (resTransform !== undefined) {
|
|
150
|
+
// where
|
|
151
|
+
params.where[fullName] = resTransform;
|
|
152
|
+
// join
|
|
153
|
+
if (joinInfo) {
|
|
154
|
+
if (!params.joins) params.joins = [];
|
|
155
|
+
if (params.joins.findIndex(item => item[1] === joinInfo.joinTable) === -1) {
|
|
156
|
+
params.joins.push(joinInfo);
|
|
157
|
+
}
|
|
152
158
|
}
|
|
153
159
|
}
|
|
154
|
-
if (op === '_eq_') {
|
|
155
|
-
params.where[fullName] = fieldValue;
|
|
156
|
-
} else {
|
|
157
|
-
params.where[fullName] = {
|
|
158
|
-
[op]: fieldValue
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
160
|
}
|
|
162
|
-
_transformFields(params, value, options) {
|
|
161
|
+
async _transformFields(params, value, options) {
|
|
163
162
|
// loop
|
|
164
163
|
for (const key in value) {
|
|
165
|
-
this._transformField(key, value[key], params, value, options);
|
|
166
|
-
}
|
|
167
|
-
// custom transform
|
|
168
|
-
this._performTransformFn(options, {
|
|
169
|
-
params,
|
|
170
|
-
query: value,
|
|
171
|
-
options
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
_performTransformFn(options, info) {
|
|
175
|
-
if (options.transformFn) {
|
|
176
|
-
if (typeof options.transformFn === 'string') {
|
|
177
|
-
const controller = this.ctx.getControllerBean();
|
|
178
|
-
if (!controller[options.transformFn]) {
|
|
179
|
-
throw new Error(`transformFn not found: ${this.ctx.getControllerBeanFullName()}`);
|
|
180
|
-
}
|
|
181
|
-
return controller[options.transformFn](info);
|
|
182
|
-
} else {
|
|
183
|
-
return options.transformFn(this.ctx, info);
|
|
184
|
-
}
|
|
185
|
-
} else {
|
|
186
|
-
const controller = this.ctx.getControllerBean();
|
|
187
|
-
const transformFn = `${String(this.ctx.getHandlerName())}QueryTransform`;
|
|
188
|
-
if (controller[transformFn]) {
|
|
189
|
-
return controller[transformFn](info);
|
|
190
|
-
}
|
|
164
|
+
await this._transformField(key, value[key], params, value, options);
|
|
191
165
|
}
|
|
192
166
|
}
|
|
193
|
-
}) || _class$
|
|
194
|
-
const
|
|
167
|
+
}) || _class$8) || _class$8);
|
|
168
|
+
const ArgFilterPro = createArgumentPipe('a-web:filter');
|
|
195
169
|
|
|
196
|
-
var _dec$
|
|
197
|
-
let PipeValid = (_dec$
|
|
170
|
+
var _dec$7, _dec2$7, _class$7;
|
|
171
|
+
let PipeValid = (_dec$7 = Pipe({
|
|
198
172
|
// ValidatorOptions
|
|
199
173
|
disableErrorMessages: false,
|
|
200
174
|
errorHttpStatusCode: 400,
|
|
201
175
|
loose: false,
|
|
202
176
|
strict: false
|
|
203
|
-
}), _dec2$
|
|
177
|
+
}), _dec2$7 = BeanInfo({
|
|
204
178
|
module: "a-web"
|
|
205
|
-
}), _dec$
|
|
179
|
+
}), _dec$7(_class$7 = _dec2$7(_class$7 = class PipeValid extends BeanBase {
|
|
206
180
|
async transform(value, metadata, options) {
|
|
207
181
|
if (options.schema) {
|
|
208
182
|
// validateSchema
|
|
@@ -210,26 +184,56 @@ let PipeValid = (_dec$4 = Pipe({
|
|
|
210
184
|
}
|
|
211
185
|
return value;
|
|
212
186
|
}
|
|
213
|
-
}) || _class$
|
|
187
|
+
}) || _class$7) || _class$7);
|
|
214
188
|
const ArgValid = createArgumentPipe('a-web:valid');
|
|
215
189
|
|
|
190
|
+
const SymbolCacheControllerRoutes = Symbol('SymbolCacheControllerRoutes');
|
|
191
|
+
function getCacheControllerRoutes(app) {
|
|
192
|
+
if (!app.meta[SymbolCacheControllerRoutes]) app.meta[SymbolCacheControllerRoutes] = {};
|
|
193
|
+
return app.meta[SymbolCacheControllerRoutes];
|
|
194
|
+
}
|
|
195
|
+
|
|
216
196
|
async function middlewareGuard(ctx, next) {
|
|
217
197
|
// check handler
|
|
218
198
|
const handler = ctx.getHandler();
|
|
219
199
|
if (!handler) return next();
|
|
220
200
|
// compose
|
|
221
|
-
const result = await ctx.app.
|
|
201
|
+
const result = await _composeGuards(ctx.app, ctx.route)(ctx);
|
|
222
202
|
if (result === false) ctx.app.throw(403);
|
|
223
203
|
// next
|
|
224
204
|
return next();
|
|
225
205
|
}
|
|
206
|
+
function _composeGuards(app, route) {
|
|
207
|
+
// compose
|
|
208
|
+
if (!app.meta[SymbolCacheComposeGuards]) app.meta[SymbolCacheComposeGuards] = {};
|
|
209
|
+
const cacheComposeGuards = app.meta[SymbolCacheComposeGuards];
|
|
210
|
+
const beanFullName = route.controllerBeanFullName;
|
|
211
|
+
const handlerName = route.action;
|
|
212
|
+
const key = `${beanFullName}:${handlerName}`;
|
|
213
|
+
if (!cacheComposeGuards[key]) {
|
|
214
|
+
cacheComposeGuards[key] = app.bean.onion.guard.compose(route);
|
|
215
|
+
}
|
|
216
|
+
return cacheComposeGuards[key];
|
|
217
|
+
}
|
|
226
218
|
|
|
227
219
|
async function middlewareInterceptor(ctx, next) {
|
|
228
220
|
// check handler
|
|
229
221
|
const handler = ctx.getHandler();
|
|
230
222
|
if (!handler) return next();
|
|
231
223
|
// compose
|
|
232
|
-
return await ctx.app.
|
|
224
|
+
return await _composeInterceptors(ctx.app, ctx.route)(ctx, next);
|
|
225
|
+
}
|
|
226
|
+
function _composeInterceptors(app, route) {
|
|
227
|
+
// compose
|
|
228
|
+
if (!app.meta[SymbolCacheComposeInterceptors]) app.meta[SymbolCacheComposeInterceptors] = {};
|
|
229
|
+
const cacheComposeInterceptors = app.meta[SymbolCacheComposeInterceptors];
|
|
230
|
+
const beanFullName = route.controllerBeanFullName;
|
|
231
|
+
const handlerName = route.action;
|
|
232
|
+
const key = `${beanFullName}:${handlerName}`;
|
|
233
|
+
if (!cacheComposeInterceptors[key]) {
|
|
234
|
+
cacheComposeInterceptors[key] = app.bean.onion.interceptor.compose(route);
|
|
235
|
+
}
|
|
236
|
+
return cacheComposeInterceptors[key];
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
function extractValue(ctx, argMeta) {
|
|
@@ -282,16 +286,16 @@ async function middlewarePipe(ctx, next) {
|
|
|
282
286
|
const handler = ctx.getHandler();
|
|
283
287
|
if (!handler) return next();
|
|
284
288
|
// arguments
|
|
285
|
-
ctx[SymbolRouteHandlersArgumentsValue] = await _transformArguments(ctx, ctx.
|
|
289
|
+
ctx[SymbolRouteHandlersArgumentsValue] = await _transformArguments(ctx.app, ctx.route);
|
|
286
290
|
// next
|
|
287
291
|
return next();
|
|
288
292
|
}
|
|
289
|
-
async function _transformArguments(
|
|
290
|
-
const paramtypes = appMetadata.getMetadata('design:paramtypes', controller.prototype,
|
|
293
|
+
async function _transformArguments(app, route) {
|
|
294
|
+
const paramtypes = appMetadata.getMetadata('design:paramtypes', route.controller.prototype, route.action);
|
|
291
295
|
if (!paramtypes) return;
|
|
292
296
|
|
|
293
297
|
// meta
|
|
294
|
-
const argsMeta = appMetadata.getMetadata(SymbolRouteHandlersArgumentsMeta, controller.prototype,
|
|
298
|
+
const argsMeta = appMetadata.getMetadata(SymbolRouteHandlersArgumentsMeta, route.controller.prototype, route.action);
|
|
295
299
|
if (!argsMeta) return;
|
|
296
300
|
|
|
297
301
|
// args
|
|
@@ -302,24 +306,24 @@ async function _transformArguments(ctx, controller, handler) {
|
|
|
302
306
|
const argMeta = argsMeta.find(item => item?.index === index);
|
|
303
307
|
if (!argMeta) continue;
|
|
304
308
|
// extractValue
|
|
305
|
-
const value = await _extractArgumentValue(ctx, argMeta);
|
|
309
|
+
const value = await _extractArgumentValue(app.ctx, argMeta);
|
|
306
310
|
// metadata
|
|
307
311
|
const metadata = {
|
|
308
312
|
type: argMeta.type,
|
|
309
313
|
field: argMeta.field,
|
|
310
314
|
metaType: paramtypes[index],
|
|
311
|
-
controller,
|
|
312
|
-
method:
|
|
315
|
+
controller: route.controller,
|
|
316
|
+
method: route.action,
|
|
313
317
|
index: argMeta.index
|
|
314
318
|
};
|
|
315
319
|
// transform
|
|
316
|
-
args[index] = await _transformArgument(
|
|
320
|
+
args[index] = await _transformArgument(app, route, argMeta, metadata, value);
|
|
317
321
|
}
|
|
318
322
|
return args;
|
|
319
323
|
}
|
|
320
|
-
async function _transformArgument(
|
|
324
|
+
async function _transformArgument(app, route, argMeta, metadata, value) {
|
|
321
325
|
// pipes
|
|
322
|
-
const pipes = composePipes(
|
|
326
|
+
const pipes = composePipes(app, route, argMeta, (beanInstance, value, options, _next) => {
|
|
323
327
|
if (!isNil(options.argIndex) && argMeta.index !== options.argIndex) return value;
|
|
324
328
|
return beanInstance.transform(value, metadata, options);
|
|
325
329
|
});
|
|
@@ -339,22 +343,21 @@ async function _extractArgumentValue(ctx, argMeta) {
|
|
|
339
343
|
}
|
|
340
344
|
return extractValue(ctx, argMeta);
|
|
341
345
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
const
|
|
348
|
-
const handlerName = ctx.getHandler().name;
|
|
346
|
+
function composePipes(app, route, argMeta, executeCustom) {
|
|
347
|
+
if (!app.meta[SymbolCacheComposePipes]) app.meta[SymbolCacheComposePipes] = {};
|
|
348
|
+
const cacheComposePipes = app.meta[SymbolCacheComposePipes];
|
|
349
|
+
const onionPipe = app.bean.onion.pipe;
|
|
350
|
+
const beanFullName = route.controllerBeanFullName;
|
|
351
|
+
const handlerName = route.action;
|
|
349
352
|
const key = `${beanFullName}:${handlerName}:${argMeta.index}`;
|
|
350
|
-
if (!
|
|
353
|
+
if (!cacheComposePipes[key]) {
|
|
351
354
|
const middlewares = [];
|
|
352
355
|
// pipes: global
|
|
353
356
|
for (const item of onionPipe.onionsGlobal) {
|
|
354
357
|
middlewares.push(onionPipe._wrapOnion(item, executeCustom));
|
|
355
358
|
}
|
|
356
359
|
// pipes: route
|
|
357
|
-
const middlewaresLocal = onionPipe._collectOnionsHandler(
|
|
360
|
+
const middlewaresLocal = onionPipe._collectOnionsHandler(route);
|
|
358
361
|
for (const item of middlewaresLocal) {
|
|
359
362
|
middlewares.push(onionPipe._wrapOnion(item, executeCustom));
|
|
360
363
|
}
|
|
@@ -365,9 +368,9 @@ function composePipes(ctx, argMeta, executeCustom) {
|
|
|
365
368
|
middlewares.push(onionPipe._wrapOnion(item, executeCustom));
|
|
366
369
|
}
|
|
367
370
|
}
|
|
368
|
-
|
|
371
|
+
cacheComposePipes[key] = middlewares;
|
|
369
372
|
}
|
|
370
|
-
return
|
|
373
|
+
return cacheComposePipes[key];
|
|
371
374
|
}
|
|
372
375
|
function _collectArgumentMiddlewares(onionPipe, argMeta) {
|
|
373
376
|
if (!argMeta.pipes) return;
|
|
@@ -399,17 +402,28 @@ const SymbolRequestMappingHandler = Symbol('SymbolRequestMappingHandler');
|
|
|
399
402
|
// HEAD = 'head',
|
|
400
403
|
// }
|
|
401
404
|
|
|
402
|
-
var _dec$
|
|
403
|
-
|
|
404
|
-
let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
405
|
+
var _dec$6, _dec2$6, _class$6;
|
|
406
|
+
let BeanRouter = (_dec$6 = Bean(), _dec2$6 = BeanInfo({
|
|
405
407
|
module: "a-web"
|
|
406
|
-
}), _dec$
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
408
|
+
}), _dec$6(_class$6 = _dec2$6(_class$6 = class BeanRouter extends BeanBase {
|
|
409
|
+
reRegisterController(beanFullName) {
|
|
410
|
+
const app = this.app;
|
|
411
|
+
// remove
|
|
412
|
+
const cacheControllerRoutes = getCacheControllerRoutes(this.app);
|
|
413
|
+
const routes = cacheControllerRoutes[beanFullName];
|
|
414
|
+
if (!routes) return;
|
|
415
|
+
delete cacheControllerRoutes[beanFullName];
|
|
416
|
+
for (const route of routes) {
|
|
417
|
+
app.router.off(route.routeMethod.toUpperCase(), route.routePath);
|
|
418
|
+
}
|
|
419
|
+
// register
|
|
420
|
+
this.registerController(beanFullName);
|
|
421
|
+
}
|
|
422
|
+
registerController(beanFullName) {
|
|
410
423
|
// controller options
|
|
411
|
-
const beanOptions = appResource.getBean(
|
|
424
|
+
const beanOptions = appResource.getBean(beanFullName);
|
|
412
425
|
if (!beanOptions) return;
|
|
426
|
+
const controller = beanOptions.beanClass;
|
|
413
427
|
const controllerBeanFullName = beanOptions.beanFullName;
|
|
414
428
|
const controllerOptions = beanOptions.options;
|
|
415
429
|
const controllerPath = controllerOptions.path;
|
|
@@ -420,7 +434,7 @@ let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
|
420
434
|
const desc = descs[actionKey];
|
|
421
435
|
if (['constructor'].includes(actionKey)) continue;
|
|
422
436
|
if (!desc.value || typeof desc.value !== 'function') continue;
|
|
423
|
-
this._registerControllerAction(
|
|
437
|
+
this._registerControllerAction(beanOptions.module, controller, controllerBeanFullName, controllerPath, controllerMiddlewaresOptions, actionKey, desc);
|
|
424
438
|
}
|
|
425
439
|
}
|
|
426
440
|
register(method, moduleName, path, simplify, fn) {
|
|
@@ -438,7 +452,7 @@ let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
|
438
452
|
const _path = app.util.combineApiPath(path, moduleName, true, simplify);
|
|
439
453
|
return app.router.findRoute(method, _path);
|
|
440
454
|
}
|
|
441
|
-
_registerControllerAction(
|
|
455
|
+
_registerControllerAction(moduleName, controller, controllerBeanFullName, controllerPath, controllerMiddlewaresOptions, actionKey, desc) {
|
|
442
456
|
// app
|
|
443
457
|
const app = this.app;
|
|
444
458
|
|
|
@@ -448,8 +462,8 @@ let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
|
448
462
|
const actionPath = handlerMetadata.path || '';
|
|
449
463
|
const actionMethod = handlerMetadata.method || 'get';
|
|
450
464
|
// routePath
|
|
451
|
-
const routePath = app.util.combineApiPathControllerAndAction(
|
|
452
|
-
const routePathRaw = app.util.combineApiPathControllerAndActionRaw(
|
|
465
|
+
const routePath = app.util.combineApiPathControllerAndAction(moduleName, controllerPath, actionPath, true, true);
|
|
466
|
+
const routePathRaw = app.util.combineApiPathControllerAndActionRaw(moduleName, controllerPath, actionPath, true);
|
|
453
467
|
|
|
454
468
|
// middlewares options
|
|
455
469
|
const actionMiddlewaresOptions = appMetadata.getMetadata(SymbolUseOnionOptions, controller.prototype, actionKey);
|
|
@@ -461,8 +475,6 @@ let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
|
461
475
|
|
|
462
476
|
// route
|
|
463
477
|
const _route = {
|
|
464
|
-
pid: info.pid,
|
|
465
|
-
module: info.name,
|
|
466
478
|
controller,
|
|
467
479
|
actionDescriptor: desc,
|
|
468
480
|
controllerBeanFullName,
|
|
@@ -474,22 +486,33 @@ let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
|
474
486
|
};
|
|
475
487
|
|
|
476
488
|
// fn
|
|
477
|
-
const self = this;
|
|
478
489
|
const fn = function (_req, _res, params, _store, searchParams) {
|
|
479
490
|
const ctx = this;
|
|
480
491
|
ctx.route = _route;
|
|
481
492
|
ctx.request.params = params;
|
|
482
493
|
ctx.request.query = searchParams;
|
|
483
|
-
|
|
484
|
-
_route[SymbolRouteComposeMiddlewaresCache] = self._registerComposeMiddlewares(ctx);
|
|
485
|
-
}
|
|
486
|
-
return _route[SymbolRouteComposeMiddlewaresCache](ctx);
|
|
494
|
+
return _composeMiddlewares(this.app, _route)(ctx);
|
|
487
495
|
};
|
|
488
496
|
|
|
497
|
+
// add
|
|
498
|
+
const cacheControllerRoutes = getCacheControllerRoutes(this.app);
|
|
499
|
+
if (!cacheControllerRoutes[controllerBeanFullName]) {
|
|
500
|
+
cacheControllerRoutes[controllerBeanFullName] = [];
|
|
501
|
+
}
|
|
502
|
+
cacheControllerRoutes[controllerBeanFullName].push(_route);
|
|
503
|
+
|
|
489
504
|
// register
|
|
490
|
-
app.router.on(_route.routeMethod.toUpperCase(), _route.routePath
|
|
505
|
+
app.router.on(_route.routeMethod.toUpperCase(), _route.routePath, fn);
|
|
491
506
|
}
|
|
492
|
-
|
|
507
|
+
}) || _class$6) || _class$6);
|
|
508
|
+
function _composeMiddlewares(app, route) {
|
|
509
|
+
// compose
|
|
510
|
+
if (!app.meta[SymbolCacheComposeMiddlewares]) app.meta[SymbolCacheComposeMiddlewares] = {};
|
|
511
|
+
const cacheComposeMiddlewares = app.meta[SymbolCacheComposeMiddlewares];
|
|
512
|
+
const beanFullName = route.controllerBeanFullName;
|
|
513
|
+
const handlerName = route.action;
|
|
514
|
+
const key = `${beanFullName}:${handlerName}`;
|
|
515
|
+
if (!cacheComposeMiddlewares[key]) {
|
|
493
516
|
// start
|
|
494
517
|
const fnStart = routeStartMiddleware;
|
|
495
518
|
// mid: guard/interceptor/pipes/tail
|
|
@@ -500,10 +523,10 @@ let BeanRouter = (_dec$3 = Bean(), _dec2$3 = BeanInfo({
|
|
|
500
523
|
fnMid.push(routeTailDoneMiddleware);
|
|
501
524
|
// end: controller
|
|
502
525
|
const fnEnd = classControllerMiddleware;
|
|
503
|
-
|
|
504
|
-
return this.app.bean.onion.middleware.compose(ctx, fnStart, fnMid, fnEnd);
|
|
526
|
+
cacheComposeMiddlewares[key] = app.bean.onion.middleware.compose(route, fnStart, fnMid, fnEnd);
|
|
505
527
|
}
|
|
506
|
-
|
|
528
|
+
return cacheComposeMiddlewares[key];
|
|
529
|
+
}
|
|
507
530
|
function classControllerMiddleware(ctx) {
|
|
508
531
|
const handlerName = ctx.getHandlerName();
|
|
509
532
|
const controller = ctx.getControllerBean();
|
|
@@ -526,61 +549,10 @@ async function routeTailDoneMiddleware(ctx, next) {
|
|
|
526
549
|
return res;
|
|
527
550
|
}
|
|
528
551
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
// const app = this.app;
|
|
532
|
-
// // args
|
|
533
|
-
// let args: any[] = [];
|
|
534
|
-
// // middlewares: start
|
|
535
|
-
// const fnStart = async (ctx: VonaContext, next: Next) => {
|
|
536
|
-
// // route
|
|
537
|
-
// ctx.route = route;
|
|
538
|
-
// // next
|
|
539
|
-
// const res = await next();
|
|
540
|
-
// // invoke callbackes: handle secondly
|
|
541
|
-
// await ctx.commitsDone();
|
|
542
|
-
// // ok
|
|
543
|
-
// return res;
|
|
544
|
-
// };
|
|
545
|
-
// fnStart._name = 'start';
|
|
546
|
-
// args.push(fnStart);
|
|
547
|
-
|
|
548
|
-
// // middlewares: globals
|
|
549
|
-
// args.push(...app.bean.onion.middleware.composedOnionsGlobal);
|
|
550
|
-
// // middlewares: guard/interceptor/pipes
|
|
551
|
-
// args.push(middlewareGuard);
|
|
552
|
-
// args.push(middlewareInterceptor);
|
|
553
|
-
// args.push(middlewarePipe);
|
|
554
|
-
|
|
555
|
-
// // middlewares: tailDone
|
|
556
|
-
// const fnTailDone = async (ctx, next) => {
|
|
557
|
-
// // next
|
|
558
|
-
// const res = await next();
|
|
559
|
-
// // invoke callbackes: handle firstly
|
|
560
|
-
// await ctx.commitsDone();
|
|
561
|
-
// // ok
|
|
562
|
-
// return res;
|
|
563
|
-
// };
|
|
564
|
-
// fnTailDone._name = 'tailDone';
|
|
565
|
-
// args.push(fnTailDone);
|
|
566
|
-
|
|
567
|
-
// // middlewares
|
|
568
|
-
// if (middlewaresLocal.length > 0) {
|
|
569
|
-
// args = args.concat(middlewaresLocal);
|
|
570
|
-
// }
|
|
571
|
-
|
|
572
|
-
// // load
|
|
573
|
-
// if (route.routeName) {
|
|
574
|
-
// app.router[route.routeMethod](route.routeName, route.routePath, ...args);
|
|
575
|
-
// } else {
|
|
576
|
-
// app.router[route.routeMethod](route.routePath, ...args);
|
|
577
|
-
// }
|
|
578
|
-
// }
|
|
579
|
-
|
|
580
|
-
var _dec$2, _dec2$2, _class$2;
|
|
581
|
-
let ServiceWeb = (_dec$2 = Service(), _dec2$2 = BeanInfo({
|
|
552
|
+
var _dec$5, _dec2$5, _class$5;
|
|
553
|
+
let ServiceWeb = (_dec$5 = Service(), _dec2$5 = BeanInfo({
|
|
582
554
|
module: "a-web"
|
|
583
|
-
}), _dec$
|
|
555
|
+
}), _dec$5(_class$5 = _dec2$5(_class$5 = class ServiceWeb extends BeanBase {
|
|
584
556
|
combineControllerActionApiPath(controller, actionKey, prefix, simplify) {
|
|
585
557
|
// beanOptions
|
|
586
558
|
const beanOptions = appResource.getBean(controller);
|
|
@@ -594,14 +566,14 @@ let ServiceWeb = (_dec$2 = Service(), _dec2$2 = BeanInfo({
|
|
|
594
566
|
// combine
|
|
595
567
|
return this.app.util.combineApiPathControllerAndAction(beanOptions.module, controllerPath, actionPath, prefix, simplify);
|
|
596
568
|
}
|
|
597
|
-
}) || _class$
|
|
569
|
+
}) || _class$5) || _class$5);
|
|
598
570
|
|
|
599
|
-
var _dec$
|
|
600
|
-
let StartupListen = (_dec$
|
|
571
|
+
var _dec$4, _dec2$4, _class$4;
|
|
572
|
+
let StartupListen = (_dec$4 = Startup({
|
|
601
573
|
after: true
|
|
602
|
-
}), _dec2$
|
|
574
|
+
}), _dec2$4 = BeanInfo({
|
|
603
575
|
module: "a-web"
|
|
604
|
-
}), _dec$
|
|
576
|
+
}), _dec$4(_class$4 = _dec2$4(_class$4 = class StartupListen extends BeanBase {
|
|
605
577
|
async execute() {
|
|
606
578
|
if (!this.app.config.server.listen.disable) {
|
|
607
579
|
this.app.server = this._listen(this.app.config.server.listen.port, this.app.config.server.listen.hostname);
|
|
@@ -627,6 +599,83 @@ let StartupListen = (_dec$1 = Startup({
|
|
|
627
599
|
}); // not set instanceName
|
|
628
600
|
};
|
|
629
601
|
}
|
|
602
|
+
}) || _class$4) || _class$4);
|
|
603
|
+
|
|
604
|
+
function FilterTransform(options) {
|
|
605
|
+
return createBeanDecorator('filterTransform', options);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
var _dec$3, _dec2$3, _class$3;
|
|
609
|
+
let FilterTransformBase = (_dec$3 = FilterTransform(), _dec2$3 = BeanInfo({
|
|
610
|
+
module: "a-web"
|
|
611
|
+
}), _dec$3(_class$3 = _dec2$3(_class$3 = class FilterTransformBase extends BeanBase {
|
|
612
|
+
async where(info, _options) {
|
|
613
|
+
const {
|
|
614
|
+
value,
|
|
615
|
+
type,
|
|
616
|
+
openapi
|
|
617
|
+
} = info;
|
|
618
|
+
let op = openapi?.filter?.op;
|
|
619
|
+
if (!op) {
|
|
620
|
+
if (type === 'string') {
|
|
621
|
+
op = '_includesI_';
|
|
622
|
+
} else {
|
|
623
|
+
op = '_eq_';
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
let where;
|
|
627
|
+
if (op === '_eq_') {
|
|
628
|
+
where = value;
|
|
629
|
+
} else {
|
|
630
|
+
where = {
|
|
631
|
+
[op]: value
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
return where;
|
|
635
|
+
}
|
|
636
|
+
}) || _class$3) || _class$3);
|
|
637
|
+
|
|
638
|
+
var _dec$2, _dec2$2, _class$2;
|
|
639
|
+
let FilterTransformDateRange = (_dec$2 = FilterTransform({
|
|
640
|
+
separator: '~'
|
|
641
|
+
}), _dec2$2 = BeanInfo({
|
|
642
|
+
module: "a-web"
|
|
643
|
+
}), _dec$2(_class$2 = _dec2$2(_class$2 = class FilterTransformDateRange extends BeanBase {
|
|
644
|
+
async where(info, options) {
|
|
645
|
+
const {
|
|
646
|
+
value
|
|
647
|
+
} = info;
|
|
648
|
+
const [dateStartStr, dateEndStr] = value.split(options.separator);
|
|
649
|
+
if (!dateStartStr && !dateEndStr) return;
|
|
650
|
+
//
|
|
651
|
+
const where = {};
|
|
652
|
+
if (dateStartStr) {
|
|
653
|
+
const dateStart = DateTime.fromISO(dateStartStr, {
|
|
654
|
+
zone: this.ctx.tz
|
|
655
|
+
});
|
|
656
|
+
where._gte_ = dateStart.toJSDate();
|
|
657
|
+
}
|
|
658
|
+
if (dateEndStr) {
|
|
659
|
+
const dateEnd = DateTime.fromISO(dateEndStr, {
|
|
660
|
+
zone: this.ctx.tz
|
|
661
|
+
}).plus({
|
|
662
|
+
day: 1
|
|
663
|
+
});
|
|
664
|
+
where._lt_ = dateEnd.toJSDate();
|
|
665
|
+
}
|
|
666
|
+
return where;
|
|
667
|
+
}
|
|
668
|
+
}) || _class$2) || _class$2);
|
|
669
|
+
|
|
670
|
+
var _dec$1, _dec2$1, _class$1;
|
|
671
|
+
let HmrController = (_dec$1 = Hmr(), _dec2$1 = BeanInfo({
|
|
672
|
+
module: "a-web"
|
|
673
|
+
}), _dec$1(_class$1 = _dec2$1(_class$1 = class HmrController extends BeanBase {
|
|
674
|
+
async reload(beanOptions) {
|
|
675
|
+
clearCacheComposesRouter(this.app);
|
|
676
|
+
this.bean.router.reRegisterController(beanOptions.beanFullName);
|
|
677
|
+
await this.$scope.openapi.service.openapi.clearAllCaches();
|
|
678
|
+
}
|
|
630
679
|
}) || _class$1) || _class$1);
|
|
631
680
|
|
|
632
681
|
function config(_app) {
|
|
@@ -660,36 +709,18 @@ class Main extends BeanSimple {
|
|
|
660
709
|
}
|
|
661
710
|
});
|
|
662
711
|
// register controllers
|
|
663
|
-
for (const controller of this.bean.onion.controller.
|
|
664
|
-
this.bean.router.registerController(controller.beanOptions.
|
|
712
|
+
for (const controller of this.bean.onion.controller.getOnionsEnabledCached()) {
|
|
713
|
+
this.bean.router.registerController(controller.beanOptions.beanFullName);
|
|
665
714
|
}
|
|
666
715
|
// middleware: system
|
|
667
|
-
|
|
668
|
-
return this.
|
|
716
|
+
this.app.use((ctx, next) => {
|
|
717
|
+
return _composeMiddlewareSystems(this.app)(ctx, next);
|
|
669
718
|
});
|
|
670
|
-
this.app.use(compose(middlewares));
|
|
671
719
|
// middleware: router
|
|
672
720
|
this.app[SymbolRouterMiddleware] = routerMiddleware(this[SymbolRouter]);
|
|
673
721
|
this.app.use(this.app[SymbolRouterMiddleware]);
|
|
674
722
|
}
|
|
675
723
|
async configLoaded(_config) {}
|
|
676
|
-
_wrapOnion(item) {
|
|
677
|
-
const fn = (_ctx, next) => {
|
|
678
|
-
const options = item.beanOptions.options;
|
|
679
|
-
if (!this.bean.onion.checkOnionOptionsEnabled(options, this.ctx.path)) {
|
|
680
|
-
return next();
|
|
681
|
-
}
|
|
682
|
-
// execute
|
|
683
|
-
const beanFullName = item.beanOptions.beanFullName;
|
|
684
|
-
const beanInstance = this.app.bean._getBean(beanFullName);
|
|
685
|
-
if (!beanInstance) {
|
|
686
|
-
throw new Error(`middlewareSystem bean not found: ${beanFullName}`);
|
|
687
|
-
}
|
|
688
|
-
return beanInstance.execute(options, next);
|
|
689
|
-
};
|
|
690
|
-
fn._name = item.name;
|
|
691
|
-
return fn;
|
|
692
|
-
}
|
|
693
724
|
}
|
|
694
725
|
function routerMiddleware(router) {
|
|
695
726
|
return function (ctx) {
|
|
@@ -701,6 +732,33 @@ function routerMiddleware(router) {
|
|
|
701
732
|
});
|
|
702
733
|
};
|
|
703
734
|
}
|
|
735
|
+
function _composeMiddlewareSystems(app) {
|
|
736
|
+
// compose
|
|
737
|
+
if (!app.meta[SymbolCacheComposeMiddlewareSystems]) {
|
|
738
|
+
const middlewares = app.bean.onion.middlewareSystem.getOnionsEnabledWrapped(item => {
|
|
739
|
+
return _wrapOnion(app, item);
|
|
740
|
+
});
|
|
741
|
+
app.meta[SymbolCacheComposeMiddlewareSystems] = compose(middlewares);
|
|
742
|
+
}
|
|
743
|
+
return app.meta[SymbolCacheComposeMiddlewareSystems];
|
|
744
|
+
}
|
|
745
|
+
function _wrapOnion(app, item) {
|
|
746
|
+
const fn = (_ctx, next) => {
|
|
747
|
+
const options = item.beanOptions.options;
|
|
748
|
+
if (!app.bean.onion.checkOnionOptionsEnabled(options, app.ctx.path)) {
|
|
749
|
+
return next();
|
|
750
|
+
}
|
|
751
|
+
// execute
|
|
752
|
+
const beanFullName = item.beanOptions.beanFullName;
|
|
753
|
+
const beanInstance = app.bean._getBean(beanFullName);
|
|
754
|
+
if (!beanInstance) {
|
|
755
|
+
throw new Error(`middlewareSystem bean not found: ${beanFullName}`);
|
|
756
|
+
}
|
|
757
|
+
return beanInstance.execute(options, next);
|
|
758
|
+
};
|
|
759
|
+
fn._name = item.name;
|
|
760
|
+
return fn;
|
|
761
|
+
}
|
|
704
762
|
|
|
705
763
|
var _dec, _dec2, _class;
|
|
706
764
|
let ScopeModuleAWeb = (_dec = Scope(), _dec2 = BeanInfo({
|
|
@@ -766,13 +824,12 @@ function File(property, ...schemaLikes) {
|
|
|
766
824
|
function User(...schemaLikes) {
|
|
767
825
|
return createPipesArgumentDecorator('user')(undefined, ...schemaLikes);
|
|
768
826
|
}
|
|
769
|
-
function
|
|
827
|
+
function ArgFilter(schemaLike) {
|
|
770
828
|
return function (target, prop, index) {
|
|
771
829
|
const schema = $schema(schemaLike);
|
|
772
|
-
setArgumentPipe('a-web:
|
|
830
|
+
setArgumentPipe('a-web:filter', {
|
|
773
831
|
type: 'query',
|
|
774
|
-
schema
|
|
775
|
-
transformFn
|
|
832
|
+
schema
|
|
776
833
|
}, target, prop, index);
|
|
777
834
|
};
|
|
778
835
|
}
|
|
@@ -786,7 +843,7 @@ const Arg = {
|
|
|
786
843
|
files: Files,
|
|
787
844
|
file: File,
|
|
788
845
|
user: User,
|
|
789
|
-
|
|
846
|
+
filter: ArgFilter
|
|
790
847
|
};
|
|
791
848
|
|
|
792
849
|
function Controller(path, options) {
|
|
@@ -879,11 +936,4 @@ const Web = {
|
|
|
879
936
|
head: Head
|
|
880
937
|
};
|
|
881
938
|
|
|
882
|
-
|
|
883
|
-
return path;
|
|
884
|
-
}
|
|
885
|
-
function $apiPathAndCombineParamsAndQuery(path, options) {
|
|
886
|
-
return combineParamsAndQuery(path, options);
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
export { $apiPath, $apiPathAndCombineParamsAndQuery, Arg, ArgQueryPro$1 as ArgQueryPro, ArgValid, BeanRouter, Controller, Dto, Main, PipeQuery, PipeValid, RequestMapping, ScopeModuleAWeb, ServiceWeb, StartupListen, SymbolRequestMappingHandler, Web, config, createPipesArgumentDecorator, mergeActionsOpenapiMetadata };
|
|
939
|
+
export { Arg, ArgFilterPro, ArgValid, BeanRouter, Controller, Dto, FilterTransform, FilterTransformBase, FilterTransformDateRange, HmrController, Main, PipeFilter, PipeValid, RequestMapping, ScopeModuleAWeb, ServiceWeb, StartupListen, SymbolCacheControllerRoutes, SymbolRequestMappingHandler, Web, config, createPipesArgumentDecorator, getCacheControllerRoutes, mergeActionsOpenapiMetadata };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { VonaApplication } from 'vona';
|
|
2
|
+
import type { ContextRoute } from '../types/router.ts';
|
|
3
|
+
export declare const SymbolCacheControllerRoutes: unique symbol;
|
|
4
|
+
export declare function getCacheControllerRoutes(app: VonaApplication): Record<string, ContextRoute[]>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Constructable } from 'vona';
|
|
2
2
|
import type { SchemaLike } from 'vona-module-a-openapiutils';
|
|
3
3
|
import type z from 'zod';
|
|
4
|
-
import type { TypePipeOptionsQueryTransform } from '../../bean/pipe.query.ts';
|
|
5
4
|
declare function Param(): ParameterDecorator;
|
|
6
5
|
declare function Param(...schemaLikes: SchemaLike[]): ParameterDecorator;
|
|
7
6
|
declare function Param(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
|
|
@@ -27,7 +26,7 @@ declare function File(): ParameterDecorator;
|
|
|
27
26
|
declare function File(...schemaLikes: SchemaLike[]): ParameterDecorator;
|
|
28
27
|
declare function File(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
|
|
29
28
|
declare function User(...schemaLikes: SchemaLike[]): ParameterDecorator;
|
|
30
|
-
declare function
|
|
29
|
+
declare function ArgFilter(schemaLike: z.ZodType | Constructable): any;
|
|
31
30
|
export declare const Arg: {
|
|
32
31
|
param: typeof Param;
|
|
33
32
|
query: typeof Query;
|
|
@@ -38,6 +37,6 @@ export declare const Arg: {
|
|
|
38
37
|
files: typeof Files;
|
|
39
38
|
file: typeof File;
|
|
40
39
|
user: typeof User;
|
|
41
|
-
|
|
40
|
+
filter: typeof ArgFilter;
|
|
42
41
|
};
|
|
43
42
|
export {};
|
package/dist/lib/index.d.ts
CHANGED
package/dist/main.d.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IModelSelectParamsJoinType, ITableRecord, TypeOpsNormal } from 'vona-module-a-orm';
|
|
2
|
+
import type { IDecoratorFilterTransformOptions, IFilterTransformRecord } from './filterTransform.ts';
|
|
3
|
+
export interface ISchemaObjectExtensionFieldFilterJoin {
|
|
4
|
+
type?: IModelSelectParamsJoinType;
|
|
5
|
+
table: keyof ITableRecord;
|
|
6
|
+
on: [string, string];
|
|
7
|
+
}
|
|
8
|
+
export interface ISchemaObjectExtensionFieldFilterCapabilities {
|
|
9
|
+
where?: boolean;
|
|
10
|
+
order?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type TypeSchemaObjectExtensionFieldFilterTransform = [keyof IFilterTransformRecord, IDecoratorFilterTransformOptions | undefined];
|
|
13
|
+
export interface ISchemaObjectExtensionFieldFilter {
|
|
14
|
+
capabilities?: ISchemaObjectExtensionFieldFilterCapabilities;
|
|
15
|
+
table?: keyof ITableRecord;
|
|
16
|
+
joinType?: IModelSelectParamsJoinType;
|
|
17
|
+
joinOn?: [string, string];
|
|
18
|
+
originalName?: string;
|
|
19
|
+
op?: TypeOpsNormal;
|
|
20
|
+
transform?: TypeSchemaObjectExtensionFieldFilterTransform;
|
|
21
|
+
}
|
|
22
|
+
declare module 'vona-module-a-openapi' {
|
|
23
|
+
interface ISchemaObjectExtensionField {
|
|
24
|
+
filter?: ISchemaObjectExtensionFieldFilter;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { OmitNever } from 'vona';
|
|
2
|
+
import type { ServiceOnion } from 'vona-module-a-onion';
|
|
3
|
+
import type { ISchemaObjectExtensionField } from 'vona-module-a-openapi';
|
|
4
|
+
import type { IQueryParams } from 'vona-module-a-orm';
|
|
5
|
+
import type z from 'zod';
|
|
6
|
+
import type { IPipeOptionsFilter } from '../bean/pipe.filter.ts';
|
|
7
|
+
export type TypeQueryParamsPatch = IQueryParams & {
|
|
8
|
+
where: {};
|
|
9
|
+
};
|
|
10
|
+
export interface IPipeOptionsFilterTransformInfo {
|
|
11
|
+
params: TypeQueryParamsPatch;
|
|
12
|
+
query: any;
|
|
13
|
+
options: IPipeOptionsFilter;
|
|
14
|
+
originalName: string;
|
|
15
|
+
fullName: string;
|
|
16
|
+
key?: string;
|
|
17
|
+
value?: any;
|
|
18
|
+
type?: string;
|
|
19
|
+
schema?: z.ZodType;
|
|
20
|
+
openapi?: ISchemaObjectExtensionField;
|
|
21
|
+
}
|
|
22
|
+
export interface IFilterTransformRecord {
|
|
23
|
+
}
|
|
24
|
+
export interface IFilterTransformWhere {
|
|
25
|
+
where(info: IPipeOptionsFilterTransformInfo, options: IDecoratorFilterTransformOptions): Promise<boolean>;
|
|
26
|
+
}
|
|
27
|
+
export interface IDecoratorFilterTransformOptions {
|
|
28
|
+
}
|
|
29
|
+
declare module 'vona-module-a-onion' {
|
|
30
|
+
interface BeanOnion {
|
|
31
|
+
filterTransform: ServiceOnion<IFilterTransformRecord>;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
declare module 'vona' {
|
|
35
|
+
interface ConfigOnions {
|
|
36
|
+
filterTransform: OmitNever<IFilterTransformRecord>;
|
|
37
|
+
}
|
|
38
|
+
interface IBeanSceneRecord {
|
|
39
|
+
filterTransform: never;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/router.d.ts
CHANGED
|
@@ -5,16 +5,14 @@ export interface ContextRouteMetadata {
|
|
|
5
5
|
meta: any;
|
|
6
6
|
}
|
|
7
7
|
export interface ContextRoute {
|
|
8
|
-
pid: string;
|
|
9
|
-
module: string;
|
|
10
8
|
controller: Constructable;
|
|
11
9
|
actionDescriptor: PropertyDescriptor;
|
|
12
10
|
controllerBeanFullName: string;
|
|
13
11
|
action: string;
|
|
14
12
|
route: ContextRouteMetadata;
|
|
15
13
|
routeMethod: TypeRequestMethod;
|
|
16
|
-
routePath: string
|
|
17
|
-
routePathRaw: string
|
|
14
|
+
routePath: string;
|
|
15
|
+
routePathRaw: string;
|
|
18
16
|
}
|
|
19
17
|
declare module 'vona' {
|
|
20
18
|
interface VonaApplication {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-module-a-web",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.32",
|
|
5
5
|
"title": "a-web",
|
|
6
6
|
"vonaModule": {
|
|
7
7
|
"capabilities": {
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
"optionsGlobalInterfaceFrom": "vona-module-a-web",
|
|
23
23
|
"boilerplate": "cli/controller/boilerplate",
|
|
24
24
|
"metadataCustom": "cli/controller/metadata/generate.ts"
|
|
25
|
+
},
|
|
26
|
+
"filterTransform": {
|
|
27
|
+
"optionsGlobalInterfaceName": "IDecoratorFilterTransformOptions",
|
|
28
|
+
"optionsGlobalInterfaceFrom": "vona-module-a-web",
|
|
29
|
+
"boilerplate": "cli/filterTransform/boilerplate"
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
},
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { VonaContext } from 'vona';
|
|
2
|
-
import type { IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, IPipeTransform } from 'vona-module-a-aspect';
|
|
3
|
-
import type { ISchemaObjectExtensionField, RouteHandlerArgumentMeta } from 'vona-module-a-openapi';
|
|
4
|
-
import type { IQueryParams } from 'vona-module-a-orm';
|
|
5
|
-
import type { ValidatorOptions } from 'vona-module-a-validation';
|
|
6
|
-
import type z from 'zod';
|
|
7
|
-
import { BeanBase } from 'vona';
|
|
8
|
-
export type TypePipeQueryData = unknown;
|
|
9
|
-
export type TypePipeQueryResult = TypePipeQueryData;
|
|
10
|
-
export interface IPipeOptionsQuery extends IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, ValidatorOptions {
|
|
11
|
-
transformFn?: TypePipeOptionsQueryTransform | string;
|
|
12
|
-
}
|
|
13
|
-
export type TypeQueryParamsPatch = IQueryParams & {
|
|
14
|
-
where: {};
|
|
15
|
-
};
|
|
16
|
-
export interface IPipeOptionsQueryTransformInfo {
|
|
17
|
-
params: TypeQueryParamsPatch;
|
|
18
|
-
query: any;
|
|
19
|
-
options: IPipeOptionsQuery;
|
|
20
|
-
originalName: string;
|
|
21
|
-
fullName: string;
|
|
22
|
-
key?: string;
|
|
23
|
-
value?: any;
|
|
24
|
-
schema?: z.ZodType;
|
|
25
|
-
openapi?: ISchemaObjectExtensionField;
|
|
26
|
-
}
|
|
27
|
-
export type TypePipeOptionsQueryTransform = (ctx: VonaContext, info: IPipeOptionsQueryTransformInfo) => boolean | undefined;
|
|
28
|
-
export declare class PipeQuery extends BeanBase implements IPipeTransform<TypePipeQueryData, TypePipeQueryResult> {
|
|
29
|
-
transform(value: TypePipeQueryData, metadata: RouteHandlerArgumentMeta, options: IPipeOptionsQuery): Promise<TypePipeQueryResult>;
|
|
30
|
-
private _transform;
|
|
31
|
-
private _transformSystem;
|
|
32
|
-
private _transformOrders;
|
|
33
|
-
private _transformField;
|
|
34
|
-
private _transformFields;
|
|
35
|
-
private _performTransformFn;
|
|
36
|
-
}
|
|
37
|
-
export declare const ArgQueryPro: (options?: Partial<IPipeOptionsQuery> | undefined) => any;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/lib/utils.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { IApiPathRecord } from '../types/controller.ts';
|
|
2
|
-
export declare function $apiPath<K extends keyof IApiPathRecord>(path: K): K;
|
|
3
|
-
export declare function $apiPathAndCombineParamsAndQuery<K extends keyof IApiPathRecord>(path: K, options?: {
|
|
4
|
-
params?: object;
|
|
5
|
-
query?: object;
|
|
6
|
-
}): string;
|