package store import ( "context" "database/sql" "errors" "g.fc.run/misc/byre/internal/api" ) const previewColumns = `task_id, name, port, created_at` func (s *Store) SetPreview(ctx context.Context, p api.Preview, actor string) ([]int, error) { dropped := []int{} err := s.write(ctx, func(tx *sql.Tx, emit emitFunc) error { projectID := "" err := tx.QueryRowContext(ctx, `SELECT project_id FROM tasks WHERE id = ? AND status = ?`, p.TaskId, string(api.TaskStatusActive)).Scan(&projectID) if errors.Is(err, sql.ErrNoRows) { return ErrNotFound } if err != nil { return err } rows, err := tx.QueryContext(ctx, `DELETE FROM previews WHERE task_id = ? AND (name = ? OR port = ?) RETURNING port`, p.TaskId, p.Name, p.Port) if err != nil { return err } for rows.Next() { port := 0 err = rows.Scan(&port) if err != nil { rows.Close() return err } if port != p.Port { dropped = append(dropped, port) } } rows.Close() err = rows.Err() if err != nil { return err } _, err = tx.ExecContext(ctx, `INSERT INTO previews (`+previewColumns+`) VALUES (?, ?, ?, ?)`, p.TaskId, p.Name, p.Port, formatTime(p.CreatedAt)) if err != nil { return err } return emit(api.Event{Kind: "preview.exposed", ProjectId: &projectID, TaskId: &p.TaskId, Actor: actor, Payload: ToPayload(p)}) }) return dropped, err } func (s *Store) ListPreviews(ctx context.Context, taskID string) ([]api.Preview, error) { rows, err := s.db.QueryContext(ctx, `SELECT `+previewColumns+` FROM previews WHERE task_id = ? ORDER BY name`, taskID) if err != nil { return nil, err } defer rows.Close() previews := []api.Preview{} for rows.Next() { p := api.Preview{} createdAt := "" err = rows.Scan(&p.TaskId, &p.Name, &p.Port, &createdAt) if err != nil { return nil, err } p.CreatedAt, err = parseTime(createdAt) if err != nil { return nil, err } previews = append(previews, p) } return previews, rows.Err() }