Skip to content
quarry Artifact [0681aba374]
Login

Artifact [0681aba374]

Artifact 0681aba3744272d3a87828a09052661b3295d9d1edc590f73b15e7353a5c439d:


package oltp

// once.go runs a data migration exactly one time per database.
//
// The additive schema changes elsewhere in this package are idempotent
// by construction (CREATE IF NOT EXISTS, ALTER guarded on "duplicate
// column"), and carryPraise is idempotent because it drops the table it
// reads. A migration that REWRITES rows is neither: run twice, it would
// undo whatever an admin changed in between. So each one is named, and
// its name is recorded the first time it runs.

const onceSchema = `
CREATE TABLE IF NOT EXISTS applied_migration (
	name TEXT PRIMARY KEY,
	at   TEXT NOT NULL
);`

// runOnce runs fn under name unless a previous open already did.
func (d *DB) runOnce(name string, fn func() error) error {
	if _, err := d.w.Exec(onceSchema); err != nil {
		return err
	}
	var one int
	if err := d.db.QueryRow(`SELECT 1 FROM applied_migration WHERE name = ?`, name).Scan(&one); err == nil {
		return nil
	}
	if err := fn(); err != nil {
		return err
	}
	_, err := d.w.Exec(`INSERT INTO applied_migration (name, at) VALUES (?, ?)`, name, now())
	return err
}

// mirrorChatOff is the one-time counterpart of SetMirror's default:
// every mirror registered before mirrors started with chat off has chat
// on, because the column defaults to 1 and nothing ever asked. A
// bridged mirror keeps it — the bridge is the syndication an admin set
// up, and it is what the channel is for.
func (d *DB) mirrorChatOff() error {
	return d.runOnce("mirror-chat-off", func() error {
		_, err := d.w.Exec(`UPDATE repo SET chat = 0
			WHERE name IN (SELECT repo FROM mirror WHERE enabled = 1)
			  AND name NOT IN (SELECT repo FROM mirror_chatbridge)`)
		return err
	})
}