Skip to content
quarry Artifact [fe9917d1f2]
Login

Artifact [fe9917d1f2]

Artifact fe9917d1f27216dd32f00ce3c670cca0fc68f7f74d5548012b05a341f279da7d:


// savedview.go stores named tracker reports. A saved view is a NAME for
// a URL this forge could already produce — it invents no query the
// address bar cannot say, which is why it needs no schema of its own
// beyond the name and the parameters, and why deleting one loses
// nothing but the shortcut.
package oltp

const savedViewSchema = `
CREATE TABLE IF NOT EXISTS saved_view (
	account TEXT NOT NULL,
	-- The listing this view belongs to: a repository's tracker name, or
	-- the empty string for the cross-repository listing. A report saved
	-- against one tracker means nothing on another, so the two never
	-- appear in each other's rail.
	repo    TEXT NOT NULL,
	name    TEXT NOT NULL,
	query   TEXT NOT NULL, -- the report, as a URL query string
	at      TEXT NOT NULL,
	PRIMARY KEY (account, repo, name)
);`

// SavedView is one named report.
type SavedView struct {
	Name  string `json:"name"`
	Query string `json:"query"`
}

// SaveView records a report under a name, replacing a view of the same
// name: saving twice with one name is how a reader corrects it, not an
// error and not a second entry that shadows the first.
func (d *DB) SaveView(account, repo, name, query string) error {
	_, err := d.db.Exec(`INSERT INTO saved_view (account, repo, name, query, at)
		VALUES (?, ?, ?, ?, ?)
		ON CONFLICT (account, repo, name)
		DO UPDATE SET query = excluded.query, at = excluded.at`,
		account, repo, name, query, now())
	return err
}

// DeleteView drops one. A view nobody has is not an error to remove:
// the caller asked for it to be gone and afterwards it is.
func (d *DB) DeleteView(account, repo, name string) error {
	_, err := d.db.Exec(`DELETE FROM saved_view
		WHERE account = ? AND repo = ? AND name = ?`, account, repo, name)
	return err
}

// SavedViews lists one account's views for one listing, by name — the
// order a reader put them in their own head, not by when they saved.
func (d *DB) SavedViews(account, repo string) ([]SavedView, error) {
	if account == "" {
		return nil, nil
	}
	rows, err := d.db.Query(`SELECT name, query FROM saved_view
		WHERE account = ? AND repo = ? ORDER BY lower(name)`, account, repo)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []SavedView
	for rows.Next() {
		var v SavedView
		if err := rows.Scan(&v.Name, &v.Query); err != nil {
			return nil, err
		}
		out = append(out, v)
	}
	return out, rows.Err()
}