原型阶段

This commit is contained in:
2026-06-09 23:44:31 +08:00
parent ea1d0fb3bd
commit 01b3375395
22 changed files with 1077 additions and 27 deletions
+72
View File
@@ -50,6 +50,12 @@ type Repository interface {
UpdateIssueAssignee(ctx context.Context, id uuid.UUID, assignee *uuid.UUID) (*Issue, error)
CloseIssue(ctx context.Context, id uuid.UUID) error
ReopenIssue(ctx context.Context, id uuid.UUID) error
// Prototype
CreatePrototype(ctx context.Context, p *Prototype) (*Prototype, error)
ListPrototypesByRequirement(ctx context.Context, requirementID uuid.UUID) ([]*Prototype, error)
GetPrototypeByVersion(ctx context.Context, requirementID uuid.UUID, version int) (*Prototype, error)
GetMaxPrototypeVersion(ctx context.Context, requirementID uuid.UUID) (int, error)
}
// IsUniqueViolation 报告 err 是否为 PG 唯一约束冲突。Service 层在 Create*
@@ -491,3 +497,69 @@ func (r *pgRepo) ReopenIssue(ctx context.Context, id uuid.UUID) error {
}
return nil
}
// ===== Prototype =====
func rowToPrototype(row projectsqlc.RequirementPrototype) *Prototype {
return &Prototype{
ID: fromPgUUID(row.ID),
RequirementID: fromPgUUID(row.RequirementID),
Version: int(row.Version),
Content: row.Content,
Note: row.Note,
CreatedBy: fromPgUUID(row.CreatedBy),
CreatedAt: row.CreatedAt.Time,
}
}
func (r *pgRepo) CreatePrototype(ctx context.Context, in *Prototype) (*Prototype, error) {
row, err := r.q.CreateRequirementPrototype(ctx, projectsqlc.CreateRequirementPrototypeParams{
ID: toPgUUID(in.ID),
RequirementID: toPgUUID(in.RequirementID),
Version: int32(in.Version), //nolint:gosec // version 来自 max+1,正常区间不溢出
Content: in.Content,
Note: in.Note,
CreatedBy: toPgUUID(in.CreatedBy),
})
if err != nil {
if IsUniqueViolation(err) {
return nil, err // service 层据此重试一次
}
return nil, errs.Wrap(err, errs.CodeInternal, "create prototype")
}
return rowToPrototype(row), nil
}
func (r *pgRepo) ListPrototypesByRequirement(ctx context.Context, requirementID uuid.UUID) ([]*Prototype, error) {
rows, err := r.q.ListRequirementPrototypesByRequirement(ctx, toPgUUID(requirementID))
if err != nil {
return nil, errs.Wrap(err, errs.CodeInternal, "list prototypes by requirement")
}
out := make([]*Prototype, 0, len(rows))
for _, row := range rows {
out = append(out, rowToPrototype(row))
}
return out, nil
}
func (r *pgRepo) GetPrototypeByVersion(ctx context.Context, requirementID uuid.UUID, version int) (*Prototype, error) {
row, err := r.q.GetRequirementPrototypeByVersion(ctx, projectsqlc.GetRequirementPrototypeByVersionParams{
RequirementID: toPgUUID(requirementID),
Version: int32(version), //nolint:gosec // version 来自 service 层 int,原值即来自 DB int32
})
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, errs.New(errs.CodeNotFound, "prototype 不存在")
}
return nil, errs.Wrap(err, errs.CodeInternal, "get prototype by version")
}
return rowToPrototype(row), nil
}
func (r *pgRepo) GetMaxPrototypeVersion(ctx context.Context, requirementID uuid.UUID) (int, error) {
max, err := r.q.GetMaxRequirementPrototypeVersion(ctx, toPgUUID(requirementID))
if err != nil {
return 0, errs.Wrap(err, errs.CodeInternal, "get max prototype version")
}
return int(max), nil
}