Skip to content

Commit

Permalink
Merge branch 'master' into retenogit/master
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilia-Solodiankin committed Nov 20, 2023
2 parents 0eb0abd + a583ef6 commit 40df793
Show file tree
Hide file tree
Showing 29 changed files with 588 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal interface RetenoDatabase {

fun delete(table: String, whereClause: String? = null, whereArgs: Array<String?>? = null): Int

fun getRowCount(tableName: String): Long
fun getRowCount(tableName: String, whereClause: String? = null, whereArgs: Array<String?>? = null): Long

/**
* Call this method each time you remove any record from Event table (Child table)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.database.sqlite.SQLiteDatabaseLockedException
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteOpenHelper
import android.os.SystemClock
import android.util.Log
import com.reteno.core.BuildConfig
import com.reteno.core.data.local.database.schema.AppInboxSchema
import com.reteno.core.data.local.database.schema.DbSchema.DATABASE_NAME
Expand Down Expand Up @@ -88,7 +89,7 @@ internal class RetenoDatabaseImpl(private val context: Context) : RetenoDatabase
}
if (oldVersion < 4) {
try {
/*@formatter:off*/ Logger.i(TAG, "onUpgrade(): start update table \"Interaction\"", "old DB version = ",oldVersion,", newVersion = ",newVersion )
/*@formatter:off*/ Logger.i(TAG, "onUpgrade(): start update table \"Interaction\"", " old DB version = ",oldVersion,", newVersion = ",newVersion )
/*@formatter:on*/
db.execSQL(InteractionSchema.SQL_UPGRADE_TABLE_VERSION_4)
} catch (e: SQLiteException) {
Expand All @@ -100,6 +101,32 @@ internal class RetenoDatabaseImpl(private val context: Context) : RetenoDatabase
}
}
}
if (oldVersion < 6) {
try {
/*@formatter:off*/ Logger.i(TAG, "onUpgrade(): start update table \"User\"", " old DB version = ",oldVersion,", newVersion = ",newVersion )
/*@formatter:on*/
db.execSQL(UserSchema.SQL_UPGRADE_TABLE_VERSION_6)
} catch (e: SQLiteException) {
if (e.toString().startsWith("duplicate column name")) {
/*@formatter:off*/ Logger.e(TAG, "onUpgrade(): Ignoring this exception", e)
/*@formatter:on*/
} else {
throw e
}
}
try {
/*@formatter:off*/ Logger.i(TAG, "onUpgrade(): start update table \"Device\"", " old DB version = ",oldVersion,", newVersion = ",newVersion )
/*@formatter:on*/
db.execSQL(DeviceSchema.SQL_UPGRADE_TABLE_VERSION_6)
} catch (e: SQLiteException) {
if (e.toString().startsWith("duplicate column name")) {
/*@formatter:off*/ Logger.e(TAG, "onUpgrade(): Ignoring this exception", e)
/*@formatter:on*/
} else {
throw e
}
}
}
}

override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
Expand Down Expand Up @@ -336,7 +363,12 @@ internal class RetenoDatabaseImpl(private val context: Context) : RetenoDatabase
} catch (e: IllegalStateException) {
/*@formatter:off*/ Logger.e(TAG, "delete(): Error under delete transaction under table: $table with whereClause: $whereClause and whereArgs: $whereArgs", e)
/*@formatter:on*/
} finally {
} catch (e: Throwable) {
/*@formatter:off*/ Log.e(TAG, "delete(): Error under delete transaction under table: $table with whereClause: $whereClause and whereArgs: $whereArgs", e)
/*@formatter:on*/
e.printStackTrace()
}
finally {
try {
writableSQLDatabase.endTransaction() // May throw if transaction was never opened or DB is full.
} catch (e: IllegalStateException) {
Expand All @@ -352,11 +384,16 @@ internal class RetenoDatabaseImpl(private val context: Context) : RetenoDatabase
return count
}

override fun getRowCount(tableName: String): Long {
override fun getRowCount(tableName: String, whereClause: String?, whereArgs: Array<String?>?): Long {
var count: Long = 0

try {
count = DatabaseUtils.queryNumEntries(getSQLiteDatabaseWithRetries(), tableName)
count = DatabaseUtils.queryNumEntries(
getSQLiteDatabaseWithRetries(),
tableName,
whereClause,
whereArgs
)
} catch (ex: SQLiteException) {
/*@formatter:off*/ Logger.e(TAG, "getRowCount(): ", ex)
/*@formatter:on*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ interface RetenoDatabaseManagerDevice {
fun getDevices(limit: Int? = null): List<DeviceDb>
fun getDeviceCount(): Long
fun deleteDevice(device: DeviceDb): Boolean
fun deleteDevices(devices: List<DeviceDb>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.reteno.core.data.local.database.schema.DbSchema
import com.reteno.core.data.local.database.schema.DeviceSchema
import com.reteno.core.data.local.database.util.getDevice
import com.reteno.core.data.local.database.util.putDevice
import com.reteno.core.data.local.model.BooleanDb
import com.reteno.core.data.local.model.device.DeviceDb
import com.reteno.core.util.Logger

Expand Down Expand Up @@ -74,7 +75,11 @@ internal class RetenoDatabaseManagerDeviceImpl(private val database: RetenoDatab
return deviceEvents
}

override fun getDeviceCount(): Long = database.getRowCount(DeviceSchema.TABLE_NAME_DEVICE)
override fun getDeviceCount(): Long = database.getRowCount(
DeviceSchema.TABLE_NAME_DEVICE,
whereClause = "${DeviceSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND}<>?",
whereArgs = arrayOf(BooleanDb.TRUE.toString())
)

override fun deleteDevice(device: DeviceDb): Boolean {
/*@formatter:off*/ Logger.i(TAG, "deleteDevice(): ", "device = [", device, "]")
Expand All @@ -89,6 +94,21 @@ internal class RetenoDatabaseManagerDeviceImpl(private val database: RetenoDatab
return removedRecordsCount > 0
}

override fun deleteDevices(devices: List<DeviceDb>) {
/*@formatter:off*/ Logger.i(TAG, "deleteDevices(): ", "devices: [", devices, "]")
/*@formatter:on*/

val rowIds = devices.mapNotNull { it.rowId }

for (rowId: String in rowIds) {
database.delete(
table = DeviceSchema.TABLE_NAME_DEVICE,
whereClause = "${DeviceSchema.COLUMN_DEVICE_ROW_ID}=?",
whereArgs = arrayOf(rowId)
)
}
}

companion object {
private val TAG: String = RetenoDatabaseManagerDeviceImpl::class.java.simpleName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ interface RetenoDatabaseManagerUser {
fun getUsers(limit: Int? = null): List<UserDb>
fun getUserCount(): Long
fun deleteUser(user: UserDb): Boolean
fun deleteUsers(users: List<UserDb>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.reteno.core.data.local.database.util.getUser
import com.reteno.core.data.local.database.util.putUser
import com.reteno.core.data.local.database.util.putUserAddress
import com.reteno.core.data.local.database.util.putUserAttributes
import com.reteno.core.data.local.model.BooleanDb
import com.reteno.core.data.local.model.user.UserDb
import com.reteno.core.util.Logger

Expand Down Expand Up @@ -58,6 +59,7 @@ internal class RetenoDatabaseManagerUserImpl(private val database: RetenoDatabas
" ${UserSchema.TABLE_NAME_USER}.${UserSchema.COLUMN_SUBSCRIPTION_KEYS} AS ${UserSchema.COLUMN_SUBSCRIPTION_KEYS}," +
" ${UserSchema.TABLE_NAME_USER}.${UserSchema.COLUMN_GROUP_NAMES_INCLUDE} AS ${UserSchema.COLUMN_GROUP_NAMES_INCLUDE}," +
" ${UserSchema.TABLE_NAME_USER}.${UserSchema.COLUMN_GROUP_NAMES_EXCLUDE} AS ${UserSchema.COLUMN_GROUP_NAMES_EXCLUDE}," +
" ${UserSchema.TABLE_NAME_USER}.${UserSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND} AS ${UserSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND}," +
" ${UserSchema.UserAttributesSchema.TABLE_NAME_USER_ATTRIBUTES}.${UserSchema.UserAttributesSchema.COLUMN_PHONE} AS ${UserSchema.UserAttributesSchema.COLUMN_PHONE}," +
" ${UserSchema.UserAttributesSchema.TABLE_NAME_USER_ATTRIBUTES}.${UserSchema.UserAttributesSchema.COLUMN_EMAIL} AS ${UserSchema.UserAttributesSchema.COLUMN_EMAIL}," +
" ${UserSchema.UserAttributesSchema.TABLE_NAME_USER_ATTRIBUTES}.${UserSchema.UserAttributesSchema.COLUMN_FIRST_NAME} AS ${UserSchema.UserAttributesSchema.COLUMN_FIRST_NAME}," +
Expand Down Expand Up @@ -107,7 +109,11 @@ internal class RetenoDatabaseManagerUserImpl(private val database: RetenoDatabas
return userList
}

override fun getUserCount(): Long = database.getRowCount(UserSchema.TABLE_NAME_USER)
override fun getUserCount(): Long = database.getRowCount(
UserSchema.TABLE_NAME_USER,
whereClause = "${UserSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND}<>?",
whereArgs = arrayOf(BooleanDb.TRUE.toString())
)

override fun deleteUser(user: UserDb): Boolean {
/*@formatter:off*/ Logger.i(TAG, "deleteUser(): ", "user = [", user, "]")
Expand All @@ -122,6 +128,21 @@ internal class RetenoDatabaseManagerUserImpl(private val database: RetenoDatabas
return removedRecordsCount > 0
}

override fun deleteUsers(users: List<UserDb>) {
/*@formatter:off*/ Logger.i(TAG, "deleteUsers(): ", "users: [", users, "]")
/*@formatter:on*/

val rowIds = users.mapNotNull { it.rowId }

for (rowId: String in rowIds) {
database.delete(
table = UserSchema.TABLE_NAME_USER,
whereClause = "${UserSchema.COLUMN_USER_ROW_ID}=?",
whereArgs = arrayOf(rowId)
)
}
}

companion object {
private val TAG: String = RetenoDatabaseManagerUserImpl::class.java.simpleName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ package com.reteno.core.data.local.database.schema

internal object DbSchema {
internal const val DATABASE_NAME = "reteno.db"
internal const val DATABASE_VERSION = 5
internal const val DATABASE_VERSION = 6
internal const val COLUMN_TIMESTAMP = "timeStamp"
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal object DeviceSchema {
internal const val COLUMN_LANGUAGE_CODE = "languageCode"
internal const val COLUMN_TIMEZONE = "timeZone"
internal const val COLUMN_ADVERTISING_ID = "advertisingId"
internal const val COLUMN_SYNCHRONIZED_WITH_BACKEND = "synchronizedWithBackend"

internal const val SQL_CREATE_TABLE =
"CREATE TABLE IF NOT EXISTS $TABLE_NAME_DEVICE" +
Expand All @@ -33,12 +34,16 @@ internal object DeviceSchema {
"$COLUMN_APP_VERSION TEXT, " +
"$COLUMN_LANGUAGE_CODE TEXT, " +
"$COLUMN_TIMEZONE TEXT, " +
"$COLUMN_ADVERTISING_ID TEXT" +
"$COLUMN_ADVERTISING_ID TEXT, " +
"$COLUMN_SYNCHRONIZED_WITH_BACKEND TEXT" +
")"

internal const val SQL_UPGRADE_TABLE_VERSION_2 =
"ALTER TABLE $TABLE_NAME_DEVICE ADD COLUMN $COLUMN_PUSH_SUBSCRIBED TEXT"

internal const val SQL_UPGRADE_TABLE_VERSION_6 =
"ALTER TABLE $TABLE_NAME_DEVICE ADD COLUMN $COLUMN_SYNCHRONIZED_WITH_BACKEND TEXT"

fun getAllColumns(): Array<String> = arrayOf(
COLUMN_DEVICE_ROW_ID,
DbSchema.COLUMN_TIMESTAMP,
Expand All @@ -53,6 +58,7 @@ internal object DeviceSchema {
COLUMN_APP_VERSION,
COLUMN_LANGUAGE_CODE,
COLUMN_TIMEZONE,
COLUMN_ADVERTISING_ID
COLUMN_ADVERTISING_ID,
COLUMN_SYNCHRONIZED_WITH_BACKEND
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal object UserSchema {
internal const val COLUMN_SUBSCRIPTION_KEYS = "subscriptionKeys"
internal const val COLUMN_GROUP_NAMES_INCLUDE = "groupNamesInclude"
internal const val COLUMN_GROUP_NAMES_EXCLUDE = "groupNamesExclude"
internal const val COLUMN_SYNCHRONIZED_WITH_BACKEND = "synchronizedWithBackend"

internal const val SQL_CREATE_TABLE =
"CREATE TABLE IF NOT EXISTS $TABLE_NAME_USER" +
Expand All @@ -19,9 +20,13 @@ internal object UserSchema {
"$COLUMN_EXTERNAL_USER_ID TEXT, " +
"$COLUMN_SUBSCRIPTION_KEYS TEXT, " +
"$COLUMN_GROUP_NAMES_INCLUDE TEXT, " +
"$COLUMN_GROUP_NAMES_EXCLUDE TEXT" +
"$COLUMN_GROUP_NAMES_EXCLUDE TEXT," +
"$COLUMN_SYNCHRONIZED_WITH_BACKEND TEXT" +
")"

internal const val SQL_UPGRADE_TABLE_VERSION_6 =
"ALTER TABLE $TABLE_NAME_USER ADD COLUMN $COLUMN_SYNCHRONIZED_WITH_BACKEND TEXT"

internal object UserAttributesSchema {
internal const val TABLE_NAME_USER_ATTRIBUTES = "UserAttributes"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.reteno.core.data.local.database.util
import android.content.ContentValues
import android.database.Cursor
import androidx.core.database.getStringOrNull
import com.reteno.core.data.local.database.schema.DbSchema
import com.reteno.core.data.local.database.schema.DeviceSchema
import com.reteno.core.data.local.model.BooleanDb
import com.reteno.core.data.local.model.device.DeviceCategoryDb
import com.reteno.core.data.local.model.device.DeviceDb
import com.reteno.core.data.local.model.device.DeviceOsDb
import com.reteno.core.util.Util

fun ContentValues.putDevice(device: DeviceDb) {
put(DeviceSchema.COLUMN_DEVICE_ID, device.deviceId)
Expand All @@ -22,10 +24,12 @@ fun ContentValues.putDevice(device: DeviceDb) {
put(DeviceSchema.COLUMN_LANGUAGE_CODE, device.languageCode)
put(DeviceSchema.COLUMN_TIMEZONE, device.timeZone)
put(DeviceSchema.COLUMN_ADVERTISING_ID, device.advertisingId)
put(DeviceSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND, device.isSynchronizedWithBackend?.toString())
}

fun Cursor.getDevice(): DeviceDb? {
val rowId = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_DEVICE_ROW_ID))
val createdAt = getStringOrNull(getColumnIndex(DbSchema.COLUMN_TIMESTAMP))
val deviceId = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_DEVICE_ID))
val externalUserId = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_EXTERNAL_USER_ID))
val pushToken = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_PUSH_TOKEN))
Expand All @@ -39,12 +43,15 @@ fun Cursor.getDevice(): DeviceDb? {
val languageCode = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_LANGUAGE_CODE))
val timeZone = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_TIMEZONE))
val advertisingId = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_ADVERTISING_ID))
val synchronizedWithBackendString = getStringOrNull(getColumnIndex(DeviceSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND))
val synchronizedWithBackend: BooleanDb? = BooleanDb.fromString(synchronizedWithBackendString)

return if (deviceId == null) {
return if (deviceId == null || createdAt == null) {
null
} else {
DeviceDb(
rowId = rowId,
createdAt = Util.formatSqlDateToTimestamp(createdAt),
deviceId = deviceId,
externalUserId = externalUserId,
pushToken = pushToken,
Expand All @@ -56,7 +63,8 @@ fun Cursor.getDevice(): DeviceDb? {
appVersion = appVersion,
languageCode = languageCode,
timeZone = timeZone,
advertisingId = advertisingId
advertisingId = advertisingId,
isSynchronizedWithBackend = synchronizedWithBackend
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package com.reteno.core.data.local.database.util
import android.content.ContentValues
import android.database.Cursor
import androidx.core.database.getStringOrNull
import com.reteno.core.data.local.database.schema.DbSchema
import com.reteno.core.data.local.database.schema.UserSchema
import com.reteno.core.data.local.model.BooleanDb
import com.reteno.core.data.local.model.user.AddressDb
import com.reteno.core.data.local.model.user.UserAttributesDb
import com.reteno.core.data.local.model.user.UserCustomFieldDb
import com.reteno.core.data.local.model.user.UserDb
import com.reteno.core.data.remote.mapper.fromJson
import com.reteno.core.data.remote.mapper.listFromJson
import com.reteno.core.data.remote.mapper.toJson
import com.reteno.core.util.Util
import com.reteno.core.util.allElementsNull

fun ContentValues.putUser(user: UserDb) {
Expand All @@ -25,6 +28,7 @@ fun ContentValues.putUser(user: UserDb) {
user.groupNamesExclude?.toJson()?.let { groupNamesExclude ->
put(UserSchema.COLUMN_GROUP_NAMES_EXCLUDE, groupNamesExclude)
}
put(UserSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND, user.isSynchronizedWithBackend?.toString())
}

fun ContentValues.putUserAttributes(parentRowId: Long, userAttributes: UserAttributesDb) {
Expand Down Expand Up @@ -97,23 +101,28 @@ fun Cursor.getUser(): UserDb? {
}

val rowId = getStringOrNull(getColumnIndex(UserSchema.COLUMN_USER_ROW_ID))
val createdAt = getStringOrNull(getColumnIndex(DbSchema.COLUMN_TIMESTAMP))
val deviceId = getStringOrNull(getColumnIndex(UserSchema.COLUMN_DEVICE_ID))
val externalUserId = getStringOrNull(getColumnIndex(UserSchema.COLUMN_EXTERNAL_USER_ID))
val subscriptionKeys = getStringOrNull(getColumnIndex(UserSchema.COLUMN_SUBSCRIPTION_KEYS))?.fromJson<List<String>>()
val groupNamesInclude = getStringOrNull(getColumnIndex(UserSchema.COLUMN_GROUP_NAMES_INCLUDE))?.fromJson<List<String>>()
val groupNamesExclude = getStringOrNull(getColumnIndex(UserSchema.COLUMN_GROUP_NAMES_EXCLUDE))?.fromJson<List<String>>()
val synchronizedWithBackendString = getStringOrNull(getColumnIndex(UserSchema.COLUMN_SYNCHRONIZED_WITH_BACKEND))
val synchronizedWithBackend: BooleanDb? = BooleanDb.fromString(synchronizedWithBackendString)

return if (deviceId == null) {
null
} else {
return if (deviceId != null && createdAt != null) {
UserDb(
rowId = rowId,
createdAt = Util.formatSqlDateToTimestamp(createdAt),
deviceId = deviceId,
externalUserId = externalUserId,
userAttributes = userAttributes,
subscriptionKeys = subscriptionKeys,
groupNamesInclude = groupNamesInclude,
groupNamesExclude = groupNamesExclude
groupNamesExclude = groupNamesExclude,
isSynchronizedWithBackend = synchronizedWithBackend
)
} else {
null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.reteno.core.data.local.model.BooleanDb

data class DeviceDb(
val rowId: String? = null,
val createdAt: Long = 0L,
val deviceId: String,
val externalUserId: String?,
val pushToken: String?,
Expand All @@ -15,5 +16,6 @@ data class DeviceDb(
val appVersion: String?,
val languageCode: String?,
val timeZone: String?,
val advertisingId: String?
val advertisingId: String?,
val isSynchronizedWithBackend: BooleanDb? = null
)

0 comments on commit 40df793

Please sign in to comment.