[RFC] tegg 支持 leoric
<!-- 相关 RFC 示例：https://git.io/fphwy -->

## 背景

在 tegg 中以注解的方式来集成我们的 ORM 框架 [Leoric](https://leoric.js.org/)。注解的几点优势：
- 配置元信息化，不需要启动应用即可获取信息。方便静态分析，比如产出 sql
- 类型强类型化，字段不用通过 define/attributes 等静态方法来定义，直接定义在类中

## 伪代码
```ts
import { Model, Index, Attribute, DataTypes, Bone, DataSource } from '@eggjs/tegg/orm';

// model/User.ts
@DataSource('foo')
@Model({
  tableName: 'users',
})
@Index([ 'gmt_modified' ])
@Index([ 'name' ], { unique: true, name: 'uk_name' })
export class User extends Bone {
  @Attribute(DataTypes.BIGINT, { primary: true, allowNull: false, autoIncrement: true })
  id: number;

  @Attribute(DataTypes.STRING, { name: 'user_name', allowNull: false })
  name: string;

  @Attribute(DataTypes.DATE)
  gmtModified: Date;
}
```

## 注解定义
### Model
```ts
function Model (opts: {
  // 默认值为类名转 _ + s
  tableName?: string;
  // 未来可以扩展 comment, encoding 等字段
})
```

### Index
```ts
function Index (fields: string[], opts?: {
  // 是否为唯一索引，默认 false
  unique?: boolean;
  // 是否为主键，默认 false
  primary?: boolean;
  // 索引名
  // 普通索引默认为 idx + 字段名
  // 唯一索引默认为 uk + 字段名
  name?: string;
})
```

### Attribute
```ts
function Attribute(dataType: DataTypes, opts?: {
  // 字段名，默认为属性名
  name?: string;
 // 是否可空，默认为 true
 allowNull?: boolean;
 // 是否自增，默认 false
 autoIncrement?: boolean;
 // 是否是主键，默认 false
 // 如果是联合主键，请使用 Index 注解
 primary?: boolean;
 // 是否唯一，默认 false
 // 如果是联合索引，请使用 Index 注解
 unique?: boolean;
})
```

### DataSource
```ts
// 多数据源情况下，指定数据源名称
// 对应 egg 的多客户端配置
function DataSource(dataSource) {
}
```

## 包导出
通过 `@eggjs/tegg` 包的 `orm` 路径来导出注解以及继承基类。Model, Index, Attribute, DataTypes 等注解没有问题，Bone 会有问题。Bone 中涉及了大量 ORM 实现细节，注解包不应该耦合实现，并且可能存在版本不统一情况。

解决方案：注解包可以将 leoric 设置为 peerDep，安装了 orm 插件之后即可统一，没有安装的情况下按照指定的版本为 leoric。存在一种特殊的情况，插件安装路径不是在项目的 node_modules 下面，这种还是会导致有两个 leoric 的存在，需要插件在启动时把注解中的 leoric 替换为实际运行时的。

## 跟进

- [ ] PR URL
