Skip to content

Commit f0e2e56

Browse files
committed
🐘 Added PostgreSQL
p.s. tested basic functionality, but can still have bugs
1 parent 1a61a4a commit f0e2e56

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ You should also change settings for database connection. Supported database back
9393
Example: `"./storage.db"`
9494
- `mongodb` - MongoDB database. Connection string should be a valid MongoDB connection string.
9595
Example: `"mongodb://127.0.0.1:27017/dbname"`
96+
- `postgres` - PostgreSQL database. Database must be created manually (tables will be created automatically). Connection string should be a valid PostgreSQL connection string.
97+
Example: `"postgres://user:password@localhost:5432/dbname"`
9698

9799
Run the bot:
98100
```

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"mongodb": "^5.7.0",
3030
"nodemon": "^3.0.1",
3131
"opusscript": "^0.1.0",
32+
"pg": "^8.11.2",
3233
"sqlite3": "^5.1.6"
3334
},
3435
"devDependencies": {

src/database/postgres.js

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
const DatabaseContext = require('../types/db_context');
2+
const { Client } = require('pg');
3+
const config = require('../../config.json');
4+
5+
module.exports = class PostgresContext extends DatabaseContext {
6+
async init() {
7+
this.logger.info('Database', '🐘 Connecting to PostgreSQL database...');
8+
this.client = new Client(this.connection_string);
9+
await this.client.connect();
10+
11+
// Create tables if they don't exist
12+
const createTable = async (name, columns) => {
13+
const res = await this.client.query(`SELECT to_regclass('${name}')`);
14+
if (!res.rows[0].to_regclass) {
15+
await this.client.query(`CREATE TABLE ${name} (${columns})`);
16+
}
17+
}
18+
19+
await createTable('guilds', 'id BIGINT PRIMARY KEY, prefix TEXT, language TEXT, xp_enabled BOOLEAN, automod_enabled BOOLEAN, welcome_channel BIGINT, welcome_msg TEXT, log_channel BIGINT');
20+
await createTable('users', 'id BIGINT, guild_id BIGINT, xp BIGINT, PRIMARY KEY (id, guild_id)');
21+
await createTable('profiles', 'id BIGINT PRIMARY KEY, description TEXT, color TEXT');
22+
await createTable('custom_commands', 'guild_id BIGINT, command_name TEXT, response TEXT, PRIMARY KEY (guild_id, command_name)');
23+
await createTable('stats', 'commands_executed BIGINT, slash_commands BIGINT');
24+
}
25+
26+
close() {
27+
this.client.end();
28+
}
29+
30+
async getGuilds() {
31+
const guilds = await this.client.query('SELECT * FROM guilds');
32+
return guilds.rows;
33+
}
34+
async getGuild(guild_id) {
35+
const guild = await this.client.query('SELECT * FROM guilds WHERE id = $1', [guild_id]);
36+
return guild.rows[0];
37+
}
38+
async createGuild(guild_id) {
39+
const guild = {
40+
id: guild_id,
41+
prefix: config.bot.prefix,
42+
language: config.default_language,
43+
xp_enabled: config.bot.xp.enabled ? 1 : 0,
44+
automod_enabled: config.bot.automod.enabled ? 1 : 0,
45+
welcome_channel: null,
46+
welcome_msg: null,
47+
log_channel: null,
48+
};
49+
50+
await this.client.query('INSERT INTO guilds (id, prefix, language, xp_enabled, automod_enabled, welcome_channel, welcome_msg, log_channel) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)', [guild.id, guild.prefix, guild.language, guild.xp_enabled, guild.automod_enabled, guild.welcome_channel, guild.welcome_msg, guild.log_channel]);
51+
52+
return guild;
53+
}
54+
async updateGuild(guild) {
55+
await this.client.query('UPDATE guilds SET prefix = $1, language = $2, xp_enabled = $3, automod_enabled = $4, welcome_channel = $5, welcome_msg = $6, log_channel = $7 WHERE id = $8', [guild.prefix, guild.language, guild.xp_enabled, guild.automod_enabled, guild.welcome_channel, guild.welcome_msg, guild.log_channel, guild.id]);
56+
}
57+
async deleteGuild(guild_id) {
58+
await this.client.query('DELETE FROM guilds WHERE id = $1', [guild_id]);
59+
}
60+
61+
async getUsers(guild_id) {
62+
const users = await this.client.query('SELECT * FROM users WHERE guild_id = $1 ORDER BY xp DESC', [guild_id]);
63+
return users.rows;
64+
}
65+
async getUser(user_id, guild_id) {
66+
const user = await this.client.query('SELECT * FROM users WHERE id = $1 AND guild_id = $2', [user_id, guild_id]);
67+
return user.rows[0];
68+
}
69+
async createUser(user) {
70+
await this.client.query('INSERT INTO users (id, guild_id, xp) VALUES ($1, $2, $3)', [user.id, user.guild_id, user.xp]);
71+
}
72+
async updateUser(user) {
73+
await this.client.query('UPDATE users SET xp = $1 WHERE id = $2 AND guild_id = $3', [user.xp, user.id, user.guild_id]);
74+
}
75+
async deleteUser(user_id, guild_id) {
76+
await this.client.query('DELETE FROM users WHERE id = $1 AND guild_id = $2', [user_id, guild_id]);
77+
}
78+
79+
async getProfiles() {
80+
const profiles = await this.client.query('SELECT * FROM profiles');
81+
return profiles.rows;
82+
}
83+
async getProfile(user_id) {
84+
const profile = await this.client.query('SELECT * FROM profiles WHERE id = $1', [user_id]);
85+
return profile.rows[0];
86+
}
87+
async createProfile(profile) {
88+
await this.client.query('INSERT INTO profiles (id, description, color) VALUES ($1, $2, $3)', [profile.id, profile.description, profile.color]);
89+
}
90+
async updateProfile(profile) {
91+
await this.client.query('UPDATE profiles SET description = $1, color = $2 WHERE id = $3', [profile.description, profile.color, profile.id]);
92+
}
93+
async deleteProfile(user_id) {
94+
await this.client.query('DELETE FROM profiles WHERE id = $1', [user_id]);
95+
}
96+
97+
async getCustomCommands(guild_id) {
98+
const custom_commands = await this.client.query('SELECT * FROM custom_commands WHERE guild_id = $1', [guild_id]);
99+
return custom_commands.rows;
100+
}
101+
async getCustomCommand(guild_id, command_name) {
102+
const custom_command = await this.client.query('SELECT * FROM custom_commands WHERE guild_id = $1 AND command_name = $2', [guild_id, command_name]);
103+
return custom_command.rows[0];
104+
}
105+
async createCustomCommand(custom_command) {
106+
await this.client.query('INSERT INTO custom_commands (guild_id, command_name, response) VALUES ($1, $2, $3)', [custom_command.guild_id, custom_command.command_name, custom_command.response]);
107+
}
108+
async updateCustomCommand(custom_command) {
109+
await this.client.query('UPDATE custom_commands SET response = $1 WHERE guild_id = $2 AND command_name = $3', [custom_command.response, custom_command.guild_id, custom_command.command_name]);
110+
}
111+
async deleteCustomCommand(guild_id, command_name) {
112+
await this.client.query('DELETE FROM custom_commands WHERE guild_id = $1 AND command_name = $2', [guild_id, command_name]);
113+
}
114+
115+
async getStats() {
116+
const stats = await this.client.query('SELECT * FROM stats');
117+
if (stats.rows.length === 0) {
118+
await this.client.query('INSERT INTO stats (commands_executed, slash_commands) VALUES (0, 0)');
119+
return { commands_executed: 0, slash_commands: 0 };
120+
}
121+
return {
122+
commands_executed: parseInt(stats.rows[0].commands_executed),
123+
slash_commands: parseInt(stats.rows[0].slash_commands)
124+
}
125+
}
126+
127+
async updateStats(stats) {
128+
await this.client.query('UPDATE stats SET commands_executed = $1, slash_commands = $2', [stats.commands_executed, stats.slash_commands]);
129+
}
130+
131+
async incrementCommandUsage() {
132+
await this.client.query('UPDATE stats SET commands_executed = commands_executed + 1');
133+
}
134+
135+
async incrementSlashCommandUsage() {
136+
await this.client.query('UPDATE stats SET slash_commands = slash_commands + 1');
137+
}
138+
}

0 commit comments

Comments
 (0)