Merge emoji and discord_file tables

Also fix duplicate reaction when reacting with custom emoji from Matrix
This commit is contained in:
Tulir Asokan
2023-01-30 01:35:17 +02:00
parent e183f5cffa
commit 466139164c
9 changed files with 114 additions and 235 deletions

View File

@@ -21,7 +21,6 @@ type Database struct {
Message *MessageQuery
Thread *ThreadQuery
Reaction *ReactionQuery
Emoji *EmojiQuery
Guild *GuildQuery
Role *RoleQuery
File *FileQuery
@@ -54,10 +53,6 @@ func New(baseDB *dbutil.Database, log maulogger.Logger) *Database {
db: db,
log: log.Sub("Reaction"),
}
db.Emoji = &EmojiQuery{
db: db,
log: log.Sub("Emoji"),
}
db.Guild = &GuildQuery{
db: db,
log: log.Sub("Guild"),

View File

@@ -1,99 +0,0 @@
package database
import (
"database/sql"
"errors"
log "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix/id"
"maunium.net/go/mautrix/util/dbutil"
)
type EmojiQuery struct {
db *Database
log log.Logger
}
const (
emojiSelect = "SELECT discord_id, discord_name, matrix_url FROM emoji"
)
func (eq *EmojiQuery) New() *Emoji {
return &Emoji{
db: eq.db,
log: eq.log,
}
}
func (eq *EmojiQuery) GetByDiscordID(discordID string) *Emoji {
query := emojiSelect + " WHERE discord_id=$1"
return eq.get(query, discordID)
}
func (eq *EmojiQuery) GetByMatrixURL(matrixURL id.ContentURI) *Emoji {
query := emojiSelect + " WHERE matrix_url=$1"
return eq.get(query, matrixURL.String())
}
func (eq *EmojiQuery) get(query string, args ...interface{}) *Emoji {
return eq.New().Scan(eq.db.QueryRow(query, args...))
}
type Emoji struct {
db *Database
log log.Logger
DiscordID string
DiscordName string
MatrixURL id.ContentURI
}
func (e *Emoji) Scan(row dbutil.Scannable) *Emoji {
var matrixURL sql.NullString
err := row.Scan(&e.DiscordID, &e.DiscordName, &matrixURL)
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
e.log.Errorln("Database scan failed:", err)
panic(err)
}
return nil
}
e.MatrixURL, _ = id.ParseContentURI(matrixURL.String)
return e
}
func (e *Emoji) Insert() {
query := "INSERT INTO emoji" +
" (discord_id, discord_name, matrix_url)" +
" VALUES ($1, $2, $3);"
_, err := e.db.Exec(query, e.DiscordID, e.DiscordName, e.MatrixURL.String())
if err != nil {
e.log.Warnfln("Failed to insert emoji %s: %v", e.DiscordID, err)
panic(err)
}
}
func (e *Emoji) Delete() {
query := "DELETE FROM emoji WHERE discord_id=$1"
_, err := e.db.Exec(query, e.DiscordID)
if err != nil {
e.log.Warnfln("Failed to delete emoji %s: %v", e.DiscordID, err)
panic(err)
}
}
func (e *Emoji) APIName() string {
if e.DiscordID != "" && e.DiscordName != "" {
return e.DiscordName + ":" + e.DiscordID
} else if e.DiscordName != "" {
return e.DiscordName
}
return e.DiscordID
}

View File

@@ -20,10 +20,10 @@ type FileQuery struct {
// language=postgresql
const (
fileSelect = "SELECT url, encrypted, id, mxc, size, width, height, mime_type, decryption_info, timestamp FROM discord_file"
fileSelect = "SELECT url, encrypted, mxc, id, emoji_name, size, width, height, mime_type, decryption_info, timestamp FROM discord_file"
fileInsert = `
INSERT INTO discord_file (url, encrypted, id, mxc, size, width, height, mime_type, decryption_info, timestamp)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
INSERT INTO discord_file (url, encrypted, mxc, id, emoji_name, size, width, height, mime_type, decryption_info, timestamp)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
`
)
@@ -39,15 +39,21 @@ func (fq *FileQuery) Get(url string, encrypted bool) *File {
return fq.New().Scan(fq.db.QueryRow(query, url, encrypted))
}
func (fq *FileQuery) GetByMXC(mxc id.ContentURI) *File {
query := fileSelect + " WHERE mxc=$1"
return fq.New().Scan(fq.db.QueryRow(query, mxc.String()))
}
type File struct {
db *Database
log log.Logger
URL string
Encrypted bool
MXC id.ContentURI
ID string
MXC id.ContentURI
ID string
EmojiName string
Size int
Width int
@@ -55,16 +61,15 @@ type File struct {
MimeType string
DecryptionInfo *attachment.EncryptedFile
Timestamp time.Time
Timestamp time.Time
}
func (f *File) Scan(row dbutil.Scannable) *File {
var fileID, decryptionInfo sql.NullString
var fileID, emojiName, decryptionInfo sql.NullString
var width, height sql.NullInt32
var timestamp int64
var mxc string
err := row.Scan(&f.URL, &f.Encrypted, &fileID, &mxc, &f.Size, &width, &height, &f.MimeType, &decryptionInfo, &timestamp)
err := row.Scan(&f.URL, &f.Encrypted, &mxc, &fileID, &emojiName, &f.Size, &width, &height, &f.MimeType, &decryptionInfo, &timestamp)
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
f.log.Errorln("Database scan failed:", err)
@@ -73,6 +78,7 @@ func (f *File) Scan(row dbutil.Scannable) *File {
return nil
}
f.ID = fileID.String
f.EmojiName = emojiName.String
f.Timestamp = time.UnixMilli(timestamp)
f.Width = int(width.Int32)
f.Height = int(height.Int32)
@@ -114,7 +120,7 @@ func (f *File) Insert(txn dbutil.Execable) {
decryptionInfoStr.String = string(decryptionInfo)
}
_, err := txn.Exec(fileInsert,
f.URL, f.Encrypted, strPtr(f.ID), f.MXC.String(), f.Size,
f.URL, f.Encrypted, f.MXC.String(), strPtr(f.ID), strPtr(f.EmojiName), f.Size,
positiveIntToNullInt32(f.Width), positiveIntToNullInt32(f.Height), f.MimeType,
decryptionInfoStr, f.Timestamp.UnixMilli(),
)

View File

@@ -1,4 +1,4 @@
-- v0 -> v12: Latest revision
-- v0 -> v13: Latest revision
CREATE TABLE guild (
dcid TEXT PRIMARY KEY,
@@ -126,12 +126,6 @@ CREATE TABLE reaction (
CONSTRAINT reaction_message_fkey FOREIGN KEY (dc_msg_id, dc_first_attachment_id, _dc_first_edit_index, dc_chan_id, dc_chan_receiver) REFERENCES message (dcid, dc_attachment_id, dc_edit_index, dc_chan_id, dc_chan_receiver) ON DELETE CASCADE
);
CREATE TABLE emoji (
discord_id TEXT PRIMARY KEY,
discord_name TEXT,
matrix_url TEXT
);
CREATE TABLE role (
dc_guild_id TEXT,
dcid TEXT,
@@ -151,21 +145,20 @@ CREATE TABLE role (
CONSTRAINT role_guild_fkey FOREIGN KEY (dc_guild_id) REFERENCES guild (dcid) ON DELETE CASCADE
);
CREATE TABLE discord_file (
CREATE TABLE new_discord_file (
url TEXT,
encrypted BOOLEAN,
mxc TEXT NOT NULL UNIQUE,
id TEXT,
mxc TEXT NOT NULL,
size BIGINT NOT NULL,
width INTEGER,
height INTEGER,
mime_type TEXT NOT NULL,
id TEXT,
emoji_name TEXT,
size BIGINT NOT NULL,
width INTEGER,
height INTEGER,
mime_type TEXT NOT NULL,
decryption_info jsonb,
timestamp BIGINT NOT NULL,
timestamp BIGINT NOT NULL,
PRIMARY KEY (url, encrypted)
);

View File

@@ -0,0 +1,4 @@
-- v13: Merge tables used for cached custom emojis and attachments
ALTER TABLE discord_file ADD CONSTRAINT mxc_unique UNIQUE (mxc);
ALTER TABLE discord_file ADD COLUMN emoji_name TEXT;
DROP TABLE emoji;

View File

@@ -0,0 +1,24 @@
-- v13: Merge tables used for cached custom emojis and attachments
CREATE TABLE new_discord_file (
url TEXT,
encrypted BOOLEAN,
mxc TEXT NOT NULL UNIQUE,
id TEXT,
emoji_name TEXT,
size BIGINT NOT NULL,
width INTEGER,
height INTEGER,
mime_type TEXT NOT NULL,
decryption_info jsonb,
timestamp BIGINT NOT NULL,
PRIMARY KEY (url, encrypted)
);
INSERT INTO new_discord_file (url, encrypted, id, mxc, size, width, height, mime_type, decryption_info, timestamp)
SELECT url, encrypted, id, mxc, size, width, height, mime_type, decryption_info, timestamp FROM discord_file;
DROP TABLE discord_file;
ALTER TABLE new_discord_file RENAME TO discord_file;