Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ internal class EventUpSyncTask @Inject constructor(
.also { listOfEvents -> emit(listOfEvents.size) }
} catch (ex: Exception) {
if (ex is JsonParseException || ex is JsonMappingException) {
Simber.i("Failed to un-marshal events", ex, tag = SYNC)
Simber.e("Failed to un-marshal events", ex, tag = SYNC)
} else {
throw ex
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
{
"formatVersion": 1,
"database": {
"version": 17,
"identityHash": "d5dd0e6fc8f6d48c5f58e7b191bc8d3d",
"entities": [
{
"tableName": "DbEvent",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` TEXT NOT NULL, `projectId` TEXT, `scopeId` TEXT, `eventJson` TEXT NOT NULL, `createdAt_unixMs` INTEGER NOT NULL, `createdAt_isTrustworthy` INTEGER NOT NULL, `createdAt_msSinceBoot` INTEGER, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "projectId",
"columnName": "projectId",
"affinity": "TEXT"
},
{
"fieldPath": "scopeId",
"columnName": "scopeId",
"affinity": "TEXT"
},
{
"fieldPath": "eventJson",
"columnName": "eventJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "createdAt.unixMs",
"columnName": "createdAt_unixMs",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "createdAt.isTrustworthy",
"columnName": "createdAt_isTrustworthy",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "createdAt.msSinceBoot",
"columnName": "createdAt_msSinceBoot",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "DbEventScope",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `projectId` TEXT NOT NULL, `type` TEXT NOT NULL, `payloadJson` TEXT NOT NULL, `start_unixMs` INTEGER NOT NULL, `start_isTrustworthy` INTEGER NOT NULL, `start_msSinceBoot` INTEGER, `end_unixMs` INTEGER, `end_isTrustworthy` INTEGER, `end_msSinceBoot` INTEGER, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "projectId",
"columnName": "projectId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "payloadJson",
"columnName": "payloadJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "createdAt.unixMs",
"columnName": "start_unixMs",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "createdAt.isTrustworthy",
"columnName": "start_isTrustworthy",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "createdAt.msSinceBoot",
"columnName": "start_msSinceBoot",
"affinity": "INTEGER"
},
{
"fieldPath": "endedAt.unixMs",
"columnName": "end_unixMs",
"affinity": "INTEGER"
},
{
"fieldPath": "endedAt.isTrustworthy",
"columnName": "end_isTrustworthy",
"affinity": "INTEGER"
},
{
"fieldPath": "endedAt.msSinceBoot",
"columnName": "end_msSinceBoot",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd5dd0e6fc8f6d48c5f58e7b191bc8d3d')"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.simprints.infra.events.event.local.migrations.EventMigration12to13
import com.simprints.infra.events.event.local.migrations.EventMigration13to14
import com.simprints.infra.events.event.local.migrations.EventMigration14to15
import com.simprints.infra.events.event.local.migrations.EventMigration15to16
import com.simprints.infra.events.event.local.migrations.EventMigration16to17
import com.simprints.infra.events.event.local.migrations.EventMigration1to2
import com.simprints.infra.events.event.local.migrations.EventMigration2to3
import com.simprints.infra.events.event.local.migrations.EventMigration3to4
Expand All @@ -31,7 +32,7 @@ import net.zetetic.database.sqlcipher.SupportOpenHelperFactory
DbEvent::class,
DbEventScope::class,
],
version = 16,
version = 17,
Comment thread
alexandr-simprints marked this conversation as resolved.
exportSchema = true,
)
@TypeConverters(Converters::class)
Expand Down Expand Up @@ -64,6 +65,7 @@ internal abstract class EventRoomDatabase : RoomDatabase() {
.addMigrations(EventMigration13to14())
.addMigrations(EventMigration14to15())
.addMigrations(EventMigration15to16())
.addMigrations(EventMigration16to17())

if (BuildConfig.DB_ENCRYPTION) {
builder.openHelperFactory(factory)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.simprints.infra.events.event.local.migrations

import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.simprints.core.tools.extentions.getStringWithColumnName
import com.simprints.infra.logging.LoggingConstants.CrashReportTag.MIGRATION
import com.simprints.infra.logging.Simber
import org.json.JSONArray
import org.json.JSONObject

/**
* Starting from 2025.4.0, EnrolmentEventV4 requires the `externalCredentialIds` field.
* This migration adds an empty `externalCredentialIds` array field to the EnrolmentEventV4 event
*
* This migration adds:
* "externalCredentialIds": [],
* to the payload object.
*/
internal class EventMigration16to17 : Migration(16, 17) {
override fun migrate(db: SupportSQLiteDatabase) {
Simber.i("Migrating room db from schema 16 to schema 17.", tag = MIGRATION)
migrateEnrolmentEventJson(db)
Simber.i("Migration from schema 16 to schema 17 done.", tag = MIGRATION)
}

private fun migrateEnrolmentEventJson(database: SupportSQLiteDatabase) {
val eventsQuery = database.query(
"SELECT * FROM $DB_EVENT_ENTITY WHERE type = ?",
arrayOf(EVENT_TYPE_ENROLMENT_V4),
)
eventsQuery.use { cursor ->
while (cursor.moveToNext()) {
val id = cursor.getStringWithColumnName("id") ?: continue
val jsonData = cursor.getStringWithColumnName(DB_EVENT_JSON_FIELD) ?: continue

try {
val jsonObject = JSONObject(jsonData)
val payload = jsonObject.optJSONObject(PAYLOAD_JSON_FIELD) ?: continue

// Only adding if 'externalCredentialIds' field doesn't exist
if (!payload.has(EXTERNAL_CREDENTIAL_IDS_JSON_FIELD)) {
payload.put(EXTERNAL_CREDENTIAL_IDS_JSON_FIELD, JSONArray())
val migratedJson = jsonObject.toString()
database.execSQL(
"UPDATE $DB_EVENT_ENTITY SET $DB_EVENT_JSON_FIELD = ? WHERE id = ?",
arrayOf(migratedJson, id),
)
}
} catch (e: Exception) {
Simber.e(
"Failed to migrate room db from schema 16 to schema 17.",
e,
tag = MIGRATION,
)
}
}
}
}

companion object {
private const val DB_EVENT_ENTITY = "DbEvent"
private const val DB_EVENT_JSON_FIELD = "eventJson"
private const val EVENT_TYPE_ENROLMENT_V4 = "ENROLMENT_V4"
private const val EXTERNAL_CREDENTIAL_IDS_JSON_FIELD = "externalCredentialIds"
private const val PAYLOAD_JSON_FIELD = "payload"
}
}
Loading