主流程

This commit is contained in:
2026-06-10 17:53:09 +08:00
parent c6f239f424
commit b20435c027
66 changed files with 2779 additions and 1181 deletions
+50 -38
View File
@@ -51,11 +51,12 @@ type Repository interface {
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)
// Artifact
CreateArtifact(ctx context.Context, a *Artifact) (*Artifact, error)
// ListArtifactsByRequirement 的 phase 传零值("")表示不过滤阶段。
ListArtifactsByRequirement(ctx context.Context, requirementID uuid.UUID, phase Phase) ([]*Artifact, error)
GetArtifactByVersion(ctx context.Context, requirementID uuid.UUID, phase Phase, version int) (*Artifact, error)
GetMaxArtifactVersion(ctx context.Context, requirementID uuid.UUID, phase Phase) (int, error)
}
// IsUniqueViolation 报告 err 是否为 PG 唯一约束冲突。Service 层在 Create*
@@ -498,68 +499,79 @@ func (r *pgRepo) ReopenIssue(ctx context.Context, id uuid.UUID) error {
return nil
}
// ===== Prototype =====
// ===== Artifact =====
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 rowToArtifact(row projectsqlc.RequirementArtifact) *Artifact {
return &Artifact{
ID: fromPgUUID(row.ID),
RequirementID: fromPgUUID(row.RequirementID),
Phase: Phase(row.Phase),
Version: int(row.Version),
Content: row.Content,
Note: row.Note,
SourceMessageID: row.SourceMessageID,
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),
func (r *pgRepo) CreateArtifact(ctx context.Context, in *Artifact) (*Artifact, error) {
row, err := r.q.CreateRequirementArtifact(ctx, projectsqlc.CreateRequirementArtifactParams{
ID: toPgUUID(in.ID),
RequirementID: toPgUUID(in.RequirementID),
Phase: string(in.Phase),
Version: int32(in.Version), //nolint:gosec // version 来自 max+1,正常区间不溢出
Content: in.Content,
Note: in.Note,
SourceMessageID: in.SourceMessageID,
CreatedBy: toPgUUID(in.CreatedBy),
})
if err != nil {
if IsUniqueViolation(err) {
return nil, err // service 层据此重试一次
}
return nil, errs.Wrap(err, errs.CodeInternal, "create prototype")
return nil, errs.Wrap(err, errs.CodeInternal, "create artifact")
}
return rowToPrototype(row), nil
return rowToArtifact(row), nil
}
func (r *pgRepo) ListPrototypesByRequirement(ctx context.Context, requirementID uuid.UUID) ([]*Prototype, error) {
rows, err := r.q.ListRequirementPrototypesByRequirement(ctx, toPgUUID(requirementID))
func (r *pgRepo) ListArtifactsByRequirement(ctx context.Context, requirementID uuid.UUID, phase Phase) ([]*Artifact, error) {
rows, err := r.q.ListRequirementArtifactsByRequirement(ctx, projectsqlc.ListRequirementArtifactsByRequirementParams{
RequirementID: toPgUUID(requirementID),
Column2: string(phase),
})
if err != nil {
return nil, errs.Wrap(err, errs.CodeInternal, "list prototypes by requirement")
return nil, errs.Wrap(err, errs.CodeInternal, "list artifacts by requirement")
}
out := make([]*Prototype, 0, len(rows))
out := make([]*Artifact, 0, len(rows))
for _, row := range rows {
out = append(out, rowToPrototype(row))
out = append(out, rowToArtifact(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{
func (r *pgRepo) GetArtifactByVersion(ctx context.Context, requirementID uuid.UUID, phase Phase, version int) (*Artifact, error) {
row, err := r.q.GetRequirementArtifactByVersion(ctx, projectsqlc.GetRequirementArtifactByVersionParams{
RequirementID: toPgUUID(requirementID),
Phase: string(phase),
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.New(errs.CodeNotFound, "artifact 不存在")
}
return nil, errs.Wrap(err, errs.CodeInternal, "get prototype by version")
return nil, errs.Wrap(err, errs.CodeInternal, "get artifact by version")
}
return rowToPrototype(row), nil
return rowToArtifact(row), nil
}
func (r *pgRepo) GetMaxPrototypeVersion(ctx context.Context, requirementID uuid.UUID) (int, error) {
max, err := r.q.GetMaxRequirementPrototypeVersion(ctx, toPgUUID(requirementID))
func (r *pgRepo) GetMaxArtifactVersion(ctx context.Context, requirementID uuid.UUID, phase Phase) (int, error) {
max, err := r.q.GetMaxRequirementArtifactVersion(ctx, projectsqlc.GetMaxRequirementArtifactVersionParams{
RequirementID: toPgUUID(requirementID),
Phase: string(phase),
})
if err != nil {
return 0, errs.Wrap(err, errs.CodeInternal, "get max prototype version")
return 0, errs.Wrap(err, errs.CodeInternal, "get max artifact version")
}
return int(max), nil
}