diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/AdvancedCorePlugin.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/AdvancedCorePlugin.java index 1bed9a5caf..3b82d9b019 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/AdvancedCorePlugin.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/AdvancedCorePlugin.java @@ -1023,8 +1023,10 @@ public void updateReplacements() { * * @param storageType the storage type to load */ - @SuppressWarnings("deprecation") public void loadUserAPI(UserStorage storageType) { + if (storageType == null) { + throw new IllegalArgumentException("User storage must be SQLITE or MYSQL"); + } if (storageType.equals(UserStorage.SQLITE)) { ArrayList columns = new ArrayList<>(); Column key = new Column("uuid", DataType.STRING); @@ -1043,8 +1045,6 @@ public void loadUserAPI(UserStorage storageType) { getOptions().getYmlConfig().getData().getConfigurationSection("MySQL"))); } - } else if (storageType.equals(UserStorage.FLAT)) { - getLogger().severe("Detected using FLAT storage, this will be removed in the future!"); } } diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserData.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserData.java index f05924bd98..cf2cc5637b 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserData.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserData.java @@ -5,12 +5,9 @@ import java.util.List; import java.util.Map.Entry; -import org.bukkit.configuration.file.FileConfiguration; - import com.bencodez.advancedcore.api.user.usercache.UserDataCache; import com.bencodez.advancedcore.api.user.usercache.change.UserDataChangeInt; import com.bencodez.advancedcore.api.user.usercache.change.UserDataChangeString; -import com.bencodez.advancedcore.thread.FileThread; import com.bencodez.simpleapi.array.ArrayUtils; import com.bencodez.simpleapi.sql.Column; import com.bencodez.simpleapi.sql.data.DataValue; @@ -65,11 +62,6 @@ public boolean getBoolean(String key, boolean useCache, boolean waitForCache) { return getBoolean(key, UserDataFetchMode.fromBooleans(useCache, waitForCache)); } - @Deprecated - public FileConfiguration getData(String uuid) { - return FileThread.getInstance().getThread().getData(this, uuid); - } - public DataValue getDataValue(String key) { boolean isInt = user.getPlugin().getUserManager().getDataManager().isInt(key); if (isInt) { @@ -127,15 +119,8 @@ public int getInt(String key, int def, boolean useCache, boolean waitForCache) { UserDataFetchMode.fromBooleans(useCache, waitForCache)); } - @SuppressWarnings("deprecation") public int getInt(UserStorage storage, String key, int def, UserDataFetchMode mode) { if (key == null || key.isEmpty()) { - if (storage.equals(UserStorage.FLAT)) { - try { - return getData(user.getUUID()).getInt(key, def); - } catch (Exception ignored) { - } - } return def; } @@ -241,11 +226,6 @@ public int getInt(UserStorage storage, String key, int def, UserDataFetchMode mo } } } - } else if (storage.equals(UserStorage.FLAT)) { - try { - return getData(user.getUUID()).getInt(key, def); - } catch (Exception ignored) { - } } return def; @@ -263,12 +243,9 @@ public ArrayList getKeys() { return getKeys(user.getPlugin().getStorageType()); } - @SuppressWarnings("deprecation") public ArrayList getKeys(UserStorage storage) { ArrayList keys = new ArrayList<>(); - if (storage.equals(UserStorage.FLAT)) { - keys = new ArrayList<>(getData(user.getUUID()).getConfigurationSection("").getKeys(false)); - } else if (storage.equals(UserStorage.MYSQL)) { + if (storage.equals(UserStorage.MYSQL)) { List col = getMySqlRow(); if (col != null && !col.isEmpty()) { for (Column c : col) { @@ -319,7 +296,6 @@ public String getString(String key, UserDataFetchMode mode) { return getString(user.getPlugin().getStorageType(), key, mode); } - @SuppressWarnings("deprecation") public String getString(UserStorage storage, String key, UserDataFetchMode mode) { if (key == null || key.isEmpty()) { return ""; @@ -388,11 +364,6 @@ public String getString(UserStorage storage, String key, UserDataFetchMode mode) } } } - } else if (storage.equals(UserStorage.FLAT)) { - try { - return getData(user.getUUID()).getString(key, ""); - } catch (Exception ignored) { - } } return ""; @@ -454,49 +425,31 @@ public HashMap getValues() { return getValues(user.getPlugin().getStorageType()); } - @SuppressWarnings("deprecation") public HashMap getValues(UserStorage storage) { if (storage.equals(UserStorage.MYSQL)) { return convert(getMySqlRow()); } if (storage.equals(UserStorage.SQLITE)) { return convert(getSQLiteRow()); - } else if (storage.equals(UserStorage.FLAT)) { - HashMap list = new HashMap<>(); - FileConfiguration data = getData(user.getUUID()); - for (String str : data.getKeys(false)) { - if (data.isInt(str)) { - list.put(str, new DataValueInt(data.getInt(str))); - } else { - list.put(str, new DataValueString(data.getString(str, ""))); - } - } - return list; } return null; } - @SuppressWarnings("deprecation") public boolean hasData() { if (user.getPlugin().getStorageType().equals(UserStorage.MYSQL)) { return user.getPlugin().getMysql().containsKey(user.getUUID()); } if (user.getPlugin().getStorageType().equals(UserStorage.SQLITE)) { return user.getPlugin().getSQLiteUserTable().containsKey(user.getUUID()); - } else if (user.getPlugin().getStorageType().equals(UserStorage.FLAT)) { - return FileThread.getInstance().getThread().hasPlayerFile(user.getUUID()); } return false; } - @SuppressWarnings("deprecation") public void remove() { if (user.getPlugin().getStorageType().equals(UserStorage.MYSQL)) { user.getPlugin().getMysql().deletePlayer(user.getUUID()); } else if (user.getPlugin().getStorageType().equals(UserStorage.SQLITE)) { user.getPlugin().getSQLiteUserTable().delete(new Column("uuid", new DataValueString(user.getUUID()))); - } else if (user.getPlugin().getStorageType().equals(UserStorage.FLAT)) { - FileThread.getInstance().getThread().deletePlayerFile(user.getUUID()); } user.clearCache(); } @@ -509,11 +462,6 @@ public void setBoolean(String key, boolean value, boolean queue) { setString(key, "" + value, queue); } - @Deprecated - private void setData(final String uuid, final String path, final Object value) { - FileThread.getInstance().getThread().setData(this, uuid, path, value); - } - public void setInt(final String key, final int value) { setInt(key, value, true); } @@ -530,7 +478,6 @@ public void setInt(UserStorage storage, final String key, final int value, boole setInt(storage, key, value, queue, false); } - @SuppressWarnings("deprecation") public void setInt(final UserStorage storage, final String key, final int value, boolean queue, boolean async) { if (key.equals("")) { user.getPlugin().debug("No key: " + key + " to " + value); @@ -565,8 +512,6 @@ public void run() { user.getPlugin().getSQLiteUserTable().update(primary, columns); } else if (storage.equals(UserStorage.MYSQL)) { user.getPlugin().getMysql().update(user.getUUID(), key, new DataValueInt(value)); - } else if (storage.equals(UserStorage.FLAT)) { - setData(user.getUUID(), key, value); } if (!user.isCached()) { @@ -585,8 +530,6 @@ public void run() { user.getPlugin().getSQLiteUserTable().update(primary, columns); } else if (storage.equals(UserStorage.MYSQL)) { user.getPlugin().getMysql().update(user.getUUID(), key, new DataValueInt(value)); - } else if (storage.equals(UserStorage.FLAT)) { - setData(user.getUUID(), key, value); } if (!user.isCached()) { @@ -611,7 +554,6 @@ public void setString(UserStorage storage, final String key, final String value, setString(storage, key, value, queue, false); } - @SuppressWarnings("deprecation") public void setString(final UserStorage storage, final String key, final String value, boolean queue, boolean async) { if (key.equals("") && value != null) { @@ -647,8 +589,6 @@ public void run() { user.getPlugin().getSQLiteUserTable().update(primary, columns); } else if (storage.equals(UserStorage.MYSQL)) { user.getPlugin().getMysql().update(user.getUUID(), key, new DataValueString(value)); - } else if (storage.equals(UserStorage.FLAT)) { - setData(user.getUUID(), key, value); } if (!user.isCached()) { user.getPlugin().getUserManager().onChange(user, key); @@ -665,8 +605,6 @@ public void run() { user.getPlugin().getSQLiteUserTable().update(primary, columns); } else if (storage.equals(UserStorage.MYSQL)) { user.getPlugin().getMysql().update(user.getUUID(), key, new DataValueString(value)); - } else if (storage.equals(UserStorage.FLAT)) { - setData(user.getUUID(), key, value); } if (!user.isCached()) { user.getPlugin().getUserManager().onChange(user, key); @@ -700,7 +638,6 @@ public void setValues(String key, DataValue value) { setValues(user.getPlugin().getStorageType(), values); } - @SuppressWarnings("deprecation") public void setValues(UserStorage storage, HashMap values) { if (storage.equals(UserStorage.MYSQL)) { if (user.getPlugin().getMysql() != null) { @@ -721,14 +658,6 @@ public void setValues(UserStorage storage, HashMap values) { user.getPlugin().getSQLiteUserTable().update(new Column("uuid", new DataValueString(user.getUUID())), cols); } - } else if (storage.equals(UserStorage.FLAT)) { - for (Entry entry : values.entrySet()) { - if (entry.getValue() instanceof DataValueString) { - setData(user.getUUID(), entry.getKey(), entry.getValue().getString()); - } else if (entry.getValue() instanceof DataValueInt) { - setData(user.getUUID(), entry.getKey(), entry.getValue().getInt()); - } - } } } diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserManager.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserManager.java index edb608a9a9..28007d0809 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserManager.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserManager.java @@ -1,6 +1,5 @@ package com.bencodez.advancedcore.api.user; -import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -20,7 +19,6 @@ import com.bencodez.simpleapi.array.ArrayUtils; import com.bencodez.simpleapi.sql.Column; import com.bencodez.simpleapi.sql.DataType; -import com.bencodez.simpleapi.sql.data.DataValue; import com.bencodez.simpleapi.sql.data.DataValueString; import lombok.Getter; @@ -49,23 +47,14 @@ public UserManager(AdvancedCorePlugin plugin) { load(); } - @SuppressWarnings("deprecation") public void copyColumnData(String columnFromName, String columnToName) { if (plugin.getStorageType().equals(UserStorage.MYSQL)) { plugin.getMysql().copyColumnData(columnFromName, columnToName, DataType.STRING); } else if (plugin.getStorageType().equals(UserStorage.SQLITE)) { plugin.getSQLiteUserTable().copyColumnData(columnFromName, columnToName, DataType.STRING); - } else if (plugin.getStorageType().equals(UserStorage.FLAT)) { - for (String uuid : getAllUUIDs()) { - AdvancedCoreUser user = getUser(UUID.fromString(uuid)); - user.userDataFetechMode(UserDataFetchMode.NO_CACHE); - DataValue data = user.getData().getDataValue(columnFromName); - user.getData().setValues(columnToName, data); - } } } - @SuppressWarnings("deprecation") public List getAllColumns() { UserStorage storage = plugin.getStorageType(); if (storage.equals(UserStorage.SQLITE)) { @@ -73,14 +62,8 @@ public List getAllColumns() { } if (storage.equals(UserStorage.MYSQL)) { return plugin.getMysql().getColumns(); - } else { - AdvancedCoreUser user = getRandomUser(); - if (user == null) { - return new ArrayList<>(); - } - user.userDataFetechMode(UserDataFetchMode.NO_CACHE); - return new ArrayList<>(user.getData().getData(user.getUUID()).getConfigurationSection("").getKeys(false)); } + return new ArrayList<>(); } @Deprecated @@ -94,34 +77,14 @@ public HashMap> getAllKeys(UserStorage storage) { } if (storage.equals(UserStorage.MYSQL)) { return plugin.getMysql().getAllQuery(); - } else { - HashMap> cols = new HashMap<>(); - for (String uuid : getAllUUIDs()) { - AdvancedCoreUser user = getUser(UUID.fromString(uuid)); - user.userDataFetechMode(UserDataFetchMode.NO_CACHE); - ArrayList col = new ArrayList<>(); - for (Entry entry : user.getData().getValues().entrySet()) { - col.add(new Column(entry.getKey(), entry.getValue())); - } - cols.put(UUID.fromString(uuid), col); - } - return cols; } + return new HashMap<>(); } - @SuppressWarnings("deprecation") public ArrayList getAllPlayerNames() { if (plugin.isLoadUserData()) { ArrayList names = new ArrayList<>(); - if (AdvancedCorePlugin.getInstance().getStorageType().equals(UserStorage.FLAT)) { - for (String uuid : getAllUUIDs()) { - AdvancedCoreUser user = getUser(UUID.fromString(uuid)); - String name = user.getPlayerName(); - if (name != null && !name.isEmpty() && !name.equalsIgnoreCase("Error getting name")) { - names.add(name); - } - } - } else if (AdvancedCorePlugin.getInstance().getStorageType().equals(UserStorage.SQLITE)) { + if (AdvancedCorePlugin.getInstance().getStorageType().equals(UserStorage.SQLITE)) { ArrayList data = plugin.getSQLiteUserTable().getNames(); for (String name : data) { if (name != null && !name.isEmpty() && !name.equalsIgnoreCase("Error getting name")) { @@ -145,13 +108,11 @@ public ArrayList getAllPlayerNames() { * Storage-agnostic streaming iteration over all users + their column data. * * MYSQL: uses plugin.getMysql().forEachUser(...) SQLITE: uses - * plugin.getSQLiteUserTable().forEachUser(...) FLAT: iterates UUID files and - * builds columns per user (no giant map). + * plugin.getSQLiteUserTable().forEachUser(...). * * @param perUser BiConsumer called per user with UUID and column list * @param onFinished Consumer called once after all users processed with total */ - @SuppressWarnings("deprecation") public void forEachUserKeys(BiConsumer> perUser, Consumer onFinished) { UserStorage storage = plugin.getStorageType(); @@ -173,60 +134,15 @@ public void forEachUserKeys(BiConsumer> perUser, Consume return; } - // FLAT fallback (stream-like; no giant HashMap) - int processed = 0; - try { - for (String uuidStr : getAllUUIDs(UserStorage.FLAT)) { - if (uuidStr == null || uuidStr.isEmpty() || "null".equalsIgnoreCase(uuidStr)) { - continue; - } - - UUID uuid; - try { - uuid = UUID.fromString(uuidStr); - } catch (IllegalArgumentException ignored) { - continue; - } - - AdvancedCoreUser user = getUser(uuid); - user.userDataFetechMode(UserDataFetchMode.NO_CACHE); - - ArrayList colList = new ArrayList<>(); - for (Entry entry : user.getData().getValues().entrySet()) { - colList.add(new Column(entry.getKey(), entry.getValue())); - } - - processed++; - perUser.accept(uuid, colList); - } - } finally { - if (onFinished != null) { - onFinished.accept(processed); - } - } + throw new IllegalStateException("User storage is not configured"); } public ArrayList getAllUUIDs() { return ArrayUtils.removeDuplicates(getAllUUIDs(plugin.getStorageType())); } - @SuppressWarnings("deprecation") public ArrayList getAllUUIDs(UserStorage storage) { if (plugin.isLoadUserData()) { - if (storage.equals(UserStorage.FLAT)) { - File folder = new File(plugin.getDataFolder() + File.separator + "Data"); - String[] fileNames = folder.list(); - ArrayList uuids = new ArrayList<>(); - if (fileNames != null) { - for (String playerFile : fileNames) { - if (!playerFile.equals("null") && !playerFile.equals("")) { - String uuid = playerFile.replace(".yml", ""); - uuids.add(uuid); - } - } - } - return uuids; - } if (storage.equals(UserStorage.SQLITE)) { List cols = plugin.getSQLiteUserTable().getRows(); ArrayList uuids = new ArrayList<>(); @@ -253,22 +169,12 @@ public ArrayList getAllUUIDs(UserStorage storage) { return new ArrayList<>(); } - @SuppressWarnings("deprecation") public ArrayList getNumbersInColumn(String columnName) { if (plugin.getStorageType().equals(UserStorage.MYSQL)) { return plugin.getMysql().getNumbersInColumn(columnName); } if (plugin.getStorageType().equals(UserStorage.SQLITE)) { return plugin.getSQLiteUserTable().getNumbersInColumn(columnName); - } else if (plugin.getStorageType().equals(UserStorage.FLAT)) { - ArrayList nums = new ArrayList<>(); - for (String uuid : getAllUUIDs()) { - AdvancedCoreUser user = getUser(UUID.fromString(uuid)); - user.userDataFetechMode(UserDataFetchMode.NO_CACHE); - int num = user.getData().getInt(columnName, 0, true, true); - nums.add(num); - } - return nums; } return new ArrayList<>(); } @@ -462,21 +368,6 @@ public void removeAllKeyValues(String key, DataType type) { plugin.getSQLiteUserTable().wipeColumnData(key, type); } else if (plugin.getStorageType().equals(UserStorage.MYSQL)) { plugin.getMysql().wipeColumnData(key, type); - } else { - for (String uuid : getAllUUIDs()) { - AdvancedCoreUser user = getUser(UUID.fromString(uuid)); - user.userDataFetechMode(UserDataFetchMode.NO_CACHE); - switch (type) { - case INTEGER: - user.getData().setInt(key, 0); - break; - case STRING: - user.getData().setString(key, ""); - break; - default: - break; - } - } } } diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserStorage.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserStorage.java index 6e062a37f8..aae6e9ea0f 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserStorage.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/UserStorage.java @@ -2,13 +2,13 @@ public enum UserStorage { - MYSQL, SQLITE, @Deprecated - FLAT; + MYSQL, SQLITE; public static UserStorage value(String str) { - // if (str.equalsIgnoreCase("FLAT")) { - // return SQLITE; - // } + if (str != null && "FLAT".equalsIgnoreCase(str.trim())) { + throw new IllegalArgumentException("FLAT user storage has been removed. Convert existing data to " + + "SQLITE or MYSQL using the previous version before upgrading; existing Data files are not modified."); + } for (UserStorage s : values()) { if (s.toString().equalsIgnoreCase(str)) { return s; diff --git a/AdvancedCore/src/main/java/com/bencodez/advancedcore/thread/FileThread.java b/AdvancedCore/src/main/java/com/bencodez/advancedcore/thread/FileThread.java index cd99a21afe..7043b87930 100644 --- a/AdvancedCore/src/main/java/com/bencodez/advancedcore/thread/FileThread.java +++ b/AdvancedCore/src/main/java/com/bencodez/advancedcore/thread/FileThread.java @@ -1,13 +1,6 @@ package com.bencodez.advancedcore.thread; -import java.io.File; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - import com.bencodez.advancedcore.AdvancedCorePlugin; -import com.bencodez.advancedcore.api.misc.files.FilesManager; -import com.bencodez.advancedcore.api.user.UserData; /** * The Class Thread. @@ -19,100 +12,6 @@ public class FileThread { */ public class ReadThread extends java.lang.Thread { - /** - * Deletes a player file. - * - * @param uuid the player UUID - */ - @Deprecated - public void deletePlayerFile(String uuid) { - synchronized (FileThread.getInstance()) { - try { - File dFile = new File(AdvancedCorePlugin.getInstance().getDataFolder() + File.separator + "Data", - uuid + ".yml"); - if (dFile.exists()) { - dFile.delete(); - } - - } catch (Exception e) { - AdvancedCorePlugin.getInstance().debug(e); - } - } - } - - /** - * Gets data for a player. - * - * @param userData the user data - * @param uuid the player UUID - * @return the file configuration - */ - @Deprecated - public FileConfiguration getData(UserData userData, String uuid) { - synchronized (FileThread.getInstance()) { - try { - File dFile = getPlayerFile(uuid); - if (dFile != null) { - FileConfiguration data = YamlConfiguration.loadConfiguration(dFile); - return data; - } - } catch (Exception e) { - AdvancedCorePlugin.getInstance().debug(e); - } - AdvancedCorePlugin.getInstance().getLogger() - .warning("Filed to load " + uuid + ".yml, turn debug on to see full stacktraces"); - return null; - } - - } - - /** - * Gets the player file. - * - * @param uuid the player UUID - * @return the file - */ - @Deprecated - public File getPlayerFile(String uuid) { - synchronized (FileThread.getInstance()) { - try { - File dFile = new File(AdvancedCorePlugin.getInstance().getDataFolder() + File.separator + "Data", - uuid + ".yml"); - FileConfiguration data = YamlConfiguration.loadConfiguration(dFile); - if (!dFile.exists()) { - FilesManager.getInstance().editFile(dFile, data); - } - return dFile; - } catch (Exception e) { - AdvancedCorePlugin.getInstance().debug(e); - } - AdvancedCorePlugin.getInstance().getLogger() - .warning("Failed to load " + uuid + ".yml, turn debug on to see full stacktraces"); - return null; - } - } - - /** - * Checks if a player file exists. - * - * @param uuid the player UUID - * @return true if file exists - */ - @Deprecated - public boolean hasPlayerFile(String uuid) { - synchronized (FileThread.getInstance()) { - try { - File dFile = new File(AdvancedCorePlugin.getInstance().getDataFolder() + File.separator + "Data", - uuid + ".yml"); - return dFile.exists(); - - } catch (Exception e) { - AdvancedCorePlugin.getInstance().debug(e); - } - return false; - } - } - @Override public void run() { while (!isInterrupted()) { @@ -136,31 +35,6 @@ public void run(Runnable run) { } } - - /** - * Sets data for a player. - * - * @param userData the user data - * @param uuid the player UUID - * @param path the data path - * @param value the value to set - */ - @Deprecated - public void setData(UserData userData, final String uuid, final String path, final Object value) { - synchronized (FileThread.getInstance()) { - try { - File dFile = getPlayerFile(uuid); - FileConfiguration data = getData(userData, uuid); - data.set(path, value); - data.save(dFile); - } catch (Exception e) { - AdvancedCorePlugin.getInstance().getLogger().warning( - "Failed to set a value for " + uuid + ".yml, turn debug on to see full stacktraces"); - AdvancedCorePlugin.getInstance().debug(e); - } - } - - } } /** The instance. */ diff --git a/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/SqlOnlyUserDataTest.java b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/SqlOnlyUserDataTest.java new file mode 100644 index 0000000000..9603099187 --- /dev/null +++ b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/SqlOnlyUserDataTest.java @@ -0,0 +1,115 @@ +package com.bencodez.advancedcore.tests.user; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import com.bencodez.advancedcore.AdvancedCorePlugin; +import com.bencodez.advancedcore.api.user.AdvancedCoreUser; +import com.bencodez.advancedcore.api.user.UserData; +import com.bencodez.advancedcore.api.user.UserDataFetchMode; +import com.bencodez.advancedcore.api.user.UserManager; +import com.bencodez.advancedcore.api.user.UserStorage; +import com.bencodez.advancedcore.api.user.userstorage.mysql.MySQL; +import com.bencodez.advancedcore.api.user.userstorage.sql.UserTable; +import com.bencodez.simpleapi.sql.Column; +import com.bencodez.simpleapi.sql.data.DataValue; +import com.bencodez.simpleapi.sql.data.DataValueInt; +import com.bencodez.simpleapi.sql.data.DataValueString; + +class SqlOnlyUserDataTest { + @Test + void bothSqlBackendsRetainReadAndExistenceBehavior() { + for (UserStorage storage : UserStorage.values()) { + Fixture fixture = new Fixture(storage); + ArrayList row = new ArrayList<>(List.of(new Column("Points", new DataValueInt(12)), + new Column("PlayerName", new DataValueString("Ben")))); + when(fixture.mysql.getExact(fixture.id)).thenReturn(row); + when(fixture.sqlite.getExact(any(Column.class))).thenReturn(row); + when(fixture.mysql.containsKey(fixture.id)).thenReturn(true); + when(fixture.sqlite.containsKey(fixture.id)).thenReturn(true); + assertEquals(12, fixture.data.getInt("Points", 0, UserDataFetchMode.NO_CACHE)); + assertEquals("Ben", fixture.data.getString("PlayerName", UserDataFetchMode.NO_CACHE)); + assertEquals(List.of("Points", "PlayerName"), fixture.data.getKeys()); + assertEquals(2, fixture.data.getValues().size()); + assertTrue(fixture.data.hasData()); + verify(fixture.plugin, never()).getDataFolder(); + } + } + + @Test + void scalarWritesKeepUuidAndSqlValueTypes() { + Fixture sqlite = new Fixture(UserStorage.SQLITE); + sqlite.data.setInt("Points", 24, false); + sqlite.data.setString("PlayerName", "Ben", false); + ArgumentCaptor key = ArgumentCaptor.forClass(Column.class); + @SuppressWarnings({ "rawtypes", "unchecked" }) + ArgumentCaptor> rows = ArgumentCaptor.forClass((Class) ArrayList.class); + verify(sqlite.sqlite, times(2)).update(key.capture(), rows.capture()); + assertEquals(sqlite.id, key.getValue().getValue().getString()); + assertEquals("uuid", rows.getAllValues().get(0).get(0).getName()); + assertEquals(24, rows.getAllValues().get(0).get(1).getValue().getInt()); + assertEquals("Ben", rows.getAllValues().get(1).get(1).getValue().getString()); + verify(sqlite.manager).onChange(sqlite.user, "Points"); + verify(sqlite.manager).onChange(sqlite.user, "PlayerName"); + + Fixture mysql = new Fixture(UserStorage.MYSQL); + mysql.data.setInt("Points", 24, false); + mysql.data.setString("PlayerName", "Ben", false); + ArgumentCaptor values = ArgumentCaptor.forClass(DataValue.class); + verify(mysql.mysql).update(eq(mysql.id), eq("Points"), values.capture()); + assertEquals(24, values.getValue().getInt()); + verify(mysql.mysql).update(eq(mysql.id), eq("PlayerName"), values.capture()); + assertEquals("Ben", values.getValue().getString()); + verify(mysql.plugin, never()).getDataFolder(); + verify(sqlite.plugin, never()).getDataFolder(); + } + + @Test + void removalUsesSelectedSqlTableThenClearsExistingUserCache() { + for (UserStorage storage : UserStorage.values()) { + Fixture fixture = new Fixture(storage); + fixture.data.remove(); + if (storage == UserStorage.MYSQL) { + var order = inOrder(fixture.mysql, fixture.user); + order.verify(fixture.mysql).deletePlayer(fixture.id); + order.verify(fixture.user).clearCache(); + } else { + ArgumentCaptor key = ArgumentCaptor.forClass(Column.class); + var order = inOrder(fixture.sqlite, fixture.user); + order.verify(fixture.sqlite).delete(key.capture()); + order.verify(fixture.user).clearCache(); + assertEquals("uuid", key.getValue().getName()); + assertEquals(fixture.id, key.getValue().getValue().getString()); + } + verify(fixture.plugin, never()).getDataFolder(); + } + } + + private static final class Fixture { + final String id = UUID.randomUUID().toString(); + final AdvancedCorePlugin plugin = mock(AdvancedCorePlugin.class); + final AdvancedCoreUser user = mock(AdvancedCoreUser.class); + final MySQL mysql = mock(MySQL.class); + final UserTable sqlite = mock(UserTable.class); + final UserManager manager = mock(UserManager.class); + final UserData data = new UserData(user); + + Fixture(UserStorage storage) { + when(user.getPlugin()).thenReturn(plugin); + when(user.getUUID()).thenReturn(id); + when(user.getPlayerName()).thenReturn("Ben"); + when(plugin.getStorageType()).thenReturn(storage); + when(plugin.getMysql()).thenReturn(mysql); + when(plugin.getSQLiteUserTable()).thenReturn(sqlite); + when(plugin.getUserManager()).thenReturn(manager); + } + } +} diff --git a/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/UserStorageTest.java b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/UserStorageTest.java index 79017c79d1..76e730bd28 100644 --- a/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/UserStorageTest.java +++ b/AdvancedCore/src/test/java/com/bencodez/advancedcore/tests/user/UserStorageTest.java @@ -15,7 +15,6 @@ public class UserStorageTest { public void testValue_caseInsensitiveMatches() { assertEquals(UserStorage.MYSQL, UserStorage.value("mysql")); assertEquals(UserStorage.SQLITE, UserStorage.value("SQLITE")); - assertEquals(UserStorage.FLAT, UserStorage.value("flat")); } @Test @@ -24,4 +23,18 @@ public void testValue_unknownReturnsNull() { assertNull(UserStorage.value("")); assertNull(UserStorage.value(" ")); } + + @Test + public void flatIsNotAnAvailableStorageType() { + assertArrayEquals(new UserStorage[] { UserStorage.MYSQL, UserStorage.SQLITE }, UserStorage.values()); + assertThrows(IllegalArgumentException.class, () -> UserStorage.valueOf("FLAT")); + } + + @Test + public void retiredFlatConfigurationFailsRatherThanSelectingAnEmptySqlDatabase() { + for (String value : new String[] { "FLAT", "flat", "Flat", " FLAT " }) { + IllegalArgumentException failure = assertThrows(IllegalArgumentException.class, () -> UserStorage.value(value)); + assertTrue(failure.getMessage().contains("previous version")); + } + } } diff --git a/docs/sql-only-user-storage.md b/docs/sql-only-user-storage.md new file mode 100644 index 0000000000..c730fad214 --- /dev/null +++ b/docs/sql-only-user-storage.md @@ -0,0 +1,24 @@ +# SQL-only user storage + +User storage now supports `SQLITE` and `MYSQL` only. `FLAT` is removed from the +enum, normal reads/writes, enumeration, column operations, startup, and deprecated +per-player file helpers. Existing `Data/*.yml` files are neither deleted nor +converted by this change. Ordinary YAML configuration and generic file utilities +remain available. + +An explicit `DataStorage: FLAT` setting fails with an explanatory error instead +of silently starting with an empty SQL database. Complete conversion with the +existing conversion commands in the previous version before upgrading, then +select the populated `SQLITE` or `MYSQL` backend. No new migration, automatic +storage switch, schema change, or rewrite of the existing SQL converter is added. +SQL-to-SQL conversion remains available through `convertDataStorage`. + +This deliberately removes the deprecated `UserStorage.FLAT` enum constant, +`UserData.getData(String)`, and the per-player file CRUD methods on +`FileThread.ReadThread`. Integrations still calling those FLAT-only APIs must +migrate before upgrading. SQL-facing public APIs, fetch modes, cached changes, +write scheduling, serialized values, and reward queues are unchanged. + +The follow-up SQL abstraction builds on this removal. Coordinate both branches +with changes to user data/cache code in PR #317; this removal does not merge or +modify that PR. SimpleAPI remains `1.0.2-SNAPSHOT` in the single Maven project.