2022-12-12 17:36:08 +00:00
import { commands , messageCommands , disabledCache , disabledCmdCache , prefixCache } from "../collections.js" ;
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
import sqlite3 from "better-sqlite3" ;
2021-07-02 04:42:12 +00:00
const connection = sqlite3 ( process . env . DB . replace ( "sqlite://" , "" ) ) ;
2022-11-26 21:31:00 +00:00
const schema = `
CREATE TABLE guilds (
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 = [
2022-02-19 05:05:41 +00:00
"" , // reserved
2022-02-22 00:55:25 +00:00
"ALTER TABLE guilds ADD COLUMN accessed int" ,
2022-10-25 17:37:55 +00:00
"ALTER TABLE guilds DROP COLUMN accessed" ,
2022-11-26 21:31:00 +00:00
` CREATE TABLE settings (
id smallint PRIMARY KEY ,
broadcast VARCHAR ,
CHECK ( id = 1 )
) ;
INSERT INTO settings ( id ) VALUES ( 1 ) ; ` ,
2022-02-19 05:05:41 +00:00
] ;
2022-02-22 00:55:25 +00:00
export async function setup ( ) {
2022-12-12 17:15:10 +00:00
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 ) ;
2021-07-02 04:42:12 +00:00
}
2022-12-12 17:36:08 +00:00
}
2022-12-12 17:15:10 +00:00
for ( const command of commandNames ) {
if ( ! existingCommands . includes ( command ) ) {
connection . prepare ( "INSERT INTO counts (command, count) VALUES (?, ?)" ) . run ( command , 0 ) ;
2021-07-02 04:42:12 +00:00
}
2022-12-12 17:36:08 +00:00
}
2022-02-22 00:55:25 +00:00
}
export async function stop ( ) {
connection . close ( ) ;
}
export async function upgrade ( logger ) {
2022-11-26 21:31:00 +00:00
connection . exec ( "BEGIN TRANSACTION" ) ;
try {
let version = connection . pragma ( "user_version" , { simple : true } ) ;
const latestVersion = updates . length - 1 ;
if ( version == 0 ) {
2022-12-12 17:36:08 +00:00
logger . info ( "Initializing SQLite database..." ) ;
2022-11-26 21:31:00 +00:00
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 ) {
2022-02-20 14:12:00 +00:00
version ++ ;
2022-11-26 21:31:00 +00:00
logger . info ( ` Running version ${ version } update script... ` ) ;
connection . exec ( updates [ version ] ) ;
2022-02-20 14:12:00 +00:00
}
2022-11-26 21:31:00 +00:00
} 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 ;
2022-02-20 14:12:00 +00:00
}
2022-11-26 21:31:00 +00:00
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 ;
2022-02-20 14:12:00 +00:00
}
2022-11-26 21:31:00 +00:00
connection . exec ( "COMMIT" ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function addCount ( command ) {
2021-07-02 04:42:12 +00:00
connection . prepare ( "UPDATE counts SET count = count + 1 WHERE command = ?" ) . run ( command ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function getCounts ( ) {
2021-07-02 04:42:12 +00:00
const counts = connection . prepare ( "SELECT * FROM counts" ) . all ( ) ;
const countObject = { } ;
for ( const { command , count } of counts ) {
countObject [ command ] = count ;
}
return countObject ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function disableCommand ( guild , command ) {
2021-08-13 03:28:09 +00:00
const guildDB = await this . getGuild ( guild ) ;
2022-01-07 17:44:18 +00:00
connection . prepare ( "UPDATE guilds SET disabled_commands = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( ( guildDB . disabledCommands ? [ ... JSON . parse ( guildDB . disabledCommands ) , command ] : [ command ] ) . filter ( ( v ) => ! ! v ) ) , guild ) ;
2022-12-12 17:36:08 +00:00
disabledCmdCache . set ( guild , guildDB . disabled _commands ? [ ... JSON . parse ( guildDB . disabledCommands ) , command ] : [ command ] . filter ( ( v ) => ! ! v ) ) ;
2021-08-19 14:19:14 +00:00
}
2021-08-13 03:28:09 +00:00
2021-08-19 14:19:14 +00:00
export async function enableCommand ( guild , command ) {
2021-08-13 03:28:09 +00:00
const guildDB = await this . getGuild ( guild ) ;
const newDisabled = guildDB . disabledCommands ? JSON . parse ( guildDB . disabledCommands ) . filter ( item => item !== command ) : [ ] ;
connection . prepare ( "UPDATE guilds SET disabled_commands = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( newDisabled ) , guild ) ;
2022-12-12 17:36:08 +00:00
disabledCmdCache . set ( guild , newDisabled ) ;
2021-08-19 14:19:14 +00:00
}
2021-08-13 03:28:09 +00:00
2021-08-19 14:19:14 +00:00
export async function disableChannel ( channel ) {
2022-09-24 03:25:16 +00:00
const guildDB = await this . getGuild ( channel . guildID ) ;
connection . prepare ( "UPDATE guilds SET disabled = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( [ ... JSON . parse ( guildDB . disabled ) , channel . id ] ) , channel . guildID ) ;
2022-12-12 17:36:08 +00:00
disabledCache . set ( channel . guildID , [ ... JSON . parse ( guildDB . disabled ) , channel . id ] ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function enableChannel ( channel ) {
2022-09-24 03:25:16 +00:00
const guildDB = await this . getGuild ( channel . guildID ) ;
2021-07-02 04:42:12 +00:00
const newDisabled = JSON . parse ( guildDB . disabled ) . filter ( item => item !== channel . id ) ;
2022-09-24 03:25:16 +00:00
connection . prepare ( "UPDATE guilds SET disabled = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( newDisabled ) , channel . guildID ) ;
2022-12-12 17:36:08 +00:00
disabledCache . set ( channel . guildID , newDisabled ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function getTag ( guild , tag ) {
2021-08-14 13:00:16 +00:00
const tagResult = connection . prepare ( "SELECT * FROM tags WHERE guild_id = ? AND name = ?" ) . get ( guild , tag ) ;
return tagResult ? { content : tagResult . content , author : tagResult . author } : undefined ;
2021-08-19 14:19:14 +00:00
}
2021-08-14 13:00:16 +00:00
2021-08-19 14:19:14 +00:00
export async function getTags ( guild ) {
2021-08-11 15:00:35 +00:00
const tagArray = connection . prepare ( "SELECT * FROM tags WHERE guild_id = ?" ) . all ( guild ) ;
const tags = { } ;
if ( ! tagArray ) return [ ] ;
for ( const tag of tagArray ) {
tags [ tag . name ] = { content : tag . content , author : tag . author } ;
}
return tags ;
2021-08-19 14:19:14 +00:00
}
2021-08-11 01:25:29 +00:00
2021-08-19 14:19:14 +00:00
export async function setTag ( name , content , guild ) {
2021-08-11 15:00:35 +00:00
const tag = {
id : guild . id ,
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 ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function removeTag ( name , guild ) {
2021-08-11 15:00:35 +00:00
connection . prepare ( "DELETE FROM tags WHERE guild_id = ? AND name = ?" ) . run ( guild . id , name ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function editTag ( name , content , guild ) {
2021-08-11 15:00:35 +00:00
connection . prepare ( "UPDATE tags SET content = ?, author = ? WHERE guild_id = ? AND name = ?" ) . run ( content . content , content . author , guild . id , name ) ;
2021-08-19 14:19:14 +00:00
}
2021-08-11 01:25:29 +00:00
2022-10-25 17:37:55 +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 ;
}
2021-08-19 14:19:14 +00:00
export async function setPrefix ( prefix , guild ) {
2021-07-02 04:42:12 +00:00
connection . prepare ( "UPDATE guilds SET prefix = ? WHERE guild_id = ?" ) . run ( prefix , guild . id ) ;
2022-12-12 17:36:08 +00:00
prefixCache . set ( guild . id , prefix ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function getGuild ( query ) {
2022-12-12 17:15:10 +00:00
let guild ;
connection . transaction ( ( ) => {
guild = connection . prepare ( "SELECT * FROM guilds WHERE guild_id = ?" ) . get ( query ) ;
if ( ! guild ) {
guild = {
id : query ,
prefix : process . env . PREFIX ,
disabled : "[]" ,
disabledCommands : "[]"
} ;
connection . prepare ( "INSERT INTO guilds (guild_id, prefix, disabled, disabled_commands) VALUES (@id, @prefix, @disabled, @disabledCommands)" ) . run ( guild ) ;
}
} ) ( ) ;
return guild ;
2021-08-19 14:19:14 +00:00
}