mirror of
https://github.com/songoda/SongodaCore.git
synced 2024-11-23 10:35:18 +01:00
New data system.
This commit is contained in:
parent
8e644a4be9
commit
fc232fa8b1
@ -0,0 +1,6 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
public interface ComputedValue {
|
||||
|
||||
Object compute();
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public interface DatabaseConnector {
|
||||
|
||||
/**
|
||||
* Checks if the connection to the database has been created
|
||||
*
|
||||
* @return true if the connection is created, otherwise false
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Closes all open connections to the database
|
||||
*/
|
||||
void closeConnection();
|
||||
|
||||
/**
|
||||
* Executes a callback with a Connection passed and automatically closes it when finished
|
||||
*
|
||||
* @param callback The callback to execute once the connection is retrieved
|
||||
*/
|
||||
default void connect(ConnectionCallback callback) {
|
||||
connect(true, callback);
|
||||
}
|
||||
|
||||
void connect(boolean sqlThread, ConnectionCallback callback);
|
||||
|
||||
/**
|
||||
* Wraps a connection in a callback which will automagically handle catching sql errors
|
||||
*/
|
||||
interface ConnectionCallback {
|
||||
void accept(DSLContext ctx) throws SQLException;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import com.craftaro.core.SongodaPlugin;
|
||||
import com.craftaro.core.configuration.Config;
|
||||
import com.craftaro.core.data.connector.H2Connector;
|
||||
import com.craftaro.core.data.connector.MariaDBConnector;
|
||||
import com.craftaro.core.data.connector.MySQLConnector;
|
||||
import com.craftaro.core.data.connector.SQLiteConnector;
|
||||
import com.craftaro.core.thread.MonitoredThread;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DatabaseManager {
|
||||
|
||||
private static DatabaseManager INSTANCE;
|
||||
|
||||
private final MonitoredThread thread;
|
||||
private DatabaseConnector connector;
|
||||
|
||||
private final Config databaseConfig;
|
||||
|
||||
public DatabaseManager(SongodaPlugin plugin) {
|
||||
INSTANCE = this;
|
||||
thread = new MonitoredThread(plugin.getName().toLowerCase() + "-sql-thread", 15, TimeUnit.SECONDS);
|
||||
databaseConfig = new Config(plugin, "database.yml");
|
||||
|
||||
if (!new File(plugin.getDataFolder(), "database.yml").exists())
|
||||
plugin.saveResource("database.yml", false);
|
||||
databaseConfig.load();
|
||||
|
||||
String type = databaseConfig.getString("type", "H2").toUpperCase();
|
||||
String host = databaseConfig.getString("host", "localhost");
|
||||
int port = databaseConfig.getInt("port", 3306);
|
||||
String database = databaseConfig.getString("database", "plugin");
|
||||
String username = databaseConfig.getString("username", "root");
|
||||
String password = databaseConfig.getString("password", "");
|
||||
int poolSize = databaseConfig.getInt("poolSize", 10);
|
||||
boolean useSSL = databaseConfig.getBoolean("useSSL", false);
|
||||
boolean autoReconnect = databaseConfig.getBoolean("autoReconnect", true);
|
||||
|
||||
String dataPath = plugin.getDataFolder().getPath().replaceAll("\\\\", "/") + "/";
|
||||
|
||||
String dbFile = "./" + dataPath + databaseConfig.getString("file", "data");
|
||||
|
||||
switch (DatabaseType.valueOf(type)) {
|
||||
case H2:
|
||||
connector = new H2Connector(dbFile, poolSize);
|
||||
break;
|
||||
case MYSQL:
|
||||
connector = new MySQLConnector(host, port, database, username, password, useSSL, autoReconnect, poolSize);
|
||||
break;
|
||||
case SQLITE:
|
||||
connector = new SQLiteConnector(dbFile, poolSize);
|
||||
break;
|
||||
case MARIADB:
|
||||
connector = new MariaDBConnector(host, port, database, username, password, useSSL, autoReconnect, poolSize);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid database type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(Runnable runnable) {
|
||||
execute(runnable, false);
|
||||
}
|
||||
|
||||
public void execute(Runnable runnable, boolean nonDisruptable) {
|
||||
thread.execute(runnable, nonDisruptable);
|
||||
}
|
||||
|
||||
public void load(String name, Runnable load) {
|
||||
load.run();
|
||||
System.out.println("Loaded " + name);
|
||||
}
|
||||
|
||||
public DatabaseConnector getDatabaseConnector() {
|
||||
return connector;
|
||||
}
|
||||
|
||||
public Config getConfig() {
|
||||
return databaseConfig;
|
||||
}
|
||||
|
||||
public static DatabaseManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
26
Core/src/main/java/com/craftaro/core/data/DatabaseType.java
Normal file
26
Core/src/main/java/com/craftaro/core/data/DatabaseType.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.SQLDialect;
|
||||
|
||||
public enum DatabaseType {
|
||||
|
||||
MARIADB,
|
||||
MYSQL,
|
||||
H2,
|
||||
SQLITE;
|
||||
|
||||
public SQLDialect getDialect() {
|
||||
switch (this) {
|
||||
case MARIADB:
|
||||
return SQLDialect.MARIADB;
|
||||
case MYSQL:
|
||||
return SQLDialect.MYSQL;
|
||||
case SQLITE:
|
||||
return SQLDialect.SQLITE;
|
||||
case H2:
|
||||
return SQLDialect.H2;
|
||||
default:
|
||||
return SQLDialect.DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
19
Core/src/main/java/com/craftaro/core/data/LoadsData.java
Normal file
19
Core/src/main/java/com/craftaro/core/data/LoadsData.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
|
||||
public interface LoadsData {
|
||||
|
||||
|
||||
default void loadData() {
|
||||
DatabaseManager.getInstance().getDatabaseConnector().connect(false, ctx -> {
|
||||
setupTables(ctx);
|
||||
loadDataImpl(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
void loadDataImpl(DSLContext ctx);
|
||||
|
||||
void setupTables(DSLContext ctx);
|
||||
|
||||
}
|
46
Core/src/main/java/com/craftaro/core/data/SQLBase.java
Normal file
46
Core/src/main/java/com/craftaro/core/data/SQLBase.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class SQLBase {
|
||||
|
||||
protected final DSLContext ctx;
|
||||
|
||||
public SQLBase(DSLContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
protected Object cleanValue(Object value) {
|
||||
if (value instanceof ComputedValue) {
|
||||
ComputedValue c = (ComputedValue) value;
|
||||
value = c.compute();
|
||||
}
|
||||
if (value instanceof Collection) {
|
||||
Collection<?> c = (Collection<?>) value;
|
||||
if (c.isEmpty()) {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
if (value instanceof String) {
|
||||
String s = (String) value;
|
||||
if (s.trim().isEmpty()) {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
value = (Boolean) value ? 1 : 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected Field getField(String field, Class<?> type) {
|
||||
String fieldFinal = "`" + field + "`";
|
||||
if (type == boolean.class)
|
||||
return DSL.field(fieldFinal, int.class);
|
||||
return type == null ? DSL.field(fieldFinal) : DSL.field(fieldFinal, type);
|
||||
}
|
||||
}
|
50
Core/src/main/java/com/craftaro/core/data/SQLBatch.java
Normal file
50
Core/src/main/java/com/craftaro/core/data/SQLBatch.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class SQLBatch implements SavesData {
|
||||
|
||||
private final List<SavesData> batch = new LinkedList<>();
|
||||
|
||||
public SQLBatch add(SavesData... data) {
|
||||
batch.addAll(Arrays.asList(data));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLBatch addAll(Collection<? extends SavesData> data) {
|
||||
batch.addAll(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<SavesData> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String... columns) {
|
||||
DatabaseManager.getInstance().getDatabaseConnector().connect(ctx -> {
|
||||
for (SavesData data : batch)
|
||||
data.saveImpl(ctx, columns);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveImpl(DSLContext ctx, String... columns) {
|
||||
for (SavesData data : batch)
|
||||
data.saveImpl(ctx, columns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteImpl(DSLContext ctx) {
|
||||
for (SavesData data : batch)
|
||||
data.deleteImpl(ctx);
|
||||
}
|
||||
|
||||
}
|
24
Core/src/main/java/com/craftaro/core/data/SQLDelete.java
Normal file
24
Core/src/main/java/com/craftaro/core/data/SQLDelete.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
public class SQLDelete extends SQLBase {
|
||||
|
||||
private SQLDelete(DSLContext ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
public static SQLDelete create(DSLContext ctx) {
|
||||
return new SQLDelete(ctx);
|
||||
}
|
||||
|
||||
public void delete(String table, String id, Object value) {
|
||||
new SQLExecutable(ctx, ctx.delete(DSL.table(table)).where(DSL.field(id).eq(value))).execute();
|
||||
}
|
||||
|
||||
public void delete(String table, String id, Object value, String id2, Object value2) {
|
||||
new SQLExecutable(ctx, ctx.delete(DSL.table(table)).where(DSL.field(id).eq(value))
|
||||
.and(DSL.field(id2).eq(value2))).execute();
|
||||
}
|
||||
}
|
40
Core/src/main/java/com/craftaro/core/data/SQLExecutable.java
Normal file
40
Core/src/main/java/com/craftaro/core/data/SQLExecutable.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.ResultQuery;
|
||||
import org.jooq.SelectSelectStep;
|
||||
import org.jooq.UpdateReturningStep;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SQLExecutable extends SQLBase {
|
||||
|
||||
protected Query query;
|
||||
|
||||
public SQLExecutable(DSLContext ctx, Query query) {
|
||||
super(ctx);
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public int execute() {
|
||||
return query.execute();
|
||||
}
|
||||
|
||||
public Stream<SQLResult.StoredRecord> get() {
|
||||
if (query instanceof ResultQuery) {
|
||||
ResultQuery<?> resultQuery = (ResultQuery<?>) query;
|
||||
Result<?> result = resultQuery.getResult();
|
||||
return result.stream().map(SQLResult::new).map(SQLResult::getResults).flatMap(List::stream);
|
||||
} else {
|
||||
throw new IllegalStateException("Query is not an instance of ResultQuery");
|
||||
}
|
||||
}
|
||||
|
||||
public interface SQLResultI {
|
||||
void forEach(SQLResult.StoredRecord result);
|
||||
}
|
||||
}
|
96
Core/src/main/java/com/craftaro/core/data/SQLInsert.java
Normal file
96
Core/src/main/java/com/craftaro/core/data/SQLInsert.java
Normal file
@ -0,0 +1,96 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.InsertOnDuplicateSetMoreStep;
|
||||
import org.jooq.InsertOnDuplicateSetStep;
|
||||
import org.jooq.InsertValuesStepN;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SQLInsert extends SQLBase {
|
||||
|
||||
private String table;
|
||||
private final Map<String, Object> fields = new LinkedHashMap<>();
|
||||
private boolean voidedKey = false;
|
||||
|
||||
private InsertValuesStepN currentStep;
|
||||
|
||||
public SQLInsert(DSLContext ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
public static SQLInsert create(DSLContext ctx) {
|
||||
return new SQLInsert(ctx);
|
||||
}
|
||||
|
||||
public SQLInsert insertInto(String table) {
|
||||
this.table = table;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLInsert withField(String field, Object value, boolean voidKey) {
|
||||
if (voidKey)
|
||||
voidedKey = true;
|
||||
return voidKey ? this : withField(field, value);
|
||||
}
|
||||
|
||||
public SQLInsert withField(String field, Object value) {
|
||||
if (field.equalsIgnoreCase("desc"))
|
||||
field = "`desc`";
|
||||
fields.put(field.toLowerCase(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
// For some reason this must be used before we submit. So I'm going to apply the values here.
|
||||
public SQLExecutable onDuplicateKeyUpdate(String... columns) {
|
||||
currentStep = ctx.insertInto(DSL.table(table), fields.keySet().stream().map(DSL::field).toArray(Field[]::new));
|
||||
currentStep = currentStep.values(fields.values().stream().map(this::cleanValue).toArray());
|
||||
|
||||
if (voidedKey)
|
||||
return new SQLExecutable(ctx, currentStep);
|
||||
|
||||
SQLOnDupeUpdate sqlOnDupeUpdate = new SQLOnDupeUpdate(ctx, currentStep, columns);
|
||||
for (String column : (columns.length > 0 ? new HashSet<>(Arrays.asList(columns)) : fields.keySet()))
|
||||
sqlOnDupeUpdate.set(column.replace("`", ""), fields.get(column.toLowerCase()));
|
||||
return sqlOnDupeUpdate;
|
||||
}
|
||||
|
||||
public static class SQLOnDupeUpdate extends SQLExecutable {
|
||||
|
||||
private InsertOnDuplicateSetStep currentStep;
|
||||
private final List<String> columnsToUpdate = new ArrayList<>();
|
||||
|
||||
|
||||
public SQLOnDupeUpdate(DSLContext ctx, InsertValuesStepN currentStep, String... columns) {
|
||||
super(ctx, null);
|
||||
this.currentStep = currentStep.onDuplicateKeyUpdate();
|
||||
columnsToUpdate.addAll(Arrays.asList(columns));
|
||||
}
|
||||
|
||||
public SQLOnDupeUpdate set(String field, Object value) {
|
||||
if (!columnsToUpdate.isEmpty() && !columnsToUpdate.contains(field))
|
||||
return this;
|
||||
|
||||
value = cleanValue(value);
|
||||
Field fieldName = getField(field, value == null ? null : value.getClass());
|
||||
|
||||
if (currentStep != null) {
|
||||
this.query = value == null ? this.currentStep.setNull(fieldName)
|
||||
: this.currentStep.set(fieldName, value);
|
||||
currentStep = null;
|
||||
} else {
|
||||
this.query = value == null ? ((InsertOnDuplicateSetMoreStep) this.query).setNull(fieldName)
|
||||
: ((InsertOnDuplicateSetMoreStep) this.query).set(fieldName, value);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
63
Core/src/main/java/com/craftaro/core/data/SQLResult.java
Normal file
63
Core/src/main/java/com/craftaro/core/data/SQLResult.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SQLResult {
|
||||
private final List<StoredRecord> results = new LinkedList<>();
|
||||
|
||||
public SQLResult(Result<?> result) {
|
||||
for (Record record : result) {
|
||||
Map<String, StoredData> map = new java.util.HashMap<>();
|
||||
for (Field<?> field : record.fields()) {
|
||||
String fieldName = field.getName();
|
||||
Object value = record.get(fieldName);
|
||||
map.put(fieldName, new StoredData(value));
|
||||
}
|
||||
results.add(new StoredRecord(map));
|
||||
}
|
||||
}
|
||||
|
||||
public SQLResult(Record record) {
|
||||
Map<String, StoredData> map = new java.util.HashMap<>();
|
||||
for (Field<?> field : record.fields()) {
|
||||
String fieldName = field.getName();
|
||||
Object value = record.get(fieldName);
|
||||
map.put(fieldName, new StoredData(value));
|
||||
}
|
||||
results.add(new StoredRecord(map));
|
||||
}
|
||||
|
||||
public List<StoredRecord> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public interface SQLResultI {
|
||||
void forEach(StoredRecord result);
|
||||
}
|
||||
|
||||
public static class StoredRecord {
|
||||
private final Map<String, StoredData> record;
|
||||
|
||||
public StoredRecord(Map<String, StoredData> record) {
|
||||
this.record = record;
|
||||
}
|
||||
|
||||
public StoredData get(String key) {
|
||||
return record.get(key);
|
||||
}
|
||||
|
||||
public boolean has(String key) {
|
||||
return record.containsKey(key) && record.get(key).asString() != null;
|
||||
}
|
||||
|
||||
public boolean isNull(String key) {
|
||||
return record.containsKey(key) && record.get(key).isNull();
|
||||
}
|
||||
}
|
||||
}
|
57
Core/src/main/java/com/craftaro/core/data/SQLSelect.java
Normal file
57
Core/src/main/java/com/craftaro/core/data/SQLSelect.java
Normal file
@ -0,0 +1,57 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SelectSelectStep;
|
||||
import org.jooq.SelectWhereStep;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
public class SQLSelect extends SQLBase {
|
||||
|
||||
private Select<?> currentStep;
|
||||
|
||||
public SQLSelect(DSLContext ctx) {
|
||||
super(ctx);
|
||||
this.currentStep = ctx.select();
|
||||
}
|
||||
|
||||
public static SQLSelect create(DSLContext ctx) {
|
||||
return new SQLSelect(ctx);
|
||||
}
|
||||
|
||||
public SQLSelect select(String... fields) {
|
||||
if (fields.length > 0) {
|
||||
currentStep = ctx.select(DSL.field(fields[0]));
|
||||
for (int i = 1; i < fields.length; i++) {
|
||||
currentStep = ((SelectSelectStep<?>)currentStep).select(DSL.field(fields[i]));
|
||||
}
|
||||
} else {
|
||||
currentStep = ctx.select();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLSelect from(String table) {
|
||||
currentStep = ((SelectSelectStep<?>)currentStep).from(DSL.table(table));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void from(String table, SQLResult.SQLResultI result) {
|
||||
Result<?> resultData = ((SelectSelectStep<?>)currentStep).from(DSL.table(table)).fetch();
|
||||
SQLResult rs = new SQLResult(resultData);
|
||||
for (SQLResult.StoredRecord record : rs.getResults()) {
|
||||
result.forEach(record);
|
||||
}
|
||||
}
|
||||
|
||||
public SQLWhere where(String id, Object value) {
|
||||
currentStep = ((SelectWhereStep<?>)currentStep).where(DSL.field(id).eq(value));
|
||||
return new SQLWhere(ctx, currentStep);
|
||||
}
|
||||
|
||||
public SQLWhere whereBetween(String id, Object value1, Object value2) {
|
||||
currentStep = ((SelectWhereStep<?>)currentStep).where(DSL.field(id).between(value1, value2));
|
||||
return new SQLWhere(ctx, currentStep);
|
||||
}
|
||||
}
|
47
Core/src/main/java/com/craftaro/core/data/SQLUpdate.java
Normal file
47
Core/src/main/java/com/craftaro/core/data/SQLUpdate.java
Normal file
@ -0,0 +1,47 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.UpdateSetMoreStep;
|
||||
import org.jooq.UpdateSetStep;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SQLUpdate extends SQLBase {
|
||||
|
||||
private final List<String> columnsToUpdate = new ArrayList<>();
|
||||
|
||||
private UpdateSetStep currentStep;
|
||||
|
||||
private SQLUpdate(DSLContext ctx, String... columns) {
|
||||
super(ctx);
|
||||
columnsToUpdate.addAll(Arrays.asList(columns));
|
||||
}
|
||||
|
||||
public static SQLUpdate create(DSLContext ctx, String... columns) {
|
||||
return new SQLUpdate(ctx, columns);
|
||||
}
|
||||
|
||||
public SQLUpdate update(String table) {
|
||||
this.currentStep = ctx.update(DSL.table(table));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLUpdate set(String field, Object value) {
|
||||
if (!columnsToUpdate.isEmpty() && !columnsToUpdate.contains(field))
|
||||
return this;
|
||||
|
||||
value = cleanValue(value);
|
||||
Field fieldName = getField(field, value == null ? null : value.getClass());
|
||||
|
||||
this.currentStep = value == null ? this.currentStep.setNull(fieldName) : this.currentStep.set(fieldName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLWhere where(String id, Object value) {
|
||||
return new SQLWhere(ctx, ((UpdateSetMoreStep) this.currentStep).where(DSL.field(id).eq(value)));
|
||||
}
|
||||
}
|
23
Core/src/main/java/com/craftaro/core/data/SQLWhere.java
Normal file
23
Core/src/main/java/com/craftaro/core/data/SQLWhere.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.UpdateConditionStep;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
public class SQLWhere extends SQLExecutable {
|
||||
|
||||
public SQLWhere(DSLContext ctx, Query query) {
|
||||
super(ctx, query);
|
||||
}
|
||||
|
||||
public SQLWhere and(String id, Object value) {
|
||||
query = ((UpdateConditionStep) query).and(DSL.field(id).eq(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLWhere or(String id, Object value) {
|
||||
query = ((UpdateConditionStep) query).or(DSL.field(id).eq(value));
|
||||
return this;
|
||||
}
|
||||
}
|
40
Core/src/main/java/com/craftaro/core/data/SavesData.java
Normal file
40
Core/src/main/java/com/craftaro/core/data/SavesData.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
public interface SavesData {
|
||||
|
||||
default void save(String... columns) {
|
||||
DatabaseManager.getInstance().getDatabaseConnector().connect(ctx ->
|
||||
saveImpl(ctx, columns));
|
||||
}
|
||||
|
||||
default void save(Runnable callback, String... columns) {
|
||||
DatabaseManager.getInstance().getDatabaseConnector().connect(ctx -> {
|
||||
saveImpl(ctx, columns);
|
||||
callback.run();
|
||||
});
|
||||
}
|
||||
|
||||
default void delete() {
|
||||
DatabaseManager.getInstance().getDatabaseConnector().connect(this::deleteImpl);
|
||||
}
|
||||
|
||||
void saveImpl(DSLContext ctx, String... columns);
|
||||
|
||||
void deleteImpl(DSLContext ctx);
|
||||
|
||||
default int lastInsertedId(String table, DSLContext ctx) {
|
||||
try {
|
||||
Result<Record1<Object>> results = ctx.select(DSL.field("id")).from(DSL.table(table)).orderBy(DSL.field("id").desc()).fetch();
|
||||
Record1<Object> result = results.get(0);
|
||||
return result != null ? result.get(DSL.field("id"), Integer.class) : -1;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
75
Core/src/main/java/com/craftaro/core/data/StoredData.java
Normal file
75
Core/src/main/java/com/craftaro/core/data/StoredData.java
Normal file
@ -0,0 +1,75 @@
|
||||
package com.craftaro.core.data;
|
||||
|
||||
import com.craftaro.core.utils.ItemSerializer;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
public class StoredData {
|
||||
|
||||
private Object object;
|
||||
|
||||
public StoredData(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
if (object == null) return null;
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
if (object == null) return 0;
|
||||
return Integer.parseInt(asString());
|
||||
}
|
||||
|
||||
public double asDouble() {
|
||||
return Double.parseDouble(asString());
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
String string = asString();
|
||||
if (string == null) return 0;
|
||||
return Long.parseLong(string);
|
||||
}
|
||||
|
||||
public Instant asInstant() {
|
||||
return Instant.ofEpochMilli(asLong());
|
||||
}
|
||||
|
||||
public boolean asBoolean() {
|
||||
if (object instanceof Integer)
|
||||
return (int) object == 1;
|
||||
return Boolean.parseBoolean(asString());
|
||||
}
|
||||
|
||||
public void swap(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return object == null;
|
||||
}
|
||||
|
||||
// get longblob
|
||||
public byte[] asBytes() {
|
||||
return (byte[]) object;
|
||||
}
|
||||
|
||||
public UUID asUniqueID() {
|
||||
return UUID.fromString(asString());
|
||||
}
|
||||
|
||||
public ItemStack asItemStack() {
|
||||
return ItemSerializer.deserializeItem(asBytes());
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.craftaro.core.data.connector;
|
||||
|
||||
import com.craftaro.core.data.DatabaseConnector;
|
||||
import com.craftaro.core.data.DatabaseManager;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
public class H2Connector implements DatabaseConnector {
|
||||
private HikariDataSource hikari;
|
||||
private boolean initializedSuccessfully;
|
||||
|
||||
public H2Connector(String databaseFile, int poolSize) {
|
||||
System.out.println("Connecting to H2 database: " + databaseFile);
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setDriverClassName("com;craftaro;third_party;org;h2;Driver".replace(";", "."));
|
||||
config.setJdbcUrl("jdbc:h2:" + databaseFile + ";AUTO_RECONNECT=TRUE;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE");
|
||||
config.setMaximumPoolSize(poolSize);
|
||||
|
||||
try {
|
||||
this.hikari = new HikariDataSource(config);
|
||||
this.initializedSuccessfully = true;
|
||||
} catch (Exception ex) {
|
||||
this.initializedSuccessfully = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return this.initializedSuccessfully;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
this.hikari.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(boolean sqlThread, ConnectionCallback callback) {
|
||||
Runnable runnable = () -> {
|
||||
try (Connection connection = this.hikari.getConnection()) {
|
||||
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
|
||||
} catch (Exception ex) {
|
||||
System.out.println("An error occurred executing an H2 query: " + ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
if (sqlThread)
|
||||
DatabaseManager.getInstance().execute(runnable);
|
||||
else
|
||||
runnable.run();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.craftaro.core.data.connector;
|
||||
|
||||
import com.craftaro.core.data.DatabaseConnector;
|
||||
import com.craftaro.core.data.DatabaseManager;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
public class MariaDBConnector implements DatabaseConnector {
|
||||
private HikariDataSource hikari;
|
||||
private boolean initializedSuccessfully;
|
||||
|
||||
public MariaDBConnector(String hostname, int port, String database, String username, String password, boolean useSSL, boolean autoReconnect, int poolSize) {
|
||||
System.out.println("Connecting to MariaDB: " + hostname + ":" + port);
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:mariadb://" + hostname + ":" + port + "/" + database);
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
config.setMaximumPoolSize(poolSize);
|
||||
config.addDataSourceProperty("useSSL", useSSL);
|
||||
config.addDataSourceProperty("autoReconnect", autoReconnect);
|
||||
|
||||
try {
|
||||
this.hikari = new HikariDataSource(config);
|
||||
this.initializedSuccessfully = true;
|
||||
} catch (Exception ex) {
|
||||
this.initializedSuccessfully = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return this.initializedSuccessfully;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
this.hikari.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(boolean sqlThread, ConnectionCallback callback) {
|
||||
Runnable runnable = () -> {
|
||||
try (Connection connection = this.hikari.getConnection()) {
|
||||
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
|
||||
} catch (Exception ex) {
|
||||
System.out.println("An error occurred executing a MariaDB query: " + ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
if (sqlThread) DatabaseManager.getInstance().execute(runnable);
|
||||
else runnable.run();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.craftaro.core.data.connector;
|
||||
|
||||
import com.craftaro.core.data.DatabaseConnector;
|
||||
import com.craftaro.core.data.DatabaseManager;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
public class MySQLConnector implements DatabaseConnector {
|
||||
|
||||
private HikariDataSource hikari;
|
||||
private boolean initializedSuccessfully;
|
||||
|
||||
public MySQLConnector(String hostname, int port, String database, String username, String password, boolean useSSL, boolean autoReconnect, int poolSize) {
|
||||
|
||||
System.out.println("Connecting to " + hostname + " : " + port);
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database + "?useSSL=" + useSSL + "&autoReconnect=" + autoReconnect);
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
config.setMaximumPoolSize(poolSize);
|
||||
|
||||
try {
|
||||
this.hikari = new HikariDataSource(config);
|
||||
this.initializedSuccessfully = true;
|
||||
} catch (Exception ex) {
|
||||
this.initializedSuccessfully = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return this.initializedSuccessfully;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
this.hikari.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(boolean sqlThread, ConnectionCallback callback) {
|
||||
Runnable runnable = () -> {
|
||||
try (Connection connection = this.hikari.getConnection()) {
|
||||
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
|
||||
} catch (Exception ex) {
|
||||
System.out.println("An error occurred executing a MySQL query: " + ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
};
|
||||
if (sqlThread)
|
||||
DatabaseManager.getInstance().execute(runnable);
|
||||
else
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.craftaro.core.data.connector;
|
||||
|
||||
import com.craftaro.core.data.DatabaseConnector;
|
||||
import com.craftaro.core.data.DatabaseManager;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.DSL;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
public class SQLiteConnector implements DatabaseConnector {
|
||||
private HikariDataSource hikari;
|
||||
private boolean initializedSuccessfully;
|
||||
|
||||
public SQLiteConnector(String databaseFile, int poolSize) {
|
||||
System.out.println("Connecting to SQLite database: " + databaseFile);
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:sqlite:" + databaseFile);
|
||||
config.setMaximumPoolSize(poolSize);
|
||||
|
||||
try {
|
||||
this.hikari = new HikariDataSource(config);
|
||||
this.initializedSuccessfully = true;
|
||||
} catch (Exception ex) {
|
||||
this.initializedSuccessfully = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return this.initializedSuccessfully;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
this.hikari.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(boolean sqlThread, ConnectionCallback callback) {
|
||||
Runnable runnable = () -> {
|
||||
try (Connection connection = this.hikari.getConnection()) {
|
||||
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
|
||||
} catch (Exception ex) {
|
||||
System.out.println("An error occurred executing a SQLite query: " + ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
if (sqlThread)
|
||||
DatabaseManager.getInstance().execute(runnable);
|
||||
else
|
||||
runnable.run();
|
||||
}
|
||||
}
|
66
Core/src/main/java/com/craftaro/core/data/lazy/Lazy.java
Normal file
66
Core/src/main/java/com/craftaro/core/data/lazy/Lazy.java
Normal file
@ -0,0 +1,66 @@
|
||||
package com.craftaro.core.data.lazy;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class Lazy<T> {
|
||||
|
||||
private Supplier<T> supplier = null;
|
||||
private T value = null;
|
||||
|
||||
public synchronized T get() {
|
||||
if (value == null && supplier != null) {
|
||||
value = supplier.get();
|
||||
supplier = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public synchronized T getOrDefault(T def) {
|
||||
T value = get();
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
public synchronized Lazy<T> reset() {
|
||||
value = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized Lazy<T> set(T value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Lazy<T> set(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized boolean isLoaded() {
|
||||
return supplier != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return get().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == get()) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof Lazy) {
|
||||
Lazy<?> other = (Lazy<?>) obj;
|
||||
return get().equals(other.get());
|
||||
}
|
||||
return get().equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return get().hashCode();
|
||||
}
|
||||
}
|
66
Core/src/main/java/com/craftaro/core/data/lazy/LazyList.java
Normal file
66
Core/src/main/java/com/craftaro/core/data/lazy/LazyList.java
Normal file
@ -0,0 +1,66 @@
|
||||
package com.craftaro.core.data.lazy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyList<T> {
|
||||
|
||||
private final List<T> list;
|
||||
private List<Lazy<T>> lazyList;
|
||||
|
||||
public LazyList(List list) {
|
||||
this.list = list == null ? new LinkedList<>() : list;
|
||||
this.lazyList = new LinkedList<>();
|
||||
}
|
||||
|
||||
public List<T> getList() {
|
||||
loadList();
|
||||
return list;
|
||||
}
|
||||
|
||||
public Set<T> getSet() {
|
||||
loadList();
|
||||
return new HashSet<>(list);
|
||||
}
|
||||
|
||||
public void add(Supplier<T> supplier) {
|
||||
if (lazyList == null)
|
||||
list.add(supplier.get());
|
||||
else if (supplier != null)
|
||||
lazyList.add(new Lazy<T>().set(supplier));
|
||||
}
|
||||
|
||||
public void add(T items) {
|
||||
list.add(items);
|
||||
}
|
||||
|
||||
public void addAll(List<T> items) {
|
||||
list.addAll(items);
|
||||
}
|
||||
|
||||
public void addAll(Supplier<T>... suppliers) {
|
||||
for (Supplier<T> supplier : suppliers)
|
||||
add(supplier);
|
||||
}
|
||||
|
||||
private void loadList() {
|
||||
if (lazyList == null) return;
|
||||
for (Lazy<T> lazy : lazyList)
|
||||
list.add(lazy.get());
|
||||
lazyList = null;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
list.clear();
|
||||
lazyList.clear();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
if (lazyList != null)
|
||||
return lazyList.isEmpty();
|
||||
return list.isEmpty();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user