Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/db/AppDatabaseMigrations.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package fr.free.nrw.commons.db

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import fr.free.nrw.commons.data.DBOpenHelper

/**
* Room [Migration] definitions shared by the app and tests.
*
* @see fr.free.nrw.commons.di.CommonsApplicationModule.provideAppDataBase
*/
object AppDatabaseMigrations {

/**
* Adds [fr.free.nrw.commons.contributions.Contribution.hasInvalidLocation] to the contribution table.
*/
val MIGRATION_1_2: Migration =
object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"ALTER TABLE contribution " + " ADD COLUMN hasInvalidLocation INTEGER NOT NULL DEFAULT 0",
)
}
}

/**
* Copies bookmarked places from the legacy [DBOpenHelper] database ([LEGACY_COMMONS_DATABASE_NAME],
* table [DBOpenHelper.BOOKMARKS_LOCATIONS]) into Room's `bookmarks_locations` table.
*
* @param applicationContext used to resolve the on-disk path of the legacy DB
*/
fun migrationBookmarksFromLegacyCommonsDb(applicationContext: Context): Migration =
object : Migration(19, 20) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS bookmarks_locations (
location_name TEXT NOT NULL PRIMARY KEY,
location_language TEXT NOT NULL,
location_description TEXT NOT NULL,
location_lat REAL NOT NULL,
location_long REAL NOT NULL,
location_category TEXT NOT NULL,
location_label_text TEXT NOT NULL,
location_label_icon INTEGER,
location_image_url TEXT NOT NULL DEFAULT '',
location_wikipedia_link TEXT NOT NULL,
location_wikidata_link TEXT NOT NULL,
location_commons_link TEXT NOT NULL,
location_pic TEXT NOT NULL,
location_exists INTEGER NOT NULL CHECK(location_exists IN (0, 1))
)
""",
)

val oldDbPath =
applicationContext
.getDatabasePath(LEGACY_COMMONS_DATABASE_NAME)
.path
val oldDb =
SQLiteDatabase.openDatabase(
oldDbPath,
null,
SQLiteDatabase.OPEN_READONLY,
)

val cursor = oldDb.rawQuery("SELECT * FROM ${DBOpenHelper.BOOKMARKS_LOCATIONS}", null)

while (cursor.moveToNext()) {
val locationName =
cursor.getString(cursor.getColumnIndexOrThrow("location_name"))
val locationLanguage =
cursor.getString(cursor.getColumnIndexOrThrow("location_language"))
val locationDescription =
cursor.getString(cursor.getColumnIndexOrThrow("location_description"))
val locationCategory =
cursor.getString(cursor.getColumnIndexOrThrow("location_category"))
val locationLabelText =
cursor.getString(cursor.getColumnIndexOrThrow("location_label_text"))
val locationLabelIcon =
cursor.getInt(cursor.getColumnIndexOrThrow("location_label_icon"))
val locationLat =
cursor.getDouble(cursor.getColumnIndexOrThrow("location_lat"))
val locationLong =
cursor.getDouble(cursor.getColumnIndexOrThrow("location_long"))

val locationImageUrl =
cursor.getString(
cursor.getColumnIndexOrThrow("location_image_url"),
) ?: ""
val locationWikipediaLink =
cursor.getString(
cursor.getColumnIndexOrThrow("location_wikipedia_link"),
) ?: ""
val locationWikidataLink =
cursor.getString(
cursor.getColumnIndexOrThrow("location_wikidata_link"),
) ?: ""
val locationCommonsLink =
cursor.getString(
cursor.getColumnIndexOrThrow("location_commons_link"),
) ?: ""
val locationPic =
cursor.getString(
cursor.getColumnIndexOrThrow("location_pic"),
) ?: ""
val locationExists =
cursor.getInt(
cursor.getColumnIndexOrThrow("location_exists"),
)

db.execSQL(
"""
INSERT OR REPLACE INTO bookmarks_locations (
location_name, location_language, location_description, location_category,
location_label_text, location_label_icon, location_lat, location_long,
location_image_url, location_wikipedia_link, location_wikidata_link,
location_commons_link, location_pic, location_exists
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
arrayOf(
locationName,
locationLanguage,
locationDescription,
locationCategory,
locationLabelText,
locationLabelIcon,
locationLat,
locationLong,
locationImageUrl,
locationWikipediaLink,
locationWikidataLink,
locationCommonsLink,
locationPic,
locationExists,
),
)
}

cursor.close()
oldDb.close()
}
}

/** Same file name as [fr.free.nrw.commons.data.DBOpenHelper] (field is private there). */
const val LEGACY_COMMONS_DATABASE_NAME: String = "commons.db"
}
115 changes: 3 additions & 112 deletions app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ import android.app.Activity
import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.view.inputmethod.InputMethodManager
import androidx.collection.LruCache
import androidx.room.Room.databaseBuilder
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.google.gson.Gson
import dagger.Module
import dagger.Provides
Expand All @@ -24,6 +21,7 @@ import fr.free.nrw.commons.customselector.database.UploadedStatusDao
import fr.free.nrw.commons.customselector.ui.selector.ImageFileLoader
import fr.free.nrw.commons.data.DBOpenHelper
import fr.free.nrw.commons.db.AppDatabase
import fr.free.nrw.commons.db.AppDatabaseMigrations
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.location.LocationServiceManager
import fr.free.nrw.commons.nearby.PlaceDao
Expand Down Expand Up @@ -200,8 +198,8 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
AppDatabase::class.java,
"commons_room.db"
).addMigrations(
MIGRATION_1_2,
MIGRATION_19_TO_20
AppDatabaseMigrations.MIGRATION_1_2,
AppDatabaseMigrations.migrationBookmarksFromLegacyCommonsDb(applicationContext),
).fallbackToDestructiveMigration().build()

@Provides
Expand Down Expand Up @@ -248,112 +246,5 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
companion object {
const val IO_THREAD: String = "io_thread"
const val MAIN_THREAD: String = "main_thread"

lateinit var appContext: Context
private set

val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"ALTER TABLE contribution " + " ADD COLUMN hasInvalidLocation INTEGER NOT NULL DEFAULT 0"
)
}
}

private val MIGRATION_19_TO_20 = object : Migration(19, 20) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS bookmarks_locations (
location_name TEXT NOT NULL PRIMARY KEY,
location_language TEXT NOT NULL,
location_description TEXT NOT NULL,
location_lat REAL NOT NULL,
location_long REAL NOT NULL,
location_category TEXT NOT NULL,
location_label_text TEXT NOT NULL,
location_label_icon INTEGER,
location_image_url TEXT NOT NULL DEFAULT '',
location_wikipedia_link TEXT NOT NULL,
location_wikidata_link TEXT NOT NULL,
location_commons_link TEXT NOT NULL,
location_pic TEXT NOT NULL,
location_exists INTEGER NOT NULL CHECK(location_exists IN (0, 1))
)
"""
)

val oldDbPath = appContext.getDatabasePath("commons.db").path
val oldDb = SQLiteDatabase
.openDatabase(oldDbPath, null, SQLiteDatabase.OPEN_READONLY)

val cursor = oldDb.rawQuery("SELECT * FROM bookmarksLocations", null)

while (cursor.moveToNext()) {
val locationName =
cursor.getString(cursor.getColumnIndexOrThrow("location_name"))
val locationLanguage =
cursor.getString(cursor.getColumnIndexOrThrow("location_language"))
val locationDescription =
cursor.getString(cursor.getColumnIndexOrThrow("location_description"))
val locationCategory =
cursor.getString(cursor.getColumnIndexOrThrow("location_category"))
val locationLabelText =
cursor.getString(cursor.getColumnIndexOrThrow("location_label_text"))
val locationLabelIcon =
cursor.getInt(cursor.getColumnIndexOrThrow("location_label_icon"))
val locationLat =
cursor.getDouble(cursor.getColumnIndexOrThrow("location_lat"))
val locationLong =
cursor.getDouble(cursor.getColumnIndexOrThrow("location_long"))

// Handle NULL values safely
val locationImageUrl =
cursor.getString(
cursor.getColumnIndexOrThrow("location_image_url")
) ?: ""
val locationWikipediaLink =
cursor.getString(
cursor.getColumnIndexOrThrow("location_wikipedia_link")
) ?: ""
val locationWikidataLink =
cursor.getString(
cursor.getColumnIndexOrThrow("location_wikidata_link")
) ?: ""
val locationCommonsLink =
cursor.getString(
cursor.getColumnIndexOrThrow("location_commons_link")
) ?: ""
val locationPic =
cursor.getString(
cursor.getColumnIndexOrThrow("location_pic")
) ?: ""
val locationExists =
cursor.getInt(
cursor.getColumnIndexOrThrow("location_exists")
)

db.execSQL(
"""
INSERT OR REPLACE INTO bookmarks_locations (
location_name, location_language, location_description, location_category,
location_label_text, location_label_icon, location_lat, location_long,
location_image_url, location_wikipedia_link, location_wikidata_link,
location_commons_link, location_pic, location_exists
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
arrayOf(
locationName, locationLanguage, locationDescription, locationCategory,
locationLabelText, locationLabelIcon, locationLat, locationLong,
locationImageUrl, locationWikipediaLink, locationWikidataLink,
locationCommonsLink, locationPic, locationExists
)
)
}

cursor.close()
oldDb.close()
}
}
}
}
Loading