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(
28 Function
<HikariDataSource
, T
> newDatabase
29 ) throws SQLException
{
30 HikariDataSource dataSource
= null;
33 dataSource
= getHikariDataSource(databaseFile
.getAbsolutePath());
35 final var result
= newDatabase
.apply(dataSource
);
40 if (dataSource
!= null) {
46 public final Connection
getConnection() throws SQLException
{
47 return dataSource
.getConnection();
55 protected final void initDb() throws SQLException
{
56 try (final var connection
= dataSource
.getConnection()) {
57 connection
.setAutoCommit(false);
58 final var userVersion
= getUserVersion(connection
);
59 logger
.trace("Current database version: {} Program database version: {}", userVersion
, databaseVersion
);
61 if (userVersion
== 0) {
62 createDatabase(connection
);
63 setUserVersion(connection
, databaseVersion
);
64 } else if (userVersion
> databaseVersion
) {
65 logger
.error("Database has been updated by a newer signal-cli version");
66 throw new SQLException("Database has been updated by a newer signal-cli version");
67 } else if (userVersion
< databaseVersion
) {
68 upgradeDatabase(connection
, userVersion
);
69 setUserVersion(connection
, databaseVersion
);
75 protected abstract void createDatabase(final Connection connection
) throws SQLException
;
77 protected abstract void upgradeDatabase(final Connection connection
, long oldVersion
) throws SQLException
;
79 private static long getUserVersion(final Connection connection
) throws SQLException
{
80 try (final var statement
= connection
.createStatement()) {
81 final var resultSet
= statement
.executeQuery("PRAGMA user_version");
82 return resultSet
.getLong(1);
86 private static void setUserVersion(final Connection connection
, long userVersion
) throws SQLException
{
87 try (final var statement
= connection
.createStatement()) {
88 statement
.executeUpdate("PRAGMA user_version = " + userVersion
);
92 private static HikariDataSource
getHikariDataSource(final String databaseFile
) {
93 final var sqliteConfig
= new SQLiteConfig();
94 sqliteConfig
.setBusyTimeout(60_000);
95 sqliteConfig
.setTransactionMode(SQLiteConfig
.TransactionMode
.IMMEDIATE
);
97 HikariConfig config
= new HikariConfig();
98 config
.setJdbcUrl("jdbc:sqlite:" + databaseFile
+ "?foreign_keys=ON");
99 config
.setDataSourceProperties(sqliteConfig
.toProperties());
100 config
.setMinimumIdle(1);
101 return new HikariDataSource(config
);