Files

210 lines
5.6 KiB
Go

package sqlite
import (
"context"
"database/sql"
"fmt"
"inbox/internal/domain/lane"
)
func (s *Store) CreateLane(ctx context.Context, value lane.Record) (lane.Record, error) {
if err := value.Validate(); err != nil {
return lane.Record{}, err
}
if value.ID == "" {
id, err := s.newID("lane")
if err != nil {
return lane.Record{}, err
}
value.ID = id
}
now := s.now()
value.CreatedAt = coalesceString(value.CreatedAt, now)
value.UpdatedAt = now
if _, err := s.db.ExecContext(ctx, `
INSERT INTO lanes(
id, workspace_id, topic_id, name, slug, purpose, status, base_branch, branch_name, head_commit, worktree_path,
container_name, runtime_endpoint, created_by_role_name, result_summary_markdown, error_message,
created_at, updated_at, started_at, completed_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`,
value.ID,
value.WorkspaceID,
value.TopicID,
value.Name,
value.Slug,
value.Purpose,
string(value.Status),
value.BaseBranch,
value.BranchName,
value.HeadCommit,
value.WorktreePath,
value.ContainerName,
value.RuntimeEndpoint,
value.CreatedByRoleName,
value.ResultSummaryMarkdown,
value.ErrorMessage,
value.CreatedAt,
value.UpdatedAt,
nullableString(value.StartedAt),
nullableString(value.CompletedAt),
); err != nil {
return lane.Record{}, fmt.Errorf("create lane: %w", err)
}
return value, nil
}
func (s *Store) GetLane(ctx context.Context, laneID string) (lane.Record, error) {
row := s.db.QueryRowContext(ctx, `
SELECT id, workspace_id, topic_id, name, slug, purpose, status, base_branch, branch_name, head_commit, worktree_path,
container_name, runtime_endpoint, created_by_role_name, result_summary_markdown, error_message,
created_at, updated_at, started_at, completed_at
FROM lanes
WHERE id = ?
`, laneID)
return scanLane(row)
}
func (s *Store) ListLanesByTopic(ctx context.Context, topicID string) ([]lane.Record, error) {
rows, err := s.db.QueryContext(ctx, `
SELECT id, workspace_id, topic_id, name, slug, purpose, status, base_branch, branch_name, head_commit, worktree_path,
container_name, runtime_endpoint, created_by_role_name, result_summary_markdown, error_message,
created_at, updated_at, started_at, completed_at
FROM lanes
WHERE topic_id = ?
ORDER BY created_at, id
`, topicID)
if err != nil {
return nil, fmt.Errorf("list lanes by topic: %w", err)
}
defer rows.Close()
var out []lane.Record
for rows.Next() {
item, err := scanLane(rows)
if err != nil {
return nil, err
}
out = append(out, item)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate lanes by topic: %w", err)
}
return out, nil
}
func (s *Store) ListLanesByWorkspace(ctx context.Context, workspaceID string) ([]lane.Record, error) {
rows, err := s.db.QueryContext(ctx, `
SELECT id, workspace_id, topic_id, name, slug, purpose, status, base_branch, branch_name, head_commit, worktree_path,
container_name, runtime_endpoint, created_by_role_name, result_summary_markdown, error_message,
created_at, updated_at, started_at, completed_at
FROM lanes
WHERE workspace_id = ?
ORDER BY created_at, id
`, workspaceID)
if err != nil {
return nil, fmt.Errorf("list lanes by workspace: %w", err)
}
defer rows.Close()
var out []lane.Record
for rows.Next() {
item, err := scanLane(rows)
if err != nil {
return nil, err
}
out = append(out, item)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate lanes by workspace: %w", err)
}
return out, nil
}
func (s *Store) UpdateLane(ctx context.Context, value lane.Record) (lane.Record, error) {
if value.ID == "" {
return lane.Record{}, fmt.Errorf("lane id is required")
}
before, err := s.GetLane(ctx, value.ID)
if err != nil {
return lane.Record{}, err
}
value.CreatedAt = before.CreatedAt
value.UpdatedAt = s.now()
if err := value.Validate(); err != nil {
return lane.Record{}, err
}
if _, err := s.db.ExecContext(ctx, `
UPDATE lanes
SET workspace_id = ?, topic_id = ?, name = ?, slug = ?, purpose = ?, status = ?, base_branch = ?, branch_name = ?, head_commit = ?,
worktree_path = ?, container_name = ?, runtime_endpoint = ?, created_by_role_name = ?,
result_summary_markdown = ?, error_message = ?, updated_at = ?, started_at = ?, completed_at = ?
WHERE id = ?
`,
value.WorkspaceID,
value.TopicID,
value.Name,
value.Slug,
value.Purpose,
string(value.Status),
value.BaseBranch,
value.BranchName,
value.HeadCommit,
value.WorktreePath,
value.ContainerName,
value.RuntimeEndpoint,
value.CreatedByRoleName,
value.ResultSummaryMarkdown,
value.ErrorMessage,
value.UpdatedAt,
nullableString(value.StartedAt),
nullableString(value.CompletedAt),
value.ID,
); err != nil {
return lane.Record{}, fmt.Errorf("update lane: %w", err)
}
return s.GetLane(ctx, value.ID)
}
func scanLane(s scanner) (lane.Record, error) {
var item lane.Record
var status string
var startedAt sql.NullString
var completedAt sql.NullString
if err := s.Scan(
&item.ID,
&item.WorkspaceID,
&item.TopicID,
&item.Name,
&item.Slug,
&item.Purpose,
&status,
&item.BaseBranch,
&item.BranchName,
&item.HeadCommit,
&item.WorktreePath,
&item.ContainerName,
&item.RuntimeEndpoint,
&item.CreatedByRoleName,
&item.ResultSummaryMarkdown,
&item.ErrorMessage,
&item.CreatedAt,
&item.UpdatedAt,
&startedAt,
&completedAt,
); err != nil {
return lane.Record{}, err
}
item.Status = lane.Status(status)
if startedAt.Valid {
item.StartedAt = startedAt.String
}
if completedAt.Valid {
item.CompletedAt = completedAt.String
}
return item, nil
}