add support for MySQL and SQLite3 with sqlz (Sequelize)
Signed-off-by: Rajdeep Malakar <rajdeepm.dev@gmail.com>
This commit is contained in:
		
							parent
							
								
									7a88d053e1
								
							
						
					
					
						commit
						ff93a9d7ee
					
				|  | @ -128,3 +128,8 @@ dist | |||
| .yarn/build-state.yml | ||||
| .yarn/install-state.gz | ||||
| .pnp.* | ||||
| 
 | ||||
| # Cx-specific | ||||
| package-lock.json | ||||
| db.sql | ||||
| db.sql-journal | ||||
|  |  | |||
|  | @ -0,0 +1,59 @@ | |||
| { | ||||
|   "xan.guilds": { | ||||
|     "uuid": "text", | ||||
|     "serverId": "text", | ||||
|     "channelId": "text", | ||||
|     "networks": "text", | ||||
|     "client": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.messages": { | ||||
|     "uuid": "text", | ||||
|     "authorName": "text", | ||||
|     "authorId": "text", | ||||
|     "authorIcon": "text", | ||||
|     "serverIcon": "text", | ||||
|     "channelId": "text", | ||||
|     "message": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.userBans": { | ||||
|     "uuid": "text", | ||||
|     "userId": "text", | ||||
|     "mod": "text", | ||||
|     "reason": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.messageDelivery": { | ||||
|     "uuid": "text", | ||||
|     "channelId": "text", | ||||
|     "messageId": "text", | ||||
|     "client": "text", | ||||
|     "link": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.serverBans": { | ||||
|     "uuid": "text", | ||||
|     "serverId": "text", | ||||
|     "mod": "text", | ||||
|     "reason": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.userPrefs": { | ||||
|     "uuid": "text", | ||||
|     "userId": "text", | ||||
|     "prefs": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.serverPrefs": { | ||||
|     "uuid": "text", | ||||
|     "serverId": "text", | ||||
|     "prefs": "text" | ||||
|   }, | ||||
| 
 | ||||
|   "xan.networks": { | ||||
|     "uuid": "text", | ||||
|     "networkId": "text", | ||||
|     "address": "text" | ||||
|   } | ||||
| } | ||||
|  | @ -5,5 +5,6 @@ | |||
|     "xan.messages", | ||||
|     "xan.messageDelivery", | ||||
|     "xan.networks", | ||||
|     "xan.server_prefs" | ||||
|     "xan.serverPrefs", | ||||
|     "xan.userPrefs" | ||||
| ] | ||||
|  |  | |||
|  | @ -10,22 +10,22 @@ module.exports.initMongoDBInstance = async (client,config,callback) => { | |||
| 
 | ||||
|     var call_data = { | ||||
|         createStore: async (name, callback) => { | ||||
|             db.createCollection(name).then(() => { | ||||
|                 callback(true); | ||||
|             db.createCollection(name).then(async () => { | ||||
|                 await callback(true); | ||||
|             }).catch(() => { | ||||
|                 callback(false); | ||||
|                 await callback(false); | ||||
|             }) | ||||
|         }, | ||||
| 
 | ||||
|         list: async (table , data, callback) => { | ||||
|         list: async (table, data, callback) => { | ||||
|             var collection = db.collection(table); | ||||
| 
 | ||||
|             var found_data = await collection.find(data).toArray(); | ||||
| 
 | ||||
|             callback(found_data); | ||||
|             await callback(found_data); | ||||
|         }, | ||||
| 
 | ||||
|         insert: async (table, data,callback) => { | ||||
|         insert: async (table, data, callback) => { | ||||
|             var uuid = require('node:crypto').randomUUID(); | ||||
| 
 | ||||
|             var collection = db.collection(table); | ||||
|  | @ -35,26 +35,26 @@ module.exports.initMongoDBInstance = async (client,config,callback) => { | |||
|                 ...data | ||||
|             }) | ||||
| 
 | ||||
|             callback(uuid) | ||||
|             await callback(uuid) | ||||
|         }, | ||||
| 
 | ||||
|         delete: async (table, uuid , callback) => { | ||||
|         delete: async (table, uuid, callback) => { | ||||
|             var collection = db.collection(table); | ||||
| 
 | ||||
|             collection.deleteOne({ uuid: uuid }); | ||||
| 
 | ||||
|             callback(true); | ||||
|             await callback(true); | ||||
|         }, | ||||
| 
 | ||||
|         search: async (table, data , callback) => { | ||||
|         search: async (table, data, callback) => { | ||||
|             var collection = db.collection(table); | ||||
| 
 | ||||
|             var found_data = await collection.findOne(data); | ||||
| 
 | ||||
|             callback(found_data); | ||||
|             await callback(found_data); | ||||
|         }, | ||||
| 
 | ||||
|         edit: async (table, uuid, data , callback) => { | ||||
|         edit: async (table, uuid, data, callback) => { | ||||
|             var collection = db.collection(table); | ||||
| 
 | ||||
|             collection.updateOne({ | ||||
|  | @ -64,15 +64,15 @@ module.exports.initMongoDBInstance = async (client,config,callback) => { | |||
|                     uuid: uuid, | ||||
|                     ...data | ||||
|                 } | ||||
|             }) | ||||
|             }); | ||||
| 
 | ||||
|             callback(true); | ||||
|             await callback(true); | ||||
|         }, | ||||
| 
 | ||||
|         build: async () => { | ||||
|             var tables = require("./collection_tables.json"); | ||||
|             for(var table of tables){ | ||||
|                 call_data.createStore(table , (state) => {}); | ||||
|                 call_data.createStore(table, (state) => {}); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  |  | |||
|  | @ -1,77 +0,0 @@ | |||
| /** | ||||
|  *  | ||||
|  * @param {import('mysql2').Connection} client  | ||||
|  * @param {*} callback  | ||||
|  */ | ||||
| module.exports.initMYSQL2Connection = async (client,config,callback) => { | ||||
|     var call_data = { | ||||
|         createStore: async (name, callback) => { | ||||
|             client.query( | ||||
|                 `CREATE TABLE ${name.replace(".","")} (id INT NOT NULL AUTO_INCREMENT , uuid VARCHAR(256) NOT NULL , data LONGTEXT NOT NULL, timestamp VARCHAR(16) NOT NULL  , PRIMARY KEY (id)) ENGINE = ${config.database_engine};`, | ||||
|                 async function(err,results,fields) { | ||||
|                     callback(true); | ||||
|                 } | ||||
|             ) | ||||
|         }, | ||||
| 
 | ||||
|         list: async (table , callback) => { | ||||
|             var fetchData = []; | ||||
| 
 | ||||
|             client.query( | ||||
|                 `SELECT * FROM ${table.replace(".","")}`, | ||||
|                 async function(err,results,fields) { | ||||
|                     for(var element of results) { | ||||
|                         var data = JSON.parse(element['data']); | ||||
|                         await fetchData.push({ | ||||
|                             uuid: element['uuid'], | ||||
|                             ...data | ||||
|                         }); | ||||
| 
 | ||||
|                         await callback(fetchData); | ||||
|                     } | ||||
|                 } | ||||
|             ) | ||||
|         }, | ||||
| 
 | ||||
|         search: async (table , data , callback) => { | ||||
|             var fetchData = []; | ||||
| 
 | ||||
|             client.query( | ||||
|                 `SELECT * FROM ${table.replace(".","")}`, | ||||
|                 async function(err,results,fields) { | ||||
|                     for(var element of results) { | ||||
|                         var data = JSON.parse(element['data']); | ||||
|                         if(data) | ||||
|                         await fetchData.push({ | ||||
|                             uuid: element['uuid'], | ||||
|                             ...data | ||||
|                         }); | ||||
| 
 | ||||
|                         await callback(fetchData); | ||||
|                     } | ||||
|                 } | ||||
|             ) | ||||
|         }, | ||||
| 
 | ||||
|         insert: async (table, data,callback) => { | ||||
|             var uuid = require('node:crypto').randomUUID(); | ||||
| 
 | ||||
|             client.query( | ||||
|                 `INSERT INTO ${table.replace(".","")} (uuid, data, timestamp) VALUES 
 | ||||
|                     ('${uuid}', '${JSON.stringify(data)}', '${Date.now()}')`,
 | ||||
|                 async function(err,result,fields) { | ||||
|                     callback(uuid) | ||||
|                 } | ||||
|             ) | ||||
|         }, | ||||
| 
 | ||||
|         build: async () => { | ||||
|             var tables = require("./collection_tables.json"); | ||||
|             for(var table of tables){ | ||||
|                 call_data.createStore(table , (state) => {}); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     callback(call_data); | ||||
| } | ||||
|  | @ -0,0 +1,30 @@ | |||
| var schema = require("./collection_schemas.json"); | ||||
| const { DataTypes } = require("sequelize"); | ||||
| 
 | ||||
| let sql = fix_schema_sql(); | ||||
| let mongod = {}; | ||||
| 
 | ||||
| function sql_schema(type) { | ||||
|   switch (type) { | ||||
|     case "text": | ||||
|       return DataTypes.TEXT; | ||||
|     default: | ||||
|       return DataTypes.TEXT; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function fix_schema_sql() { | ||||
|   let __schema = {}; | ||||
|   for (let key of Object.keys(schema)) { | ||||
|     let obj = {}; | ||||
|     for (let k of Object.keys(schema[key])) { | ||||
|       obj[k] = sql_schema(schema[key][k]); | ||||
|     } | ||||
|     __schema[key.replaceAll(".", "__")] = obj; | ||||
|   } | ||||
|   return __schema; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|   sql, mongod | ||||
| }; | ||||
|  | @ -0,0 +1,71 @@ | |||
| const { Sequelize } = require("sequelize"); | ||||
| 
 | ||||
| /** | ||||
|  *  | ||||
|  * @param {Sequelize} client | ||||
|  * @param {*} callback | ||||
|  */ | ||||
| module.exports.initSQLConnection = async (client, config, callback) => { | ||||
|     let tables = {}; | ||||
|     var call_data = { | ||||
|         list: async (table, data, callback) => { | ||||
|             console.log(`Listing ${table}`); | ||||
|             let result = await tables[table].findAll({ where: data }); | ||||
|             if (!result) { | ||||
|               await callback(result); | ||||
|             } else { | ||||
|               await callback(result.map(r => r.dataValues)); | ||||
|             } | ||||
|         }, | ||||
| 
 | ||||
|         delete: async (table, uuid, callback) => { | ||||
|             await tables[table].destroy({ where: { uuid: uuid } }); | ||||
|             await callback(true); | ||||
|         }, | ||||
| 
 | ||||
|         search: async (table, data, callback) => { | ||||
|             console.log(`Searching ${table}`); | ||||
|             var result = await tables[table].findOne({ where: data }); | ||||
|             await callback(result); | ||||
|         }, | ||||
|         insert: async (table, data, callback) => { | ||||
|             console.log(`Inserting to ${table}`); | ||||
|             var uuid = require('node:crypto').randomUUID(); | ||||
|             let instance = tables[table].build({ | ||||
|               uuid: uuid, | ||||
|               ...data | ||||
|             }); | ||||
|             await instance.save(); | ||||
|             await callback(uuid); | ||||
|         }, | ||||
| 
 | ||||
|         edit: async (table, uuid, data, callback) => { | ||||
|             try { | ||||
|                 await tables[table].update({ | ||||
|                     uuid: uuid, | ||||
|                     ...data | ||||
|                 }, { | ||||
|                     where: { uuid: uuid } | ||||
|                 }); | ||||
|                 await callback(true); | ||||
|             } catch (e) { | ||||
|                 await callback(false); | ||||
|                 console.error(`Error:\n${e}`); | ||||
|             } | ||||
|         }, | ||||
| 
 | ||||
| 
 | ||||
|         build: async () => { | ||||
|             var __tables = require("./collection_tables.json"); | ||||
|             var __schema = require("./schemas.js"); | ||||
|             var schema = __schema.sql; | ||||
|             for (var table of __tables) { | ||||
|                 const model = client.define(table.replaceAll(".", "__"), schema[table.replaceAll(".", "__")], { freezeTableName: true }); | ||||
|                 tables[table] = model; | ||||
|             } | ||||
|             await client.sync(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     callback(call_data); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -18,6 +18,8 @@ | |||
|     "dotenv": "^16.4.5", | ||||
|     "mongodb": "^6.4.0", | ||||
|     "mysql2": "^3.9.2", | ||||
|     "nodemon": "^3.1.0" | ||||
|     "nodemon": "^3.1.0", | ||||
|     "sequelize": "^6.37.1", | ||||
|     "sqlite3": "^5.1.7" | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -16,18 +16,19 @@ module.exports = { | |||
| 	async execute(interaction) { | ||||
|         var channel = interaction.options.getChannel("channel"); | ||||
| 
 | ||||
|         interaction.client.database.search("xan.guilds" , { | ||||
|             serverId : interaction.guild.id | ||||
|         } , async (data) => { | ||||
|         interaction.client.database.search("xan.guilds", { | ||||
|             serverId: interaction.guild.id | ||||
|         }, async (data) => { | ||||
|             console.log(data); | ||||
|             if(data == null){ | ||||
|                 interaction.client.database.insert("xan.guilds" , { | ||||
|                     serverId : interaction.guild.id, | ||||
|                     channelId : channel.id, | ||||
|                 interaction.client.database.insert("xan.guilds", { | ||||
|                     serverId: interaction.guild.id, | ||||
|                     channelId: channel.id, | ||||
|                     client: "discord" | ||||
|                 }, async (c) => { | ||||
|                     await interaction.reply(`Saved Channel as #${channel.name} in Database as Discord Client`); | ||||
|                 }) | ||||
|             }else{ | ||||
|             } else { | ||||
|                 await interaction.reply(`Guild is already saved into Database`); | ||||
|             } | ||||
|         }); | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ module.exports = { | |||
|     discord_client_secret: process.env['discord_client_secret'] || "", | ||||
| 
 | ||||
|     // Database Configurations
 | ||||
|     // Possible Options ["mongod" , "mysqld"]
 | ||||
|     // Possible Options ["mongod", "mysqld", "sqlite"]
 | ||||
|     database_adapter: "mongod", | ||||
|     // If using MongoDB
 | ||||
|     database_uri: process.env['database_uri'] || "", | ||||
|  | @ -17,5 +17,7 @@ module.exports = { | |||
|     database_host: "localhost", | ||||
|     database_user: "root", | ||||
|     database_password: process.env['database_password'] || "", | ||||
|     database_engine: "InnoDB" | ||||
|     database_engine: "InnoDB", | ||||
|     // If using SQLite3
 | ||||
|     database_file: process.env["DATABASE_FILE"] || "" | ||||
| } | ||||
							
								
								
									
										32
									
								
								src/index.js
								
								
								
								
							
							
						
						
									
										32
									
								
								src/index.js
								
								
								
								
							|  | @ -4,7 +4,7 @@ const config = require("./config/prod"); | |||
| const fs = require('node:fs'); | ||||
| const path = require('node:path'); | ||||
| const { MongoClient } = require("mongodb"); | ||||
| const mysql = require('mysql2'); | ||||
| const { Sequelize } = require("sequelize"); | ||||
| const { Client, Events, GatewayIntentBits, Collection } = require('discord.js'); | ||||
| 
 | ||||
| const client = new Client({ | ||||
|  | @ -25,17 +25,29 @@ async function main() { | |||
| 
 | ||||
| 		require("../database/mongod").initMongoDBInstance(mongo_client, config, (back) => initMessageManager(back)); | ||||
| 	} else if (config.database_adapter == "mysqld") { | ||||
| 		const mysql_connection = mysql.createConnection({ | ||||
| 		const mysql_conn = new Sequelize(config.database_name, config.database_user, config.database_password, { | ||||
|       host: config.database_host, | ||||
| 			user: config.database_user, | ||||
| 			password: config.database_password, | ||||
| 			database: config.database_name, | ||||
|       dialect: "mysql" | ||||
|     }) | ||||
|     try { | ||||
|         await mysql_conn.authenticate(); | ||||
| 		    await require("../database/sqlz") | ||||
|           .initSQLConnection(mysql_conn, config, async (back) => await initMessageManager(back)); | ||||
| 	  } catch (e) { | ||||
|         console.error(`Error:\n${e}`); | ||||
|     } | ||||
|   } else if (config.database_adapter == "sqlite") { | ||||
|     const sql_conn = new Sequelize({ | ||||
|       dialect: "sqlite", | ||||
|       storage: config.database_file | ||||
|     }); | ||||
| 
 | ||||
| 		mysql_connection.connect(); | ||||
| 		mysql_connection.on('error', (error) => console.error); | ||||
| 
 | ||||
| 		require("../database/mysqld").initMYSQL2Connection(mysql_connection, config, (back) => initMessageManager(back)); | ||||
|     try { | ||||
|       await sql_conn.authenticate(); | ||||
|       await require("../database/sqlz") | ||||
|         .initSQLConnection(sql_conn, config, async (back) => await initMessageManager(back)); | ||||
|     } catch (e) { | ||||
|       console.error(`Error:\n${e}`); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ class Message { | |||
|      * @property {string|null} message | ||||
|      */ | ||||
| 
 | ||||
|     constructor(){ | ||||
|     constructor() { | ||||
|         this.serverId = 1; | ||||
|         this.serverName = "[No Server]"; | ||||
|         this.serverIcon = null; | ||||
|  | @ -24,7 +24,7 @@ class Message { | |||
|      * Fill Product fields with new values | ||||
|      * @param {MessageFields} newFields - Object containing new values for Category fields | ||||
|      */ | ||||
|     fill(newFields) { | ||||
|     fill (newFields) { | ||||
|         for (let field in newFields) { | ||||
|             if (this.hasOwnProperty(field) && newFields.hasOwnProperty(field)) { | ||||
|                 if (this[field] !== 'undefined') { | ||||
|  | @ -36,12 +36,12 @@ class Message { | |||
|         return this.toArray(); | ||||
|     } | ||||
| 
 | ||||
|     toArray(){ | ||||
|     toArray() { | ||||
|         return { | ||||
|             serverId : this.serverId, | ||||
|             serverName : this.serverName, | ||||
|             serverIcon : this.serverIcon, | ||||
|             authorId : this.authorId, | ||||
|             serverId: this.serverId, | ||||
|             serverName: this.serverName, | ||||
|             serverIcon: this.serverIcon, | ||||
|             authorId: this.authorId, | ||||
|             authorIcon: this.authorIcon, | ||||
|             authorName: this.authorName, | ||||
|             message: this.message | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ const { EmbedBuilder } = require("@discordjs/builders"); | |||
|  * @param {Message} message | ||||
|  * @param {Client} discord  | ||||
|  */ | ||||
| const send = (message, database, channelId , uuid , discord) => { | ||||
| const send = (message, database, channelId, uuid, discord) => { | ||||
|     discord.channels.cache?.get(channelId).send({ | ||||
|         embeds: [ | ||||
|             new EmbedBuilder() | ||||
|  | @ -35,9 +35,9 @@ const send = (message, database, channelId , uuid , discord) => { | |||
|     }).catch((error) => { | ||||
|         console.log(`Unable to Send Message to Channel [${channelId}]`); | ||||
|     }).then((_message) => { | ||||
|         database.insert("xan.messageDelivery" ,{ | ||||
|         database.insert("xan.messageDelivery", { | ||||
|             channelId: _message.channelId, | ||||
|             messageId : `${_message.id}`, | ||||
|             messageId: `${_message.id}`, | ||||
|             client: "discord", | ||||
|             link: uuid | ||||
|         }, (uuid) => {}); | ||||
|  |  | |||
|  | @ -13,11 +13,11 @@ const actionMessageManager = async ( | |||
| ) => { | ||||
|     var d_data  = { | ||||
|         find_uuid: (messageId, authorId , cb) => { | ||||
|             database.search("xan.messageDelivery" , { messageId: messageId } , (dataUid) => { | ||||
|                 database.search("xan.messages" , { uuid: dataUid.link } , (data) => { | ||||
|                     if(data.authorId.toString() == authorId.toString()){ | ||||
|             database.search("xan.messageDelivery", { messageId }, (dataUid) => { | ||||
|                 database.search("xan.messages", { uuid: dataUid.link }, (data) => { | ||||
|                     if (data.authorId.toString() == authorId.toString()) { | ||||
|                         cb(dataUid.link); | ||||
|                     }else{ | ||||
|                     } else { | ||||
|                         cb(null) | ||||
|                     } | ||||
|                 }) | ||||
|  | @ -27,7 +27,7 @@ const actionMessageManager = async ( | |||
|         delete: (uuid) => { | ||||
|             database.list("xan.messageDelivery", { | ||||
|                 link: uuid | ||||
|             } , (data) => { | ||||
|             }, (data) => { | ||||
|                 for(var message of data) { | ||||
|                     discord.channels.fetch(message['channelId']).then((channel) => { | ||||
|                         channel.messages.delete(message['messageId']).catch(e => { | ||||
|  |  | |||
|  | @ -10,20 +10,20 @@ const initMessageManager = async ( | |||
|     database, | ||||
|     discord | ||||
| ) => { | ||||
|     function postMessage(message, uuid){ | ||||
|         database.list("xan.guilds" , {} , (list) => { | ||||
|            for(var element of list){ | ||||
|             if(element.client == "discord") discordSend(message , database , element.channelId ,uuid , discord); | ||||
|     function postMessage(message, uuid) { | ||||
|         database.list("xan.guilds", {}, (list) => { | ||||
|            for (var element of list) { | ||||
|              if (element.client == "discord") discordSend(message, database, element.channelId, uuid, discord); | ||||
|            } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     discord.on(Events.MessageCreate , (message) => { | ||||
|     discord.on(Events.MessageCreate, (message) => { | ||||
|         if(message.author.bot) return; | ||||
|         database.search("xan.guilds" , { | ||||
|         database.search("xan.guilds", { | ||||
|             serverId : message.guild.id | ||||
|         } , async (data) => { | ||||
|         }, async (data) => { | ||||
|             if(data !== null){ | ||||
| 
 | ||||
|                 message.delete().catch((error) => {}); | ||||
|  | @ -37,7 +37,7 @@ const initMessageManager = async ( | |||
|                 _message.serverIcon = message.guild.iconURL(); | ||||
|                 _message.message = message.content; | ||||
| 
 | ||||
|                 database.insert("xan.messages" , _message.toArray() , (uuid) => { | ||||
|                 database.insert("xan.messages", _message.toArray(), (uuid) => { | ||||
|                     postMessage(_message.toArray(), uuid); | ||||
|                 }); | ||||
|             } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue