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 connection
.setAutoCommit(false);
57 final var userVersion
= getUserVersion(connection
);
58 logger
.trace("Current database version: {} Program database version: {}", userVersion
, databaseVersion
);
60 if (userVersion
== 0) {
61 createDatabase(connection
);
62 setUserVersion(connection
, databaseVersion
);
63 } else if (userVersion
> databaseVersion
) {
64 logger
.error("Database has been updated by a newer signal-cli version");
65 throw new SQLException("Database has been updated by a newer signal-cli version");
66 } else if (userVersion
< databaseVersion
) {
67 upgradeDatabase(connection
, userVersion
);
68 setUserVersion(connection
, databaseVersion
);
74 protected abstract void createDatabase(final Connection connection
) throws SQLException
;
76 protected abstract void upgradeDatabase(final Connection connection
, long oldVersion
) throws SQLException
;
78 private static long getUserVersion(final Connection connection
) throws SQLException
{
79 try (final var statement
= connection
.createStatement()) {
80 final var resultSet
= statement
.executeQuery("PRAGMA user_version");
81 return resultSet
.getLong(1);
85 private static void setUserVersion(final Connection connection
, long userVersion
) throws SQLException
{
86 try (final var statement
= connection
.createStatement()) {
87 statement
.executeUpdate("PRAGMA user_version = " + userVersion
);
91 private static HikariDataSource
getHikariDataSource(final String databaseFile
) {
92 final var sqliteConfig
= new SQLiteConfig();
93 sqliteConfig
.setBusyTimeout(10_000);
94 sqliteConfig
.setTransactionMode(SQLiteConfig
.TransactionMode
.IMMEDIATE
);
96 HikariConfig config
= new HikariConfig();
97 config
.setJdbcUrl("jdbc:sqlite:" + databaseFile
);
98 config
.setDataSourceProperties(sqliteConfig
.toProperties());
99 config
.setMinimumIdle(1);
100 config
.setConnectionInitSql("PRAGMA foreign_keys=ON");
101 return new HikariDataSource(config
);