2023-03-15 14:09:09 +00:00
import { commands , messageCommands , disabledCache , disabledCmdCache , prefixCache } from "../collections.js" ;
import sqlite3 from "better-sqlite3" ;
const connection = sqlite3 ( process . env . DB . replace ( "sqlite://" , "" ) ) ;
const schema = `
2023-03-17 05:19:50 +00:00
CREATE TABLE channels (
2023-03-15 14:09:09 +00:00
guild _id VARCHAR ( 30 ) NOT NULL PRIMARY KEY ,
prefix VARCHAR ( 15 ) NOT NULL ,
disabled text NOT NULL ,
disabled _commands text NOT NULL
) ;
CREATE TABLE counts (
command VARCHAR NOT NULL PRIMARY KEY ,
count integer NOT NULL
) ;
CREATE TABLE tags (
guild _id VARCHAR ( 30 ) NOT NULL ,
name text NOT NULL ,
content text NOT NULL ,
author VARCHAR ( 30 ) NOT NULL ,
UNIQUE ( guild _id , name )
) ;
CREATE TABLE settings (
id smallint PRIMARY KEY ,
broadcast VARCHAR ,
CHECK ( id = 1 )
) ;
INSERT INTO settings ( id ) VALUES ( 1 ) ;
` ;
const updates = [
"" , // reserved
2023-03-17 05:19:50 +00:00
"ALTER TABLE channels ADD COLUMN accessed int" ,
"ALTER TABLE channels DROP COLUMN accessed" ,
2023-03-15 14:09:09 +00:00
` CREATE TABLE settings (
id smallint PRIMARY KEY ,
broadcast VARCHAR ,
CHECK ( id = 1 )
) ;
INSERT INTO settings ( id ) VALUES ( 1 ) ; ` ,
] ;
export async function setup ( ) {
const existingCommands = connection . prepare ( "SELECT command FROM counts" ) . all ( ) . map ( x => x . command ) ;
const commandNames = [ ... commands . keys ( ) , ... messageCommands . keys ( ) ] ;
for ( const command of existingCommands ) {
if ( ! commandNames . includes ( command ) ) {
connection . prepare ( "DELETE FROM counts WHERE command = ?" ) . run ( command ) ;
}
}
for ( const command of commandNames ) {
if ( ! existingCommands . includes ( command ) ) {
connection . prepare ( "INSERT INTO counts (command, count) VALUES (?, ?)" ) . run ( command , 0 ) ;
}
}
}
export async function stop ( ) {
connection . close ( ) ;
}
export async function upgrade ( logger ) {
connection . exec ( "BEGIN TRANSACTION" ) ;
try {
let version = connection . pragma ( "user_version" , { simple : true } ) ;
const latestVersion = updates . length - 1 ;
if ( version == 0 ) {
logger . info ( "Initializing SQLite database..." ) ;
connection . exec ( schema ) ;
} else if ( version < latestVersion ) {
logger . info ( ` Migrating SQLite database at ${ process . env . DB } , which is currently at version ${ version } ... ` ) ;
while ( version < latestVersion ) {
version ++ ;
logger . info ( ` Running version ${ version } update script... ` ) ;
connection . exec ( updates [ version ] ) ;
}
} else if ( version > latestVersion ) {
throw new Error ( ` SQLite database is at version ${ version } , but this version of the bot only supports up to version ${ latestVersion } . ` ) ;
} else {
return ;
}
connection . pragma ( ` user_version = ${ latestVersion } ` ) ; // prepared statements don't seem to work here
} catch ( e ) {
logger . error ( ` SQLite migration failed: ${ e } ` ) ;
connection . exec ( "ROLLBACK" ) ;
logger . error ( "Unable to start the bot, quitting now." ) ;
return 1 ;
}
connection . exec ( "COMMIT" ) ;
}
export async function addCount ( command ) {
connection . prepare ( "UPDATE counts SET count = count + 1 WHERE command = ?" ) . run ( command ) ;
}
export async function getCounts ( ) {
const counts = connection . prepare ( "SELECT * FROM counts" ) . all ( ) ;
const countObject = { } ;
for ( const { command , count } of counts ) {
countObject [ command ] = count ;
}
return countObject ;
}
2023-03-17 05:19:50 +00:00
export async function disableCommand ( channel , command ) {
const channelDB = await this . getGuild ( channel ) ;
connection . prepare ( "UPDATE channels SET disabled_commands = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( ( channelDB . disabledCommands ? [ ... JSON . parse ( channelDB . disabledCommands ) , command ] : [ command ] ) . filter ( ( v ) => ! ! v ) ) , channel ) ;
disabledCmdCache . set ( channel , channelDB . disabled _commands ? [ ... JSON . parse ( channelDB . disabledCommands ) , command ] : [ command ] . filter ( ( v ) => ! ! v ) ) ;
2023-03-15 14:09:09 +00:00
}
2023-03-17 05:19:50 +00:00
export async function enableCommand ( channel , command ) {
const channelDB = await this . getGuild ( channel ) ;
const newDisabled = channelDB . disabledCommands ? JSON . parse ( channelDB . disabledCommands ) . filter ( item => item !== command ) : [ ] ;
connection . prepare ( "UPDATE channels SET disabled_commands = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( newDisabled ) , channel ) ;
disabledCmdCache . set ( channel , newDisabled ) ;
2023-03-15 14:09:09 +00:00
}
export async function disableChannel ( channel ) {
2023-03-17 05:19:50 +00:00
const channelDB = await this . getGuild ( channel . channelID ) ;
connection . prepare ( "UPDATE channels SET disabled = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( [ ... JSON . parse ( channelDB . disabled ) , channel ] ) , channel . channelID ) ;
disabledCache . set ( channel . channelID , [ ... JSON . parse ( channelDB . disabled ) , channel ] ) ;
2023-03-15 14:09:09 +00:00
}
export async function enableChannel ( channel ) {
2023-03-17 05:19:50 +00:00
const channelDB = await this . getGuild ( channel . channelID ) ;
const newDisabled = JSON . parse ( channelDB . disabled ) . filter ( item => item !== channel ) ;
connection . prepare ( "UPDATE channels SET disabled = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( newDisabled ) , channel . channelID ) ;
disabledCache . set ( channel . channelID , newDisabled ) ;
2023-03-15 14:09:09 +00:00
}
2023-03-17 05:19:50 +00:00
export async function getTag ( channel , tag ) {
const tagResult = connection . prepare ( "SELECT * FROM tags WHERE guild_id = ? AND name = ?" ) . get ( channel , tag ) ;
2023-03-15 14:09:09 +00:00
return tagResult ? { content : tagResult . content , author : tagResult . author } : undefined ;
}
2023-03-17 05:19:50 +00:00
export async function getTags ( channel ) {
const tagArray = connection . prepare ( "SELECT * FROM tags WHERE guild_id = ?" ) . all ( channel ) ;
2023-03-15 14:09:09 +00:00
const tags = { } ;
if ( ! tagArray ) return [ ] ;
for ( const tag of tagArray ) {
tags [ tag . name ] = { content : tag . content , author : tag . author } ;
}
return tags ;
}
2023-03-17 05:19:50 +00:00
export async function setTag ( name , content , channel ) {
2023-03-15 14:09:09 +00:00
const tag = {
2023-03-17 05:19:50 +00:00
id : channel ,
2023-03-15 14:09:09 +00:00
name : name ,
content : content . content ,
author : content . author
} ;
connection . prepare ( "INSERT INTO tags (guild_id, name, content, author) VALUES (@id, @name, @content, @author)" ) . run ( tag ) ;
}
2023-03-17 05:19:50 +00:00
export async function removeTag ( name , channel ) {
connection . prepare ( "DELETE FROM tags WHERE guild_id = ? AND name = ?" ) . run ( channel , name ) ;
2023-03-15 14:09:09 +00:00
}
2023-03-17 05:19:50 +00:00
export async function editTag ( name , content , channel ) {
connection . prepare ( "UPDATE tags SET content = ?, author = ? WHERE guild_id = ? AND name = ?" ) . run ( content . content , content . author , channel , name ) ;
2023-03-15 14:09:09 +00:00
}
export async function setBroadcast ( msg ) {
connection . prepare ( "UPDATE settings SET broadcast = ? WHERE id = 1" ) . run ( msg ) ;
}
export async function getBroadcast ( ) {
const result = connection . prepare ( "SELECT broadcast FROM settings WHERE id = 1" ) . all ( ) ;
return result [ 0 ] . broadcast ;
}
2023-03-17 05:19:50 +00:00
export async function setPrefix ( prefix , channel ) {
connection . prepare ( "UPDATE channels SET prefix = ? WHERE guild_id = ?" ) . run ( prefix , channel ) ;
prefixCache . set ( channel , prefix ) ;
2023-03-15 14:09:09 +00:00
}
export async function getGuild ( query ) {
2023-03-17 05:19:50 +00:00
let channel ;
2023-03-15 14:09:09 +00:00
connection . transaction ( ( ) => {
2023-03-17 05:19:50 +00:00
channel = connection . prepare ( "SELECT * FROM channels WHERE guild_id = ?" ) . get ( query ) ;
if ( ! channel ) {
channel = {
2023-03-15 14:09:09 +00:00
id : query ,
prefix : process . env . PREFIX ,
disabled : "[]" ,
disabledCommands : "[]"
} ;
2023-03-17 05:19:50 +00:00
connection . prepare ( "INSERT INTO channels (guild_id, prefix, disabled, disabled_commands) VALUES (@id, @prefix, @disabled, @disabledCommands)" ) . run ( channel ) ;
2023-03-15 14:09:09 +00:00
}
} ) ( ) ;
2023-03-17 05:19:50 +00:00
return channel ;
2023-03-15 14:09:09 +00:00
}