From f22da92cab38dc97354133da42b260a7aed74517 Mon Sep 17 00:00:00 2001 From: Jkibbels Date: Tue, 14 Jan 2025 22:56:38 -0500 Subject: [PATCH] [factions-banking] VERY start of SQL stuff for the banking system. Tables are figured out locally; implementing logic for JBDC driver here --- .../BankMgr/TransactionMetadata.java | 6 +- .../keeblarcraft/Commands/BankCommands.java | 27 +---- .../keeblarcraft/ConfigMgr/SQLConfig.java | 102 ++++++++++++++---- .../keeblarcraft/ConfigMgr/SQLInitServer.java | 23 ++++ .../ConfigMgr/SQLTypeSupport.java | 27 +++++ .../keeblarcraft/ConfigMgr/SQLUnitTest.java | 38 +++++++ .../java/jesse/keeblarcraft/Keeblarcraft.java | 4 +- 7 files changed, 178 insertions(+), 49 deletions(-) create mode 100644 src/main/java/jesse/keeblarcraft/ConfigMgr/SQLInitServer.java create mode 100644 src/main/java/jesse/keeblarcraft/ConfigMgr/SQLTypeSupport.java create mode 100644 src/main/java/jesse/keeblarcraft/ConfigMgr/SQLUnitTest.java diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/TransactionMetadata.java b/src/main/java/jesse/keeblarcraft/BankMgr/TransactionMetadata.java index 64c122b..1fa54f7 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/TransactionMetadata.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/TransactionMetadata.java @@ -4,11 +4,13 @@ package jesse.keeblarcraft.BankMgr; public class TransactionMetadata { enum TRANSACTION_TYPE { DEBIT, - CREDIT + CREDIT, + WITHDRAWAL, + DEPOSIT } public String fromParty; // Account ID - public String toParty; // Account ID + public String toParty; // Account ID or party (like ATM/self,etc) public Integer amount; public String transactionId; public TRANSACTION_TYPE transactionType; diff --git a/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java b/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java index 9d2c247..2a69593 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java +++ b/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java @@ -394,29 +394,6 @@ public class BankCommands { }); } - ///////////////////////////////////////////////////////////////////////////// - /// @fn RemoveFillerWords - /// - /// @brief Takes in a list of arguments with the intention to remove - /// all words found in the filler list. This helps with dynamic - /// typing - /// - /// @return List of arguments without filler words - ///////////////////////////////////////////////////////////////////////////// - public List RemoveFillerWords(List argList) { - int index = 0; - for (String str : argList) { - if (FILLER_WORDS.contains(str)) { - argList.remove(index); - } - - // Also make every word lower case - str = str.toLowerCase(); - index++; - } - return argList; - } - public int SelectBank(ServerPlayerEntity player, String bank) { System.out.println("Select bank called"); BankManager.GetInstance().ChangeDefaultSelectedBank(player, bank); @@ -552,6 +529,7 @@ public class BankCommands { return 0; } + // TODO: make prettier public int ListAllBanks(ServerPlayerEntity sourcePlayer) { sourcePlayer.sendMessage(Text.of("Here is a list of available banks on the server: " + BankManager.GetInstance().GetAllBankNames())); return 0; @@ -668,9 +646,6 @@ public class BankCommands { return 0; } - // Possible code paths: - // REQUIRED = {AMOUNT} {ACCOUNT_ID} [optional] - // OPTIONAL = [reason] ///////////////////////////////////////////////////////////////////////////// /// @fn WireCommand /// diff --git a/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLConfig.java b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLConfig.java index 16075df..d743d79 100644 --- a/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLConfig.java +++ b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLConfig.java @@ -6,6 +6,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import jesse.keeblarcraft.ConfigMgr.SQLTypeSupport.VALID_SQL_TYPE; import jesse.keeblarcraft.Utils.CommonStructures.Pair; public class SQLConfig { @@ -17,6 +18,20 @@ public class SQLConfig { private Boolean connected = false; private Connection conn = null; // Actual connection object + private enum SQL_RUN_TYPE { + GENERAL, + QUERY, + UPDATE + } + + // Direct return object in relation to the SQL_RUN_TYPE of the SQL command that was used. Only one will + // be filled out properly for what you run - the other values will be null and not cleared! + private class SQLRunReturn { + Boolean generalRet; + ResultSet queryReturn; + Integer updateReturn; + } + public static SQLConfig GetInstance() { if (static_inst == null) { static_inst = new SQLConfig(); @@ -44,28 +59,38 @@ public class SQLConfig { dbPass = GeneralConfig.GetInstance().GetSQLPassword(); dbAddr = "jdbc:mysql://" + GeneralConfig.GetInstance().GetSQLAddress() + "/" + dbName; conn = DriverManager.getConnection(dbAddr, dbUser, dbPass); - Statement stmnt = conn.createStatement(); - String testSql = "SELECT * FROM test_table"; - ResultSet rs = stmnt.executeQuery(testSql); - - System.out.println("Printing out result set from test query"); - while (rs.next()) { - System.out.println("[RS]: " + rs.getString("test_name")); - } } catch (SQLException e) {} } } - private ResultSet RunCommand(String sqlCommand) { - ResultSet cmdResult = null; + private SQLRunReturn RunCommand(String sqlCommand, SQL_RUN_TYPE type) { + SQLRunReturn sqlData = new SQLRunReturn(); + // If conn is null; we may need to reconnect before running the command + if (conn == null) { + Connect(); + } + if (conn != null) { try { Statement statement = conn.createStatement(); - cmdResult = statement.executeQuery(sqlCommand); - } catch (Exception e) {} + + switch(type) { + case GENERAL: + sqlData.generalRet = statement.execute(sqlCommand); + break; + case QUERY: + sqlData.queryReturn = statement.executeQuery(sqlCommand); + break; + case UPDATE: + sqlData.updateReturn = statement.executeUpdate(sqlCommand); + break; + } + } catch (SQLException e) { + System.out.println(e.getSQLState()); + } } - return cmdResult; + return sqlData; } // Re-attempt the connection @@ -88,7 +113,8 @@ public class SQLConfig { return conn != null && this.connected; } - private Boolean TableExists(String name) { + // The case is converted to upper case automatically to be case insensitive + public Boolean DoesTableExist(String name) { boolean tableExists = false; try (ResultSet rs = conn.getMetaData().getTables(null, null, name, null)) { while (rs.next()) { @@ -102,18 +128,54 @@ public class SQLConfig { return tableExists; } + public Boolean MakeNonNullable(String table, String columnName) { + return false; + } + + public Integer AddPrimaryKey(String tableName, String primaryKeyColumn) { + SQLRunReturn success = new SQLRunReturn(); + + if (DoesTableExist(tableName)) { + String sqlCmd = "ALTER TABLE " + tableName + " ADD PRIMARY KEY (" + primaryKeyColumn + ");"; + + success = RunCommand(sqlCmd, SQL_RUN_TYPE.UPDATE); + } + + return success.updateReturn; + } + + public Integer AddForeignKey(String primaryTableName, String primaryColumnName, String foreignTableName, String foreignKeyColumn) { + SQLRunReturn success = new SQLRunReturn(); + Boolean primaryTableExists = DoesTableExist(primaryTableName); + Boolean foreignTableExists = DoesTableExist(foreignTableName); + + if (primaryTableExists && foreignTableExists) { + String sqlCmd = "ALTER TABLE " + primaryTableName + " ADD FOREIGN KEY (" + primaryColumnName + ") REFERENCES " + foreignTableName + " (" + foreignKeyColumn + ")"; + success = RunCommand(sqlCmd, SQL_RUN_TYPE.UPDATE); + } + return success.updateReturn; + } + // Might fix heap pollution decay in future with enum types or something. For now we assume the user isn't horrifically stupid and will give a SQL-able type - public Boolean CreateTable(String tableName, Pair... columnPairs) { + public Boolean CreateTable(String tableName, Pair... columnPairs) { Boolean success = false; - if (!TableExists(tableName.toUpperCase())) { + if (!DoesTableExist(tableName.toUpperCase())) { String sqlCommand = "CREATE TABLE " + tableName.toUpperCase() + "("; - for (Pair colPair : columnPairs) { - sqlCommand = sqlCommand + " " + colPair.GetKey() + " " + String.valueOf(colPair.GetValue()) + ","; + for (Pair colPair : columnPairs) { + sqlCommand = sqlCommand + " " + colPair.GetKey() + " " + SQLTypeSupport.GetSqlStrForType(colPair.GetValue()) + ","; } - System.out.println("DEBUG STATEMENT, SQL STATEMENT: " + sqlCommand); - ResultSet rs = RunCommand(sqlCommand); + // Strip the leading comma and append the ending ');' on the SQL statement + sqlCommand = sqlCommand.substring(0, sqlCommand.length() - 1) + ");"; + + SQLRunReturn rs = RunCommand(sqlCommand, SQL_RUN_TYPE.GENERAL); + + try { + while (rs.queryReturn.next()) { + + } + } catch (Exception e) {} } return success; } diff --git a/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLInitServer.java b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLInitServer.java new file mode 100644 index 0000000..7a40035 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLInitServer.java @@ -0,0 +1,23 @@ +package jesse.keeblarcraft.ConfigMgr; + +import jesse.keeblarcraft.ConfigMgr.SQLTypeSupport.VALID_SQL_TYPE; +import jesse.keeblarcraft.Utils.CommonStructures.Pair; + +public class SQLInitServer { + // Initial run-time checks to make sure tables are all setup in advanced + public void Initialize() { + SetupTables(); + } + + private void SetupTables() { + // These are all hard coded and non-changeable in this version of the mod + String accountsTable = "ACCOUNTS"; + String banksTable = "BANKS"; + String customerTable = "CUSTOMER"; + String transactionTable = "TRANSACTION"; + + Pair pairOne = new Pair<>("name", VALID_SQL_TYPE.VARCHAR); + Pair pairTwo = new Pair<>("address", VALID_SQL_TYPE.BIGINT); + Pair pairThree = new Pair<>("email", VALID_SQL_TYPE.TEXT); + } +} diff --git a/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLTypeSupport.java b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLTypeSupport.java new file mode 100644 index 0000000..82995a1 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLTypeSupport.java @@ -0,0 +1,27 @@ +package jesse.keeblarcraft.ConfigMgr; + +public class SQLTypeSupport { + public enum VALID_SQL_TYPE { + VARCHAR, + BIGINT, + INT, + TEXT + } + + // Produces the word that SQL would expect for the given datatype. In general it's usually just the word itself but in cases + // like 'varchar' you usually specify a size too. For now it defaults 255 but this can be expanded in the future + public static String GetSqlStrForType(VALID_SQL_TYPE type) { + switch(type) { + case VARCHAR: + return "VARCHAR(255)"; + case BIGINT: + return "BIGINT"; + case INT: + return "INT"; + case TEXT: + return "TEXT"; + } + + return null; // This should never get hit + } +} diff --git a/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLUnitTest.java b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLUnitTest.java new file mode 100644 index 0000000..8afae14 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/ConfigMgr/SQLUnitTest.java @@ -0,0 +1,38 @@ +package jesse.keeblarcraft.ConfigMgr; + +import jesse.keeblarcraft.ConfigMgr.SQLTypeSupport.VALID_SQL_TYPE; +import jesse.keeblarcraft.Utils.CommonStructures.Pair; + +// Random commands to run to test the SQL class +public class SQLUnitTest { + + public void RunTests() { + CreateTableTest(); + ForeignKeyTest(); + } + public void CreateTableTest() { + String tableName = "test_table"; + Pair pairOne = new Pair<>("name", VALID_SQL_TYPE.VARCHAR); + Pair pairTwo = new Pair<>("address", VALID_SQL_TYPE.BIGINT); + Pair pairThree = new Pair<>("email", VALID_SQL_TYPE.TEXT); + + SQLConfig.GetInstance().CreateTable(tableName, pairOne, pairTwo, pairThree); + } + + public void DoesTableExistTest() { + String tableName = "test_table"; + Boolean temp = SQLConfig.GetInstance().DoesTableExist(tableName.toUpperCase()); + + System.out.println("[SQL-UnitTest]: Does the table " + tableName + " exist? " + (temp ? "YES":"NO")); + } + + public void ForeignKeyTest() { + String primTableName = "test_table"; + String primColName = "name"; + String foreTableName = "accounts"; + String foreColName = "global_account_id"; + + Integer ret = SQLConfig.GetInstance().AddForeignKey(primTableName, primColName, foreTableName, foreColName); + System.out.println("[SQL-UnitTest]: Update foreign key test. Got return result number: " + ret); + } +} diff --git a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java index d6d25fe..6b21095 100644 --- a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java +++ b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java @@ -41,6 +41,7 @@ import jesse.keeblarcraft.AttributeMgr.AttributeTree; import jesse.keeblarcraft.BankMgr.BankManager; import jesse.keeblarcraft.Commands.CustomCommandManager; import jesse.keeblarcraft.ConfigMgr.SQLConfig; +import jesse.keeblarcraft.ConfigMgr.SQLUnitTest; import jesse.keeblarcraft.CustomBlocks.BlockList; import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration; import jesse.keeblarcraft.CustomItems.ItemManager; @@ -120,8 +121,9 @@ public class Keeblarcraft implements ModInitializer { BankManager.GetInstance().InitializeBanks(); System.out.println("Attempting SQL Registration call"); - SQLConfig.GetInstance(); + SQLUnitTest sqlTests = new SQLUnitTest(); + sqlTests.RunTests(); /// THE BELOW ITEMS MUST BE DONE LAST IN THE STEPS // Register items