Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
.claude/

### IntelliJ IDEA ###
.idea/modules.xml
Expand Down
79 changes: 30 additions & 49 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,22 @@ import java.util.Locale

plugins {
`java-library`
id("com.github.johnrengelman.shadow") version "7.1.2" // Pour remplacer maven-shade-plugin
id("re.alwyn974.groupez.publish") version "1.0.0"
id("com.gradleup.shadow") version "9.0.0-beta11"
`maven-publish`
}

rootProject.extra.properties["sha"]?.let { sha ->
version = sha
}

group = "fr.maxlego08.sarah"
version = "1.20.2"


extra.set("targetFolder", file("target/"))
extra.set("apiFolder", file("target-api/"))
extra.set("classifier", System.getProperty("archive.classifier"))
extra.set("sha", System.getProperty("github.sha"))

group = "fr.maxlego08.sarah"
version = "1.21"

rootProject.extra.properties["sha"]?.let { sha ->
version = sha
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
Expand All @@ -33,6 +32,16 @@ repositories {

dependencies {
implementation("com.zaxxer:HikariCP:4.0.3")

// Test dependencies
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.3")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3")
testImplementation("org.mockito:mockito-core:5.3.1")
testImplementation("org.mockito:mockito-junit-jupiter:5.3.1")
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")
}

tasks.withType<Jar> {
Expand All @@ -52,44 +61,16 @@ tasks.build {
dependsOn(tasks.shadowJar)
}

publishing {

var repository = System.getProperty("repository.name", "snapshots").replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }

repositories {
maven {
name = "groupez${repository}"
url = uri("https://repo.groupez.dev/${repository.lowercase()}")
credentials {
username = findProperty("${name}Username") as String? ?: System.getenv("MAVEN_USERNAME")
password = findProperty("${name}Password") as String? ?: System.getenv("MAVEN_PASSWORD")
}
authentication {
create<BasicAuthentication>("basic")
}
}
}
tasks.shadowJar {
archiveClassifier.set("")
destinationDirectory.set(rootProject.extra["targetFolder"] as File)
}

publications {
register<MavenPublication>("groupez${repository}") {
pom {
groupId = project.group as String?
artifactId = rootProject.name.lowercase()
version = if (repository.lowercase() == "snapshots") {
System.getProperty("github.sha")
} else {
project.version as String?
}

scm {
connection = "scm:git:git://github.com/GroupeZ-dev/${rootProject.name}.git"
developerConnection = "scm:git:ssh://github.com/GroupeZ-dev/${rootProject.name}.git"
url = "https://github.com/GroupeZ-dev/${rootProject.name}/"
}
}
artifact(tasks.shadowJar)
// artifact(tasks.javadocJar)
// artifact(tasks.sourcesJar)
}
}
tasks.test {
useJUnitPlatform()
}

publishConfig {
githubOwner = "GroupeZ-dev"
useRootProjectName = true
}
Empty file modified gradlew
100755 → 100644
Empty file.
12 changes: 11 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
rootProject.name = "Sarah"
rootProject.name = "Sarah"

pluginManagement {
repositories {
maven {
name = "groupezReleases"
url = uri("https://repo.groupez.dev/releases")
}
gradlePluginPortal()
}
}
2 changes: 2 additions & 0 deletions src/main/java/fr/maxlego08/sarah/Column.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@
String type() default "";

boolean nullable() default false;

boolean unique() default false;
}
18 changes: 16 additions & 2 deletions src/main/java/fr/maxlego08/sarah/ConsumerConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;
import java.util.function.Consumer;
Expand Down Expand Up @@ -39,8 +40,18 @@ public static Consumer<Schema> createConsumerFromTemplate(Class<?> template, Obj
Constructor<?> firstConstructor = constructors[0];
firstConstructor.setAccessible(true);

Field[] fields = template.getDeclaredFields();
if (fields.length != firstConstructor.getParameterCount()) {
Field[] allFields = template.getDeclaredFields();
// Filter out synthetic fields (added by compiler for local/anonymous classes)
Field[] fields = Arrays.stream(allFields)
.filter(f -> !f.isSynthetic())
.toArray(Field[]::new);

// For local/anonymous classes, count only non-synthetic constructor parameters
long nonSyntheticParamCount = Arrays.stream(firstConstructor.getParameters())
.filter(p -> !p.isSynthetic())
.count();

if (fields.length != nonSyntheticParamCount) {
throw new IllegalArgumentException("Fields count does not match constructor parameters count");
}

Expand Down Expand Up @@ -102,6 +113,9 @@ public static Consumer<Schema> createConsumerFromTemplate(Class<?> template, Obj
if (column.nullable()) {
schema.nullable();
}
if (column.unique()) {
schema.unique();
}
}

if (i == 0 && !primaryAlready) {
Expand Down
44 changes: 34 additions & 10 deletions src/main/java/fr/maxlego08/sarah/DatabaseConnection.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.database.DatabaseType;
import fr.maxlego08.sarah.exceptions.DatabaseException;
import fr.maxlego08.sarah.logger.Logger;
import fr.maxlego08.sarah.transaction.Transaction;

import java.sql.Connection;
import java.sql.SQLException;
Expand All @@ -12,10 +15,12 @@
public abstract class DatabaseConnection {

protected final DatabaseConfiguration databaseConfiguration;
protected final Logger logger;
protected Connection connection;

public DatabaseConnection(DatabaseConfiguration databaseConfiguration) {
public DatabaseConnection(DatabaseConfiguration databaseConfiguration, Logger logger) {
this.databaseConfiguration = databaseConfiguration;
this.logger = logger;
}

/**
Expand Down Expand Up @@ -46,14 +51,10 @@ public boolean isValid() {
}

if (!isConnected(connection)) {
try {
Connection temp_connection = this.connectToDatabase();

if (isConnected(temp_connection)) {
temp_connection.close();
}
try (Connection tempConnection = this.connectToDatabase()) {
return isConnected(tempConnection);
} catch (Exception exception) {
exception.printStackTrace();
this.logger.info("Failed to validate database connection: " + exception.getMessage());
return false;
}
}
Expand Down Expand Up @@ -87,7 +88,7 @@ public void disconnect() {
try {
connection.close();
} catch (SQLException exception) {
exception.printStackTrace();
this.logger.info("Failed to disconnect from database: " + exception.getMessage());
}
}
}
Expand All @@ -100,7 +101,8 @@ public void connect() {
try {
connection = this.connectToDatabase();
} catch (Exception exception) {
exception.printStackTrace();
this.logger.info("Failed to connect to database: " + exception.getMessage());
throw new DatabaseException("connect", exception);
}
}
}
Expand All @@ -117,4 +119,26 @@ public Connection getConnection() {
connect();
return connection;
}

/**
* Begins a new database transaction.
* Use try-with-resources to ensure proper cleanup:
* <pre>
* try (Transaction tx = connection.beginTransaction()) {
* // Execute operations
* tx.commit();
* } // Automatically rolls back if not committed
* </pre>
*
* @return a new Transaction instance
* @throws DatabaseException if the transaction cannot be started
*/
public Transaction beginTransaction() {
try {
return new Transaction(getConnection());
} catch (SQLException exception) {
this.logger.info("Failed to begin transaction: " + exception.getMessage());
throw new DatabaseException("begin-transaction", exception);
}
}
}
10 changes: 6 additions & 4 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.exceptions.DatabaseException;
import fr.maxlego08.sarah.logger.Logger;

import javax.sql.DataSource;
import java.sql.Connection;
Expand All @@ -26,8 +28,8 @@ public class HikariDatabaseConnection extends DatabaseConnection {

private HikariDataSource dataSource;

public HikariDatabaseConnection(DatabaseConfiguration databaseConfiguration) {
super(databaseConfiguration);
public HikariDatabaseConnection(DatabaseConfiguration databaseConfiguration, Logger logger) {
super(databaseConfiguration, logger);
this.initializeDataSource();
}

Expand Down Expand Up @@ -126,8 +128,8 @@ public Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException exception) {
exception.printStackTrace();
return null;
this.logger.info("Failed to get connection from Hikari pool: " + exception.getMessage());
throw new DatabaseException("getConnection", exception);
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/fr/maxlego08/sarah/MariaDbConnection.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.logger.Logger;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
Expand All @@ -9,8 +11,8 @@
*/
public class MariaDbConnection extends DatabaseConnection {

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

@Override
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/fr/maxlego08/sarah/MigrationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import fr.maxlego08.sarah.database.DatabaseType;
import fr.maxlego08.sarah.database.Migration;
import fr.maxlego08.sarah.database.Schema;
import fr.maxlego08.sarah.exceptions.DatabaseException;
import fr.maxlego08.sarah.logger.Logger;

import java.sql.Connection;
Expand Down Expand Up @@ -120,7 +121,8 @@ public static void execute(DatabaseConnection databaseConnection, Logger logger)
}
mustBeAdd.addAll(columnDefinitions);
} catch (SQLException exception) {
exception.printStackTrace();
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()) {
Expand Down Expand Up @@ -187,7 +189,8 @@ private static void createMigrationTable(DatabaseConnection databaseConnection,
try {
schema.execute(databaseConnection, logger);
} catch (SQLException exception) {
exception.printStackTrace();
logger.info("Failed to create migration table: " + exception.getMessage());
throw new DatabaseException("create-migration-table", migrationTableName, exception);
}
}

Expand All @@ -203,7 +206,7 @@ private static List<String> getMigrations(DatabaseConnection databaseConnection,
try {
return schema.executeSelect(MigrationTable.class, databaseConnection, logger).stream().map(MigrationTable::getMigration).collect(Collectors.toList());
} catch (Exception exception) {
exception.printStackTrace();
logger.info("Failed to get migrations list: " + exception.getMessage());
}
return new ArrayList<>();
}
Expand All @@ -221,7 +224,8 @@ private static void insertMigration(DatabaseConnection databaseConnection, Logge
try {
SchemaBuilder.insert(migrationTableName, schema -> schema.string("migration", migration.getClass().getSimpleName())).execute(databaseConnection, logger);
} catch (SQLException exception) {
exception.printStackTrace();
logger.info("Failed to insert migration record: " + exception.getMessage());
throw new DatabaseException("insert-migration", migrationTableName, exception);
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/fr/maxlego08/sarah/MySqlConnection.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package fr.maxlego08.sarah;

import fr.maxlego08.sarah.logger.Logger;

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

public class MySqlConnection extends DatabaseConnection {

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

@Override
Expand Down
Loading
Loading