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
17 changes: 17 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.20.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.20.4</version>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
92 changes: 92 additions & 0 deletions src/main/java/massbank/db/DatabaseConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*******************************************************************************
* Copyright (C) 2025 MassBank consortium
*
* This file is part of MassBank.
*
* MassBank is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
******************************************************************************/
package massbank.db;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.stream.Collectors;

/**
* Utility class for managing database connections.
*/
public class DatabaseConnection {
private static final Logger logger = LogManager.getLogger(DatabaseConnection.class);

/**
* Creates a connection to a PostgreSQL database.
*
* @param url The JDBC URL
* @param username The database username
* @param password The database password
* @return A Connection object
* @throws SQLException if a database access error occurs
*/
public static Connection getConnection(String url, String username, String password) throws SQLException {
logger.info("Connecting to database: {}", url);
return DriverManager.getConnection(url, username, password);
}

/**
* Initializes the database schema from the schema.sql file.
*
* @param connection The database connection
* @throws SQLException if a database error occurs
* @throws IOException if the schema file cannot be read
*/
public static void initializeSchema(Connection connection) throws SQLException, IOException {
logger.info("Initializing database schema");

String schemaScript = loadResourceAsString("/db/schema.sql");

try (Statement stmt = connection.createStatement()) {
stmt.execute(schemaScript);
}

logger.info("Database schema initialized successfully");
}

/**
* Loads a resource file as a String.
*
* @param resourcePath The path to the resource
* @return The contents of the resource as a String
* @throws IOException if the resource cannot be read
*/
private static String loadResourceAsString(String resourcePath) throws IOException {
try (InputStream is = DatabaseConnection.class.getResourceAsStream(resourcePath)) {
if (is == null) {
throw new IOException("Resource not found: " + resourcePath);
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
}
}
120 changes: 120 additions & 0 deletions src/main/java/massbank/db/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# PostgreSQL Database Support for MassBank Records

This package provides PostgreSQL database support for storing and retrieving MassBank `Record` objects.

## Features

- Store and retrieve MassBank records in PostgreSQL database
- JSONB support for complex data structures
- Full CRUD operations (Create, Read, Update, Delete)
- Upsert support (automatic update on conflict)
- Comprehensive unit tests with TestContainers

## Usage

### 1. Initialize Database Connection

```java
import massbank.db.DatabaseConnection;
import massbank.db.RecordRepository;
import java.sql.Connection;

// Create connection
Connection connection = DatabaseConnection.getConnection(
"jdbc:postgresql://localhost:5432/massbank",
"username",
"password"
);

// Initialize schema (first time only)
DatabaseConnection.initializeSchema(connection);

// Create repository
RecordRepository repository = new RecordRepository(connection);
```

### 2. Store a Record

```java
import massbank.Record;

Record record = new Record();
// ... populate record fields ...

repository.store(record);
```

### 3. Retrieve a Record

```java
// Retrieve by accession ID
Record record = repository.retrieve("MSBNK-TEST-00001");

// Retrieve all records
List<Record> allRecords = repository.retrieveAll();
```

### 4. Update a Record

```java
// Store with same accession ID to update
record.AUTHORS("Updated Author");
repository.store(record);
```

### 5. Delete a Record

```java
boolean deleted = repository.delete("MSBNK-TEST-00001");
```

### 6. Check if Record Exists

```java
boolean exists = repository.exists("MSBNK-TEST-00001");
```

## Database Schema

The schema is automatically created by the `DatabaseConnection.initializeSchema()` method.

Key features:
- Primary key on `accession` field
- JSONB columns for complex structures (lists, maps)
- GIN indexes on JSONB columns for efficient queries
- Timestamps for created_at and updated_at

## Dependencies

Add these dependencies to your `pom.xml`:

```xml
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
</dependency>
```

## Testing

The package includes comprehensive unit tests using TestContainers:

```bash
mvn test
```

Tests cover:
- Basic CRUD operations
- Complex record with all fields
- Deprecated records
- Peak data storage
- Annotation data storage
- Update operations

## Notes

- JSONB is used for complex data structures to maintain flexibility
- The repository uses prepared statements to prevent SQL injection
- All operations are logged using log4j
- Connection management is left to the caller (not auto-closed)
Loading