Add new WHERE feature to my funny orm

This commit is contained in:
Cadence Ember 2023-10-06 12:31:10 +13:00
parent 28abdac5b6
commit 475cd5b724
30 changed files with 149 additions and 105 deletions

View file

@ -14,9 +14,9 @@ const emoji = sync.require("../converters/emoji")
* @param {Ty.Event.Outer<Ty.Event.M_Reaction>} event
*/
async function addReaction(event) {
const channelID = select("channel_room", "channel_id", "WHERE room_id = ?").pluck().get(event.room_id)
const channelID = select("channel_room", "channel_id", {room_id: event.room_id}).pluck().get()
if (!channelID) return // We just assume the bridge has already been created
const messageID = select("event_message", "message_id", "WHERE event_id = ? AND part = 0").pluck().get(event.content["m.relates_to"].event_id) // 0 = primary
const messageID = select("event_message", "message_id", {event_id: event.content["m.relates_to"].event_id, part: 0}).pluck().get() // 0 = primary
if (!messageID) return // Nothing can be done if the parent message was never bridged.
const key = event.content["m.relates_to"].key // TODO: handle custom text or emoji reactions

View file

@ -14,7 +14,7 @@ const {discord, db, select} = passthrough
*/
async function ensureWebhook(channelID, forceCreate = false) {
if (!forceCreate) {
const row = select("webhook", ["webhook_id", "webhook_token"], "WHERE channel_id = ?").get(channelID)
const row = select("webhook", ["webhook_id", "webhook_token"], {channel_id: channelID}).get()
if (row) {
return {
id: row.webhook_id,

View file

@ -12,7 +12,7 @@ const utils = sync.require("../converters/utils")
* @param {Ty.Event.Outer_M_Room_Redaction} event
*/
async function deleteMessage(event) {
const rows = from("event_message").join("message_channel", "message_id").select("channel_id", "message_id").and("WHERE event_id = ?").all(event.redacts)
const rows = from("event_message").join("message_channel", "message_id").select("channel_id", "message_id").where({event_id: event.redacts}).all()
for (const row of rows) {
discord.snow.channel.deleteMessage(row.channel_id, row.message_id, event.content.reason)
}
@ -23,7 +23,8 @@ async function deleteMessage(event) {
*/
async function removeReaction(event) {
const hash = utils.getEventIDHash(event.redacts)
const row = from("reaction").join("message_channel", "message_id").select("channel_id", "message_id", "encoded_emoji").and("WHERE hashed_event_id = ?").get(hash)
// TODO: this works but fix the type
const row = from("reaction").join("message_channel", "message_id").select("channel_id", "message_id", "encoded_emoji").where({hashed_event_id: hash}).get()
if (!row) return
await discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji)
db.prepare("DELETE FROM reaction WHERE hashed_event_id = ?").run(hash)

View file

@ -58,7 +58,7 @@ async function resolvePendingFiles(message) {
/** @param {Ty.Event.Outer_M_Room_Message | Ty.Event.Outer_M_Room_Message_File | Ty.Event.Outer_M_Sticker} event */
async function sendEvent(event) {
const row = select("channel_room", ["channel_id", "thread_parent"], "WHERE room_id = ?").get(event.room_id)
const row = select("channel_room", ["channel_id", "thread_parent"], {room_id: event.room_id}).get()
if (!row) return // allow the bot to exist in unbridged rooms, just don't do anything with it
let channelID = row.channel_id
let threadID = undefined

View file

@ -7,19 +7,19 @@ const passthrough = require("../../passthrough")
const {sync, select} = passthrough
/**
* @param {string} emoji
* @param {string} input
* @param {string | null | undefined} shortcode
* @returns {string?}
*/
function encodeEmoji(emoji, shortcode) {
function encodeEmoji(input, shortcode) {
let discordPreferredEncoding
if (emoji.startsWith("mxc://")) {
if (input.startsWith("mxc://")) {
// Custom emoji
let row = select("emoji", ["id", "name"], "WHERE mxc_url = ?").get(emoji)
let row = select("emoji", ["emoji_id", "name"], {mxc_url: input}).get()
if (!row && shortcode) {
// Use the name to try to find a known emoji with the same name.
const name = shortcode.replace(/^:|:$/g, "")
row = select("emoji", ["id", "name"], "WHERE name = ?").get(name)
row = select("emoji", ["emoji_id", "name"], {name: name}).get()
}
if (!row) {
// We don't have this emoji and there's no realistic way to just-in-time upload a new emoji somewhere.
@ -27,11 +27,11 @@ function encodeEmoji(emoji, shortcode) {
return null
}
// Cool, we got an exact or a candidate emoji.
discordPreferredEncoding = encodeURIComponent(`${row.name}:${row.id}`)
discordPreferredEncoding = encodeURIComponent(`${row.name}:${row.emoji_id}`)
} else {
// Default emoji
// https://github.com/discord/discord-api-docs/issues/2723#issuecomment-807022205 ????????????
const encoded = encodeURIComponent(emoji)
const encoded = encodeURIComponent(input)
const encodedTrimmed = encoded.replace(/%EF%B8%8F/g, "")
const forceTrimmedList = [
@ -42,10 +42,10 @@ function encodeEmoji(emoji, shortcode) {
discordPreferredEncoding =
( forceTrimmedList.includes(encodedTrimmed) ? encodedTrimmed
: encodedTrimmed !== encoded && [...emoji].length === 2 ? encoded
: encodedTrimmed !== encoded && [...input].length === 2 ? encoded
: encodedTrimmed)
console.log("add reaction from matrix:", emoji, encoded, encodedTrimmed, "chosen:", discordPreferredEncoding)
console.log("add reaction from matrix:", input, encoded, encodedTrimmed, "chosen:", discordPreferredEncoding)
}
return discordPreferredEncoding
}

View file

@ -121,7 +121,7 @@ turndownService.addRule("emoji", {
replacement: function (content, node) {
const mxcUrl = node.getAttribute("src")
// Get the known emoji from the database. (We may not be able to actually use this if it was from another server.)
const row = select("emoji", ["id", "name", "animated"], "WHERE mxc_url = ?").get(mxcUrl)
const row = select("emoji", ["emoji_id", "name", "animated"], {mxc_url: mxcUrl}).get()
// Also guess a suitable emoji based on the ID (if available) or name
let guess = null
const guessedName = node.getAttribute("title").replace(/^:|:$/g, "")
@ -129,7 +129,7 @@ turndownService.addRule("emoji", {
/** @type {{name: string, id: string, animated: number}[]} */
// @ts-ignore
const emojis = guild.emojis
const match = emojis.find(e => e.id === row?.id) || emojis.find(e => e.name === guessedName) || emojis.find(e => e.name?.toLowerCase() === guessedName.toLowerCase())
const match = emojis.find(e => e.id === row?.emoji_id) || emojis.find(e => e.name === guessedName) || emojis.find(e => e.name?.toLowerCase() === guessedName.toLowerCase())
if (match) {
guess = match
break
@ -180,7 +180,7 @@ turndownService.addRule("fencedCodeBlock", {
* @returns {Promise<{displayname?: string?, avatar_url?: string?}>}
*/
async function getMemberFromCacheOrHomeserver(roomID, mxid, api) {
const row = select("member_cache", ["displayname", "avatar_url"], "WHERE room_id = ? AND mxid = ?").get(roomID, mxid)
const row = select("member_cache", ["displayname", "avatar_url"], {room_id: roomID, mxid}).get()
if (row) return row
return api.getStateEvent(roomID, "m.room.member", mxid).then(event => {
db.prepare("REPLACE INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES (?, ?, ?, ?)").run(roomID, mxid, event?.displayname || null, event?.avatar_url || null)
@ -285,7 +285,7 @@ async function eventToMessage(event, guild, di) {
if (relType !== "m.replace") return
const originalEventId = relatesTo.event_id
if (!originalEventId) return
messageIDsToEdit = select("event_message", "message_id", "WHERE event_id = ? ORDER BY part").pluck().all(originalEventId)
messageIDsToEdit = select("event_message", "message_id", {event_id: originalEventId}, "ORDER BY part").pluck().all()
if (!messageIDsToEdit.length) return
// Ok, it's an edit.
@ -316,7 +316,7 @@ async function eventToMessage(event, guild, di) {
if (!repliedToEventId) return
let repliedToEvent = await di.api.getEvent(event.room_id, repliedToEventId)
if (!repliedToEvent) return
const row = from("event_message").join("message_channel", "message_id").select("channel_id", "message_id").and("WHERE event_id = ? ORDER BY part").get(repliedToEventId)
const row = from("event_message").join("message_channel", "message_id").select("channel_id", "message_id").where({event_id: repliedToEventId}).and("ORDER BY part").get()
if (row) {
replyLine = `<:L1:1144820033948762203><:L2:1144820084079087647>https://discord.com/channels/${guild.id}/${row.channel_id}/${row.message_id} `
} else {
@ -324,7 +324,7 @@ async function eventToMessage(event, guild, di) {
}
const sender = repliedToEvent.sender
const senderName = sender.match(/@([^:]*)/)?.[1] || sender
const authorID = select("sim", "user_id", "WHERE mxid = ?").pluck().get(repliedToEvent.sender)
const authorID = select("sim", "user_id", {mxid: repliedToEvent.sender}).pluck().get()
if (authorID) {
replyLine += `<@${authorID}>`
} else {
@ -367,14 +367,14 @@ async function eventToMessage(event, guild, di) {
// Handling mentions of Discord users
input = input.replace(/("https:\/\/matrix.to\/#\/(@[^"]+)")>/g, (whole, attributeValue, mxid) => {
if (!utils.eventSenderIsFromDiscord(mxid)) return whole
const userID = select("sim", "user_id", "WHERE mxid = ?").pluck().get(mxid)
const userID = select("sim", "user_id", {mxid: mxid}).pluck().get()
if (!userID) return whole
return `${attributeValue} data-user-id="${userID}">`
})
// Handling mentions of Discord rooms
input = input.replace(/("https:\/\/matrix.to\/#\/(![^"]+)")>/g, (whole, attributeValue, roomID) => {
const channelID = select("channel_room", "channel_id", "WHERE room_id = ?").pluck().get(roomID)
const channelID = select("channel_room", "channel_id", {room_id: roomID}).pluck().get()
if (!channelID) return whole
return `${attributeValue} data-channel-id="${channelID}">`
})

View file

@ -1508,7 +1508,7 @@ test("event2message: caches the member if the member is not known", async t => {
}
)
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], "WHERE room_id = '!should_be_newly_cached:cadence.moe'").all(), [
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!should_be_newly_cached:cadence.moe"}).all(), [
{avatar_url: "mxc://cadence.moe/this_is_the_avatar", displayname: null, mxid: "@should_be_newly_cached:cadence.moe"}
])
t.equal(called, 1, "getStateEvent should be called once")
@ -1551,7 +1551,7 @@ test("event2message: skips caching the member if the member does not exist, some
}]
}
)
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], "WHERE room_id = '!not_real:cadence.moe'").all(), [])
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!not_real:cadence.moe"}).all(), [])
t.equal(called, 1, "getStateEvent should be called once")
})
@ -1594,7 +1594,7 @@ test("event2message: overly long usernames are shifted into the message content"
}]
}
)
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], "WHERE room_id = '!should_be_newly_cached_2:cadence.moe'").all(), [
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!should_be_newly_cached_2:cadence.moe"}).all(), [
{avatar_url: null, displayname: "I am BLACK I am WHITE I am SHORT I am LONG I am EVERYTHING YOU THINK IS IMPORTANT and I DON'T MATTER", mxid: "@should_be_newly_cached_2:cadence.moe"}
])
t.equal(called, 1, "getStateEvent should be called once")