最近用NestJS作为Web主力框架,积极拥抱TypeScript。奈何找不到一款类似MyBatis那样可以直接写SQL的数据库工具,而NestJS通常用的数据库工具都是一些很自定义语法的ORM框架,用着蛮别扭。不得已自己通过TS的装饰器写了一个类似MyBatis的注解工具——SpeedSQL,现分享给大家。
- 开源许可:MIT
- NPM地址:www.npmjs.com/package/spe…
- Github:github.com/SpeedPHP/sp…
特性
- 遵循NestJS的Module注入方式编写,内置mysql2库支持。
- 使用TypeScript的装饰器,类似Java的注解,Java背景的使用者会比较熟悉。
- 支持命名参数的方式,或者实体类的方式,进行绑定值。
- 支持数据转实体POJO类。
看代码,以下是使用方法(后面有详解),是不是很眼熟啊:
import { Injectable } from '@nestjs/common';
import { Delete, Update, Param, ResultType, Insert } from 'speedsql';
import { UserDto } from './entity/user.dto';
import { ParamDto } from './entity/param.dto';
@Injectable()
export class AppService {
@Update('update user set age = #{age} where name = #{name}')
setUserAge(@Param('name') name: string, @Param('age') age: number): number {return;}
@Delete('delete from user where name = #{name}')
deleteUser(@Param('name') name: string): number {return;}
@ResultType(UserDto)
@Select('select `name`, `age` from `user` where `uid` = #{uid} and `name` = #{name}')
getRecords(paramDto: ParamDto): UserDto[] {return;}
@Insert('insert into user (name, age) value (#{name}, #{age})')
addUser(user: UserDto): number {return;}
}
支持的注解(即TypeScript的装饰器)
@Param
, @ResultType
, @Select
, @Insert
, @Update
, @Delete
.
依赖安装
在你的package.json
里面加入依赖。
"dependencies": {
"speedsql": "latest"
}
NestJS内的配置和使用
1. 准备数据源和实体类
db.provider.ts
import { createPool, Pool } from 'speedsql';
export const DbProviders = [
{
provide: 'SPEED_POOL',
useFactory: async (): Promise<Pool> => {
return await createPool({
host: 'localhost',
user: 'root',
port: 3306,
password: 'qwer1234',
database: 'test',
});
},
},
];
entity/param.dto.ts
export class ParamDto {
constructor(public name: string, public age: number) {}
}
entity/user.dto.ts
export class UserDto {
constructor(public name: string, public age: number) {}
}
2. 作为Module导入到NestJS
app.mudule.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SpeedService } from 'speedsql';
import { DbProviders } from './db.provider';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, SpeedService, ...DbProviders],
})
export class AppModule {}
3. 使用(跟MyBatis类似的注释)
在你的Service类里面,使用Select,Insert,Update,Delete等注解。
app.service.ts
import { Injectable } from '@nestjs/common';
import { Delete, Update, Param, ResultType, Insert } from 'speedsql';
import { UserDto } from './entity/user.dto';
import { ParamDto } from './entity/param.dto';
@Injectable()
export class AppService {
@Update('update user set age = #{age} where name = #{name}')
setUserAge(@Param('name') name: string, @Param('age') age: number): number {return;}
@Delete('delete from user where name = #{name}')
deleteUser(@Param('name') name: string): number {return;}
@ResultType(UserDto)
@Select('select `name`, `age` from `user` where `uid` = #{uid} and `name` = #{name}')
getRecords(paramDto: ParamDto): UserDto[] {return;}
@Insert('insert into user (name, age) value (#{name}, #{age})')
addUser(user: UserDto): number {return;}
}
调用你的Service。
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { ParamDto } from './entity/param.dto';
import { UserDto } from "./entity/create-cat.dto";
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
async getHello() {
await this.appService.setUserAge("zzz", 20);
return "hello world";
}
}
参数绑定
参数绑定在@Select
, @Insert
, @Update
, @Delete
增删查改注解上都可以使用。
参数绑定有两种方式:(不能两种同时用在一个操作上面)
1. 参数实体类
我们可以通过建立一个实体类作为参数输入,这样挺面向对象的。
export class ParamDto {
constructor(public name: string, public age: number) {}
}
然后在查询上面定义实体类参数
import { ResultType, Select } from 'speedsql';
@ResultType(UserDto)
@Select('select `name`, `age` from `user` where `uid` = #{uid} and `name` = #{name}')
getRecords(paramDto: ParamDto): UserDto[]{return;}
最后是使用
const users: UserDto[] = await this.appService.getRecords(
new ParamDto("zzz", 10)
);
2. 命名参数方式
@Param
注解定义了绑定参数。
和MyBatis类似,SpeedSQL支持命名的方式绑定参数,而不像mysql2库那样只能通过问号占位符。
import { ResultType, Select, Param } from 'speedsql';
@ResultType(UserDto)
@Select(select `name`, `age` from `user` where `uid` = #{uid} and `name` = #{name}')
getRecords(@Param('uid') uid:number, @Param('name') name:string): UserDto[]{return;}
使用方式:
const users: UserDto[] = await this.appService.getRecords('zzz', 10);
增删查改
@Select
SpeedSQL使用 @ResultType
来注解查询结果数据的实体类,它会返回一个该实体类的数组。
建立实体类:
export class UserDto {
constructor(public name: string, public age: number) {}
}
然后查询
import { ResultType, Select, Param } from 'speedsql';
@ResultType(UserDto)
@Select('select `name`, `age` from user where uid = #{uid} and name = #{name} ')
getRecords(@Param('uid') uid:number, @Param('name') name:string): UserDto[] {return;}
如果返回数据的字段名与实体类的参数对应不上,那么可以通过SQL语法的AS
来修正到一直。
import { ResultType, Select, Param } from 'speedsql';
@ResultType(UserDto)
@Select('select `realname` as `name`, `age` from user where uid = #{uid} and name = #{name} ')
getRecords(@Param('uid') uid:number, @Param('name') name:string): UserDto[] {return;}
@Insert
@Insert
也支持绑定参数。
@Insert
返回一个数值,就是新增记录的ID,当然也可以忽略。
import { Insert } from 'speedsql';
@Insert('insert into user (name, age) value (#{name}, #{age})')
addUser(user: UserDto): number {return;}
@Update 和 @Delete
@Update
和 @Delete
也支持绑定参数。
它们也会返回一个数值,指代的是影响行数,可忽略。
import { Delete, Update, Param } from 'speedsql';
@Update('update user set age = #{age} where name = #{name}')
setUserAge(@Param('name') name: string, @Param('age') age: number): number {return;}
@Delete('delete from user where name = #{name}')
deleteUser(@Param('name') name: string): number {return;}
Issue
有任何问题或指教,请提Issue:github.com/SpeedPHP/sp…