Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ public void connect() {
}
````

### With PostgreSQL

````java
public void connect() {
DatabaseConfiguration configuration=DatabaseConfiguration.createPostgreSql(<user>,<password>,<port>,<host>,<database>);
DatabaseConnection connection=new PostgreSqlConnection(configuration,<logger>);
}
````

PostgreSQL uses the `org.postgresql:postgresql` JDBC driver. Consumers must provide this driver at runtime.

### With SQLITE

````java
Expand Down
6 changes: 4 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extra.set("classifier", System.getProperty("archive.classifier"))
extra.set("sha", System.getProperty("github.sha"))

group = "fr.maxlego08.sarah"
version = "1.23"
version = "1.24"

rootProject.extra.properties["sha"]?.let { sha ->
version = sha
Expand All @@ -37,6 +37,7 @@ dependencies {
compileOnly("org.xerial:sqlite-jdbc:3.42.0.0")
compileOnly("org.mariadb.jdbc:mariadb-java-client:3.1.4")
compileOnly("com.mysql:mysql-connector-j:8.2.0")
compileOnly("org.postgresql:postgresql:42.7.3")

// Test dependencies
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3")
Expand All @@ -47,6 +48,7 @@ dependencies {
testImplementation("org.xerial:sqlite-jdbc:3.42.0.0")
testImplementation("org.mariadb.jdbc:mariadb-java-client:3.1.4")
testImplementation("com.mysql:mysql-connector-j:8.2.0")
testImplementation("org.postgresql:postgresql:42.7.3")
}

tasks.withType<Jar> {
Expand Down Expand Up @@ -78,4 +80,4 @@ tasks.test {
publishConfig {
githubOwner = "GroupeZ-dev"
useRootProjectName = true
}
}
12 changes: 12 additions & 0 deletions src/main/java/fr/maxlego08/sarah/DatabaseConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ public static DatabaseConfiguration createMariaDb(String user, String password,
return new DatabaseConfiguration("", user, password, port, host, database, debug, DatabaseType.MARIADB);
}

public static DatabaseConfiguration createPostgreSql(String user, String password, int port, String host, String database) {
return new DatabaseConfiguration("", user, password, port, host, database, false, DatabaseType.POSTGRESQL);
}

public static DatabaseConfiguration createPostgreSql(String user, String password, int port, String host, String database, boolean debug) {
return new DatabaseConfiguration("", user, password, port, host, database, debug, DatabaseType.POSTGRESQL);
}

public static DatabaseConfiguration create(String user, String password, String host, String database, DatabaseType databaseType) {
return new DatabaseConfiguration("", user, password, 3306, host, database, false, databaseType);
}
Expand All @@ -73,6 +81,10 @@ public static DatabaseConfiguration createMariaDb(String user, String password,
return new DatabaseConfiguration("", user, password, 3306, host, database, false, DatabaseType.MARIADB);
}

public static DatabaseConfiguration createPostgreSql(String user, String password, String host, String database) {
return new DatabaseConfiguration("", user, password, 5432, host, database, false, DatabaseType.POSTGRESQL);
}

public static DatabaseConfiguration sqlite(boolean debug) {
return new DatabaseConfiguration("", null, null, 0, null, null, debug, DatabaseType.SQLITE);
}
Expand Down
7 changes: 2 additions & 5 deletions src/main/java/fr/maxlego08/sarah/DatabaseConnection.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.database.DatabaseType;
import fr.maxlego08.sarah.dialect.SqlDialects;
import fr.maxlego08.sarah.exceptions.DatabaseException;
import fr.maxlego08.sarah.logger.Logger;
import fr.maxlego08.sarah.transaction.Transaction;
Expand Down Expand Up @@ -42,11 +43,7 @@ public boolean isValid() {
DatabaseType databaseType = this.databaseConfiguration.getDatabaseType();

try {
if (databaseType == DatabaseType.MARIADB) {
Class.forName("org.mariadb.jdbc.Driver");
} else {
Class.forName("com.mysql.cj.jdbc.Driver");
}
Class.forName(SqlDialects.from(databaseType).driverClassName());
} catch (Exception ignored) {
}

Expand Down
33 changes: 20 additions & 13 deletions src/main/java/fr/maxlego08/sarah/HikariDatabaseConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import fr.maxlego08.sarah.database.DatabaseType;
import fr.maxlego08.sarah.dialect.SqlDialect;
import fr.maxlego08.sarah.dialect.SqlDialects;
import fr.maxlego08.sarah.exceptions.DatabaseException;
import fr.maxlego08.sarah.logger.Logger;

Expand Down Expand Up @@ -38,17 +40,15 @@ private void initializeDataSource() {
config.setPoolName("sarah-" + POOL_COUNTER.getAndIncrement());

DatabaseType databaseType = databaseConfiguration.getDatabaseType();
SqlDialect dialect = SqlDialects.from(databaseType);

// URL + Driver
final String jdbcUrl;
if (databaseType == DatabaseType.MARIADB) {
jdbcUrl = "jdbc:mariadb://" + databaseConfiguration.getHost() + ":" + databaseConfiguration.getPort() + "/" + databaseConfiguration.getDatabase() + "?allowMultiQueries=true";
config.setDriverClassName("org.mariadb.jdbc.Driver");
} else {
jdbcUrl = "jdbc:mysql://" + databaseConfiguration.getHost() + ":" + databaseConfiguration.getPort() + "/" + databaseConfiguration.getDatabase() + "?allowMultiQueries=true";
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
if (databaseType == DatabaseType.SQLITE) {
throw new UnsupportedOperationException("HikariDatabaseConnection does not support SQLITE. Use SqliteConnection for file-based SQLite databases.");
}
config.setJdbcUrl(jdbcUrl);

// URL + Driver
config.setJdbcUrl(dialect.jdbcUrl(databaseConfiguration));
config.setDriverClassName(dialect.driverClassName());
Comment on lines 42 to +51

// Auth
config.setUsername(databaseConfiguration.getUser());
Expand All @@ -74,10 +74,13 @@ private void initializeDataSource() {
config.setLeakDetectionThreshold(LEAK_DETECTION_THRESHOLD);

Map<String, String> commonProps = new HashMap<>();
commonProps.put("useSSL", "false");
commonProps.put("useUnicode", "true");
commonProps.put("characterEncoding", "utf8");
commonProps.put("socketTimeout", String.valueOf(TimeUnit.SECONDS.toMillis(30)));

if (databaseType == DatabaseType.MYSQL || databaseType == DatabaseType.MARIADB) {
commonProps.put("useSSL", "false");
commonProps.put("useUnicode", "true");
commonProps.put("characterEncoding", "utf8");
commonProps.put("socketTimeout", String.valueOf(TimeUnit.SECONDS.toMillis(30)));
}

if (databaseType == DatabaseType.MYSQL) {
commonProps.put("cachePrepStmts", "true");
Expand All @@ -94,6 +97,10 @@ private void initializeDataSource() {
commonProps.put("cacheCallableStmts", "true");
}

if (databaseType == DatabaseType.POSTGRESQL) {
commonProps.put("socketTimeout", "30");
}

for (Map.Entry<String, String> e : commonProps.entrySet()) {
config.addDataSourceProperty(e.getKey(), e.getValue());
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/fr/maxlego08/sarah/MariaDbConnection.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.dialect.SqlDialects;
import fr.maxlego08.sarah.logger.Logger;

import java.sql.Connection;
Expand All @@ -21,6 +22,7 @@ public Connection connectToDatabase() throws Exception {
properties.setProperty("useSSL", "false");
properties.setProperty("user", databaseConfiguration.getUser());
properties.setProperty("password", databaseConfiguration.getPassword());
return DriverManager.getConnection("jdbc:mariadb://" + databaseConfiguration.getHost() + ":" + databaseConfiguration.getPort() + "/" + databaseConfiguration.getDatabase() + "?allowMultiQueries=true", properties);
String url = SqlDialects.from(databaseConfiguration.getDatabaseType()).jdbcUrl(databaseConfiguration);
return DriverManager.getConnection(url, properties);
}
}
43 changes: 5 additions & 38 deletions src/main/java/fr/maxlego08/sarah/MigrationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
import fr.maxlego08.sarah.database.DatabaseType;
import fr.maxlego08.sarah.database.Migration;
import fr.maxlego08.sarah.database.Schema;
import fr.maxlego08.sarah.dialect.SqlDialect;
import fr.maxlego08.sarah.dialect.SqlDialects;
import fr.maxlego08.sarah.exceptions.DatabaseException;
import fr.maxlego08.sarah.logger.Logger;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -106,42 +105,10 @@ public static void execute(DatabaseConnection databaseConnection, Logger logger)
List<ColumnDefinition> mustBeAdd = new ArrayList<>();

String tableName = schema.getTableName();
tableName = tableName.replace("%prefix%", databaseConnection.getDatabaseConfiguration().getTablePrefix());
tableName = databaseConnection.getDatabaseConfiguration().replacePrefix(tableName);

if (databaseConnection.getDatabaseConfiguration().getDatabaseType() == DatabaseType.SQLITE) {
try (Connection connection = databaseConnection.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(String.format("PRAGMA table_info(%s)", tableName))) {
List<ColumnDefinition> columnDefinitions = schema.getColumns();
logger.info("Executing SQL: " + String.format("PRAGMA table_info(%s)", tableName));
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String columnName = resultSet.getString("name");
columnDefinitions.removeIf(column -> column.getName().equals(columnName));
}
}
mustBeAdd.addAll(columnDefinitions);
} catch (SQLException exception) {
logger.info("Failed to get table info for migration: " + exception.getMessage());
throw new DatabaseException("migration-table-info", tableName, exception);
}
} else {
for (ColumnDefinition column : schema.getColumns()) {
Schema columnExistQuery;
long result;
columnExistQuery = SchemaBuilder.selectCount("information_schema.COLUMNS")
.where("TABLE_NAME", tableName)
.where("TABLE_SCHEMA", databaseConnection.getDatabaseConfiguration().getDatabase())
.where("COLUMN_NAME", column.getName());
try {
result = columnExistQuery.executeSelectCount(databaseConnection, logger);
} catch (SQLException e) {
throw new RuntimeException(e);
}
if (result == 0) {
mustBeAdd.add(column);
}
}
}
SqlDialect dialect = SqlDialects.from(databaseConnection.getDatabaseConfiguration().getDatabaseType());
mustBeAdd.addAll(dialect.missingColumns(databaseConnection, logger, tableName, schema.getColumns()));

if (mustBeAdd.isEmpty()) {
return;
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/fr/maxlego08/sarah/MySqlConnection.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.dialect.SqlDialects;
import fr.maxlego08.sarah.logger.Logger;

import java.sql.Connection;
Expand All @@ -18,6 +19,7 @@ public Connection connectToDatabase() throws Exception {
properties.setProperty("useSSL", "false");
properties.setProperty("user", databaseConfiguration.getUser());
properties.setProperty("password", databaseConfiguration.getPassword());
return DriverManager.getConnection("jdbc:mysql://" + databaseConfiguration.getHost() + ":" + databaseConfiguration.getPort() + "/" + databaseConfiguration.getDatabase() + "?allowMultiQueries=true", properties);
String url = SqlDialects.from(databaseConfiguration.getDatabaseType()).jdbcUrl(databaseConfiguration);
return DriverManager.getConnection(url, properties);
}
}
24 changes: 24 additions & 0 deletions src/main/java/fr/maxlego08/sarah/PostgreSqlConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.dialect.SqlDialects;
import fr.maxlego08.sarah.logger.Logger;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

public class PostgreSqlConnection extends DatabaseConnection {

public PostgreSqlConnection(DatabaseConfiguration databaseConfiguration, Logger logger) {
super(databaseConfiguration, logger);
}

@Override
public Connection connectToDatabase() throws Exception {
Properties properties = new Properties();
properties.setProperty("user", databaseConfiguration.getUser());
properties.setProperty("password", databaseConfiguration.getPassword());
String url = SqlDialects.from(databaseConfiguration.getDatabaseType()).jdbcUrl(databaseConfiguration);
return DriverManager.getConnection(url, properties);
}
}
Loading