diff --git a/detekt/baseline.xml b/detekt/baseline.xml
index 48731680cd8..438b722e59e 100644
--- a/detekt/baseline.xml
+++ b/detekt/baseline.xml
@@ -128,6 +128,8 @@
ArgumentListWrapping:GetPaginatedFlowOfMessagesBySearchQueryAndConversationIdUseCase.kt$GetPaginatedFlowOfMessagesBySearchQueryAndConversationIdUseCase$( searchQuery, conversationId, pagingConfig, startingOffset )
ArgumentListWrapping:GetSessionsUseCase.kt$GetSessionsUseCase$( { when (it) { StorageFailure.DataNotFound -> GetAllSessionsResult.Failure.NoSessionFound is StorageFailure.Generic -> GetAllSessionsResult.Failure.Generic(it) } }, { GetAllSessionsResult.Success(it) } )
ArgumentListWrapping:GetUserInfoUseCase.kt$GetUserInfoUseCaseImpl$( { GetUserInfoResult.Failure }, { team -> GetUserInfoResult.Success(otherUser, team) })
+ ArgumentListWrapping:GlobalDBBaseTest.kt$GlobalDBBaseTest$( PlatformDatabaseData(StorageData.FileBacked(storePath)), StandardTestDispatcher(), null, false )
+ ArgumentListWrapping:GlobalDatabase.kt$( identifier = Int.MIN_VALUE, sql = """SELECT table_name FROM information_schema.tables where table_name = 'accounts'""", mapper = { if (it.next().value) { val result = it.getString(0) println("THE RESULT: $result") app.cash.sqldelight.db.QueryResult.Value(result?.isNotEmpty()) } else { app.cash.sqldelight.db.QueryResult.Value(false) } }, parameters = 0 )
ArgumentListWrapping:GuestRoomConfigHandler.kt$GuestRoomConfigHandler$( { false }, { it.isGuestRoomLinkEnabled != status } )
ArgumentListWrapping:HandleExternalRequestAction.kt$( """ Hey there, I hope you're doing well. I've got a bit of a craving for bananas, and I was wondering if you might be able to share a few with me? It would mean a lot. π Thanks a bunch, A friendly monkey ππ΅ """.trimIndent(), """ Yo, I'm in need of some bananas, my friend. Can you hook me up? I'd appreciate it big time. Respect, A neutral monkey π """.trimIndent(), """ Listen up, I ain't messin' around. I want them bananas, and I want 'em now. You better deliver or there'll be consequences. No games, An evil monkey ππΏπ """.trimIndent() )
ArgumentListWrapping:InstanceService.kt$InstanceService$( instanceRequest.email, instanceRequest.password, true, secondFactorVerificationCode = instanceRequest.verificationCode )
@@ -307,6 +309,7 @@
CommentSpacing:UserDAOTest.kt$UserDAOTest$//given
EmptyFunctionBlock:FileTestHelper.kt$FileTestHelper${ }
EmptyKtFile:FetchApiVersionUseCaseTest.kt$.FetchApiVersionUseCaseTest.kt
+ Filename:BooleanExt.kt$com.wire.kalium.persistence.dao.BooleanExt.kt
Filename:ConversationStatus.kt$com.wire.kalium.logic.data.conversation.ConversationStatus.kt
Filename:FileUtilTest.kt$com.wire.kalium.util.FileUtilTest.kt
Filename:GetOtherUserClientsUseCaseTest.kt$com.wire.kalium.logic.feature.client.GetOtherUserClientsUseCaseTest.kt
@@ -401,6 +404,7 @@
LongParameterList:ToggleReactionUseCase.kt$ToggleReactionUseCase$( clientId: ClientId, conversationId: ConversationId, date: String, messageId: String, removedReaction: String, currentReactions: UserReactions )
MagicNumber:ConversationStatus.kt$MutedConversationStatus.AllMuted$3
MagicNumber:GlobalCallManager.kt$LogHandlerImpl$3
+ MagicNumber:GlobalDatabase.kt$3
MagicNumber:NetworkUtils.kt$300
MagicNumber:NetworkUtils.kt$399
MagicNumber:NetworkUtils.kt$400
@@ -411,10 +415,6 @@
MatchingDeclarationName:ConversationStatus.kt$MutedConversationStatus
MatchingDeclarationName:CryptoboxCRUDStore.module_@wireapp_cryptobox.kt$CryptoboxCRUDStore : PreKeyStore
MatchingDeclarationName:CryptoboxSession.module_@wireapp_cryptobox.kt$CryptoboxSession
- MatchingDeclarationName:DriverBuilder.android.kt$DriverBuilder
- MatchingDeclarationName:DriverBuilder.apple.kt$DriverBuilder
- MatchingDeclarationName:DriverBuilder.js.kt$DriverBuilder
- MatchingDeclarationName:DriverBuilder.jvm.kt$DriverBuilder
MatchingDeclarationName:Encoder.module_@wireapp_cbor.kt$Encoder
MatchingDeclarationName:FileUtilTest.kt$FileTestHelper
MatchingDeclarationName:GetOtherUserClientsUseCaseTest.kt$ObserveClientsByUserIdUseCaseTest
@@ -939,7 +939,7 @@
UnusedPrivateProperty:build.gradle.kts$val jvmMain by getting { dependencies { implementation(libs.apacheTika) } }
UnusedPrivateProperty:build.gradle.kts$val jvmMain by getting { dependencies { implementation(libs.coroutines.core) } }
UnusedPrivateProperty:build.gradle.kts$val jvmMain by getting { dependencies { implementation(libs.ktor.okHttp) implementation(libs.okhttp.loggingInterceptor) } }
- UnusedPrivateProperty:build.gradle.kts$val jvmMain by getting { dependencies { implementation(libs.sqldelight.jvmDriver) implementation(libs.sqlite.xerialDriver) } }
+ UnusedPrivateProperty:build.gradle.kts$val jvmMain by getting { dependencies { implementation(libs.sqldelight.jvmDriver) implementation(libs.sqldelight.jdbcDriver) implementation(libs.sqlite.xerialDriver) implementation(libs.hikaricp) implementation(libs.postgres.driver) implementation(libs.testContainers.postgres) } }
UnusedPrivateProperty:build.gradle.kts$val jvmMain by getting { dependencies { implementation(project(":logic")) implementation(project(":calling")) } }
UnusedPrivateProperty:build.gradle.kts$val jvmTest by getting
UnusedPrivateProperty:build.gradle.kts$val jvmTest by getting { dependencies { implementation(libs.konsist) } }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f8d462c7a8a..5f4f534fd96 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -181,6 +181,7 @@ sqldelight-androidxPaging = { module = "app.cash.sqldelight:androidx-paging3-ext
sqldelight-nativeDriver = { module = "app.cash.sqldelight:native-driver", version.ref = "sqldelight" }
sqldelight-jvmDriver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
sqldelight-jsDriver = { module = "app.cash.sqldelight:web-worker-driver", version.ref = "sqldelight" }
+sqldelight-jdbcDriver = { module = "app.cash.sqldelight:jdbc-driver", version.ref = "sqldelight" }
sqldelight-primitiveAdapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
sqldelight-dialect = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
sqldelight-postgres = { module = "app.cash.sqldelight:postgresql-dialect", version.ref = "sqldelight" }
@@ -189,6 +190,8 @@ sqldelight-async = { module = "app.cash.sqldelight:async-extensions", version.re
r2dbc-postgres = { module = "org.postgresql:r2dbc-postgresql", version.ref = "postgres" }
r2dbc-spi = { module = "io.r2dbc:r2dbc-spi", version.ref = "r2dbc" }
sqlite-xerialDriver = { module = "org.xerial:sqlite-jdbc", version.ref = "xerialDriver" }
+hikaricp = { module = "com.zaxxer:HikariCP", version = "5.0.1" }
+postgres-driver = { module = "org.postgresql:postgresql", version = "42.5.4" }
# mocks and testing
mockative-runtime = { module = "io.mockative:mockative", version.ref = "mockative" }
@@ -196,6 +199,7 @@ mockative-processor = { module = "io.mockative:mockative-processor", version.ref
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
konsist = { module = "com.lemonappdev:konsist", version.ref = "konsist" }
+testContainers-postgres = { module = "org.testcontainers:postgresql", version = "1.19.6" }
# detekt
detekt-cli = { module = "io.gitlab.arturbosch.detekt:detekt-cli", version.ref = "detekt" }
diff --git a/persistence/build.gradle.kts b/persistence/build.gradle.kts
index fcdaab644cb..80a60f13125 100644
--- a/persistence/build.gradle.kts
+++ b/persistence/build.gradle.kts
@@ -87,7 +87,11 @@ kotlin {
val jvmMain by getting {
dependencies {
implementation(libs.sqldelight.jvmDriver)
+ implementation(libs.sqldelight.jdbcDriver)
implementation(libs.sqlite.xerialDriver)
+ implementation(libs.hikaricp)
+ implementation(libs.postgres.driver)
+ implementation(libs.testContainers.postgres)
}
}
val jvmTest by getting
diff --git a/persistence/src/androidInstrumentedTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/androidInstrumentedTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
index cfbb214b97b..a8a38839556 100644
--- a/persistence/src/androidInstrumentedTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
+++ b/persistence/src/androidInstrumentedTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
@@ -34,7 +34,7 @@ actual abstract class GlobalDBBaseTest {
context.deleteDatabase(FileNameUtil.globalDBName())
}
- actual fun createDatabase(): GlobalDatabaseBuilder = globalDatabaseProvider(
+ actual fun createDatabase(platformDatabaseData: PlatformDatabaseData): GlobalDatabaseBuilder = globalDatabaseProvider(
platformDatabaseData = PlatformDatabaseData(ApplicationProvider.getApplicationContext()),
queriesContext = KaliumDispatcherImpl.unconfined,
passphrase = GlobalDatabaseSecret("test_db_secret".toByteArray()),
diff --git a/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
index edb29062eb1..0e1776e07cf 100644
--- a/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
+++ b/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
@@ -19,13 +19,14 @@
package com.wire.kalium.persistence
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
+import com.wire.kalium.persistence.db.PlatformDatabaseData
actual abstract class GlobalDBBaseTest {
actual fun deleteDatabase() {
TODO("Not yet implemented")
}
- actual fun createDatabase(): GlobalDatabaseBuilder {
+ actual fun createDatabase(platformDatabaseData: PlatformDatabaseData): GlobalDatabaseBuilder {
TODO("Not yet implemented")
}
}
diff --git a/persistence/src/appleTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/appleTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
index 48d3e69d0d2..4d6239a66ad 100644
--- a/persistence/src/appleTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
+++ b/persistence/src/appleTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
@@ -37,7 +37,7 @@ actual abstract class GlobalDBBaseTest {
deleteDatabase(FileNameUtil.globalDBName(), storePath)
}
- actual fun createDatabase(): GlobalDatabaseBuilder {
+ actual fun createDatabase(platformDatabaseData: PlatformDatabaseData): GlobalDatabaseBuilder {
return globalDatabaseProvider(
PlatformDatabaseData(StorageData.FileBacked(storePath)), StandardTestDispatcher(), null, false
)
diff --git a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/Accounts.sq b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/Accounts.sq
index 3130400058e..e6fff03cbaf 100644
--- a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/Accounts.sq
+++ b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/Accounts.sq
@@ -1,7 +1,9 @@
import com.wire.kalium.persistence.dao.ManagedByEntity;
import com.wire.kalium.persistence.dao.QualifiedIDEntity;
import com.wire.kalium.persistence.model.LogoutReason;
+import com.wire.kalium.persistence.dao.BooleanEntity;
import kotlin.Boolean;
+import kotlin.Int;
CREATE TABLE Accounts (
id TEXT AS QualifiedIDEntity PRIMARY KEY NOT NULL,
@@ -10,12 +12,12 @@ CREATE TABLE Accounts (
tenant TEXT,
server_config_id TEXT NOT NULL,
logout_reason TEXT AS LogoutReason,
- isPersistentWebSocketEnabled INTEGER AS Boolean NOT NULL DEFAULT 0,
+ isPersistentWebSocketEnabled INTEGER AS BooleanEntity NOT NULL DEFAULT 0,
managed_by TEXT AS ManagedByEntity
);
insertOrReplace:
-INSERT OR REPLACE INTO Accounts (id, scim_external_id, subject, tenant, server_config_id, logout_reason, isPersistentWebSocketEnabled)
+INSERT INTO Accounts (id, scim_external_id, subject, tenant, server_config_id, logout_reason, isPersistentWebSocketEnabled)
VALUES (:id, :scimExternalId, :subject, :tenant, :serverConfigId, :logoutReason,:isPersistentWebSocketEnabled);
delete:
diff --git a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/CurrentAccount.sq b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/CurrentAccount.sq
index d1a8b6ac658..a2c48892a22 100644
--- a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/CurrentAccount.sq
+++ b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/CurrentAccount.sq
@@ -7,7 +7,7 @@ CREATE TABLE CurrentAccount (
);
update:
-INSERT OR REPLACE INTO CurrentAccount (id, user_id) VALUES (1, :user_id);
+INSERT INTO CurrentAccount (id, user_id) VALUES (1, :user_id);
currentAccountInfo:
SELECT id, logout_reason FROM Accounts WHERE id = (SELECT user_id FROM CurrentAccount WHERE id = 1);
diff --git a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/GlobalDatabaseProperties.sq b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/GlobalDatabaseProperties.sq
index 7fbdb5dbd98..e69de29bb2d 100644
--- a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/GlobalDatabaseProperties.sq
+++ b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/GlobalDatabaseProperties.sq
@@ -1,3 +0,0 @@
-
-enableForeignKeyContraints:
-PRAGMA foreign_keys = 1;
diff --git a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq
index b09efc6e29a..b1249a12ce2 100644
--- a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq
+++ b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq
@@ -1,5 +1,6 @@
import kotlin.Boolean;
import kotlin.Int;
+import com.wire.kalium.persistence.dao.BooleanEntity;
CREATE TABLE ServerConfiguration (
id TEXT PRIMARY KEY NOT NULL,
@@ -10,12 +11,12 @@ CREATE TABLE ServerConfiguration (
blackListUrl TEXT NOT NULL,
teamsUrl TEXT NOT NULL,
websiteUrl TEXT NOT NULL,
- isOnPremises INTEGER AS Boolean NOT NULL,
+ isOnPremises INTEGER AS BooleanEntity NOT NULL,
domain TEXT,
commonApiVersion INTEGER AS Int NOT NULL,
- federation INTEGER AS Boolean NOT NULL,
+ federation INTEGER AS BooleanEntity NOT NULL,
apiProxyHost TEXT,
- apiProxyNeedsAuthentication INTEGER AS Boolean,
+ apiProxyNeedsAuthentication INTEGER AS BooleanEntity,
apiProxyPort INTEGER AS Int,
lastBlackListCheck TEXT,
CONSTRAINT server_config_unique UNIQUE (title, apiBaseUrl, webSocketBaseUrl, domain, apiProxyHost, apiProxyPort)
@@ -25,7 +26,7 @@ deleteById:
DELETE FROM ServerConfiguration WHERE id = ?;
insert:
-INSERT OR FAIL INTO ServerConfiguration(id, apiBaseUrl, accountBaseUrl, webSocketBaseUrl, blackListUrl, teamsUrl, websiteUrl, title, isOnPremises, federation, domain, commonApiVersion, apiProxyHost, apiProxyNeedsAuthentication, apiProxyPort)
+INSERT INTO ServerConfiguration(id, apiBaseUrl, accountBaseUrl, webSocketBaseUrl, blackListUrl, teamsUrl, websiteUrl, title, isOnPremises, federation, domain, commonApiVersion, apiProxyHost, apiProxyNeedsAuthentication, apiProxyPort)
VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?);
updateApiVersion:
diff --git a/persistence/src/commonMain/db_global/migrations/3.sqm b/persistence/src/commonMain/db_global/migrations/3.sqm
index 2c31ce86111..3527f9c7b71 100644
--- a/persistence/src/commonMain/db_global/migrations/3.sqm
+++ b/persistence/src/commonMain/db_global/migrations/3.sqm
@@ -1,4 +1,4 @@
-import kotlin.Boolean;
+import com.wire.kalium.persistence.dao.BooleanEntity;
ALTER TABLE Accounts
-ADD COLUMN isPersistentWebSocketEnabled INTEGER AS Boolean NOT NULL DEFAULT(0);
+ADD COLUMN isPersistentWebSocketEnabled INTEGER AS BooleanEntity NOT NULL DEFAULT(0);
diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/adapter/CrossCompatBooleanAdapter.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/adapter/CrossCompatBooleanAdapter.kt
new file mode 100644
index 00000000000..68fda79abb4
--- /dev/null
+++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/adapter/CrossCompatBooleanAdapter.kt
@@ -0,0 +1,38 @@
+/*
+ * Wire
+ * Copyright (C) 2024 Wire Swiss GmbH
+ *
+ * This program 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 3 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, see http://www.gnu.org/licenses/.
+ */
+package com.wire.kalium.persistence.adapter
+
+import app.cash.sqldelight.ColumnAdapter
+import com.wire.kalium.persistence.dao.BooleanEntity
+
+internal object CrossCompatBooleanAdapter : ColumnAdapter {
+ override fun decode(databaseValue: Long?): BooleanEntity {
+ return databaseValue == 1L
+ }
+
+ override fun encode(value: BooleanEntity): Long {
+ return value.toLong()
+ }
+}
+
+fun Boolean.toLong(): Long {
+ return when (this) {
+ true -> 1
+ false -> 0
+ }
+}
diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/BooleanExt.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/BooleanExt.kt
new file mode 100644
index 00000000000..20df1cc3716
--- /dev/null
+++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/BooleanExt.kt
@@ -0,0 +1,20 @@
+/*
+ * Wire
+ * Copyright (C) 2024 Wire Swiss GmbH
+ *
+ * This program 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 3 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, see http://www.gnu.org/licenses/.
+ */
+package com.wire.kalium.persistence.dao
+
+typealias BooleanEntity = Boolean
diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabaseBuilder.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabaseBuilder.kt
index 180f339779c..e5e1b562b90 100644
--- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabaseBuilder.kt
+++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabaseBuilder.kt
@@ -18,6 +18,7 @@
package com.wire.kalium.persistence.db
+import app.cash.sqldelight.ColumnAdapter
import app.cash.sqldelight.EnumColumnAdapter
import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
import app.cash.sqldelight.db.SqlDriver
@@ -25,8 +26,10 @@ import com.wire.kalium.persistence.Accounts
import com.wire.kalium.persistence.CurrentAccount
import com.wire.kalium.persistence.GlobalDatabase
import com.wire.kalium.persistence.ServerConfiguration
+import com.wire.kalium.persistence.adapter.CrossCompatBooleanAdapter
import com.wire.kalium.persistence.adapter.LogoutReasonAdapter
import com.wire.kalium.persistence.adapter.QualifiedIDAdapter
+import com.wire.kalium.persistence.dao.BooleanEntity
import com.wire.kalium.persistence.daokaliumdb.AccountsDAO
import com.wire.kalium.persistence.daokaliumdb.AccountsDAOImpl
import com.wire.kalium.persistence.daokaliumdb.ServerConfigurationDAO
@@ -49,12 +52,16 @@ class GlobalDatabaseBuilder internal constructor(
sqlDriver,
ServerConfigurationAdapter = ServerConfiguration.Adapter(
commonApiVersionAdapter = IntColumnAdapter,
- apiProxyPortAdapter = IntColumnAdapter
+ isOnPremisesAdapter = CrossCompatBooleanAdapter as ColumnAdapter,
+ apiProxyPortAdapter = IntColumnAdapter,
+ federationAdapter = CrossCompatBooleanAdapter as ColumnAdapter,
+ apiProxyNeedsAuthenticationAdapter = CrossCompatBooleanAdapter as ColumnAdapter
),
AccountsAdapter = Accounts.Adapter(
idAdapter = QualifiedIDAdapter,
logout_reasonAdapter = LogoutReasonAdapter,
- managed_byAdapter = EnumColumnAdapter()
+ managed_byAdapter = EnumColumnAdapter(),
+ isPersistentWebSocketEnabledAdapter = CrossCompatBooleanAdapter as ColumnAdapter
),
CurrentAccountAdapter = CurrentAccount.Adapter(
user_idAdapter = QualifiedIDAdapter
@@ -62,7 +69,7 @@ class GlobalDatabaseBuilder internal constructor(
)
init {
- database.globalDatabasePropertiesQueries.enableForeignKeyContraints()
+ // database.globalDatabasePropertiesQueries.enableForeignKeyContraints()
}
val serverConfigurationDAO: ServerConfigurationDAO
diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
index e4b88696644..43ec5e146a2 100644
--- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
+++ b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
@@ -19,8 +19,9 @@
package com.wire.kalium.persistence
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
+import com.wire.kalium.persistence.db.PlatformDatabaseData
expect abstract class GlobalDBBaseTest() {
fun deleteDatabase()
- fun createDatabase(): GlobalDatabaseBuilder
+ fun createDatabase(platformDatabaseData: PlatformDatabaseData): GlobalDatabaseBuilder
}
diff --git a/persistence/src/jsTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/jsTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
index edb29062eb1..0e1776e07cf 100644
--- a/persistence/src/jsTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
+++ b/persistence/src/jsTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
@@ -19,13 +19,14 @@
package com.wire.kalium.persistence
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
+import com.wire.kalium.persistence.db.PlatformDatabaseData
actual abstract class GlobalDBBaseTest {
actual fun deleteDatabase() {
TODO("Not yet implemented")
}
- actual fun createDatabase(): GlobalDatabaseBuilder {
+ actual fun createDatabase(platformDatabaseData: PlatformDatabaseData): GlobalDatabaseBuilder {
TODO("Not yet implemented")
}
}
diff --git a/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabase.kt b/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabase.kt
index 616d00e93af..09ec2bb4321 100644
--- a/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabase.kt
+++ b/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/GlobalDatabase.kt
@@ -18,10 +18,15 @@
package com.wire.kalium.persistence.db
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.jdbc.asJdbcDriver
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
import com.wire.kalium.persistence.GlobalDatabase
import com.wire.kalium.persistence.util.FileNameUtil
+import com.zaxxer.hikari.HikariConfig
+import com.zaxxer.hikari.HikariDataSource
import kotlinx.coroutines.CoroutineDispatcher
+import javax.sql.DataSource
actual fun globalDatabaseProvider(
platformDatabaseData: PlatformDatabaseData,
@@ -29,31 +34,34 @@ actual fun globalDatabaseProvider(
passphrase: GlobalDatabaseSecret?,
enableWAL: Boolean,
): GlobalDatabaseBuilder {
- val storageData = platformDatabaseData.storageData
- if (storageData is StorageData.InMemory) {
- return createGlobalInMemoryDatabase(queriesContext)
- }
-
- if (storageData !is StorageData.FileBacked) {
- throw IllegalStateException("Unsupported storage data type: $storageData")
- }
-
if (passphrase != null) {
throw NotImplementedError("Encrypted DB is not supported on JVM")
}
- val databasePath = storageData.file.resolve(FileNameUtil.globalDBName())
- val databaseExists = databasePath.exists()
-
- // Make sure all intermediate directories exist
- storageData.file.mkdirs()
- val driver = databaseDriver("jdbc:sqlite:${databasePath.absolutePath}") {
- isWALEnabled = enableWAL
- areForeignKeyConstraintsEnforced = true
- }
+ val driver = when (val storageData = platformDatabaseData.storageData) {
+ is StorageData.InMemory -> return createGlobalInMemoryDatabase(queriesContext)
+ is StorageData.FileBacked -> {
+ val databasePath = storageData.file.resolve(FileNameUtil.globalDBName())
+ val databaseExists = databasePath.exists()
+ storageData.file.mkdirs()
+ val driver = databaseDriver("jdbc:sqlite:${databasePath.absolutePath}") {
+ isWALEnabled = enableWAL
+ areForeignKeyConstraintsEnforced = true
+ }
+ if (!databaseExists) {
+ GlobalDatabase.Schema.create(driver)
+ }
+ driver
+ }
- if (!databaseExists) {
- GlobalDatabase.Schema.create(driver)
+ is StorageData.Postgres -> {
+ val driver = createDataSource(storageData).asJdbcDriver()
+ val databaseExists = driver.databaseExists()
+ if (!databaseExists) {
+ GlobalDatabase.Schema.create(driver)
+ }
+ driver
+ }
}
return GlobalDatabaseBuilder(driver, platformDatabaseData, queriesContext)
@@ -71,3 +79,37 @@ fun createGlobalInMemoryDatabase(dispatcher: CoroutineDispatcher): GlobalDatabas
GlobalDatabase.Schema.create(driver)
return GlobalDatabaseBuilder(driver, PlatformDatabaseData(StorageData.InMemory), dispatcher)
}
+
+private fun createDataSource(storageData: StorageData.Postgres): DataSource {
+ val dataSourceConfig = HikariConfig().apply {
+ val poolSize = 3
+ driverClassName = "org.postgresql.Driver"
+ jdbcUrl = storageData.uri
+ username = storageData.username
+ password = storageData.password
+ maximumPoolSize = poolSize
+ isAutoCommit = true
+ transactionIsolation = "TRANSACTION_REPEATABLE_READ"
+ validate()
+ }
+ return HikariDataSource(dataSourceConfig)
+}
+
+fun SqlDriver.databaseExists(): Boolean {
+ val result = executeQuery(
+ identifier = Int.MIN_VALUE, sql = """SELECT table_name FROM information_schema.tables where table_name = 'accounts'""",
+ mapper = {
+ if (it.next().value) {
+ val result = it.getString(0)
+ println("THE RESULT: $result")
+ app.cash.sqldelight.db.QueryResult.Value(result?.isNotEmpty())
+ } else {
+ app.cash.sqldelight.db.QueryResult.Value(false)
+ }
+
+ },
+ parameters = 0
+ )
+ println("Exists: ${result.value}")
+ return result.value ?: false
+}
diff --git a/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/PlatformDatabaseData.kt b/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/PlatformDatabaseData.kt
index 2cf574d3f33..50834db385e 100644
--- a/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/PlatformDatabaseData.kt
+++ b/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/PlatformDatabaseData.kt
@@ -29,6 +29,7 @@ actual data class PlatformDatabaseData(
sealed interface StorageData {
data class FileBacked(val file: File) : StorageData
data object InMemory : StorageData
+ data class Postgres(val uri: String, val username: String, val password: String) : StorageData
}
fun databaseDriver(uri: String, config: DriverConfigurationBuilder.() -> Unit = {}): SqlDriver {
diff --git a/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt b/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt
index cf5b97a23e0..c9f7587a387 100644
--- a/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt
+++ b/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt
@@ -117,4 +117,5 @@ internal actual fun nuke(
): Boolean = when (val storageData = platformDatabaseData.storageData) {
StorageData.InMemory -> clearInMemoryDatabase(userId)
is StorageData.FileBacked -> storageData.file.resolve(DATABASE_NAME).delete()
+ is StorageData.Postgres -> throw NotImplementedError("RDBMS nuke is not supported on JVM, truncate by query")
}
diff --git a/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
index 64f8f267ed1..21c716207fa 100644
--- a/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
+++ b/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt
@@ -20,25 +20,24 @@ package com.wire.kalium.persistence
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
import com.wire.kalium.persistence.db.PlatformDatabaseData
-import com.wire.kalium.persistence.db.StorageData
import com.wire.kalium.persistence.db.globalDatabaseProvider
-import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import java.nio.file.Files
actual abstract class GlobalDBBaseTest {
- private val dispatcher: TestDispatcher = StandardTestDispatcher()
- private val databaseFile = Files.createTempDirectory("test-storage").toFile().resolve("test-kalium.db")
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private val dispatcher: TestDispatcher = UnconfinedTestDispatcher()
+ val databaseFile = Files.createTempDirectory("test-storage").toFile().resolve("test-kalium.db")
actual fun deleteDatabase() {
databaseFile.delete()
}
- actual fun createDatabase(): GlobalDatabaseBuilder {
+ actual fun createDatabase(platformDatabaseData: PlatformDatabaseData): GlobalDatabaseBuilder {
return globalDatabaseProvider(
- platformDatabaseData = PlatformDatabaseData(
- StorageData.FileBacked(databaseFile)
- ),
+ platformDatabaseData = platformDatabaseData,
queriesContext = dispatcher,
passphrase = null,
enableWAL = false
diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt b/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt
similarity index 97%
rename from persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt
rename to persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt
index 5ab0fe61e87..05df3cabefc 100644
--- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt
+++ b/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt
@@ -22,6 +22,8 @@ package com.wire.kalium.persistence.daokaliumdb
import com.wire.kalium.persistence.GlobalDBBaseTest
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
+import com.wire.kalium.persistence.db.PlatformDatabaseData
+import com.wire.kalium.persistence.db.StorageData
import com.wire.kalium.persistence.model.ServerConfigEntity
import com.wire.kalium.persistence.utils.stubs.newServerConfig
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,7 +47,7 @@ class ServerConfigurationDAOTest : GlobalDBBaseTest() {
@BeforeTest
fun setup() {
- globalDatabaseBuilder = createDatabase()
+ globalDatabaseBuilder = createDatabase(PlatformDatabaseData(StorageData.FileBacked(databaseFile)))
}
@AfterTest
diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt b/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt
similarity index 94%
rename from persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt
rename to persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt
index 31ba21d5bb5..add0815979b 100644
--- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt
+++ b/persistence/src/jvmTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt
@@ -26,11 +26,15 @@ import com.wire.kalium.persistence.daokaliumdb.FullAccountEntity
import com.wire.kalium.persistence.daokaliumdb.PersistentWebSocketStatusEntity
import com.wire.kalium.persistence.daokaliumdb.ServerConfigurationDAO
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
+import com.wire.kalium.persistence.db.PlatformDatabaseData
+import com.wire.kalium.persistence.db.StorageData
import com.wire.kalium.persistence.model.LogoutReason
import com.wire.kalium.persistence.model.ServerConfigEntity
import com.wire.kalium.persistence.model.SsoIdEntity
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.testcontainers.containers.PostgreSQLContainer
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -39,12 +43,23 @@ import kotlin.test.assertNull
@OptIn(ExperimentalCoroutinesApi::class)
class AccountsDAOTest : GlobalDBBaseTest() {
+ @JvmField
+ @Rule
+ var postgresContainer: PostgreSQLContainer<*> = PostgreSQLContainer("postgres:15-alpine")
+
lateinit var globalDatabaseBuilder: GlobalDatabaseBuilder
@BeforeTest
fun setUp() = runTest {
- deleteDatabase()
- globalDatabaseBuilder = createDatabase()
+ globalDatabaseBuilder = createDatabase(
+ PlatformDatabaseData(
+ StorageData.Postgres(
+ postgresContainer.jdbcUrl,
+ postgresContainer.username,
+ postgresContainer.password,
+ )
+ )
+ )
with(SERVER_CONFIG) {
globalDatabaseBuilder.serverConfigurationDAO.insert(