com.ptsmods.mysqlw.collection.DbMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of MySQLw Show documentation
Show all versions of MySQLw Show documentation
A wrapper for MySQL connections
package com.ptsmods.mysqlw.collection;
import com.google.common.base.Preconditions;
import com.ptsmods.mysqlw.Database;
import com.ptsmods.mysqlw.query.QueryCondition;
import com.ptsmods.mysqlw.query.SelectResults;
import com.ptsmods.mysqlw.table.ColumnType;
import com.ptsmods.mysqlw.table.TableIndex;
import com.ptsmods.mysqlw.table.TablePreset;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.BiFunction;
public class DbMap extends AbstractMap implements DbCollection {
private static final TablePreset preset = TablePreset.create("map_")
.putColumn("m_key", ColumnType.VARCHAR.createStructure()
.satiateSupplier(sup -> sup.apply(255))
.setPrimary(true)
.setNullAllowed(false))
.putColumn("m_val", ColumnType.TEXT.createStructure())
.addIndex(TableIndex.index("m_key", TableIndex.Type.FULLTEXT));
private static final Map> cache = new HashMap<>();
private final Database db;
private final String table;
private final String name;
private final BiFunction keyToString;
private final BiFunction valueToString;
private final BiFunction keyFromString;
private final BiFunction valueFromString;
/**
* Parses a String representation of a DbMap into a DbMap.
* @param db The database this map belongs to. Used when creating a new map.
* @param s The String to parse.
* @param keyToString The function used to convert a key object of this map into a String. Used when creating a new map.
* @param valueToString The function used to convert a value object of this map into a String. Used when creating a new map.
* @param keyFromString The function used to convert a String into a key object of this map. Used when creating a new map.
* @param valueFromString The function used to convert a String into a value object of this map. Used when creating a new map.
* @param The key type of this map.
* @param The value type of this map.
* @return A new DbMap or a cached one if available.
*/
public static DbMap parseString(Database db, String s, BiFunction keyToString, BiFunction valueToString, BiFunction keyFromString, BiFunction valueFromString) {
return s.startsWith("DbMap[name=") ? getMap(db, Database.readQuotedString(s.substring("DbMap[name=".length())), keyToString, valueToString, keyFromString, valueFromString) : null;
}
/**
* Gets a map from cache or creates a new one.
* @param db The database this map belongs to. Used when creating a new map.
* @param name The name of this map.
* @param keyType The class of the type of the keys in this map, registered at {@link DbCF}. Used when creating a new map.
* @param valueType The class of the type of the values in this map, registered at {@link DbCF}. Used when creating a new map.
* @param The type of the keys in this map.
* @param The type of the values in this map.
* @return A new DbMap or a cached one if available.
*/
public static DbMap getMap(Database db, String name, Class keyType, Class valueType) {
return getMap(db, name, DbCF.getTo(keyType), DbCF.getTo(valueType), DbCF.getFrom(keyType), DbCF.getFrom(valueType));
}
/**
* Gets a map from cache or creates a new one.
* @param db The database this map belongs to. Used when creating a new map.
* @param name The name of this map.
* @param keyToString The function used to convert a key object of this map into a String. Used when creating a new map.
* @param valueToString The function used to convert a value object of this map into a String. Used when creating a new map.
* @param keyFromString The function used to convert a String into a key object of this map. Used when creating a new map.
* @param valueFromString The function used to convert a String into a value object of this map. Used when creating a new map.
* @param The type of the keys in this map.
* @param The type of the values in this map.
* @return A new DbMap or a cached one if available.
*/
public static DbMap getMap(Database db, String name, BiFunction keyToString, BiFunction valueToString, BiFunction keyFromString, BiFunction valueFromString) {
if (cache.containsKey(name))
try {
return (DbMap) cache.get(name);
} catch (ClassCastException e) {
throw new IllegalArgumentException("Wrong types! Cached DbMap with the given name has different types than requested.", e);
}
else return new DbMap<>(db, name, keyToString, valueToString, keyFromString, valueFromString);
}
private DbMap(Database db, String name, BiFunction keyToString, BiFunction valueToString, BiFunction keyFromString, BiFunction valueFromString) {
if (cache.containsKey(name)) throw new IllegalArgumentException("A DbMap by this name already exists.");
Preconditions.checkNotNull(db, "database");
Preconditions.checkNotNull(keyToString, "keyToString");
Preconditions.checkNotNull(keyFromString, "keyFromString");
Preconditions.checkNotNull(valueToString, "valueToString");
Preconditions.checkNotNull(valueFromString, "valueFromString");
this.db = db;
this.table = "map_" + name;
this.name = name;
// We could first check if the table exists, but if we're gonna make a call to the database anyway,
// we might as well just make one call that only creates a new table if it does not yet exist.
// Otherwise we'd have to make a call to check if the table exists and then one to make it if it doesn't.
preset.setName(table).create(db);
this.keyToString = keyToString;
this.valueToString = valueToString;
this.keyFromString = keyFromString;
this.valueFromString = valueFromString;
cache.put(name, this);
}
@Override
public int size() {
return db.count(table, "m_key", null);
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public boolean containsKey(Object key) {
return db.select(table, "m_key", QueryCondition.equals("m_key", keyToString.apply((K) key, this)), null, null).size() > 0;
}
@Override
public boolean containsValue(Object value) {
return db.select(table, "m_val", QueryCondition.equals("m_val", value == null ? null : valueToString.apply((V) value, this)), null, null).size() > 0;
}
@Override
public V get(Object key) {
SelectResults data = db.select(table, "m_val", QueryCondition.equals("m_key", keyToString.apply((K) key, this)), null, null);
if (data.isEmpty()) return null;
else return data.get(0).get("m_val") == null ? null : valueFromString.apply(String.valueOf(data.get(0).get("m_val")), this);
}
@Nullable
@Override
public V put(K key, V value) {
if (key == null) throw new NullPointerException("Key cannot be null.");
V old = get(key);
db.replace(table, new String[] {"m_key", "m_val"}, new String[] {keyToString.apply(key, this), value == null ? null : valueToString.apply(value, this)});
return old;
}
@Override
public V remove(Object key) {
V value = get(key);
db.delete(table, QueryCondition.equals("m_key", keyToString.apply((K) key, this)));
return value;
}
@Override
public void putAll(@Nonnull Map extends K, ? extends V> m) { // Way more efficient to put them all in at once than going at it one by one and calling #put.
List