Add new WHERE feature to my funny orm
This commit is contained in:
		
							parent
							
								
									28abdac5b6
								
							
						
					
					
						commit
						475cd5b724
					
				
					 30 changed files with 149 additions and 105 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}">`
 | 
			
		||||
			})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue