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.
@@ -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.query.ts';
2
+ export * from '../bean/pipe.filter.ts';
3
3
  export * from '../bean/pipe.valid.ts';
4
- import type { IPipeOptionsQuery } from '../bean/pipe.query.ts';
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:query': IPipeOptionsQuery;
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 PipeQuery {
14
+ interface PipeFilter {
15
15
  }
16
- interface PipeQuery {
17
- get $beanFullName(): 'a-web.pipe.query';
18
- get $onionName(): 'a-web:query';
19
- get $onionOptions(): IPipeOptionsQuery;
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
- registerController(moduleName: string, controller: Constructable): void;
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, createBeanDecorator } from 'vona';
2
- import { isNil, combineParamsAndQuery } from '@cabloy/utils';
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-openapi';
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$5, _dec2$5, _class$5;
18
+ var _dec$8, _dec2$8, _class$8;
18
19
  const __FieldsSystem = ['columns', 'where', 'orders', 'pageNo', 'pageSize'];
19
- let PipeQuery = (_dec$5 = Pipe({
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$5 = BeanInfo({
26
+ }), _dec2$8 = BeanInfo({
26
27
  module: "a-web"
27
- }), _dec$5(_class$5 = _dec2$5(_class$5 = class PipeQuery extends BeanBase {
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 pipeQuery: ${metadata.controller.name}.${metadata.method}#${metadata.index}`);
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?.query?.table;
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.unwrapChained(ZodMetadata.getFieldSchema(options.schema, field));
87
+ const fieldSchema = ZodMetadata.getFieldSchema(options.schema, field);
87
88
  if (fieldSchema) {
88
89
  const openapi = ZodMetadata.getOpenapiMetadata(fieldSchema);
89
- if (openapi?.query?.table) {
90
- tableCurrent = openapi?.query?.table;
90
+ if (openapi?.filter?.table) {
91
+ tableCurrent = openapi?.filter?.table;
91
92
  }
92
- if (openapi?.query?.originalName) {
93
- fieldCurrent = openapi?.query?.originalName;
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.unwrapChained(ZodMetadata.getFieldSchema(options.schema, key));
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?.query?.originalName ?? key;
109
+ const originalName = openapi?.filter?.originalName ?? key;
107
110
  let fullName;
108
111
  // joins
109
112
  let joinInfo;
110
- if (openapi?.query?.joinOn) {
111
- const joinType = openapi.query.joinType ?? 'innerJoin';
112
- const joinTable = openapi.query.table;
113
- const joinOn = openapi.query.joinOn;
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
- // custom transform
122
- const resTransform = this._performTransformFn(options, {
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
- // res: ignore
134
- if (resTransform === false) return;
135
- // join
136
- if (joinInfo) {
137
- if (!params.joins) params.joins = [];
138
- if (params.joins.findIndex(item => item[1] === joinInfo.joinTable) === -1) {
139
- params.joins.push(joinInfo);
140
- }
141
- }
142
- // res: done
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$5) || _class$5);
194
- const ArgQueryPro$1 = createArgumentPipe('a-web:query');
167
+ }) || _class$8) || _class$8);
168
+ const ArgFilterPro = createArgumentPipe('a-web:filter');
195
169
 
196
- var _dec$4, _dec2$4, _class$4;
197
- let PipeValid = (_dec$4 = Pipe({
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$4 = BeanInfo({
177
+ }), _dec2$7 = BeanInfo({
204
178
  module: "a-web"
205
- }), _dec$4(_class$4 = _dec2$4(_class$4 = class PipeValid extends BeanBase {
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$4) || _class$4);
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.bean.onion.guard.compose(ctx)(ctx);
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.bean.onion.interceptor.compose(ctx)(ctx, next);
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.getController(), handler);
289
+ ctx[SymbolRouteHandlersArgumentsValue] = await _transformArguments(ctx.app, ctx.route);
286
290
  // next
287
291
  return next();
288
292
  }
289
- async function _transformArguments(ctx, controller, handler) {
290
- const paramtypes = appMetadata.getMetadata('design:paramtypes', controller.prototype, handler.name);
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, handler.name);
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: handler.name,
315
+ controller: route.controller,
316
+ method: route.action,
313
317
  index: argMeta.index
314
318
  };
315
319
  // transform
316
- args[index] = await _transformArgument(ctx, argMeta, metadata, value);
320
+ args[index] = await _transformArgument(app, route, argMeta, metadata, value);
317
321
  }
318
322
  return args;
319
323
  }
320
- async function _transformArgument(ctx, argMeta, metadata, value) {
324
+ async function _transformArgument(app, route, argMeta, metadata, value) {
321
325
  // pipes
322
- const pipes = composePipes(ctx, argMeta, (beanInstance, value, options, _next) => {
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
- const SymbolCacheMiddlewaresArgument = Symbol('SymbolCacheMiddlewaresArgument');
343
- function composePipes(ctx, argMeta, executeCustom) {
344
- if (!ctx.app.meta[SymbolCacheMiddlewaresArgument]) ctx.app.meta[SymbolCacheMiddlewaresArgument] = {};
345
- const __cacheMiddlewaresArgument = ctx.app.meta[SymbolCacheMiddlewaresArgument];
346
- const onionPipe = ctx.app.bean.onion.pipe;
347
- const beanFullName = ctx.getControllerBeanFullName();
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 (!__cacheMiddlewaresArgument[key]) {
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(ctx);
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
- __cacheMiddlewaresArgument[key] = middlewares;
371
+ cacheComposePipes[key] = middlewares;
369
372
  }
370
- return __cacheMiddlewaresArgument[key];
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$3, _dec2$3, _class$3;
403
- const SymbolRouteComposeMiddlewaresCache = Symbol('SymbolRouteComposeMiddlewaresCache');
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$3(_class$3 = _dec2$3(_class$3 = class BeanRouter extends BeanBase {
407
- registerController(moduleName, controller) {
408
- // info
409
- const info = ModuleInfo.parseInfo(moduleName);
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(controller);
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(info, controller, controllerBeanFullName, controllerPath, controllerMiddlewaresOptions, actionKey, desc);
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(info, controller, controllerBeanFullName, controllerPath, controllerMiddlewaresOptions, actionKey, desc) {
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(info.relativeName, controllerPath, actionPath, true, true);
452
- const routePathRaw = app.util.combineApiPathControllerAndActionRaw(info.relativeName, controllerPath, actionPath, true);
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
- if (!_route[SymbolRouteComposeMiddlewaresCache]) {
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.toString(), fn);
505
+ app.router.on(_route.routeMethod.toUpperCase(), _route.routePath, fn);
491
506
  }
492
- _registerComposeMiddlewares(ctx) {
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
- // compose
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
- }) || _class$3) || _class$3);
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
- // _registerInner(route, middlewaresLocal) {
530
- // // app
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$2(_class$2 = _dec2$2(_class$2 = class ServiceWeb extends BeanBase {
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$2) || _class$2);
569
+ }) || _class$5) || _class$5);
598
570
 
599
- var _dec$1, _dec2$1, _class$1;
600
- let StartupListen = (_dec$1 = Startup({
571
+ var _dec$4, _dec2$4, _class$4;
572
+ let StartupListen = (_dec$4 = Startup({
601
573
  after: true
602
- }), _dec2$1 = BeanInfo({
574
+ }), _dec2$4 = BeanInfo({
603
575
  module: "a-web"
604
- }), _dec$1(_class$1 = _dec2$1(_class$1 = class StartupListen extends BeanBase {
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.getOnionsEnabled()) {
664
- this.bean.router.registerController(controller.beanOptions.module, controller.beanOptions.beanClass);
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
- const middlewares = this.bean.onion.middlewareSystem.getOnionsEnabledWrapped(item => {
668
- return this._wrapOnion(item);
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 ArgQueryPro(schemaLike, transformFn) {
827
+ function ArgFilter(schemaLike) {
770
828
  return function (target, prop, index) {
771
829
  const schema = $schema(schemaLike);
772
- setArgumentPipe('a-web:query', {
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
- queryPro: ArgQueryPro
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
- function $apiPath(path) {
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 ArgQueryPro(schemaLike: z.ZodType | Constructable, transformFn?: TypePipeOptionsQueryTransform | string): any;
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
- queryPro: typeof ArgQueryPro;
40
+ filter: typeof ArgFilter;
42
41
  };
43
42
  export {};
@@ -0,0 +1,2 @@
1
+ import type { IDecoratorFilterTransformOptions } from '../../types/filterTransform.ts';
2
+ export declare function FilterTransform<T extends IDecoratorFilterTransformOptions>(options?: T): ClassDecorator;
@@ -1,5 +1,5 @@
1
1
  export * from './arguments.ts';
2
2
  export * from './bean.ts';
3
+ export * from './filterTransform.ts';
3
4
  export * from './pipesArgument.ts';
4
5
  export * from './request.ts';
5
- export * from './response.ts';
@@ -1,2 +1,2 @@
1
+ export * from './const.ts';
1
2
  export * from './decorator/index.ts';
2
- export * from './utils.ts';
package/dist/main.d.ts CHANGED
@@ -6,6 +6,5 @@ export declare class Main extends BeanSimple implements IModuleMain {
6
6
  moduleLoading(): Promise<void>;
7
7
  moduleLoaded(): Promise<void>;
8
8
  configLoaded(_config: any): Promise<void>;
9
- private _wrapOnion;
10
9
  }
11
10
  export {};
@@ -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
+ }
@@ -1,5 +1,7 @@
1
1
  export * from './controller.ts';
2
2
  export * from './dto.ts';
3
+ export * from './filter.ts';
4
+ export * from './filterTransform.ts';
3
5
  export * from './request.ts';
4
6
  export * from './response.ts';
5
7
  export * from './router.ts';
@@ -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 | RegExp;
17
- routePathRaw: string | RegExp;
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.30",
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 {};
@@ -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;