mirror of
https://github.com/certd/certd.git
synced 2026-06-10 18:57:33 +08:00
refactor(backend): 统一使用buildUserProjectQuery处理用户和项目查询条件
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
- 无事务链路需求的普通查询、纯函数和简单私有方法继续使用明确参数。
|
||||
- service 内部需要根据事务上下文选择 Repository 时,优先使用 `BaseService.getRepo(ctx, EntityClass)`;不要在业务方法里反复写 `ctx.manager?.getRepository(Entity) || this.xxxRepository`。
|
||||
- 拿到 repo 后 save/update/delete/find 都能做,不需要再包一层 `saveEntity` 之类的单一用途方法。
|
||||
- service 拼接用户与项目范围查询条件时,优先使用 `BaseService.buildUserProjectQuery(userId, projectId)`;不要直接写 `{ userId, projectId }`,否则 `projectId` 为空时可能把 `null`/`undefined` 带入 TypeORM 条件,导致查询或 update 不符合预期。
|
||||
- `ctx` 类型统一从 `BaseService` 导出的 `ServiceContext` 复用,不要在每个 service 里重复定义。
|
||||
- 需要“有事务则复用、无事务则开启”时,使用 `BaseService.transactionWithCtx(ctx, callback)`:`ctx.manager` 存在则直接执行 callback,否则自动 `this.transaction()`。不要在业务代码里手写 `if (ctx.manager) { ... } else { await this.transaction(...) }`。
|
||||
- 新增方法注意不要与 `BaseService` 基类方法签名冲突,例如 `delete(id)` vs `BaseService.delete(ids, where?)`,ts-node 下会直接 TS2416 编译报错。冲突时改用具体名称如 `deleteById`。
|
||||
|
||||
@@ -47,6 +47,7 @@ Certd 是支持私有化部署的 SSL/TLS 证书自动化管理平台,提供 W
|
||||
- 不要把 `packages/ui/certd-server/data/`、`logs/`、生成的 metadata/dist 等运行时或构建产物纳入改动,除非任务明确要求。
|
||||
- 做数据库结构变更时,添加或更新迁移脚本,不要依赖 TypeORM 自动同步。
|
||||
- 做插件相关任务时,先读取对应 `.trae/skills/<skill>/SKILL.md`,再进入具体实现。
|
||||
- 后端 service 拼接可选 `projectId` 查询条件时,不要直接写 `{ userId, projectId }`;应使用 `BaseService.buildUserProjectQuery(userId, projectId)`,只有 `projectId != null` 时才加入查询条件。
|
||||
|
||||
## 工作方式
|
||||
|
||||
|
||||
@@ -56,6 +56,16 @@ export abstract class BaseService<T> {
|
||||
return dataSource.getRepository(entity);
|
||||
}
|
||||
|
||||
protected buildUserProjectQuery(userId: number, projectId?: number) {
|
||||
const query: { userId: number; projectId?: number } = {
|
||||
userId,
|
||||
};
|
||||
if (projectId != null) {
|
||||
query.projectId = projectId;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得单个ID
|
||||
* @param id ID
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"sourceMap": false,
|
||||
"inlineSourceMap": false
|
||||
"inlineSourceMap": false,
|
||||
"declarationMap": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ const development = {
|
||||
type: "better-sqlite3",
|
||||
database: "./data/db.sqlite",
|
||||
synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true
|
||||
logging: false,
|
||||
logging: true,
|
||||
highlightSql: false,
|
||||
|
||||
// 配置实体模型 或者 entities: '/entity',
|
||||
|
||||
@@ -134,5 +134,6 @@ export class MainConfiguration {
|
||||
});
|
||||
|
||||
logger.info("当前环境:", this.app.getEnv()); // prod
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -3,6 +3,7 @@ import { CertApplyTemplateService } from "./cert-apply-template-service.js";
|
||||
|
||||
function createService(list: any[]) {
|
||||
const service = new CertApplyTemplateService();
|
||||
const updateWhereList: any[] = [];
|
||||
function matchesWhere(item: any, where: any) {
|
||||
for (const key of Object.keys(where)) {
|
||||
const expected = where[key];
|
||||
@@ -23,6 +24,7 @@ function createService(list: any[]) {
|
||||
return list.find(item => matchesWhere(item, where));
|
||||
},
|
||||
async update(where: any, patch: any) {
|
||||
updateWhereList.push({ ...where });
|
||||
for (const item of list) {
|
||||
if (matchesWhere(item, where)) {
|
||||
Object.assign(item, patch);
|
||||
@@ -30,6 +32,7 @@ function createService(list: any[]) {
|
||||
}
|
||||
},
|
||||
};
|
||||
(service as any).updateWhereList = updateWhereList;
|
||||
return service;
|
||||
}
|
||||
|
||||
@@ -158,7 +161,7 @@ describe("CertApplyTemplateService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("sets default for templates with null project id", async () => {
|
||||
it("does not include project id condition when setting default without project id", async () => {
|
||||
const list = [
|
||||
{
|
||||
id: 1,
|
||||
@@ -189,8 +192,12 @@ describe("CertApplyTemplateService", () => {
|
||||
|
||||
await service.setDefault(2, 10, null);
|
||||
|
||||
assert.deepEqual((service as any).updateWhereList, [
|
||||
{ userId: 10 },
|
||||
{ userId: 10, id: 2 },
|
||||
]);
|
||||
assert.equal(list[0].isDefault, false);
|
||||
assert.equal(list[1].isDefault, true);
|
||||
assert.equal(list[2].isDefault, true);
|
||||
assert.equal(list[2].isDefault, false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,16 +47,16 @@ export class CertApplyTemplateService extends BaseService<CertApplyTemplateEntit
|
||||
if (entity.disabled) {
|
||||
throw new ValidateException("禁用的模版不能设为默认");
|
||||
}
|
||||
await this.repository.update({ userId, projectId }, { isDefault: false });
|
||||
await this.repository.update({ id: entity.id, userId, projectId }, { isDefault: true });
|
||||
const query = this.buildUserProjectQuery(userId, projectId);
|
||||
await this.repository.update(query, { isDefault: false });
|
||||
await this.repository.update({ ...query, id: entity.id }, { isDefault: true });
|
||||
return entity;
|
||||
}
|
||||
|
||||
async getDefault(userId: number, projectId?: number) {
|
||||
return await this.repository.findOne({
|
||||
where: {
|
||||
userId,
|
||||
projectId,
|
||||
...this.buildUserProjectQuery(userId, projectId),
|
||||
isDefault: true,
|
||||
disabled: false,
|
||||
},
|
||||
@@ -87,8 +87,7 @@ export class CertApplyTemplateService extends BaseService<CertApplyTemplateEntit
|
||||
const template = await this.repository.findOne({
|
||||
where: {
|
||||
id,
|
||||
userId,
|
||||
projectId,
|
||||
...this.buildUserProjectQuery(userId, projectId),
|
||||
},
|
||||
});
|
||||
if (!template) {
|
||||
|
||||
Reference in New Issue
Block a user