$Dto.query/DtoQueryBase 
$Dto.query/DtoQueryBase is used to annotate the Query parameters
Usage of DtoQueryBase 
1. Create DTO 
In VSCode, use the Vona Create/Dto context menu to create a DTO code skeleton:
@Dto()
export class DtoOrderQuery {}2. Inherit DtoQueryBase 
@Dto()
export class DtoOrderQuery extends DtoQueryBase {}DtoQueryBase Fields 
Since DtoOrderQuery inherits from DtoQueryBase, it has the following member fields:
| Name | Description | Example | 
|---|---|---|
| columns | List of fields to query | *, id,orderNo,remark, ["id","orderNo","remark"] | 
| where | Query clause | { "orderNo": { "_include_": "order001" } } | 
| orders | Sorting | orderNo,desc, [["orderNo", "desc"], ["createdAt", "desc"]] | 
Annotating Query Parameters 
Still taking the findAll method of the Order controller as an example, we can annotate the Query parameters:
+ import type { IQueryParams } from 'vona-module-a-orm';
+ import { Arg } from 'vona-module-a-web';
class ControllerOrder extends BeanBase {
  @Web.get('findAll')
  @Api.body(v.array(DtoOrderResult))
  async findAll(
+   @Arg.queryPro(DtoOrderQuery) params: IQueryParams<ModelOrder>,
  ): Promise<DtoOrderResult[]> {
    return this.scope.model.order.select(params);
  }
}@Arg.queryPro: This Pipe transforms the Query parameter and needs to pass in the parameterDtoOrderQueryIQueryParams: The data type obtained by Pipe transforming the Query parameter isIQueryParams, and the generic parameterModelOrderneeds to be passed in to match the parameter type of themodel.order.selectmethod
The automatically generated Swagger/Openapi is as follows:

$Dto.query 
If you need to add query clause for business fields in DTO, you can use $Dto.query
@Dto()
export class DtoOrderQuery
+ extends $Dto.query(EntityOrder, ['orderNo', 'remark']) {}$Dto.query: Automatically extract the fieldorderNo/remarkfromEntityOrderand then merge it with theDtoQueryBasemember fields
The automatically generated Swagger/Openapi is as follows:

Add custom fields 
You can also add custom fields directly in the DTO
@Dto()
export class DtoOrderQuery
+ extends $Dto.query(EntityOrder, ['remark']) {
+ @Api.field(v.optional())
+ orderNo?: string;
}- Automatically extract the field 
remarkfromEntityOrder - Add custom field 
orderNo 
Openapi parameters 
We can also specify OpenAPI parameters to support more capabilities
1. Relations 
For example, if the Model Order and Model User have an n:1 relation, we can pass userName as the query condition in the Query parameters. Then, we need to add the userName field in the DTO and set the OpenAPI parameters
@Dto()
export class DtoOrderQuery
  extends $Dto.query(EntityOrder, ['orderNo', 'remark']) {
  @Api.field(v.optional(), v.openapi({
    query: {
      table: $tableName(EntityUser),
      joinType: 'innerJoin',
      joinOn: ['userId', 'testVonaUser.id'],
      originalName: 'name',
    },
  }))
  userName?: string;
}| Name | Description | 
|---|---|
| table | Table name of relation | 
| joinType | Relation Type, default is innerJoin | 
| joinOn | Relation condition | 
| originalName | Original field name | 
The automatically generated Swagger/Openapi is as follows:

2. Orders of relations 
When querying Model Order which joins with Model User, if the fields in orders exist in both tables, you must specify the table name prefix. For example: testVonaOrder.createdAt,desc
Vona ORM has built-in relations-based orders processing logic. You only need to set the Openapi parameters in the DTO:
@Dto<IDtoOptionsOrderQuery>({
+ openapi: {
+   query: {
+     table: $tableName(EntityOrder),
+   },
+ },
})
export class DtoOrderQuery
  extends $Dto.query(EntityOrder, ['orderNo', 'remark']) {
  @Api.field(v.optional(), v.openapi({
    query: {
      table: $tableName(EntityUser),
      joinType: 'innerJoin',
      joinOn: ['userId', 'testVonaUser.id'],
      originalName: 'name',
    },
  }))
  userName?: string;
}Custom Query Transform 
For custom fields, Vona ORM provides built-in Transform rules. For example:
orderNois a string, so the system automatically converts it to the conditional statement'orderNo': { _includesI_: 'some input' }userNameis also a string, so the system automatically converts it to the conditional statement'name': { _includesI_: 'some input' }
To support more complex business needs, you can provide a custom Query Transform
1. Convention Name 
For example, we use Query in the findAll method of the Order controller. Then, we only need to provide findAllQueryTransform in the current controller
@Controller
class ControllerOrder {
+  findAllQueryTransform(_info: IPipeOptionsQueryTransformInfo): boolean | undefined {
+    return undefined;
+  }
  @Web.get('findAll')
  @Api.body(v.array(DtoOrderResult))
  async findAll(
    @Arg.queryPro(DtoOrderQuery) params: IQueryParams<ModelOrder>,
  ): Promise<DtoOrderResult[]> {
    return this.scope.model.order.select(params);
  }
}If you need to convert userName into a conditional statement 'name': 'some input', the code is as follows:
class ControllerOrder {
  findAllQueryTransform(info: IPipeOptionsQueryTransformInfo): boolean | undefined {
    if (info.key === 'userName') {
      info.params.where[info.fullName] = info.value;
      return true;
    }
    return undefined;
  }
}2. Query Transform Return Value 
Query Transform returns the following values:
| Name | Description | 
|---|---|
| true | Provides custom logic and ignores system built-in rules | 
| false | No custom logic is provided, ignoring the system's built-in rules | 
| undefined | No custom logic is provided, using the system's built-in rules | 
2. Custom Name 
We can also provide a custom name for Query Transform, such as: myCustomQueryTransform
class ControllerOrder {
+ myCustomQueryTransform(info: IPipeOptionsQueryTransformInfo): boolean | undefined {
+   if (info.key === 'userName') {
+     info.params.where[info.fullName] = info.value;
+     return true;
+   }
+   return undefined;
+ }
  @Web.get('findAll')
  @Api.body(v.array(DtoOrderResult))
  async findAll(
+   @Arg.queryPro(DtoOrderQuery, 'myCustomQueryTransform') params: IQueryParams<ModelOrder>,
  ): Promise<DtoOrderResult[]> {
    return this.scope.model.order.select(params);
  }
}@Arg.queryPro: This Pipe transforms the Query parameter, passing in the parameter'myCustomQueryTransform'
3. Custom Function 
You can also provide a custom function directly:
+ function myCustomQueryTransform(_ctx: VonaContext, info: IPipeOptionsQueryTransformInfo): boolean | undefined {
+   if (info.key === 'userName') {
+     info.params.where[info.fullName] = info.value;
+     return true;
+   }
+   return undefined;
+ }
class ControllerOrder {
  @Web.get('findAll')
  @Api.body(v.array(DtoOrderResult))
  async findAll(
+   @Arg.queryPro(DtoOrderQuery, myCustomQueryTransform) params: IQueryParams<ModelOrder>,
  ): Promise<DtoOrderResult[]> {
    return this.scope.model.order.select(params);
  }
}