Skip to content

Commit

Permalink
[DB] simplify AndroidSQLiteOpenHelper.kt impl. simplify some legacy c…
Browse files Browse the repository at this point in the history
…ode with more kotlin
  • Loading branch information
agrosner committed Feb 18, 2021
1 parent 2d85b79 commit 9338ba4
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 118 deletions.
3 changes: 2 additions & 1 deletion lib/src/main/kotlin/com/dbflow5/config/DBFlowDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,14 @@ abstract class DBFlowDatabase : DatabaseWrapper {
}

private fun onOpenWithConfig(config: DatabaseConfig?, helper: OpenHelper) {
helper.performRestoreFromBackup()

var wal = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
wal = config != null && config.journalMode.adjustIfAutomatic(FlowManager.context) == JournalMode.WriteAheadLogging
helper.trySetWriteAheadLoggingEnabled(wal)
}
writeAheadLoggingEnabled = wal
helper.performRestoreFromBackup()
isOpened = true
}

Expand Down
47 changes: 15 additions & 32 deletions lib/src/main/kotlin/com/dbflow5/database/AndroidSQLiteOpenHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,24 @@ import com.dbflow5.config.OpenHelperCreator
open class AndroidSQLiteOpenHelper(
private val context: Context,
databaseDefinition: DBFlowDatabase,
listener: DatabaseCallback?)
: SQLiteOpenHelper(context,
if (databaseDefinition.isInMemory) null else databaseDefinition.databaseFileName,
null,
databaseDefinition.databaseVersion), OpenHelper {

private val databaseHelperDelegate: DatabaseHelperDelegate
private var androidDatabase: AndroidDatabase? = null
private val _databaseName = databaseDefinition.databaseFileName

init {
var backupHelper: OpenHelper? = null
listener: DatabaseCallback?,
private val databaseHelperDelegate: DatabaseHelperDelegate = DatabaseHelperDelegate(context, listener, databaseDefinition,
if (databaseDefinition.backupEnabled()) {
// Temp database mirrors existing
backupHelper = BackupHelper(context,
BackupHelper(context,
DatabaseHelperDelegate.getTempDbFileName(databaseDefinition),
databaseDefinition.databaseVersion, databaseDefinition)
}

databaseHelperDelegate = DatabaseHelperDelegate(context, listener, databaseDefinition, backupHelper)
}

override fun performRestoreFromBackup() {
databaseHelperDelegate.performRestoreFromBackup()
}

override val delegate: DatabaseHelperDelegate?
get() = databaseHelperDelegate
} else null),
) : SQLiteOpenHelper(
context,
if (databaseDefinition.isInMemory) null else databaseDefinition.databaseFileName,
null,
databaseDefinition.databaseVersion,
), OpenHelper, OpenHelperDelegate by databaseHelperDelegate {

override val isDatabaseIntegrityOk: Boolean
get() = databaseHelperDelegate.isDatabaseIntegrityOk

override fun backupDB() {
databaseHelperDelegate.backupDB()
}
private var androidDatabase: AndroidDatabase? = null
private val _databaseName = databaseDefinition.databaseFileName

override val database: DatabaseWrapper
get() {
Expand Down Expand Up @@ -97,9 +80,9 @@ open class AndroidSQLiteOpenHelper(
/**
* Simple helper to manage backup.
*/
private inner class BackupHelper(context: Context,
name: String, version: Int,
databaseDefinition: DBFlowDatabase)
private class BackupHelper(private val context: Context,
name: String, version: Int,
databaseDefinition: DBFlowDatabase)
: SQLiteOpenHelper(context, name, null, version), OpenHelper {

private var androidDatabase: AndroidDatabase? = null
Expand Down
131 changes: 65 additions & 66 deletions lib/src/main/kotlin/com/dbflow5/database/DatabaseHelperDelegate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import java.io.InputStream
* used in other helper class definitions.
*/
class DatabaseHelperDelegate(
private val context: Context,
private var databaseCallback: DatabaseCallback?,
databaseDefinition: DBFlowDatabase,
private val backupHelper: OpenHelper?)
: DatabaseHelper(AndroidMigrationFileHelper(context), databaseDefinition) {
private val context: Context,
private var databaseCallback: DatabaseCallback?,
databaseDefinition: DBFlowDatabase,
private val backupHelper: OpenHelper?)
: DatabaseHelper(AndroidMigrationFileHelper(context), databaseDefinition), OpenHelperDelegate {

/**
* @return the temporary database file name for when we have backups enabled
Expand All @@ -35,26 +35,28 @@ class DatabaseHelperDelegate(
*
* @return true if the database is ok, false if the consistency has been compromised.
*/
val isDatabaseIntegrityOk: Boolean
get() = isDatabaseIntegrityOk(writableDatabase)
override val isDatabaseIntegrityOk: Boolean
get() = isDatabaseIntegrityOk(database)

val writableDatabase: DatabaseWrapper
override val database: DatabaseWrapper
get() = databaseDefinition

fun performRestoreFromBackup() {
override fun performRestoreFromBackup() {
movePrepackagedDB(databaseDefinition.databaseFileName,
databaseDefinition.databaseFileName)
databaseDefinition.databaseFileName)

if (databaseDefinition.backupEnabled()) {
if (backupHelper == null) {
throw IllegalStateException("the passed backup helper was null, even though backup" +
" is enabled. Ensure that its passed in.")
" is enabled. Ensure that its passed in.")
}
restoreDatabase(tempDbFileName, databaseDefinition.databaseFileName)
backupHelper.database
}
}

override val delegate: DatabaseHelperDelegate = this

/**
* @param databaseCallback Listens for operations the DB and allow you to provide extra
* functionality.
Expand Down Expand Up @@ -99,7 +101,9 @@ class DatabaseHelperDelegate(
val dbPath = context.getDatabasePath(databaseName)

// If the database already exists, and is ok return
if (dbPath.exists() && (!databaseDefinition.areConsistencyChecksEnabled() || databaseDefinition.areConsistencyChecksEnabled() && isDatabaseIntegrityOk(writableDatabase))) {
if (dbPath.exists()
&& (!databaseDefinition.areConsistencyChecksEnabled()
|| (databaseDefinition.areConsistencyChecksEnabled() && isDatabaseIntegrityOk(database)))) {
return
}

Expand All @@ -110,13 +114,12 @@ class DatabaseHelperDelegate(
try {
// check existing and use that as backup
val existingDb = context.getDatabasePath(tempDbFileName)
val inputStream: InputStream
// if it exists and the integrity is ok we use backup as the main DB is no longer valid
inputStream = if (existingDb.exists()
&& (!databaseDefinition.backupEnabled() ||
(databaseDefinition.backupEnabled()
&& backupHelper != null
&& isDatabaseIntegrityOk(backupHelper.database)))) {
val inputStream = if (existingDb.exists()
&& (!databaseDefinition.backupEnabled() ||
(databaseDefinition.backupEnabled()
&& backupHelper != null
&& isDatabaseIntegrityOk(backupHelper.database)))) {
FileInputStream(existingDb)
} else {
context.assets.open(prepackagedName)
Expand All @@ -128,6 +131,44 @@ class DatabaseHelperDelegate(

}


/**
* Will use the already existing app database if [DBFlowDatabase.backupEnabled] is true. If the existing
* is not there we will try to use the prepackaged database for that purpose.
*
* @param databaseName The name of the database to restore
* @param prepackagedName The name of the prepackaged db file
*/
fun restoreDatabase(databaseName: String, prepackagedName: String) {
val dbPath = context.getDatabasePath(databaseName)

// If the database already exists, return
if (dbPath.exists()) {
return
}

// Make sure we have a path to the file
dbPath.parentFile.mkdirs()

// Try to copy database file
try {
// check existing and use that as backup
val existingDb = context.getDatabasePath(databaseDefinition.databaseFileName)
// if it exists and the integrity is ok
val inputStream = if (existingDb.exists()
&& (databaseDefinition.backupEnabled() && backupHelper != null
&& isDatabaseIntegrityOk(backupHelper.database))) {
FileInputStream(existingDb)
} else {
context.assets.open(prepackagedName)
}
writeDB(dbPath, inputStream)
} catch (e: IOException) {
FlowLog.logError(e)
}

}

/**
* Pulled partially from code, it runs a "PRAGMA quick_check(1)" to see if the database is ok.
* This method will [.restoreBackUp] if they are enabled on the database if this check fails. So
Expand All @@ -137,10 +178,7 @@ class DatabaseHelperDelegate(
*/
fun isDatabaseIntegrityOk(databaseWrapper: DatabaseWrapper): Boolean {
var integrityOk = true

var statement: DatabaseStatement? = null
try {
statement = databaseWrapper.compileStatement("PRAGMA quick_check(1)")
databaseWrapper.compileStatement("PRAGMA quick_check(1)").use { statement ->
val result = statement.simpleQueryForString()
if (result == null || !result.equals("ok", ignoreCase = true)) {
// integrity_checker failed on main or attached databases
Expand All @@ -150,10 +188,6 @@ class DatabaseHelperDelegate(
integrityOk = restoreBackUp()
}
}
} finally {
if (statement != null) {
statement.close()
}
}
return integrityOk
}
Expand Down Expand Up @@ -204,54 +238,19 @@ class DatabaseHelperDelegate(
existingDB.close()
}

/**
* Will use the already existing app database if [DBFlowDatabase.backupEnabled] is true. If the existing
* is not there we will try to use the prepackaged database for that purpose.
*
* @param databaseName The name of the database to restore
* @param prepackagedName The name of the prepackaged db file
*/
fun restoreDatabase(databaseName: String, prepackagedName: String) {
val dbPath = context.getDatabasePath(databaseName)

// If the database already exists, return
if (dbPath.exists()) {
return
}

// Make sure we have a path to the file
dbPath.parentFile.mkdirs()

// Try to copy database file
try {
// check existing and use that as backup
val existingDb = context.getDatabasePath(databaseDefinition.databaseFileName)
val inputStream: InputStream
// if it exists and the integrity is ok
inputStream = if (existingDb.exists()
&& (databaseDefinition.backupEnabled() && backupHelper != null
&& isDatabaseIntegrityOk(backupHelper.database))) {
FileInputStream(existingDb)
} else {
context.assets.open(prepackagedName)
}
writeDB(dbPath, inputStream)
} catch (e: IOException) {
FlowLog.logError(e)
}
private fun checkDBVersion() {

}


/**
* Saves the database as a backup on the [DefaultTransactionQueue].
* This will create a THIRD database to use as a backup to the backup in case somehow the overwrite fails.
*/
fun backupDB() {
override fun backupDB() {
if (!databaseDefinition.backupEnabled() || !databaseDefinition.areConsistencyChecksEnabled()) {
throw IllegalStateException("Backups are not enabled for : " +
"${databaseDefinition.databaseName}. Please consider adding both backupEnabled " +
"and consistency checks enabled to the Database annotation")
"${databaseDefinition.databaseName}. Please consider adding both backupEnabled " +
"and consistency checks enabled to the Database annotation")
}

databaseDefinition.beginTransactionAsync {
Expand Down Expand Up @@ -286,6 +285,6 @@ class DatabaseHelperDelegate(
val TEMP_DB_NAME = "temp-"

fun getTempDbFileName(databaseDefinition: DBFlowDatabase): String =
"$TEMP_DB_NAME${databaseDefinition.databaseName}.db"
"$TEMP_DB_NAME${databaseDefinition.databaseName}.db"
}
}
17 changes: 10 additions & 7 deletions lib/src/main/kotlin/com/dbflow5/database/OpenHelper.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
package com.dbflow5.database

/**
* Description: Abstracts out the [DatabaseHelperDelegate] into the one used in this library.
*/
interface OpenHelper {

interface OpenHelperDelegate {
val database: DatabaseWrapper

val delegate: DatabaseHelperDelegate?

val isDatabaseIntegrityOk: Boolean

fun setWriteAheadLoggingEnabled(enabled: Boolean)

fun performRestoreFromBackup()

fun backupDB()
}


/**
* Description: Abstracts out the [DatabaseHelperDelegate] into the one used in this library.
*/
interface OpenHelper : OpenHelperDelegate {

fun setWriteAheadLoggingEnabled(enabled: Boolean)

fun setDatabaseListener(callback: DatabaseCallback?)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,12 @@ abstract class SQLCipherOpenHelper(

init {
SQLiteDatabase.loadLibs(context)

var backupHelper: OpenHelper? = null
if (databaseDefinition.backupEnabled()) {
delegate = DatabaseHelperDelegate(context, listener, databaseDefinition, if (databaseDefinition.backupEnabled()) {
// Temp database mirrors existing
backupHelper = BackupHelper(context,
BackupHelper(context,
DatabaseHelperDelegate.getTempDbFileName(databaseDefinition),
databaseDefinition.databaseVersion, databaseDefinition)
}

delegate = DatabaseHelperDelegate(context, listener, databaseDefinition, backupHelper)
} else null)
}

override fun performRestoreFromBackup() {
Expand Down Expand Up @@ -93,7 +89,11 @@ abstract class SQLCipherOpenHelper(
}

override fun setWriteAheadLoggingEnabled(enabled: Boolean) {
throw UnsupportedOperationException("Not supported in SQLCipher")
if (enabled) {
cipherDatabase?.database?.enableWriteAheadLogging()
} else {
cipherDatabase?.database?.disableWriteAheadLogging()
}
}

override fun closeDB() {
Expand Down Expand Up @@ -126,11 +126,9 @@ abstract class SQLCipherOpenHelper(
return sqlCipherDatabase!!
}

override val delegate: DatabaseHelperDelegate?
get() = null
override val delegate: DatabaseHelperDelegate? = null

override val isDatabaseIntegrityOk: Boolean
get() = false
override val isDatabaseIntegrityOk: Boolean = false

override fun performRestoreFromBackup() = Unit

Expand Down

0 comments on commit 9338ba4

Please sign in to comment.