Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions bridgev2/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Database struct {
UserPortal *UserPortalQuery
BackfillTask *BackfillTaskQuery
KV *KVQuery
Media *MediaQuery
}

type MetaMerger interface {
Expand All @@ -48,6 +49,7 @@ type MetaTypes struct {
Message MetaTypeCreator
Reaction MetaTypeCreator
UserLogin MetaTypeCreator
Media MetaTypeCreator
}

type blankMeta struct{}
Expand All @@ -74,6 +76,9 @@ func New(bridgeID networkid.BridgeID, mt MetaTypes, db *dbutil.Database) *Databa
if mt.UserLogin == nil {
mt.UserLogin = blankMetaCreator
}
if mt.Media == nil {
mt.Media = blankMetaCreator
}
db.UpgradeTable = upgrades.Table
return &Database{
Database: db,
Expand Down Expand Up @@ -141,6 +146,12 @@ func New(bridgeID networkid.BridgeID, mt MetaTypes, db *dbutil.Database) *Databa
BridgeID: bridgeID,
Database: db,
},
Media: &MediaQuery{
BridgeID: bridgeID,
QueryHelper: dbutil.MakeQueryHelper(db, func(_ *dbutil.QueryHelper[*Media]) *Media {
return &Media{}
}),
},
}
}

Expand Down
114 changes: 114 additions & 0 deletions bridgev2/database/media.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (c) 2025 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package database

import (
"context"
"database/sql"
"database/sql/driver"
"encoding/base64"
"fmt"

"go.mau.fi/util/dbutil"

"maunium.net/go/mautrix/bridgev2/networkid"
)

type MediaQuery struct {
BridgeID networkid.BridgeID
MetaType MetaTypeCreator
*dbutil.QueryHelper[*Media]
}

type Media struct {
BridgeID networkid.BridgeID
ID networkid.MediaID

Metadata any
}

var _ driver.Value = (sqlMediaID)(nil)
var _ sql.Scanner = (sqlMediaID)(nil)

type sqlMediaID networkid.MediaID

func (id sqlMediaID) Scan(src any) (err error) {
var s string
switch v := src.(type) {
case string:
s = v
case []byte:
s = string(v)
default:
return fmt.Errorf("invalid sql type for media id: %T", v)
}

id, err = base64.RawStdEncoding.DecodeString(s)
return
}

func (id sqlMediaID) Value() (driver.Value, error) {
return base64.RawStdEncoding.EncodeToString(id), nil
}

const (
getMediaQuery = `
SELECT bridge_id, id, metadata FROM media
`
insertMediaQuery = `
INSERT INTO media (
bridge_id, id, metadata
)
VALUES ($1, $2, $3)
`
updateMediaQuery = `
UPDATE media SET metadata=$3
WHERE bridge_id=$1 AND id=$2
`
deleteMediaQuery = `
DELETE FROM media WHERE bridge_id=$1 AND id=$2
`
)

func (mq *MediaQuery) GetByID(ctx context.Context, mediaID networkid.MediaID) (*Media, error) {
return mq.QueryOne(ctx, getMediaQuery, mq.BridgeID, sqlMediaID(mediaID))
}

func (mq *MediaQuery) Insert(ctx context.Context, media *Media) (err error) {
ensureBridgeIDMatches(&media.BridgeID, mq.BridgeID)
_, err = mq.GetDB().Exec(ctx, insertMediaQuery, media.ensureHasMetadata(mq.MetaType).sqlVariables()...)
return
}

func (mq *MediaQuery) Update(ctx context.Context, media *Media) error {
ensureBridgeIDMatches(&media.BridgeID, mq.BridgeID)
return mq.Exec(ctx, updateMediaQuery, media.ensureHasMetadata(mq.MetaType).sqlVariables()...)
}

func (mq *MediaQuery) Delete(ctx context.Context, mediaID networkid.MediaID) error {
return mq.Exec(ctx, deleteMediaQuery, mq.BridgeID, sqlMediaID(mediaID))
}

func (m *Media) Scan(row dbutil.Scannable) (*Media, error) {
err := row.Scan(
&m.BridgeID, (*sqlMediaID)(&m.ID), dbutil.JSON{Data: m.Metadata},
)
return m, err
}

func (m *Media) ensureHasMetadata(metaType MetaTypeCreator) *Media {
if m.Metadata == nil {
m.Metadata = metaType()
}
return m
}

func (m *Media) sqlVariables() []any {
return []any{
m.BridgeID, sqlMediaID(m.ID), dbutil.JSON{Data: m.Metadata},
}
}
8 changes: 8 additions & 0 deletions bridgev2/database/upgrades/00-latest.sql
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,11 @@ CREATE TABLE kv_store (

PRIMARY KEY (bridge_id, key)
);

CREATE TABLE media (
bridge_id TEXT NOT NULL,
id TEXT NOT NULL,
metadata jsonb NOT NULL,

PRIMARY KEY (bridge_id, id)
);
9 changes: 9 additions & 0 deletions bridgev2/database/upgrades/23-media.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- v23 (compatible with v9+): Add media table

CREATE TABLE media (
bridge_id TEXT NOT NULL,
id TEXT NOT NULL,
metadata jsonb NOT NULL,

PRIMARY KEY (bridge_id, id)
);