Skip to content
quarry Artifact [fa2154fc23]
Login

Artifact [fa2154fc23]

Artifact fa2154fc230762ab84e3c1ad8c09a21621e87a2c3bdd4be0fae7c280407cc86d:


// chatref.go records that a chat message referenced an artifact
// (RFC 0011 §14). Chat is a window, not the DAG: these rows live and
// die with the messages they describe, which is why an artifact page
// shows their count as a window-bounded "chat" row beside the durable
// MentionRefs the index derives — the two look different because they
// ARE different, and a reader who cannot tell them apart will read a
// vanished count as data loss.
package oltp

const chatRefSchema = `
CREATE TABLE IF NOT EXISTS chat_ref (
	repo   TEXT NOT NULL,
	target TEXT NOT NULL, -- artifact hash or thread root
	seq    INTEGER NOT NULL,
	at     TEXT NOT NULL,
	PRIMARY KEY (repo, target, seq)
);
CREATE INDEX IF NOT EXISTS chat_ref_seq ON chat_ref (repo, seq);`

// RecordChatRef notes one reference, idempotently on (repo, target,
// seq): the same message replayed says the same thing, and a replay
// must never double a count.
func (d *DB) RecordChatRef(repo, target string, seq uint64, at string) error {
	if repo == "" || target == "" || seq == 0 {
		return nil
	}
	_, err := d.db.Exec(`INSERT OR IGNORE INTO chat_ref (repo, target, seq, at)
		VALUES (?, ?, ?, ?)`, repo, target, seq, at)
	return err
}

// PruneChatRefs drops rows for messages the channel window no longer
// holds. It runs on the post path rather than on a timer: the window
// only ever moves when something is posted, so a sweep with no post to
// trigger it would have nothing to do.
func (d *DB) PruneChatRefs(repo string, firstSeq uint64) error {
	if repo == "" || firstSeq == 0 {
		return nil
	}
	_, err := d.db.Exec(`DELETE FROM chat_ref WHERE repo = ? AND seq < ?`, repo, firstSeq)
	return err
}

// ChatRefs answers how often a target has been named in chat and when
// last — count, the latest message's seq (the permalink to land on),
// and its time. A target nobody has mentioned answers zero, not an
// error: "no chat about this" is an answer.
func (d *DB) ChatRefs(repo, target string) (count int, lastSeq uint64, lastAt string, err error) {
	row := d.db.QueryRow(`SELECT count(*), COALESCE(max(seq), 0),
			COALESCE((SELECT at FROM chat_ref i WHERE i.repo = o.repo AND i.target = o.target
				ORDER BY i.seq DESC LIMIT 1), '')
		FROM chat_ref o WHERE repo = ? AND target = ? GROUP BY repo, target`, repo, target)
	err = row.Scan(&count, &lastSeq, &lastAt)
	if err != nil && err.Error() == "sql: no rows in result set" {
		return 0, 0, "", nil
	}
	return count, lastSeq, lastAt, err
}