Files
tutti/services/tuttid/data/workspace/sqlite_issue_batch_create.go
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

83 lines
2.7 KiB
Go

package workspace
import (
"context"
"database/sql"
"errors"
"fmt"
workspaceissues "github.com/tutti-os/tutti/packages/workspace/issues"
)
// CreateIssueWithTasks commits the Plan-derived Issue, its initial task graph,
// and topic activity together. Event publication happens above this store
// boundary only after this transaction returns successfully.
func (s *SQLiteStore) CreateIssueWithTasks(
ctx context.Context,
issue workspaceissues.Issue,
tasks []workspaceissues.Task,
) (workspaceissues.Issue, []workspaceissues.Task, error) {
if err := s.ensureIssueDatabase(); err != nil {
return workspaceissues.Issue{}, nil, err
}
if err := s.ensureIssueWorkspace(ctx, issue.WorkspaceID); err != nil {
return workspaceissues.Issue{}, nil, err
}
if len(tasks) == 0 {
return workspaceissues.Issue{}, nil, workspaceissues.ErrInvalidArgument
}
tx, err := s.writeDB.BeginTx(ctx, nil)
if err != nil {
return workspaceissues.Issue{}, nil, fmt.Errorf("begin create workspace issue with tasks: %w", err)
}
defer func() {
_ = tx.Rollback()
}()
var topicExists int
err = tx.QueryRowContext(ctx, `
SELECT 1
FROM workspace_issue_topics
WHERE workspace_id = ? AND topic_id = ?
`, issue.WorkspaceID, issue.TopicID).Scan(&topicExists)
if errors.Is(err, sql.ErrNoRows) {
return workspaceissues.Issue{}, nil, workspaceissues.ErrTopicNotFound
}
if err != nil {
return workspaceissues.Issue{}, nil, fmt.Errorf("get workspace issue topic for batch create: %w", err)
}
createdIssue, err := insertWorkspaceIssue(ctx, tx, issue)
if err != nil {
return workspaceissues.Issue{}, nil, err
}
createdTasks := make([]workspaceissues.Task, 0, len(tasks))
for index, task := range tasks {
if task.WorkspaceID != issue.WorkspaceID || task.IssueID != issue.IssueID {
return workspaceissues.Issue{}, nil, workspaceissues.ErrInvalidArgument
}
task.SortIndex = index + 1
createdTask, err := insertWorkspaceIssueTask(ctx, tx, task)
if err != nil {
return workspaceissues.Issue{}, nil, err
}
createdTasks = append(createdTasks, createdTask)
}
result, err := tx.ExecContext(ctx, `
UPDATE workspace_issue_topics
SET last_activity_at_unix_ms = ?
WHERE workspace_id = ? AND topic_id = ?
`, issue.UpdatedAtUnixMS, issue.WorkspaceID, issue.TopicID)
if err != nil {
return workspaceissues.Issue{}, nil, fmt.Errorf("touch workspace issue topic activity during batch create: %w", err)
}
if err := requireRowsAffected(result, workspaceissues.ErrTopicNotFound, "touch workspace issue topic activity during batch create"); err != nil {
return workspaceissues.Issue{}, nil, err
}
if err := tx.Commit(); err != nil {
return workspaceissues.Issue{}, nil, fmt.Errorf("commit create workspace issue with tasks: %w", err)
}
return createdIssue, createdTasks, nil
}