@fastcar/cli 0.1.1 → 0.1.2
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/bin/cli.js +12 -9
- package/package.json +2 -2
- package/skills/fastcar-database/SKILL.md +360 -50
- package/skills/fastcar-framework/SKILL.md +465 -93
- package/src/reverse.js +86 -12
package/bin/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const init = require("../src/init");
|
|
4
4
|
const setModules = require("../src/setModules");
|
|
@@ -26,7 +26,7 @@ Commands:
|
|
|
26
26
|
clean node_modules 删除冗余的 node_modules 目录
|
|
27
27
|
compress node_modules 压缩 node_modules 目录
|
|
28
28
|
reverse 数据库表逆向生成
|
|
29
|
-
reverse:init 生成 reverse.config.json 配置文件
|
|
29
|
+
reverse:init 生成 reverse.config.yml/json 配置文件
|
|
30
30
|
pack [pm] 打包项目(排除 devDependencies)
|
|
31
31
|
pm: 包管理器 (npm/yarn/pnpm),可选,默认自动检测
|
|
32
32
|
|
|
@@ -54,7 +54,7 @@ Examples:
|
|
|
54
54
|
$ fastcar-cli init web my-project # 使用 web 模板创建 my-project
|
|
55
55
|
$ fastcar-cli clean node_modules
|
|
56
56
|
$ fastcar-cli reverse # 数据库表逆向生成
|
|
57
|
-
$ fastcar-cli reverse:init #
|
|
57
|
+
$ fastcar-cli reverse:init # 生成默认配置文件(默认 YAML 格式)
|
|
58
58
|
$ fastcar-cli pack # 打包项目(自动检测包管理器)
|
|
59
59
|
$ fastcar-cli pack yarn # 使用 yarn 安装依赖
|
|
60
60
|
$ fastcar-cli pack pnpm # 使用 pnpm 安装依赖
|
|
@@ -67,7 +67,7 @@ Examples:
|
|
|
67
67
|
$ fastcar-cli skill targets # 列出支持的 agents
|
|
68
68
|
|
|
69
69
|
Reverse 命令参数说明:
|
|
70
|
-
通过配置文件传入参数,在项目根目录创建 reverse.config.json:
|
|
70
|
+
通过配置文件传入参数,在项目根目录创建 reverse.config.yml 或 reverse.config.json:
|
|
71
71
|
|
|
72
72
|
{
|
|
73
73
|
"tables": ["test"], // 要逆向生成的表名数组(必填)
|
|
@@ -100,7 +100,7 @@ function showVersion() {
|
|
|
100
100
|
console.log(`fastcar-cli version ${packageINFO.version}`);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
function run(argv) {
|
|
103
|
+
async function run(argv) {
|
|
104
104
|
// 命令入口
|
|
105
105
|
if (!argv || argv.length === 0) {
|
|
106
106
|
showHelp();
|
|
@@ -122,7 +122,7 @@ function run(argv) {
|
|
|
122
122
|
break;
|
|
123
123
|
}
|
|
124
124
|
case "init": {
|
|
125
|
-
init(body);
|
|
125
|
+
await init(body);
|
|
126
126
|
break;
|
|
127
127
|
}
|
|
128
128
|
case "clean":
|
|
@@ -139,11 +139,11 @@ function run(argv) {
|
|
|
139
139
|
break;
|
|
140
140
|
}
|
|
141
141
|
case "reverse": {
|
|
142
|
-
reverseGenerate(body);
|
|
142
|
+
await reverseGenerate(body);
|
|
143
143
|
break;
|
|
144
144
|
}
|
|
145
145
|
case "reverse:init": {
|
|
146
|
-
initReverseConfig();
|
|
146
|
+
await initReverseConfig();
|
|
147
147
|
break;
|
|
148
148
|
}
|
|
149
149
|
case "pack": {
|
|
@@ -220,4 +220,7 @@ function run(argv) {
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
run(process.argv.slice(2))
|
|
223
|
+
run(process.argv.slice(2)).catch((err) => {
|
|
224
|
+
console.error(err);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastcar/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"homepage": "https://william_zhong.coding.net/public/fast-car/fastcar-cli/git/files",
|
|
5
5
|
"description": "fastcar-cli 脚手架快速搭建",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"commander": "^8.3.0",
|
|
25
25
|
"compressing": "^1.5.1",
|
|
26
26
|
"inquirer": "^8.2.0",
|
|
27
|
-
"yaml": "^
|
|
27
|
+
"yaml": "^2.8.3"
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
@@ -26,7 +26,7 @@ export default new APP();
|
|
|
26
26
|
#### 定义实体模型
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
import { Table, Field, DBType, PrimaryKey, NotNull, Size
|
|
29
|
+
import { Table, Field, DBType, PrimaryKey, NotNull, Size } from "@fastcar/core/annotation";
|
|
30
30
|
|
|
31
31
|
@Table("users")
|
|
32
32
|
class User {
|
|
@@ -43,11 +43,25 @@ class User {
|
|
|
43
43
|
|
|
44
44
|
@Field("profile")
|
|
45
45
|
@DBType("json")
|
|
46
|
-
|
|
47
|
-
profile: any;
|
|
46
|
+
profile!: any;
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
@Field("created_at")
|
|
49
|
+
@DBType("datetime")
|
|
50
|
+
createdAt!: Date;
|
|
51
|
+
|
|
52
|
+
constructor(args?: Partial<User>) {
|
|
53
|
+
if (args) {
|
|
54
|
+
Object.assign(this, args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
toObject() {
|
|
59
|
+
return {
|
|
60
|
+
id: this.id,
|
|
61
|
+
name: this.name,
|
|
62
|
+
profile: this.profile,
|
|
63
|
+
createdAt: this.createdAt,
|
|
64
|
+
};
|
|
51
65
|
}
|
|
52
66
|
}
|
|
53
67
|
```
|
|
@@ -66,11 +80,11 @@ class UserMapper extends MysqlMapper<User> {}
|
|
|
66
80
|
export default UserMapper;
|
|
67
81
|
```
|
|
68
82
|
|
|
69
|
-
####
|
|
83
|
+
#### MysqlMapper 完整 API 参考
|
|
70
84
|
|
|
71
85
|
```typescript
|
|
72
86
|
import { Service, Autowired } from "@fastcar/core/annotation";
|
|
73
|
-
import { OrderEnum } from "@fastcar/core/db";
|
|
87
|
+
import { OrderEnum, OperatorEnum } from "@fastcar/core/db";
|
|
74
88
|
import UserMapper from "./UserMapper";
|
|
75
89
|
import User from "./User";
|
|
76
90
|
|
|
@@ -79,73 +93,232 @@ class UserService {
|
|
|
79
93
|
@Autowired
|
|
80
94
|
private userMapper!: UserMapper;
|
|
81
95
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
// ==================== 查询方法 ====================
|
|
97
|
+
|
|
98
|
+
// 1. select(conditions) - 查询列表
|
|
99
|
+
// 返回: T[] - 实体对象数组
|
|
100
|
+
async getAllUsers() {
|
|
101
|
+
return this.userMapper.select({});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 2. selectOne(conditions) - 查询单个
|
|
105
|
+
// 返回: T | null
|
|
106
|
+
async getUserById(id: number) {
|
|
107
|
+
return this.userMapper.selectOne({
|
|
108
|
+
where: { id }
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 3. selectByPrimaryKey(row) - 根据主键查询
|
|
113
|
+
// 参数: 包含主键字段的对象
|
|
114
|
+
// 返回: T | null
|
|
115
|
+
async getUserByPK(id: number) {
|
|
116
|
+
return this.userMapper.selectByPrimaryKey({ id } as User);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 4. count(where) - 统计记录数
|
|
120
|
+
// 返回: number
|
|
121
|
+
async countUsers() {
|
|
122
|
+
return this.userMapper.count({ status: 1 });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 5. exist(where) - 判断是否存在
|
|
126
|
+
// 返回: boolean
|
|
127
|
+
async checkUserExists(name: string) {
|
|
128
|
+
return this.userMapper.exist({ name });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ==================== 条件查询详解 ====================
|
|
132
|
+
|
|
133
|
+
// 简单等于条件
|
|
134
|
+
async queryByStatus(status: number) {
|
|
135
|
+
return this.userMapper.select({
|
|
136
|
+
where: { status }
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 多条件 AND
|
|
141
|
+
async queryByConditions(name: string, status: number) {
|
|
142
|
+
return this.userMapper.select({
|
|
143
|
+
where: {
|
|
144
|
+
name,
|
|
145
|
+
status,
|
|
146
|
+
delStatus: false
|
|
147
|
+
}
|
|
148
|
+
});
|
|
85
149
|
}
|
|
86
150
|
|
|
87
|
-
//
|
|
88
|
-
async
|
|
151
|
+
// 比较运算符
|
|
152
|
+
async queryByAgeRange(minAge: number, maxAge: number) {
|
|
89
153
|
return this.userMapper.select({
|
|
90
154
|
where: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
},
|
|
94
|
-
orders: { createdAt: OrderEnum.desc },
|
|
95
|
-
limit: 10,
|
|
155
|
+
age: { $gte: minAge, $lte: maxAge }
|
|
156
|
+
}
|
|
96
157
|
});
|
|
97
158
|
}
|
|
98
159
|
|
|
99
|
-
//
|
|
160
|
+
// 支持的运算符:
|
|
161
|
+
// $eq - 等于 (默认)
|
|
162
|
+
// $gt / $gte - 大于 / 大于等于
|
|
163
|
+
// $lt / $lte - 小于 / 小于等于
|
|
164
|
+
// $ne - 不等于
|
|
165
|
+
// $in - IN 查询 (数组)
|
|
166
|
+
// $nin - NOT IN 查询
|
|
167
|
+
// $isNull - IS NULL
|
|
168
|
+
// $isNotNull - IS NOT NULL
|
|
169
|
+
|
|
170
|
+
// IN 查询
|
|
100
171
|
async queryByIds(ids: number[]) {
|
|
101
172
|
return this.userMapper.select({
|
|
102
|
-
where: { id: {
|
|
173
|
+
where: { id: { $in: ids } }
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// IS NULL 查询
|
|
178
|
+
async queryDeletedUsers() {
|
|
179
|
+
return this.userMapper.select({
|
|
180
|
+
where: { deletedAt: { $isNull: true } }
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ==================== 排序和分页 ====================
|
|
185
|
+
|
|
186
|
+
// 排序 - 必须使用 OrderEnum
|
|
187
|
+
async getUsersOrdered() {
|
|
188
|
+
return this.userMapper.select({
|
|
189
|
+
where: { status: 1 },
|
|
190
|
+
orders: { createdAt: OrderEnum.desc } // 正确: 使用 OrderEnum.desc
|
|
191
|
+
// 错误: orders: { createdAt: "DESC" }
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// OrderEnum 定义:
|
|
196
|
+
// OrderEnum.asc = "ASC"
|
|
197
|
+
// OrderEnum.desc = "DESC"
|
|
198
|
+
|
|
199
|
+
// 多字段排序
|
|
200
|
+
async getUsersMultiOrder() {
|
|
201
|
+
return this.userMapper.select({
|
|
202
|
+
orders: {
|
|
203
|
+
status: OrderEnum.asc,
|
|
204
|
+
createdAt: OrderEnum.desc
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 分页
|
|
210
|
+
async getUsersPaged(page: number, pageSize: number) {
|
|
211
|
+
return this.userMapper.select({
|
|
212
|
+
orders: { id: OrderEnum.desc },
|
|
213
|
+
offest: (page - 1) * pageSize,
|
|
214
|
+
limit: pageSize
|
|
103
215
|
});
|
|
104
216
|
}
|
|
105
217
|
|
|
106
|
-
//
|
|
218
|
+
// 只取前N条
|
|
219
|
+
async getTopUsers(limit: number) {
|
|
220
|
+
return this.userMapper.select({
|
|
221
|
+
orders: { score: OrderEnum.desc },
|
|
222
|
+
limit
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ==================== 插入方法 ====================
|
|
227
|
+
|
|
228
|
+
// 1. saveOne(row) - 插入单条
|
|
229
|
+
// 返回: number - 插入的主键ID
|
|
107
230
|
async createUser(name: string) {
|
|
108
231
|
const user = new User({ name, createdAt: new Date() });
|
|
109
|
-
|
|
232
|
+
const insertId = await this.userMapper.saveOne(user);
|
|
233
|
+
return insertId;
|
|
110
234
|
}
|
|
111
235
|
|
|
112
|
-
//
|
|
236
|
+
// 2. saveList(rows) - 批量插入
|
|
237
|
+
// 返回: boolean
|
|
113
238
|
async createUsers(users: User[]) {
|
|
114
239
|
return this.userMapper.saveList(users);
|
|
115
240
|
}
|
|
116
241
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
242
|
+
// 3. saveORUpdate(rows) - 插入或更新 (UPSERT)
|
|
243
|
+
// 主键冲突时更新,否则插入
|
|
244
|
+
// 返回: number - 主键ID
|
|
245
|
+
async saveOrUpdateUser(user: User) {
|
|
246
|
+
return this.userMapper.saveORUpdate(user);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ==================== 更新方法 ====================
|
|
250
|
+
|
|
251
|
+
// 1. update({ row, where, limit }) - 条件更新
|
|
252
|
+
// 返回: boolean
|
|
253
|
+
async updateUserName(id: number, name: string) {
|
|
254
|
+
return this.userMapper.update({
|
|
255
|
+
where: { id },
|
|
256
|
+
row: { name, updatedAt: new Date() }
|
|
257
|
+
});
|
|
120
258
|
}
|
|
121
259
|
|
|
122
|
-
//
|
|
260
|
+
// 2. updateOne({ row, where }) - 更新单条
|
|
261
|
+
// 自动限制 limit: 1
|
|
262
|
+
async updateOneUser(where: any, row: any) {
|
|
263
|
+
return this.userMapper.updateOne({ where, row });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 3. updateByPrimaryKey(row) - 根据主键更新
|
|
267
|
+
// 根据实体对象的主键字段更新
|
|
268
|
+
// 返回: boolean
|
|
123
269
|
async updateById(user: User) {
|
|
124
270
|
return this.userMapper.updateByPrimaryKey(user);
|
|
125
271
|
}
|
|
126
272
|
|
|
127
|
-
//
|
|
273
|
+
// 更新示例:软删除
|
|
274
|
+
async softDeleteUser(id: number) {
|
|
275
|
+
return this.userMapper.update({
|
|
276
|
+
where: { id },
|
|
277
|
+
row: { delStatus: true, deletedAt: new Date() }
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ==================== 删除方法 ====================
|
|
282
|
+
|
|
283
|
+
// 1. delete({ where, limit }) - 条件删除
|
|
284
|
+
// 返回: boolean
|
|
128
285
|
async deleteUser(id: number) {
|
|
129
|
-
return this.userMapper.delete({
|
|
286
|
+
return this.userMapper.delete({
|
|
287
|
+
where: { id }
|
|
288
|
+
});
|
|
130
289
|
}
|
|
131
290
|
|
|
132
|
-
//
|
|
133
|
-
async
|
|
134
|
-
return this.userMapper.
|
|
291
|
+
// 2. deleteOne(where) - 删除单条
|
|
292
|
+
async deleteOneUser(where: any) {
|
|
293
|
+
return this.userMapper.deleteOne(where);
|
|
135
294
|
}
|
|
136
295
|
|
|
137
|
-
//
|
|
138
|
-
async
|
|
139
|
-
return this.userMapper.
|
|
296
|
+
// 3. deleteByPrimaryKey(row) - 根据主键删除
|
|
297
|
+
async deleteById(id: number) {
|
|
298
|
+
return this.userMapper.deleteByPrimaryKey({ id } as User);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ==================== 高级查询 ====================
|
|
302
|
+
|
|
303
|
+
// 自定义 SQL 查询
|
|
304
|
+
// query(sql, args) - 执行查询 SQL
|
|
305
|
+
async customQuery() {
|
|
306
|
+
return this.userMapper.query(
|
|
307
|
+
"SELECT * FROM users WHERE status = ? AND created_at > ?",
|
|
308
|
+
[1, "2024-01-01"]
|
|
309
|
+
);
|
|
140
310
|
}
|
|
141
311
|
|
|
142
|
-
//
|
|
143
|
-
async
|
|
144
|
-
return this.userMapper.execute(
|
|
312
|
+
// execute(sql, args) - 执行任意 SQL
|
|
313
|
+
async customExecute() {
|
|
314
|
+
return this.userMapper.execute(
|
|
315
|
+
"UPDATE users SET login_count = login_count + 1 WHERE id = ?",
|
|
316
|
+
[1]
|
|
317
|
+
);
|
|
145
318
|
}
|
|
146
319
|
|
|
147
|
-
// 左连接查询
|
|
148
|
-
async
|
|
320
|
+
// 左连接查询 - 使用 selectByCustom
|
|
321
|
+
async leftJoinQuery() {
|
|
149
322
|
return this.userMapper.selectByCustom({
|
|
150
323
|
join: [
|
|
151
324
|
{
|
|
@@ -155,34 +328,133 @@ class UserService {
|
|
|
155
328
|
},
|
|
156
329
|
],
|
|
157
330
|
tableAlias: "t",
|
|
331
|
+
where: { "t.status": 1 }
|
|
158
332
|
});
|
|
159
333
|
}
|
|
160
334
|
|
|
161
335
|
// 强制索引
|
|
162
|
-
async
|
|
336
|
+
async forceIndexQuery() {
|
|
163
337
|
return this.userMapper.select({
|
|
164
338
|
forceIndex: ["idx_name"],
|
|
165
|
-
|
|
166
|
-
limit: 1,
|
|
339
|
+
where: { status: 1 }
|
|
167
340
|
});
|
|
168
341
|
}
|
|
169
342
|
|
|
170
|
-
//
|
|
171
|
-
async
|
|
343
|
+
// 指定查询字段
|
|
344
|
+
async selectFields() {
|
|
172
345
|
return this.userMapper.select({
|
|
173
|
-
fields: [
|
|
346
|
+
fields: ["id", "name", "email"],
|
|
347
|
+
where: { status: 1 }
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// 分组查询
|
|
352
|
+
async groupByStatus() {
|
|
353
|
+
return this.userMapper.selectByCustom({
|
|
354
|
+
fields: ["status", "COUNT(*) as count"],
|
|
355
|
+
groups: ["status"]
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// 使用数据库函数
|
|
360
|
+
async useDbFunction() {
|
|
361
|
+
return this.userMapper.selectByCustom({
|
|
362
|
+
fields: [
|
|
363
|
+
'id',
|
|
364
|
+
'name',
|
|
365
|
+
'DATE_FORMAT(created_at, "%Y-%m-%d") as createdDate'
|
|
366
|
+
]
|
|
174
367
|
});
|
|
175
368
|
}
|
|
176
369
|
}
|
|
177
370
|
```
|
|
178
371
|
|
|
179
|
-
####
|
|
372
|
+
#### 常用查询条件速查表
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
// 等于 (默认)
|
|
376
|
+
{ where: { status: 1 } }
|
|
377
|
+
|
|
378
|
+
// 不等于
|
|
379
|
+
{ where: { status: { $ne: 1 } } }
|
|
380
|
+
|
|
381
|
+
// 大于 / 大于等于
|
|
382
|
+
{ where: { age: { $gt: 18 } } }
|
|
383
|
+
{ where: { age: { $gte: 18 } } }
|
|
384
|
+
|
|
385
|
+
// 小于 / 小于等于
|
|
386
|
+
{ where: { age: { $lt: 60 } } }
|
|
387
|
+
{ where: { age: { $lte: 60 } } }
|
|
388
|
+
|
|
389
|
+
// 范围查询
|
|
390
|
+
{ where: { age: { $gte: 18, $lte: 60 } } }
|
|
391
|
+
|
|
392
|
+
// IN 查询
|
|
393
|
+
{ where: { id: { $in: [1, 2, 3] } } }
|
|
394
|
+
|
|
395
|
+
// NOT IN 查询
|
|
396
|
+
{ where: { id: { $nin: [1, 2, 3] } } }
|
|
397
|
+
|
|
398
|
+
// IS NULL
|
|
399
|
+
{ where: { deletedAt: { $isNull: true } } }
|
|
400
|
+
|
|
401
|
+
// IS NOT NULL
|
|
402
|
+
{ where: { deletedAt: { $isNotNull: true } } }
|
|
403
|
+
|
|
404
|
+
// 多条件 AND (默认)
|
|
405
|
+
{ where: { status: 1, delStatus: false } }
|
|
406
|
+
|
|
407
|
+
// 排序 (必须使用 OrderEnum)
|
|
408
|
+
import { OrderEnum } from "@fastcar/core/db";
|
|
409
|
+
{ orders: { createdAt: OrderEnum.desc } }
|
|
410
|
+
{ orders: { createdAt: OrderEnum.asc } }
|
|
411
|
+
|
|
412
|
+
// 分页
|
|
413
|
+
{ offest: 0, limit: 10 }
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
#### 事务处理
|
|
180
417
|
|
|
181
|
-
|
|
418
|
+
```typescript
|
|
419
|
+
import { SqlSession } from "@fastcar/core/annotation";
|
|
420
|
+
import { MysqlDataSourceManager } from "@fastcar/mysql";
|
|
421
|
+
|
|
422
|
+
@Service
|
|
423
|
+
class OrderService {
|
|
424
|
+
@Autowired
|
|
425
|
+
private dsm!: MysqlDataSourceManager;
|
|
182
426
|
|
|
183
|
-
|
|
427
|
+
@Autowired
|
|
428
|
+
private orderMapper!: OrderMapper;
|
|
184
429
|
|
|
185
|
-
|
|
430
|
+
@Autowired
|
|
431
|
+
private inventoryMapper!: InventoryMapper;
|
|
432
|
+
|
|
433
|
+
async createOrderWithTransaction(order: Order, inventoryUpdate: any) {
|
|
434
|
+
const sessionId = await this.dsm.beginTransaction();
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
// 插入订单
|
|
438
|
+
await this.orderMapper.saveOne(order, undefined, sessionId);
|
|
439
|
+
|
|
440
|
+
// 更新库存
|
|
441
|
+
await this.inventoryMapper.update({
|
|
442
|
+
where: { id: inventoryUpdate.id },
|
|
443
|
+
row: { quantity: inventoryUpdate.quantity }
|
|
444
|
+
}, undefined, sessionId);
|
|
445
|
+
|
|
446
|
+
// 提交事务
|
|
447
|
+
await this.dsm.commit(sessionId);
|
|
448
|
+
|
|
449
|
+
return true;
|
|
450
|
+
} catch (error) {
|
|
451
|
+
// 回滚事务
|
|
452
|
+
await this.dsm.rollback(sessionId);
|
|
453
|
+
throw error;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
```
|
|
186
458
|
|
|
187
459
|
### PostgreSQL (@fastcar/pgsql)
|
|
188
460
|
|
|
@@ -208,6 +480,8 @@ import User from "./User";
|
|
|
208
480
|
@Entity(User)
|
|
209
481
|
@Repository
|
|
210
482
|
class UserMapper extends PgsqlMapper<User> {}
|
|
483
|
+
|
|
484
|
+
export default UserMapper;
|
|
211
485
|
```
|
|
212
486
|
|
|
213
487
|
用法与 `MysqlMapper` 基本一致,支持相同的查询条件和 CRUD 操作。
|
|
@@ -236,6 +510,8 @@ import User from "./User";
|
|
|
236
510
|
@Entity(User)
|
|
237
511
|
@Repository
|
|
238
512
|
class UserMapper extends MongoMapper<User> {}
|
|
513
|
+
|
|
514
|
+
export default UserMapper;
|
|
239
515
|
```
|
|
240
516
|
|
|
241
517
|
### Redis (@fastcar/redis)
|
|
@@ -252,7 +528,7 @@ class APP {}
|
|
|
252
528
|
export default new APP();
|
|
253
529
|
```
|
|
254
530
|
|
|
255
|
-
#### 使用
|
|
531
|
+
#### 使用 RedisClient
|
|
256
532
|
|
|
257
533
|
```typescript
|
|
258
534
|
import { Service, Autowired } from "@fastcar/core/annotation";
|
|
@@ -274,6 +550,28 @@ class CacheService {
|
|
|
274
550
|
async del(key: string) {
|
|
275
551
|
await this.redis.del(key);
|
|
276
552
|
}
|
|
553
|
+
|
|
554
|
+
async expire(key: string, seconds: number) {
|
|
555
|
+
await this.redis.expire(key, seconds);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Hash 操作
|
|
559
|
+
async hset(key: string, field: string, value: string) {
|
|
560
|
+
await this.redis.hset(key, field, value);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
async hget(key: string, field: string) {
|
|
564
|
+
return this.redis.hget(key, field);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// List 操作
|
|
568
|
+
async lpush(key: string, value: string) {
|
|
569
|
+
await this.redis.lpush(key, value);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
async rpop(key: string) {
|
|
573
|
+
return this.redis.rpop(key);
|
|
574
|
+
}
|
|
277
575
|
}
|
|
278
576
|
```
|
|
279
577
|
|
|
@@ -329,6 +627,10 @@ mysql:
|
|
|
329
627
|
database: mydb
|
|
330
628
|
username: root
|
|
331
629
|
password: password
|
|
630
|
+
# 连接池配置
|
|
631
|
+
connectionLimit: 10
|
|
632
|
+
# 是否使用预处理语句
|
|
633
|
+
useServerPrepStmts: true
|
|
332
634
|
|
|
333
635
|
pgsql:
|
|
334
636
|
host: localhost
|
|
@@ -372,3 +674,11 @@ npm i @fastcar/core @fastcar/mysql @fastcar/redis
|
|
|
372
674
|
# 4. 启动应用
|
|
373
675
|
npm run debug
|
|
374
676
|
```
|
|
677
|
+
|
|
678
|
+
## 注意事项
|
|
679
|
+
|
|
680
|
+
1. **排序必须使用 OrderEnum**:`orders: { createdAt: OrderEnum.desc }`,不能使用字符串 `"DESC"`
|
|
681
|
+
2. **主键查询**:`selectByPrimaryKey` 和 `updateByPrimaryKey` 需要传入包含主键字段的对象
|
|
682
|
+
3. **时间范围查询**:使用 `$gte` 和 `$lte` 运算符
|
|
683
|
+
4. **批量插入**:`saveList` 会自动分批处理(每批1000条)
|
|
684
|
+
5. **软删除**:建议使用 `update` 方法更新 `delStatus` 字段,而不是物理删除
|