Initial migrate SearchDatabase to ROOM
This commit is contained in:
1 parent
dc48363398
commit
5e14dad961
7 files changed
+158
-167
No files matched your search
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "69230710633494b4b331e10dae436fb7",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "suggestions",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `date` LONG, `query` TEXT, PRIMARY KEY(`_id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "date",
|
||||
"columnName": "date",
|
||||
"affinity": "LONG",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "query",
|
||||
"columnName": "query",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"_id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"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, '69230710633494b4b331e10dae436fb7')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "bf4a5b5f3cb9bc7383488bae14f5d4bd",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "suggestions",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date` INTEGER NOT NULL, `query` TEXT NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "date",
|
||||
"columnName": "date",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "query",
|
||||
"columnName": "query",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"_id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"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, 'bf4a5b5f3cb9bc7383488bae14f5d4bd')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.AutoMigrationSpec
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.hippo.ehviewer.EhApplication
|
||||
|
||||
@DeleteTable(tableName = "BOOKMARKS")
|
||||
class DropBookMarkDao : AutoMigrationSpec
|
||||
@@ -86,3 +87,22 @@ fun buildMainDB(context: Context): EhDatabase {
|
||||
fun buildCookiesDB(context: Context): CookiesDatabase {
|
||||
return Room.databaseBuilder(context, CookiesDatabase::class.java, "okhttp3-cookie.db").build()
|
||||
}
|
||||
|
||||
@Database(
|
||||
entities = [Search::class],
|
||||
version = 2,
|
||||
autoMigrations = [
|
||||
AutoMigration(
|
||||
from = 1,
|
||||
to = 2,
|
||||
),
|
||||
],
|
||||
)
|
||||
abstract class SearchDatabase : RoomDatabase() {
|
||||
abstract fun searchDao(): SearchDao
|
||||
}
|
||||
|
||||
val searchDatabase by lazy {
|
||||
val context = EhApplication.application
|
||||
Room.databaseBuilder(context, SearchDatabase::class.java, "search_database.db").build()
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "suggestions")
|
||||
data class Search(
|
||||
@ColumnInfo(name = "date")
|
||||
val date: Long,
|
||||
@ColumnInfo(name = "query")
|
||||
val query: String,
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "_id")
|
||||
val id: Int? = null,
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hippo.ehviewer.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
|
||||
@Dao
|
||||
interface SearchDao {
|
||||
@Query("DELETE FROM suggestions WHERE query = :query")
|
||||
fun deleteQuery(query: String)
|
||||
|
||||
@Query("SELECT * FROM suggestions")
|
||||
fun rawSuggestions(): Array<Search>
|
||||
|
||||
@Insert
|
||||
fun insert(search: Search)
|
||||
|
||||
fun addQuery(query: String) {
|
||||
deleteQuery(query)
|
||||
val search = Search(System.currentTimeMillis(), query)
|
||||
insert(search)
|
||||
}
|
||||
|
||||
fun suggestions(prefix: String, limit: Int) = rawSuggestions().map { it.query }.toTypedArray()
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.ui.legacy;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.util.SqlUtils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public final class SearchDatabase {
|
||||
|
||||
public static final String COLUMN_QUERY = "query";
|
||||
public static final String COLUMN_DATE = "date";
|
||||
private static final String TAG = SearchDatabase.class.getSimpleName();
|
||||
private static final String DATABASE_NAME = "search_database.db";
|
||||
private static final String TABLE_SUGGESTIONS = "suggestions";
|
||||
|
||||
private static final int MAX_HISTORY = 100;
|
||||
private static SearchDatabase sInstance;
|
||||
private final SQLiteDatabase mDatabase;
|
||||
|
||||
private SearchDatabase(Context context) {
|
||||
DatabaseHelper databaseHelper = new DatabaseHelper(context);
|
||||
mDatabase = databaseHelper.getWritableDatabase();
|
||||
}
|
||||
|
||||
public static SearchDatabase getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SearchDatabase(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public String[] getSuggestions(String prefix, int limit) {
|
||||
List<String> queryList = new LinkedList<>();
|
||||
limit = Math.max(0, limit);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT * FROM ").append(TABLE_SUGGESTIONS);
|
||||
if (!TextUtils.isEmpty(prefix)) {
|
||||
sb.append(" WHERE ").append(COLUMN_QUERY).append(" LIKE '")
|
||||
.append(SqlUtils.sqlEscapeString(prefix)).append("%'");
|
||||
}
|
||||
sb.append(" ORDER BY ").append(COLUMN_DATE).append(" DESC")
|
||||
.append(" LIMIT ").append(limit);
|
||||
|
||||
try {
|
||||
Cursor cursor = mDatabase.rawQuery(sb.toString(), null);
|
||||
int queryIndex = cursor.getColumnIndex(COLUMN_QUERY);
|
||||
if (cursor.moveToFirst()) {
|
||||
while (!cursor.isAfterLast()) {
|
||||
String suggestion = cursor.getString(queryIndex);
|
||||
if (!prefix.equals(suggestion)) {
|
||||
queryList.add(suggestion);
|
||||
}
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
return queryList.toArray(new String[queryList.size()]);
|
||||
} catch (SQLException e) {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void addQuery(final String query) {
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
// Delete old first
|
||||
deleteQuery(query);
|
||||
// Add it to database
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COLUMN_QUERY, query);
|
||||
values.put(COLUMN_DATE, System.currentTimeMillis());
|
||||
mDatabase.insert(TABLE_SUGGESTIONS, null, values);
|
||||
// Remove history if more than max
|
||||
truncateHistory(MAX_HISTORY);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteQuery(final String query) {
|
||||
mDatabase.delete(TABLE_SUGGESTIONS, COLUMN_QUERY + "=?", new String[]{query});
|
||||
}
|
||||
|
||||
public void clearQuery() {
|
||||
truncateHistory(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the length of the history table, to prevent it from growing too large.
|
||||
*
|
||||
* @param maxEntries Max entries to leave in the table. 0 means remove all entries.
|
||||
*/
|
||||
private void truncateHistory(int maxEntries) {
|
||||
if (maxEntries < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
try {
|
||||
// null means "delete all". otherwise "delete but leave n newest"
|
||||
String selection = null;
|
||||
if (maxEntries > 0) {
|
||||
selection = "_id IN " +
|
||||
"(SELECT _id FROM " + TABLE_SUGGESTIONS +
|
||||
" ORDER BY " + COLUMN_DATE + " DESC" +
|
||||
" LIMIT -1 OFFSET " + maxEntries + ")";
|
||||
}
|
||||
mDatabase.delete(TABLE_SUGGESTIONS, selection, null);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "truncateHistory", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the database. This version has extra support for using the version field
|
||||
* as a mode flags field, and configures the database columns depending on the mode bits
|
||||
* (features) requested by the extending class.
|
||||
*/
|
||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE " + TABLE_SUGGESTIONS + " (" +
|
||||
"_id INTEGER PRIMARY KEY" +
|
||||
"," + COLUMN_QUERY + " TEXT" +
|
||||
"," + COLUMN_DATE + " LONG" +
|
||||
");");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_SUGGESTIONS);
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,13 +22,13 @@ import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.hippo.ehviewer.R
|
||||
import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.EhTagDatabase
|
||||
import com.hippo.ehviewer.dao.searchDatabase
|
||||
import com.hippo.ehviewer.databinding.SceneSearchbarBinding
|
||||
import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder
|
||||
import com.hippo.ehviewer.ui.legacy.SearchDatabase
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
abstract class SearchBarScene : BaseScene(), ToolBarScene {
|
||||
private var _binding: SceneSearchbarBinding? = null
|
||||
@@ -37,7 +37,7 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene {
|
||||
private var mSuggestionAdapter: SuggestionAdapter? = null
|
||||
private var mSuggestionProvider: SuggestionProvider? = null
|
||||
private var mAllowEmptySearch = true
|
||||
private val mSearchDatabase by lazy { SearchDatabase.getInstance(context) }
|
||||
private val mSearchDatabase by lazy { searchDatabase.searchDao() }
|
||||
private var onApplySearch: (String) -> Unit = {}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -296,7 +296,7 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun updateSuggestions(scrollToTop: Boolean = true) {
|
||||
_binding ?: return
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.lifecycleScope.launchIO {
|
||||
val suggestions = mutableListOf<Suggestion>()
|
||||
mergedSuggestionFlow().collect {
|
||||
suggestions.add(it)
|
||||
@@ -314,7 +314,7 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene {
|
||||
private fun mergedSuggestionFlow(): Flow<Suggestion> = flow {
|
||||
binding.searchview.editText.text?.toString()?.let { text ->
|
||||
mSuggestionProvider?.run { providerSuggestions(text)?.forEach { emit(it) } }
|
||||
mSearchDatabase.getSuggestions(text, 128).forEach { emit(KeywordSuggestion(it)) }
|
||||
mSearchDatabase.suggestions(text, 128).forEach { emit(KeywordSuggestion(it)) }
|
||||
EhTagDatabase.takeIf { it.isInitialized() }?.run {
|
||||
if (text.isNotEmpty() && !text.endsWith(' ')) {
|
||||
val keyword = text.substringAfterLast(' ')
|
||||
|
||||
Reference in new issue
Block a user