1 package org
.asamk
.signal
.manager
.storage
;
3 import com
.zaxxer
.hikari
.HikariConfig
;
4 import com
.zaxxer
.hikari
.HikariDataSource
;
6 import org
.slf4j
.Logger
;
7 import org
.sqlite
.SQLiteConfig
;
10 import java
.sql
.Connection
;
11 import java
.sql
.SQLException
;
12 import java
.util
.function
.Function
;
14 public abstract class Database
implements AutoCloseable
{
16 private final Logger logger
;
17 private final long databaseVersion
;
18 private final HikariDataSource dataSource
;
20 protected Database(final Logger logger
, final long databaseVersion
, final HikariDataSource dataSource
) {
22 this.databaseVersion
= databaseVersion
;
23 this.dataSource
= dataSource
;
26 public static <T
extends Database
> T
initDatabase(
27 File databaseFile
, Function
<HikariDataSource
, T
> newDatabase
28 ) throws SQLException
{
29 HikariDataSource dataSource
= null;
32 dataSource
= getHikariDataSource(databaseFile
.getAbsolutePath());
34 final var result
= newDatabase
.apply(dataSource
);
39 if (dataSource
!= null) {
45 public final Connection
getConnection() throws SQLException
{
46 return dataSource
.getConnection();
50 public void close() throws SQLException
{
54 protected final void initDb() throws SQLException
{
55 try (final var connection
= dataSource
.getConnection()) {
56 final var userVersion
= getUserVersion(connection
);
57 logger
.trace("Current database version: {} Program database version: {}", userVersion
, databaseVersion
);
59 if (userVersion
> databaseVersion
) {
60 logger
.error("Database has been updated by a newer signal-cli version");
61 throw new SQLException("Database has been updated by a newer signal-cli version");
62 } else if (userVersion
< databaseVersion
) {
63 upgradeDatabase(connection
, userVersion
);
64 setUserVersion(connection
, databaseVersion
);
69 protected abstract void upgradeDatabase(final Connection connection
, long oldVersion
) throws SQLException
;
71 private static long getUserVersion(final Connection connection
) throws SQLException
{
72 try (final var statement
= connection
.createStatement()) {
73 final var resultSet
= statement
.executeQuery("PRAGMA user_version");
74 return resultSet
.getLong(1);
78 private static void setUserVersion(final Connection connection
, long userVersion
) throws SQLException
{
79 try (final var statement
= connection
.createStatement()) {
80 statement
.executeUpdate("PRAGMA user_version = " + userVersion
);
84 private static HikariDataSource
getHikariDataSource(final String databaseFile
) {
85 final var sqliteConfig
= new SQLiteConfig();
86 sqliteConfig
.setBusyTimeout(10_000);
87 sqliteConfig
.setTransactionMode(SQLiteConfig
.TransactionMode
.IMMEDIATE
);
89 HikariConfig config
= new HikariConfig();
90 config
.setJdbcUrl("jdbc:sqlite:" + databaseFile
);
91 config
.setDataSourceProperties(sqliteConfig
.toProperties());
92 config
.setMinimumIdle(1);
93 config
.setConnectionInitSql("PRAGMA foreign_keys=ON");
94 return new HikariDataSource(config
);