@eggjs/dal-plugin

@eggjs/dal-plugin 支持使用注解的方式来开发 egg 中的 dal。
egg 模式
Install
# tegg 注解
npm i --save @eggjs/tegg
# tegg 插件
npm i --save @eggjs/tegg-plugin
# tegg dal 插件
npm i --save @eggjs/dal-plugin
Prepare
{
"extends": "@eggjs/tsconfig"
}
Config
exports.tegg = {
package: '@eggjs/tegg-plugin',
enable: true,
};
exports.teggDal = {
package: '@eggjs/dal-plugin',
enable: true,
};
standalone 模式
Install
# tegg 注解
npm i --save @eggjs/tegg
# tegg dal 插件
npm i --save @eggjs/dal-plugin
Prepare
{
"extends": "@eggjs/tsconfig"
}
Usage
module.yml
通过 module.yml 来配置 module 中的 mysql 数据源。
dataSource:
foo:
connectionLimit: 100
database: 'test'
host: '127.0.0.1'
user: root
port: 3306
Table
TableModel 定义一个表结构,包括表配置、列、索引。
import { Table, Index, Column, ColumnType, IndexType } from '@eggjs/tegg/dal';
@Table({
comment: 'foo table',
})
@Index({
keys: ['name'],
type: IndexType.UNIQUE,
})
export class Foo {
@Column(
{
type: ColumnType.INT,
},
{
primaryKey: true,
},
)
id: number;
@Column({
type: ColumnType.VARCHAR,
length: 100,
})
name: string;
}
详细参数定义如下,具体参数值可以参考 https://dev.mysql.com/doc/refman/8.0/en/create-table.html
建表参数,使用方式为 @Table(parmas?: TableParams)
export interface TableParams {
name?: string;
dataSourceName?: string;
comment?: string;
autoExtendSize?: number;
autoIncrement?: number;
avgRowLength?: number;
characterSet?: string;
collate?: string;
compression?: CompressionType;
encryption?: boolean;
engine?: string;
engineAttribute?: string;
insertMethod?: InsertMethod;
keyBlockSize?: number;
maxRows?: number;
minRows?: number;
rowFormat?: RowFormat;
secondaryEngineAttribute?: string;
}
建索引参数,使用方式为 @Index(parmas?: IndexParams)
export interface IndexParams {
keys: string[];
name?: string;
type?: IndexType;
storeType?: IndexStoreType;
comment?: string;
engineAttribute?: string;
secondaryEngineAttribute?: string;
parser?: string;
}
建列参数,使用方式为 @Column(type: ColumnTypeParams, parmas?: ColumnParams)
export interface ColumnParams {
name?: string;
default?: string;
canNull?: boolean;
comment?: string;
visible?: boolean;
autoIncrement?: boolean;
uniqueKey?: boolean;
primaryKey?: boolean;
collate?: string;
columnFormat?: ColumnFormat;
engineAttribute?: string;
secondaryEngineAttribute?: string;
}
支持的类型
export enum ColumnType {
BIT = 'BIT',
TINYINT = 'TINYINT',
BOOL = 'BOOL',
SMALLINT = 'SMALLINT',
MEDIUMINT = 'MEDIUMINT',
INT = 'INT',
BIGINT = 'BIGINT',
DECIMAL = 'DECIMAL',
FLOAT = 'FLOAT',
DOUBLE = 'DOUBLE',
DATE = 'DATE',
DATETIME = 'DATETIME',
TIMESTAMP = 'TIMESTAMP',
TIME = 'TIME',
YEAR = 'YEAR',
CHAR = 'CHAR',
VARCHAR = 'VARCHAR',
BINARY = 'BINARY',
VARBINARY = 'VARBINARY',
TINYBLOB = 'TINYBLOB',
TINYTEXT = 'TINYTEXT',
BLOB = 'BLOB',
TEXT = 'TEXT',
MEDIUMBLOB = 'MEDIUMBLOB',
MEDIUMTEXT = 'MEDIUMTEXT',
LONGBLOB = 'LONGBLOB',
LONGTEXT = 'LONGTEXT',
ENUM = 'ENUM',
SET = 'SET',
JSON = 'JSON',
GEOMETRY = 'GEOMETRY',
POINT = 'POINT',
LINESTRING = 'LINESTRING',
POLYGON = 'POLYGON',
MULTIPOINT = 'MULTIPOINT',
MULTILINESTRING = 'MULTILINESTRING',
MULTIPOLYGON = 'MULTIPOLYGON',
GEOMETRYCOLLECTION = 'GEOMETRYCOLLECTION',
}
支持的类型参数,详细可参考 https://dev.mysql.com/doc/refman/8.0/en/data-types.html
如果 mysql 类型和 ts 类型对应关系不确定可直接使用 ColumnTsType 类型,如
import { Table, Index, Column, ColumnType, IndexType, ColumnTsType } from '@eggjs/tegg/dal';
@Table({
comment: 'foo table',
})
@Index({
keys: ['name'],
type: IndexType.UNIQUE,
})
export class Foo {
@Column(
{
type: ColumnType.INT,
},
{
primaryKey: true,
},
)
id: ColumnTsType['INT'];
@Column({
type: ColumnType.VARCHAR,
length: 100,
})
name: ColumnTsType['VARCHAR'];
}
export interface BitParams {
type: ColumnType.BIT;
length?: number;
}
export interface BoolParams {
type: ColumnType.BOOL;
}
export interface TinyIntParams {
type: ColumnType.TINYINT;
length?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface SmallIntParams {
type: ColumnType.SMALLINT;
length?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface MediumIntParams {
type: ColumnType.MEDIUMINT;
length?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface IntParams {
type: ColumnType.INT;
length?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface BigIntParams {
type: ColumnType.BIGINT;
length?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface DecimalParams {
type: ColumnType.DECIMAL;
length?: number;
fractionalLength?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface FloatParams {
type: ColumnType.FLOAT;
length?: number;
fractionalLength?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface DoubleParams {
type: ColumnType.DOUBLE;
length?: number;
fractionalLength?: number;
unsigned?: boolean;
zeroFill?: boolean;
}
export interface DateParams {
type: ColumnType.DATE;
}
export interface DateTimeParams {
type: ColumnType.DATETIME;
precision?: number;
autoUpdate?: boolean;
}
export interface TimestampParams {
type: ColumnType.TIMESTAMP;
precision?: number;
autoUpdate?: boolean;
}
export interface TimeParams {
type: ColumnType.TIME;
precision?: number;
}
export interface YearParams {
type: ColumnType.YEAR;
}
export interface CharParams {
type: ColumnType.CHAR;
length?: number;
characterSet?: string;
collate?: string;
}
export interface VarCharParams {
type: ColumnType.VARCHAR;
length: number;
characterSet?: string;
collate?: string;
}
export interface BinaryParams {
type: ColumnType.BINARY;
length?: number;
}
export interface VarBinaryParams {
type: ColumnType.VARBINARY;
length: number;
}
export interface TinyBlobParams {
type: ColumnType.TINYBLOB;
}
export interface TinyTextParams {
type: ColumnType.TINYTEXT;
characterSet?: string;
collate?: string;
}
export interface BlobParams {
type: ColumnType.BLOB;
length?: number;
}
export interface TextParams {
type: ColumnType.TEXT;
length?: number;
characterSet?: string;
collate?: string;
}
export interface MediumBlobParams {
type: ColumnType.MEDIUMBLOB;
}
export interface LongBlobParams {
type: ColumnType.LONGBLOB;
}
export interface MediumTextParams {
type: ColumnType.MEDIUMTEXT;
characterSet?: string;
collate?: string;
}
export interface LongTextParams {
type: ColumnType.LONGTEXT;
characterSet?: string;
collate?: string;
}
export interface EnumParams {
type: ColumnType.ENUM;
enums: string[];
characterSet?: string;
collate?: string;
}
export interface SetParams {
type: ColumnType.SET;
enums: string[];
characterSet?: string;
collate?: string;
}
export interface JsonParams {
type: ColumnType.JSON;
}
export interface GeometryParams {
type: ColumnType.GEOMETRY;
SRID?: number;
}
export interface PointParams {
type: ColumnType.POINT;
SRID?: number;
}
export interface LinestringParams {
type: ColumnType.LINESTRING;
SRID?: number;
}
export interface PolygonParams {
type: ColumnType.POLYGON;
SRID?: number;
}
export interface MultiPointParams {
type: ColumnType.MULTIPOINT;
SRID?: number;
}
export interface MultiLinestringParams {
type: ColumnType.MULTILINESTRING;
SRID?: number;
}
export interface MultiPolygonParams {
type: ColumnType.MULTIPOLYGON;
SRID?: number;
}
export interface GeometryCollectionParams {
type: ColumnType.GEOMETRYCOLLECTION;
SRID?: number;
}
目录结构
运行 egg-bin dal gen 即可生成 dal 相关目录,包括 dao、extension、structure
dal
├── dao
│ ├── FooDAO.ts
│ └── base
│ └── BaseFooDAO.ts
├── extension
│ └── FooExtension.ts
└── structure
├── Foo.json
└── Foo.sql
- dao: 表访问类,生成的 BaseDAO 请勿修改,其中包含了根据表结构生成的基础访问方法,如 insert/update/delete 以及根据索引信息生成的 find 方法
- extension: 扩展文件,如果需要自定义 sql,需要在 extension 文件中定义
- structure: 建表语句以及表结构
DAO
注入 DAO 即可实现对表的访问
import { SingletonProto, Inject } from '@eggjs/tegg';
@SingletonProto()
export class FooRepository {
@Inject()
private readonly fooDAO: FooDAO;
async create(foo: Foo) {
await this.fooDAO.insert(foo);
}
}
自定义 SQL
import { type SqlMap, SqlType } from '@eggjs/tegg/dal';
export default {
findByName: {
type: SqlType.SELECT,
sql: 'SELECT {{ allColumns }} FROM egg_foo WHERE name = {{ name }}',
},
} as Record<string, SqlMap>;
import { SingletonProto, AccessLevel } from '@eggjs/tegg';
import { BaseFooDAO } from './base/BaseFooDAO';
import { Foo } from '../../Foo';
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export default class FooDAO extends BaseFooDAO {
async findByName(name: string): Promise<Foo[]> {
return this.dataSource.execute('findByName', {
name,
});
}
}
支持的自定义 filter
- toPoint
- toLine
- toPolygon
- toGeometry
- toMultiPoint
- toMultiLine
- toMultiPolygon
- toGeometryCollection
支持自定义 block 来简化 sql, 如内置的 allColumns
export default {
findByName: {
type: SqlType.BLOCK,
sql: 'id, name',
},
} as Record<string, SqlMap>;
DataSource
DataSource 仅能在 DAO 中使用,可以将 MySQL 返回的数据反序列化为类。支持的方法有
export interface DataSource<T> {
execute(sqlName: string, data?: any): Promise<Array<T>>;
executeScalar(sqlName: string, data?: any): Promise<T | null>;
executeRaw(sqlName: string, data?: any): Promise<Array<any>>;
executeRawScalar(sqlName: string, data?: any): Promise<any | null>;
paginate(sqlName: string, data: any, currentPage: number, perPageCount: number): Promise<any>;
count(sqlName: string, data?: any): Promise<number>;
}
时区问题
注意连接配置中的时区必须和数据库的时区完全一致,否则可能出现时间错误的问题。
dataSource:
foo:
connectionLimit: 100
database: 'test'
host: '127.0.0.1'
user: root
port: 3306
timezone: '+08:00'
可以通过以下 SQL 来查看数据库时区
SELECT @@GLOBAL.time_zone;
Unittest
可以在 module.yml 中开启 forkDb 配置,即可实现 unittest 环境自动创建数据库
dataSource:
foo:
forkDb: true