package store import ( "context" "database/sql" "errors" "g.fc.run/misc/byre/internal/api" ) const snapshotColumns = `id, task_id, agent_session_id, n, commit_sha, tree_sha, event_seq, trigger, created_at` func (s *Store) CreateSnapshot(ctx context.Context, snap api.Snapshot, projectID string) error { return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error { _, err := tx.ExecContext(ctx, `INSERT INTO snapshots (`+snapshotColumns+`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, snap.Id, snap.TaskId, snap.AgentSessionId, snap.N, snap.CommitSha, snap.TreeSha, snap.EventSeq, string(snap.Trigger), formatTime(snap.CreatedAt)) if err != nil { return err } return emit(api.Event{ Kind: "snapshot.created", ProjectId: &projectID, TaskId: &snap.TaskId, AgentSessionId: &snap.AgentSessionId, Actor: "byre", Payload: ToPayload(snap), }) }) } func (s *Store) ListSnapshots(ctx context.Context, taskID string) ([]api.Snapshot, error) { rows, err := s.db.QueryContext(ctx, `SELECT `+snapshotColumns+` FROM snapshots WHERE task_id = ? ORDER BY n`, taskID) if err != nil { return nil, err } defer rows.Close() snaps := []api.Snapshot{} for rows.Next() { snap, err := scanSnapshot(rows) if err != nil { return nil, err } snaps = append(snaps, snap) } return snaps, rows.Err() } func (s *Store) LastSnapshot(ctx context.Context, taskID string) (api.Snapshot, error) { snap, err := scanSnapshot(s.db.QueryRowContext(ctx, `SELECT `+snapshotColumns+` FROM snapshots WHERE task_id = ? ORDER BY n DESC LIMIT 1`, taskID)) if errors.Is(err, sql.ErrNoRows) { return snap, ErrNotFound } return snap, err } func (s *Store) LastTaskSeq(ctx context.Context, taskID string) (int64, error) { seq := int64(0) err := s.db.QueryRowContext(ctx, `SELECT COALESCE(MAX(seq), 0) FROM events WHERE task_id = ?`, taskID).Scan(&seq) return seq, err } func scanSnapshot(row scanner) (api.Snapshot, error) { snap := api.Snapshot{} trigger := "" createdAt := "" err := row.Scan(&snap.Id, &snap.TaskId, &snap.AgentSessionId, &snap.N, &snap.CommitSha, &snap.TreeSha, &snap.EventSeq, &trigger, &createdAt) if err != nil { return snap, err } snap.Trigger = api.SnapshotTrigger(trigger) snap.CreatedAt, err = parseTime(createdAt) return snap, err }