diff --git a/Database/src/main/java/fr/altarik/toolbox/database/AbstractSqlConnection.java b/Database/src/main/java/fr/altarik/toolbox/database/AbstractSqlConnection.java index 7fefcce..e2a4c15 100644 --- a/Database/src/main/java/fr/altarik/toolbox/database/AbstractSqlConnection.java +++ b/Database/src/main/java/fr/altarik/toolbox/database/AbstractSqlConnection.java @@ -25,16 +25,18 @@ public abstract class AbstractSqlConnection implements SqlConnection { return connection; } + @Override public void closeConnection() { try { - if(!connection.isClosed()) { - connection.close(); - connection = null; - } - } catch(SQLException ignored) { - // no op - } + close(); + } catch (Exception ignored) {} } - + @Override + public void close() throws Exception { + if(!connection.isClosed()) { + connection.close(); + connection = null; + } + } } diff --git a/Database/src/main/java/fr/altarik/toolbox/database/PostgresConnection.java b/Database/src/main/java/fr/altarik/toolbox/database/PostgresConnection.java index beac2bb..a20d381 100644 --- a/Database/src/main/java/fr/altarik/toolbox/database/PostgresConnection.java +++ b/Database/src/main/java/fr/altarik/toolbox/database/PostgresConnection.java @@ -5,7 +5,7 @@ import java.sql.SQLException; public class PostgresConnection extends AbstractSqlConnection { - PostgresConnection(ConnectionConfig config) throws SQLException { + public PostgresConnection(ConnectionConfig config) throws SQLException { super(config); } diff --git a/Database/src/main/java/fr/altarik/toolbox/database/SqlConnection.java b/Database/src/main/java/fr/altarik/toolbox/database/SqlConnection.java index 0b04fe4..a2839d7 100644 --- a/Database/src/main/java/fr/altarik/toolbox/database/SqlConnection.java +++ b/Database/src/main/java/fr/altarik/toolbox/database/SqlConnection.java @@ -3,14 +3,30 @@ package fr.altarik.toolbox.database; import java.sql.Connection; import java.sql.SQLException; -public interface SqlConnection { +public interface SqlConnection extends AutoCloseable { + /** + * Start the connection to sql database + * @throws SQLException if unable to connect to database + */ void connect() throws SQLException; + /** + * Get the sql connection + * @return the connection session + */ Connection getConnection(); + /** + * Reconnect you to database if it has closed or lost. + * @throws SQLException if unable to reconnect you + */ void checkConnection() throws SQLException; + /** + * @deprecated replaced with {@link AutoCloseable#close()} + */ + @Deprecated(forRemoval = true) void closeConnection(); } diff --git a/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java b/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java new file mode 100644 index 0000000..a665599 --- /dev/null +++ b/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueBuilder.java @@ -0,0 +1,59 @@ +package fr.altarik.toolbox.database.keyvalue; + +import fr.altarik.toolbox.database.SqlConnection; +import net.minecraft.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.sql.JDBCType; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class KeyValueBuilder { + + private final String tableName; + private final List additionalColumns; + private final SqlConnection connection; + + private KeyValueBuilder(SqlConnection connection, String tableName) { + this.connection = connection; + this.tableName = tableName; + this.additionalColumns = new ArrayList<>(); + } + + public static KeyValueBuilder builder(@NotNull SqlConnection connection, @NotNull String tableName) { + return new KeyValueBuilder(connection, tableName); + } + + public KeyValueBuilder addColumn(AdditionalColumn additionalColumn) { + this.additionalColumns.add(additionalColumn); + return this; + } + + public KeyValueConnection build() throws SQLException { + return new KeyValueConnection(connection, tableName, additionalColumns); + } + + public record AdditionalColumn(@NotNull String columnName, @NotNull JDBCType type, boolean notNull, @Nullable AdditionalColumnReference reference) { + public AdditionalColumn { + Objects.requireNonNull(columnName); + Objects.requireNonNull(type); + } + + public Pair toPair(Object value) { + return new Pair<>(this, value); + } + } + + public record AdditionalColumnReference(@NotNull String referenceTable, @NotNull String... referenceColumns) { + public AdditionalColumnReference { + Objects.requireNonNull(referenceTable); + if(Objects.requireNonNull(referenceColumns).length == 0) + throw new IllegalArgumentException("Reference Columns should not be empty"); + } + + } + +} diff --git a/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueConnection.java b/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueConnection.java new file mode 100644 index 0000000..9970629 --- /dev/null +++ b/Database/src/main/java/fr/altarik/toolbox/database/keyvalue/KeyValueConnection.java @@ -0,0 +1,146 @@ +package fr.altarik.toolbox.database.keyvalue; + +import fr.altarik.toolbox.database.SqlConnection; +import net.minecraft.util.Pair; +import org.jetbrains.annotations.Nullable; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; + +public class KeyValueConnection { + + private final SqlConnection connection; + private final String tableName; + private final List additionColumns; + + public KeyValueConnection(SqlConnection connection, String tableName, List additionalColumns) throws SQLException { + this.connection = connection; + this.tableName = tableName; + this.additionColumns = additionalColumns; + + try(Statement statement = connection.getConnection().createStatement()) { + StringBuilder sql = new StringBuilder("CREATE TABLE IF NOT EXISTS ").append(tableName).append("(id SERIAL,"); + for(KeyValueBuilder.AdditionalColumn additionalColumn : additionalColumns) { + sql.append(additionalColumn.columnName()).append(" ").append(additionalColumn.type().getName()); + if(additionalColumn.notNull()) { + sql.append(" NOT NULL "); + } + if(additionalColumn.reference() != null) { + sql.append("REFERENCES ").append(additionalColumn.reference().referenceTable()).append("("); + for(int i = 0; i < additionalColumn.reference().referenceColumns().length; ++i) { + sql.append(additionalColumn.reference().referenceColumns()[i]); + if(i != additionalColumn.reference().referenceColumns().length - 1) { + sql.append(", "); + } + } + sql.append(")"); + } + sql.append(","); + sql.append("key VARCHAR(50) NOT NULL,").append("value TEXT NOT NULL,").append("PRIMARY KEY(id)"); + } + statement.executeUpdate(sql.toString()); + + + } + } + + public @Nullable String getValueById(int id) throws SQLException { + try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("SELECT value FROM " + tableName + " WHERE id=?")) { + preparedStatement.setInt(1, id); + ResultSet resultSet = preparedStatement.executeQuery(); + if(resultSet.next()) { + return resultSet.getString(1); + } + return null; + } + } + + public @Nullable String getValueByAdditionalColumnAndKey(String key, List> additionalColumns) throws SQLException { + StringBuilder sql = new StringBuilder("SELECT value FROM ").append(tableName).append(" WHERE key=? AND "); + for(int i = 0; i < additionalColumns.size(); ++i) { + sql.append(additionalColumns.get(i).getLeft().columnName()).append("=?"); + if(i != additionalColumns.size() - 1) { + sql.append(" AND "); + } + } + sql.append(";"); + try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement(sql.toString())) { + preparedStatement.setString(1, key); + for(int i = 0; i < additionalColumns.size(); ++i) { + preparedStatement.setObject(i + 1, additionalColumns.get(i).getRight()); + } + ResultSet resultSet = preparedStatement.executeQuery(); + if(resultSet.next()) + return resultSet.getString(1); + return null; + } + } + + public long insertValue(String key, String value, List> additionalColumns) throws SQLException { + StringBuilder sql = new StringBuilder("INSERT INTO " + tableName + "(key, value"); + for(int i = 0; i < additionalColumns.size(); ++i) { + if(i != additionalColumns.size() - 1) { + sql.append(", "); + } + sql.append(additionalColumns.get(i).getLeft().columnName()); + + } + sql.append(") VALUES (?, ?"); + for(int i = 0; i < additionalColumns.size(); ++i) { + if(i != additionalColumns.size() - 1) { + sql.append(", "); + } + sql.append("?"); + } + sql.append(");"); + try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS)){ + preparedStatement.setString(1, key); + preparedStatement.setString(2, value); + for(int i = 0; i < additionalColumns.size(); ++i) { + preparedStatement.setObject(i + 3, additionalColumns.get(i).getRight()); + } + preparedStatement.executeUpdate(); + try(ResultSet resultSet = preparedStatement.getGeneratedKeys()) { + if(resultSet.next()) { + return resultSet.getLong(1); + } + return -1L; + } + } + } + + public void updateValueById(String key, String value) throws SQLException { + try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("UPDATE " + tableName + " SET value=? WHERE key=?")) { + preparedStatement.setString(1, value); + preparedStatement.setString(2, key); + preparedStatement.executeUpdate(); + } + + } + + public void updateValue(String key, String value, List> additionalColumns) throws SQLException { + StringBuilder sql = new StringBuilder("UPDATE " + tableName + " SET value=? WHERE key=?"); + for(int i = 0; i < additionalColumns.size(); ++i) { + if(i != additionalColumns.size() - 1) { + sql.append(" AND "); + } + sql.append(additionalColumns.get(i).getLeft().columnName()).append("=?"); + } + sql.append(";"); + try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement(sql.toString())) { + preparedStatement.setString(1, value); + preparedStatement.setString(2, key); + for(int i = 0; i < additionalColumns.size(); ++i) { + preparedStatement.setObject(3 + i, additionalColumns.get(i).getRight()); + } + preparedStatement.executeUpdate(); + } + } + + public List getAdditionColumns() { + return additionColumns; + } +} diff --git a/build.gradle b/build.gradle index d168d1d..e6c86e7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.1-SNAPSHOT' apply false + id 'fabric-loom' version '1.2-SNAPSHOT' apply false } allprojects { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 070cb70..59bc51a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists