@zenorm/generate 0.0.1 → 1.1.0
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.
- package/CHANGELOG.md +10 -4
- package/README.md +24 -251
- package/dist/bin/zenorm-generate.d.ts +2 -2
- package/dist/bin/zenorm-generate.js +27 -27
- package/dist/generate.d.ts +2 -2
- package/dist/generate.js +159 -156
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -17
- package/dist/types.d.ts +120 -88
- package/dist/types.js +2 -2
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +37 -0
- package/package.json +45 -39
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,251 +1,24 @@
|
|
|
1
|
-
# ZenORM
|
|
2
|
-
|
|
3
|
-
[
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*提示:运行时并不使用此配置*
|
|
27
|
-
|
|
28
|
-
```json title=".dbgen.json"
|
|
29
|
-
{
|
|
30
|
-
"host": "localhost",
|
|
31
|
-
"port": 3306,
|
|
32
|
-
"user": "root",
|
|
33
|
-
"password": "",
|
|
34
|
-
"database": "test"
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## 演示
|
|
39
|
-
|
|
40
|
-
以下数据库结构为演示用,在数据中创建表结构
|
|
41
|
-
|
|
42
|
-
```sql
|
|
43
|
-
CREATE TABLE `user` (
|
|
44
|
-
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
45
|
-
`name` varchar(255) NOT NULL,
|
|
46
|
-
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
47
|
-
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
48
|
-
PRIMARY KEY (`id`)
|
|
49
|
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
50
|
-
|
|
51
|
-
CREATE TABLE `profile` (
|
|
52
|
-
`id` int(11) NOT NULL,
|
|
53
|
-
`edu` varchar(255) DEFAULT NULL,
|
|
54
|
-
`work` varchar(255) DEFAULT NULL,
|
|
55
|
-
PRIMARY KEY (`id`)
|
|
56
|
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
57
|
-
|
|
58
|
-
CREATE TABLE `message` (
|
|
59
|
-
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
60
|
-
`user_id` int(11) NOT NULL,
|
|
61
|
-
`content` varchar(255) DEFAULT NULL,
|
|
62
|
-
PRIMARY KEY (`id`),
|
|
63
|
-
KEY `fk1` (`user_id`)
|
|
64
|
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
运行命令开始生成数据库结构代码
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
npm run dbgen
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 编辑模型关系
|
|
74
|
-
|
|
75
|
-
编辑生成的模型文件 `src/model/user.ts`
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
import { model, createRepositoryQuery, join, many, data } from 'zenorm';
|
|
79
|
-
import { UserTable } from './_tables';
|
|
80
|
-
import { Profile } from './profile';
|
|
81
|
-
import { Message } from './message';
|
|
82
|
-
|
|
83
|
-
@model({
|
|
84
|
-
pk: 'id',
|
|
85
|
-
table: 'user',
|
|
86
|
-
})
|
|
87
|
-
export default class User extends UserTable {
|
|
88
|
-
static query = createRepositoryQuery<User, number>(User);
|
|
89
|
-
|
|
90
|
-
// 添加以下代码
|
|
91
|
-
|
|
92
|
-
// join 描述支持使用文件名,解决互相依赖问题
|
|
93
|
-
@join(__dirname + '/profile', { type: 'OneToMany', asList: false })
|
|
94
|
-
profile?: Profile;
|
|
95
|
-
|
|
96
|
-
@join(Message)
|
|
97
|
-
messages?: Message[];
|
|
98
|
-
|
|
99
|
-
@many(Message)
|
|
100
|
-
messageList?: Message[];
|
|
101
|
-
|
|
102
|
-
@data
|
|
103
|
-
get age() {
|
|
104
|
-
return this.birthday ? (new Date().getFullYear()) - this.birthday.getFullYear() : undefined;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
set age(v) {
|
|
108
|
-
if (v === undefined) throw new Error('age is undefined');
|
|
109
|
-
const date = new Date();
|
|
110
|
-
date.setFullYear(date.getFullYear() - v, 1, 1);
|
|
111
|
-
this.birthday = date;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
编辑生成的模型文件 `src/model/profile.ts`
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
import { model, createRepositoryQuery, join } from 'zenorm';
|
|
120
|
-
import { ProfileTable } from './_tables';
|
|
121
|
-
import User from './user';
|
|
122
|
-
|
|
123
|
-
@model({
|
|
124
|
-
pk: 'id',
|
|
125
|
-
table: 'profile',
|
|
126
|
-
})
|
|
127
|
-
export default class Profile extends ProfileTable {
|
|
128
|
-
static query = createRepositoryQuery<Profile, number>(Profile);
|
|
129
|
-
|
|
130
|
-
// 添加以下代码
|
|
131
|
-
|
|
132
|
-
@join(User)
|
|
133
|
-
user?: User;
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 初始化数据库访问层
|
|
138
|
-
|
|
139
|
-
创建代码 `src/db.ts`
|
|
140
|
-
|
|
141
|
-
```ts title="src/test.ts"
|
|
142
|
-
import { createPoolCompatible } from 'mysql-easy-query';
|
|
143
|
-
import { Repositories } from './model';
|
|
144
|
-
|
|
145
|
-
// 创建数据库连接池
|
|
146
|
-
export const pool = createPoolCompatible({
|
|
147
|
-
pools: {
|
|
148
|
-
// 主库
|
|
149
|
-
MASTER: {
|
|
150
|
-
host: '10.0.0.1',
|
|
151
|
-
user: 'root',
|
|
152
|
-
database: 'test',
|
|
153
|
-
password: '',
|
|
154
|
-
},
|
|
155
|
-
// 如果需要读写分离,创建命令规则为 SLAVE* 的只读配置
|
|
156
|
-
/*
|
|
157
|
-
SLAVE1: {
|
|
158
|
-
host: '10.0.0.2'
|
|
159
|
-
},
|
|
160
|
-
*/
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// 创建仓库访问层
|
|
165
|
-
export const repositories = new Repositories(pool);
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### 开始使用
|
|
169
|
-
|
|
170
|
-
#### 常规使用
|
|
171
|
-
|
|
172
|
-
```ts
|
|
173
|
-
import { repositories } from './db';
|
|
174
|
-
|
|
175
|
-
const {
|
|
176
|
-
UserRepository,
|
|
177
|
-
MessageRepository,
|
|
178
|
-
} = repositories;
|
|
179
|
-
|
|
180
|
-
async function test() {
|
|
181
|
-
// create
|
|
182
|
-
const id = await UserRepository.create({ name: 'yf' });
|
|
183
|
-
console.log(id); // 1
|
|
184
|
-
|
|
185
|
-
// get and update
|
|
186
|
-
const user = await UserRepository.findByPk(id);
|
|
187
|
-
user.name = 'yefei';
|
|
188
|
-
user.age = 20;
|
|
189
|
-
await UserRepository.save(user);
|
|
190
|
-
|
|
191
|
-
// find all
|
|
192
|
-
const users = await UserRepository.find().all();
|
|
193
|
-
|
|
194
|
-
// find limit
|
|
195
|
-
const users = await UserRepository.find().limit(10).all();
|
|
196
|
-
|
|
197
|
-
// find by where
|
|
198
|
-
const users = await UserRepository.find({ name: { $like: `%y%` } }).all();
|
|
199
|
-
|
|
200
|
-
// get all count
|
|
201
|
-
const count = await UserRepository.count();
|
|
202
|
-
|
|
203
|
-
// page
|
|
204
|
-
const page = await UserRepository.page();
|
|
205
|
-
|
|
206
|
-
// exists
|
|
207
|
-
const exists = await UserRepository.exists({ id: 1 });
|
|
208
|
-
// or
|
|
209
|
-
const exists = await UserRepository.find({ name: 'yf' }).exists();
|
|
210
|
-
|
|
211
|
-
// update
|
|
212
|
-
const updatedCount = await UserRepository.find({ id: 1 }).update({ name: 'yf', age: 11 });
|
|
213
|
-
|
|
214
|
-
// delete
|
|
215
|
-
const user = await UserRepository.findByPk(1);
|
|
216
|
-
const deletedCount = await UserRepository.delete(user);
|
|
217
|
-
|
|
218
|
-
await UserRepository.find({ name: 'aaa' }).delete();
|
|
219
|
-
|
|
220
|
-
// join 预定义
|
|
221
|
-
const user = await UserRepository.find().join("messages").get();
|
|
222
|
-
|
|
223
|
-
// join 模型(未定义的)
|
|
224
|
-
const user = await MessageRepository.find().join(User).all();
|
|
225
|
-
|
|
226
|
-
// many 独立查询功能
|
|
227
|
-
const userList = await UserRepository.find().many("messageList").all();
|
|
228
|
-
|
|
229
|
-
// 指定使用主从库
|
|
230
|
-
await UserRepository.find().of('MASTER').all();
|
|
231
|
-
await UserRepository.find().of('SLAVE*').all();
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
#### 事物支持
|
|
236
|
-
|
|
237
|
-
```ts
|
|
238
|
-
import { pool } from './db';
|
|
239
|
-
import { User, Message } from './model';
|
|
240
|
-
|
|
241
|
-
async function test() {
|
|
242
|
-
await pool.transaction(async tx => {
|
|
243
|
-
await User.query(tx).find().update({ some: 'data' });
|
|
244
|
-
await Message.query(tx).find().update({ some: 'data' });
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## Related projects
|
|
250
|
-
[mysql-easy-query](https://www.npmjs.com/package/mysql-easy-query)
|
|
251
|
-
[sql-easy-builder](https://www.npmjs.com/package/sql-easy-builder)
|
|
1
|
+
# ZenORM Generate
|
|
2
|
+
|
|
3
|
+
[ZenORM](https://www.npmjs.com/package/zenorm) Table Structure Code Generation Tool
|
|
4
|
+
|
|
5
|
+
表结构代码生成工具
|
|
6
|
+
|
|
7
|
+
## Generate Config - 代码生成配置
|
|
8
|
+
|
|
9
|
+
| 配置项 | 类型 | 默认值 | 说明
|
|
10
|
+
| ----- | --- | ----- | ----
|
|
11
|
+
| host | `string` | 无 | 目标数据库地址
|
|
12
|
+
| port | `number` | 无 | 数据库端口
|
|
13
|
+
| user | `string` | 无 | 数据库用户名
|
|
14
|
+
| password | `string` | 无 | 数据库密码
|
|
15
|
+
| database | `string` | 无 | 数据库名
|
|
16
|
+
| outputDir | `string` | `'./src/model'` | 代码输出目录
|
|
17
|
+
| tablesFilename | `string` | `'_tables'` | 生成数据库表结构文件名
|
|
18
|
+
| repositoriesFilename | `string` | `'_repositories'` | 生成 repositories 文件名
|
|
19
|
+
| globalFilename | `string` | 无 | 全局文件名 - 如果设置所有表将继承于此 - 例如设置为:'_global' - 如果文件不存在则自动创建
|
|
20
|
+
| bindQuery | `string` | 无 | 绑定 Query 对象 - 设置 query 源,格式: 'QueryParam@filename' 例如: 'pool@../db'
|
|
21
|
+
| generateRepositories | `boolean` | `false` | 是否生成 Repositories 类 - 通常用于多租户模式做数据库前置绑定 `Query` 对象
|
|
22
|
+
| declareRepositoriesToModules | `string[]` | 无 | 是否需将 Repositories 实例定义到目标模块中 - 例如: `["@zenweb/core.Core.repositories"]`
|
|
23
|
+
| filter | `string` | 无 | 表过滤规则正则
|
|
24
|
+
| include | `string` | 无 | 表包含规则正则
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export {};
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export {};
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const generate_1 = require("../generate");
|
|
6
|
-
function getConfig() {
|
|
7
|
-
const configFile = path.join(process.cwd(),
|
|
8
|
-
const config = require(configFile);
|
|
9
|
-
return Object.assign({
|
|
10
|
-
backend: '@zenorm/mysql',
|
|
11
|
-
}, config);
|
|
12
|
-
}
|
|
13
|
-
async function main() {
|
|
14
|
-
const config = await getConfig();
|
|
15
|
-
const call = require(config.backend).default;
|
|
16
|
-
await (0, generate_1.generate)(call()(config), config);
|
|
17
|
-
}
|
|
18
|
-
if (!process.argv[2]) {
|
|
19
|
-
console.log('zenorm-generate config.json');
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
main().then(() => process.exit(), e => {
|
|
24
|
-
console.error(e);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const generate_1 = require("../generate");
|
|
6
|
+
function getConfig(filename) {
|
|
7
|
+
const configFile = path.join(process.cwd(), filename);
|
|
8
|
+
const config = require(configFile);
|
|
9
|
+
return Object.assign({
|
|
10
|
+
backend: '@zenorm/generate-mysql',
|
|
11
|
+
}, config);
|
|
12
|
+
}
|
|
13
|
+
async function main(configFilename) {
|
|
14
|
+
const config = await getConfig(configFilename);
|
|
15
|
+
const call = require(config.backend).default;
|
|
16
|
+
await (0, generate_1.generate)(call()(config), config);
|
|
17
|
+
}
|
|
18
|
+
if (!process.argv[2]) {
|
|
19
|
+
console.log('zenorm-generate config.json');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
main(process.argv[2]).then(() => process.exit(), e => {
|
|
24
|
+
console.error(e);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
27
|
+
}
|
package/dist/generate.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GenerateConfig, TabelDescribe } from './types';
|
|
2
|
-
export declare function generate(tables: AsyncGenerator<TabelDescribe>, cfg?: GenerateConfig): Promise<void>;
|
|
1
|
+
import { GenerateConfig, TabelDescribe } from './types';
|
|
2
|
+
export declare function generate(tables: AsyncGenerator<TabelDescribe>, cfg?: GenerateConfig): Promise<void>;
|
package/dist/generate.js
CHANGED
|
@@ -1,156 +1,159 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generate = void 0;
|
|
4
|
-
const fs_1 = require("fs");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const pascal_case_1 = require("pascal-case");
|
|
7
|
-
const snake_case_1 = require("snake-case");
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generate = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const pascal_case_1 = require("pascal-case");
|
|
7
|
+
const snake_case_1 = require("snake-case");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
const zenormName = process.env.ZENORM_NAME || 'zenorm';
|
|
10
|
+
async function generate(tables, cfg) {
|
|
11
|
+
console.log('generate models...');
|
|
12
|
+
const config = Object.assign({
|
|
13
|
+
outputDir: './src/model',
|
|
14
|
+
tablesFilename: '_tables',
|
|
15
|
+
repositoriesFilename: '_repositories',
|
|
16
|
+
}, cfg);
|
|
17
|
+
const outputDir = (0, utils_1.cwdPath)(config.outputDir);
|
|
18
|
+
await (0, utils_1.checkFileDir)(outputDir);
|
|
19
|
+
console.log('database:', config.database);
|
|
20
|
+
const remark = [
|
|
21
|
+
'// zenorm 自动生成文件',
|
|
22
|
+
'// 请不要修改此文件,因为此文件在每次重新生成数据库结构时会被覆盖',
|
|
23
|
+
`// create at: ${(0, utils_1.currentDatetime)()}`,
|
|
24
|
+
`// create by: ${process.env.USER || process.env.USERNAME || '-'}@${process.env.COMPUTERNAME || '-'}`,
|
|
25
|
+
`// database: ${config.database}`,
|
|
26
|
+
];
|
|
27
|
+
const structs = [
|
|
28
|
+
...remark,
|
|
29
|
+
config.globalFilename ? `import _Global from './${config.globalFilename}';` : null,
|
|
30
|
+
'',
|
|
31
|
+
];
|
|
32
|
+
const models = [];
|
|
33
|
+
const filterRegExp = config.filter ? new RegExp(config.filter) : null;
|
|
34
|
+
const includeRegExp = config.include ? new RegExp(config.include) : null;
|
|
35
|
+
for await (const t of tables) {
|
|
36
|
+
const tableName = t.name;
|
|
37
|
+
if ((filterRegExp && filterRegExp.test(tableName))
|
|
38
|
+
|| (includeRegExp && !includeRegExp.test(tableName))) {
|
|
39
|
+
// console.log('table:', tableName, 'ignore');
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const className = (0, pascal_case_1.pascalCase)(tableName);
|
|
43
|
+
const name = (0, snake_case_1.snakeCase)(tableName);
|
|
44
|
+
const outputFilename = path.join(outputDir, name + '.ts');
|
|
45
|
+
console.log('table:', tableName);
|
|
46
|
+
let pk = 'id';
|
|
47
|
+
let pkType = 'number';
|
|
48
|
+
const props = [];
|
|
49
|
+
const columns = [];
|
|
50
|
+
for (const c of t.columns) {
|
|
51
|
+
if (c.pk) {
|
|
52
|
+
pk = c.name;
|
|
53
|
+
pkType = c.type;
|
|
54
|
+
}
|
|
55
|
+
if (c.comment && c.comment.length) {
|
|
56
|
+
props.push(` /**`);
|
|
57
|
+
for (const line of c.comment) {
|
|
58
|
+
props.push(` * ${line}`);
|
|
59
|
+
}
|
|
60
|
+
props.push(` */`);
|
|
61
|
+
}
|
|
62
|
+
props.push(` ${c.name}${c.required ? '!' : '?'}: ${c.type};`);
|
|
63
|
+
columns.push(c.name);
|
|
64
|
+
}
|
|
65
|
+
structs.push(`export class ${className}Table${config.globalFilename ? ' extends _Global' : ''} {`);
|
|
66
|
+
structs.push(` static columns = ${JSON.stringify(columns)};`);
|
|
67
|
+
structs.push(...props);
|
|
68
|
+
structs.push('}');
|
|
69
|
+
structs.push('');
|
|
70
|
+
// model class
|
|
71
|
+
await (0, utils_1.notExistsPut)(outputFilename, () => {
|
|
72
|
+
return [
|
|
73
|
+
`import { model } from '${zenormName}';`,
|
|
74
|
+
`import { ${className}Table } from './${config.tablesFilename}';`,
|
|
75
|
+
'',
|
|
76
|
+
`@model({`,
|
|
77
|
+
` pk: '${pk}',`,
|
|
78
|
+
name != tableName ? ` name: '${name}',` : null,
|
|
79
|
+
` table: '${tableName}',`,
|
|
80
|
+
`})`,
|
|
81
|
+
`export default class ${className} extends ${className}Table {`,
|
|
82
|
+
`}`,
|
|
83
|
+
'',
|
|
84
|
+
].filter(i => i !== null).join('\n');
|
|
85
|
+
});
|
|
86
|
+
models.push({ name, className, pkType });
|
|
87
|
+
}
|
|
88
|
+
const tablesFilename = path.join(outputDir, config.tablesFilename + '.ts');
|
|
89
|
+
console.log(`write tables file: ${tablesFilename}`);
|
|
90
|
+
await fs_1.promises.writeFile(tablesFilename, structs.filter(i => i !== null).join('\n'));
|
|
91
|
+
const repositories = [
|
|
92
|
+
...remark,
|
|
93
|
+
`import {${config.generateRepositories ? `QueryParam, ` : ''} createRepositoryQuery } from '${zenormName}';`,
|
|
94
|
+
...models.map(({ name, className }) => `import _${className} from './${name}';`),
|
|
95
|
+
];
|
|
96
|
+
// 绑定静态 Query
|
|
97
|
+
if (config.bindQuery) {
|
|
98
|
+
const [v, p] = config.bindQuery.split('@', 2);
|
|
99
|
+
repositories.push(`import { ${v} as _query } from '${p}';`);
|
|
100
|
+
}
|
|
101
|
+
// static
|
|
102
|
+
models.forEach(({ className, pkType }) => {
|
|
103
|
+
repositories.push('', `export class ${className} extends _${className} {`, ` /** 使用指定 Query 对象查询 ${className}Repository */`, ` static query = createRepositoryQuery<${className}, ${pkType}>(${className});`);
|
|
104
|
+
if (config.bindQuery) {
|
|
105
|
+
repositories.push(` /** Query 绑定的 ${className}Repository */`);
|
|
106
|
+
repositories.push(` static repository = ${className}.query(_query);`);
|
|
107
|
+
repositories.push(...[
|
|
108
|
+
'of',
|
|
109
|
+
'find',
|
|
110
|
+
'findByPk',
|
|
111
|
+
'getByPk',
|
|
112
|
+
'create',
|
|
113
|
+
'createAndGet',
|
|
114
|
+
].map(i => ` static ${i}: typeof ${className}.repository.${i} = ${className}.repository.${i}.bind(${className}.repository);`));
|
|
115
|
+
// 实例方法
|
|
116
|
+
repositories.push(` save() { return ${className}.repository.save(this); }`);
|
|
117
|
+
repositories.push(` update(data: Partial<${className}>) { return ${className}.repository.update(this, data); }`);
|
|
118
|
+
repositories.push(` delete() { return ${className}.repository.delete(this); }`);
|
|
119
|
+
}
|
|
120
|
+
repositories.push('}');
|
|
121
|
+
});
|
|
122
|
+
// Repositories
|
|
123
|
+
if (config.generateRepositories) {
|
|
124
|
+
repositories.push(`export class Repositories {`, ` constructor(private _query: QueryParam) {}`, ...models.map(({ className }) => ` get ${className}Repository() { return ${className}.query(this._query); }`), `}`, '');
|
|
125
|
+
// 添加 Repositories 到目标模块中
|
|
126
|
+
if (config.declareRepositoriesToModules) {
|
|
127
|
+
for (const mod of config.declareRepositoriesToModules) {
|
|
128
|
+
const _m = mod.split('.');
|
|
129
|
+
repositories.push(`declare module '${_m[0]}' {`);
|
|
130
|
+
repositories.push(` interface ${_m.slice(1, -1).join('.')} {`);
|
|
131
|
+
repositories.push(` ${_m[_m.length - 1]}: Repositories;`);
|
|
132
|
+
repositories.push(` }`);
|
|
133
|
+
repositories.push(`}`);
|
|
134
|
+
repositories.push(``);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const repositoriesFilename = path.join(outputDir, config.repositoriesFilename + '.ts');
|
|
139
|
+
console.log(`write repositories file: ${repositoriesFilename}`);
|
|
140
|
+
await fs_1.promises.writeFile(repositoriesFilename, repositories.join('\n'));
|
|
141
|
+
// 生成 global.ts
|
|
142
|
+
if (config.globalFilename) {
|
|
143
|
+
const globalFilename = path.join(outputDir, config.globalFilename + '.ts');
|
|
144
|
+
await (0, utils_1.notExistsPut)(globalFilename, () => {
|
|
145
|
+
console.log(`write file: ${globalFilename}`);
|
|
146
|
+
return 'export default class Global {}';
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// 生成 index.ts
|
|
150
|
+
const indexFilename = path.join(outputDir, 'index.ts');
|
|
151
|
+
await (0, utils_1.notExistsPut)(indexFilename, () => {
|
|
152
|
+
console.log(`write file: ${indexFilename}`);
|
|
153
|
+
return [
|
|
154
|
+
`export * from './${config.tablesFilename}';`,
|
|
155
|
+
`export * from './${config.repositoriesFilename}';`,
|
|
156
|
+
].join('\n');
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
exports.generate = generate;
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './types';
|
|
1
|
+
export * from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./types"), exports);
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,88 +1,120 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 模型文件生成 - 列描述
|
|
3
|
-
*/
|
|
4
|
-
export interface ColumnDescribe {
|
|
5
|
-
/**
|
|
6
|
-
* 是否为主键
|
|
7
|
-
*/
|
|
8
|
-
pk: boolean;
|
|
9
|
-
/**
|
|
10
|
-
* 列名称
|
|
11
|
-
*/
|
|
12
|
-
name: string;
|
|
13
|
-
/**
|
|
14
|
-
* 列类型,例如 number, string, boolean
|
|
15
|
-
*/
|
|
16
|
-
type: string;
|
|
17
|
-
/**
|
|
18
|
-
* 是否为必须项(非NULL)
|
|
19
|
-
*/
|
|
20
|
-
required: boolean;
|
|
21
|
-
/**
|
|
22
|
-
* 注释信息,一行一条
|
|
23
|
-
*/
|
|
24
|
-
comment: string[];
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* 模型文件生成 - 表描述
|
|
28
|
-
*/
|
|
29
|
-
export interface TabelDescribe {
|
|
30
|
-
/**
|
|
31
|
-
* 表名称
|
|
32
|
-
*/
|
|
33
|
-
name: string;
|
|
34
|
-
/**
|
|
35
|
-
* 列描述信息
|
|
36
|
-
*/
|
|
37
|
-
columns: ColumnDescribe[];
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* 生成配置
|
|
41
|
-
*/
|
|
42
|
-
export interface GenerateConfig {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*
|
|
57
|
-
*/
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*
|
|
78
|
-
*/
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
*
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 模型文件生成 - 列描述
|
|
3
|
+
*/
|
|
4
|
+
export interface ColumnDescribe {
|
|
5
|
+
/**
|
|
6
|
+
* 是否为主键
|
|
7
|
+
*/
|
|
8
|
+
pk: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* 列名称
|
|
11
|
+
*/
|
|
12
|
+
name: string;
|
|
13
|
+
/**
|
|
14
|
+
* 列类型,例如 number, string, boolean
|
|
15
|
+
*/
|
|
16
|
+
type: string;
|
|
17
|
+
/**
|
|
18
|
+
* 是否为必须项(非NULL)
|
|
19
|
+
*/
|
|
20
|
+
required: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* 注释信息,一行一条
|
|
23
|
+
*/
|
|
24
|
+
comment: string[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 模型文件生成 - 表描述
|
|
28
|
+
*/
|
|
29
|
+
export interface TabelDescribe {
|
|
30
|
+
/**
|
|
31
|
+
* 表名称
|
|
32
|
+
*/
|
|
33
|
+
name: string;
|
|
34
|
+
/**
|
|
35
|
+
* 列描述信息
|
|
36
|
+
*/
|
|
37
|
+
columns: ColumnDescribe[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 生成配置
|
|
41
|
+
*/
|
|
42
|
+
export interface GenerateConfig {
|
|
43
|
+
/**
|
|
44
|
+
* 目标数据库地址
|
|
45
|
+
*/
|
|
46
|
+
host?: string;
|
|
47
|
+
/**
|
|
48
|
+
* 数据库端口
|
|
49
|
+
*/
|
|
50
|
+
port?: number;
|
|
51
|
+
/**
|
|
52
|
+
* 数据库用户名
|
|
53
|
+
*/
|
|
54
|
+
user?: string;
|
|
55
|
+
/**
|
|
56
|
+
* 数据库密码
|
|
57
|
+
*/
|
|
58
|
+
password?: string;
|
|
59
|
+
/**
|
|
60
|
+
* 数据库名
|
|
61
|
+
*/
|
|
62
|
+
database?: string;
|
|
63
|
+
/**
|
|
64
|
+
* 代码输出目录
|
|
65
|
+
* @default './src/model'
|
|
66
|
+
*/
|
|
67
|
+
outputDir?: string;
|
|
68
|
+
/**
|
|
69
|
+
* 生成数据库表结构文件名
|
|
70
|
+
* - 此文件每次生成都会被重新改写
|
|
71
|
+
* @default '_tables'
|
|
72
|
+
*/
|
|
73
|
+
tablesFilename?: string;
|
|
74
|
+
/**
|
|
75
|
+
* 生成 repositories 文件名
|
|
76
|
+
* - 此文件每次生成都会被重新改写
|
|
77
|
+
* @default '_repositories'
|
|
78
|
+
*/
|
|
79
|
+
repositoriesFilename?: string;
|
|
80
|
+
/**
|
|
81
|
+
* 全局文件名
|
|
82
|
+
* - 例如设置为:'_global'
|
|
83
|
+
* - 如果设置所有表将继承于此
|
|
84
|
+
* - 如果文件不存在则自动创建
|
|
85
|
+
*/
|
|
86
|
+
globalFilename?: string;
|
|
87
|
+
/**
|
|
88
|
+
* 绑定 Query 对象
|
|
89
|
+
* - 设置 query 源,格式: 'QueryParam@filename' 例如: 'pool@../db'
|
|
90
|
+
* - 生成模型的静态 Repository 方法
|
|
91
|
+
* - 对于多租户数据库系统不适用
|
|
92
|
+
*/
|
|
93
|
+
bindQuery?: string;
|
|
94
|
+
/**
|
|
95
|
+
* 是否生成 Repositories 类
|
|
96
|
+
* - 通常用于多租户模式做数据库前置绑定 `Query` 对象
|
|
97
|
+
* @default false
|
|
98
|
+
*/
|
|
99
|
+
generateRepositories?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* 是否需将 Repositories 实例定义到目标模块中
|
|
102
|
+
* - 例如: `["@zenweb/core.Core.repositories"]`
|
|
103
|
+
* - 需要启用: `generateRepositories`
|
|
104
|
+
* @default undefined
|
|
105
|
+
*/
|
|
106
|
+
declareRepositoriesToModules?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* 表过滤规则正则,默认不处理
|
|
109
|
+
*/
|
|
110
|
+
filter?: string;
|
|
111
|
+
/**
|
|
112
|
+
* 表包含规则正则,默认不处理
|
|
113
|
+
*/
|
|
114
|
+
include?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 数据库表信息生成方法
|
|
118
|
+
* - 返回表描述的处理方法
|
|
119
|
+
*/
|
|
120
|
+
export type GenerateFunction = (config: GenerateConfig) => AsyncGenerator<TabelDescribe>;
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function cwdPath(p: string): string;
|
|
2
|
+
export declare function checkFileDir(dir: string): Promise<void>;
|
|
3
|
+
export declare function fileExists(f: string): Promise<boolean>;
|
|
4
|
+
/**
|
|
5
|
+
* 文件不存在则创建并写入内容
|
|
6
|
+
* @param filename
|
|
7
|
+
* @param getContent
|
|
8
|
+
*/
|
|
9
|
+
export declare function notExistsPut(filename: string, getContent: () => string | Promise<string>): Promise<boolean>;
|
|
10
|
+
export declare function currentDatetime(): string;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.currentDatetime = exports.notExistsPut = exports.fileExists = exports.checkFileDir = exports.cwdPath = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
function cwdPath(p) {
|
|
7
|
+
if (p.startsWith('./')) {
|
|
8
|
+
return path.join(process.cwd(), p.slice(2));
|
|
9
|
+
}
|
|
10
|
+
return p;
|
|
11
|
+
}
|
|
12
|
+
exports.cwdPath = cwdPath;
|
|
13
|
+
function checkFileDir(dir) {
|
|
14
|
+
return fs_1.promises.mkdir(dir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
exports.checkFileDir = checkFileDir;
|
|
17
|
+
function fileExists(f) {
|
|
18
|
+
return fs_1.promises.access(f).then(() => true, e => false);
|
|
19
|
+
}
|
|
20
|
+
exports.fileExists = fileExists;
|
|
21
|
+
/**
|
|
22
|
+
* 文件不存在则创建并写入内容
|
|
23
|
+
* @param filename
|
|
24
|
+
* @param getContent
|
|
25
|
+
*/
|
|
26
|
+
async function notExistsPut(filename, getContent) {
|
|
27
|
+
if (!await fileExists(filename)) {
|
|
28
|
+
await fs_1.promises.writeFile(filename, await getContent());
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
exports.notExistsPut = notExistsPut;
|
|
34
|
+
function currentDatetime() {
|
|
35
|
+
return new Date().toLocaleString();
|
|
36
|
+
}
|
|
37
|
+
exports.currentDatetime = currentDatetime;
|
package/package.json
CHANGED
|
@@ -1,39 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@zenorm/generate",
|
|
3
|
-
"description": "Easy ORM, easy query. easy typing! Auto generate typescript declaration.",
|
|
4
|
-
"version": "
|
|
5
|
-
"exports": "./dist/index.js",
|
|
6
|
-
"types": "./dist/index.d.ts",
|
|
7
|
-
"repository": "https://github.com/yefei/
|
|
8
|
-
"author": "YeFei <316606233@qq.com>",
|
|
9
|
-
"license": "MIT",
|
|
10
|
-
"bin": {
|
|
11
|
-
"zenorm-generate": "./dist/bin/zenorm-generate.js"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@zenorm/generate",
|
|
3
|
+
"description": "Easy ORM, easy query. easy typing! Auto generate typescript declaration.",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"exports": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"repository": "https://github.com/yefei/zenorm-generate",
|
|
8
|
+
"author": "YeFei <316606233@qq.com>",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"bin": {
|
|
11
|
+
"zenorm-generate": "./dist/bin/zenorm-generate.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"docs",
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "rimraf dist && tsc",
|
|
19
|
+
"prepublishOnly": "npm run build",
|
|
20
|
+
"gen": "cd test && ts-node ../src/bin/zenorm-generate.ts config.json",
|
|
21
|
+
"t1": "cd test && cross-env DEBUG=* ts-node t1"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mysql",
|
|
25
|
+
"query",
|
|
26
|
+
"model",
|
|
27
|
+
"types",
|
|
28
|
+
"generate",
|
|
29
|
+
"database"
|
|
30
|
+
],
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^12.20.41",
|
|
33
|
+
"@zenorm/generate-mysql": "^1.2.0",
|
|
34
|
+
"cross-env": "^7.0.3",
|
|
35
|
+
"mysql-easy-query": "^3.12.0",
|
|
36
|
+
"rimraf": "^4.4.1",
|
|
37
|
+
"ts-node": "^10.9.1",
|
|
38
|
+
"typescript": "^4.9.5",
|
|
39
|
+
"zenorm": "^3.27.0"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"pascal-case": "^3.1.2",
|
|
43
|
+
"snake-case": "^3.0.4"
|
|
44
|
+
}
|
|
45
|
+
}
|