Implement full text search

This commit is contained in:
Kirill Kamakin
2022-11-13 09:52:52 +01:00
parent 21abf38282
commit 79631a7eb0
12 changed files with 285 additions and 12 deletions

View File

@@ -0,0 +1,201 @@
{
"formatVersion": 1,
"database": {
"version": 7,
"identityHash": "1def22b22cb1f09a27de1b3188b857d2",
"entities": [
{
"tableName": "recipe_summaries",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, `image_id` TEXT, PRIMARY KEY(`remote_id`))",
"fields": [
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "slug",
"columnName": "slug",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dateAdded",
"columnName": "date_added",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dateUpdated",
"columnName": "date_updated",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "imageId",
"columnName": "image_id",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"remote_id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "recipe",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
"fields": [
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "recipeYield",
"columnName": "recipe_yield",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"remote_id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "recipe_ingredient",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `note` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "localId",
"columnName": "local_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "recipeId",
"columnName": "recipe_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "note",
"columnName": "note",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"local_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "recipe_instruction",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `text` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "localId",
"columnName": "local_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "recipeId",
"columnName": "recipe_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "text",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"local_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"ftsVersion": "FTS4",
"ftsOptions": {
"tokenizer": "simple",
"tokenizerArgs": [],
"contentTable": "recipe_summaries",
"languageIdColumnName": "",
"matchInfo": "FTS4",
"notIndexedColumns": [],
"prefixSizes": [],
"preferredOrder": "ASC"
},
"contentSyncTriggers": [
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_recipe_summaries_fts_BEFORE_UPDATE BEFORE UPDATE ON `recipe_summaries` BEGIN DELETE FROM `recipe_summaries_fts` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_recipe_summaries_fts_BEFORE_DELETE BEFORE DELETE ON `recipe_summaries` BEGIN DELETE FROM `recipe_summaries_fts` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_recipe_summaries_fts_AFTER_UPDATE AFTER UPDATE ON `recipe_summaries` BEGIN INSERT INTO `recipe_summaries_fts`(`docid`, `remote_id`, `name`) VALUES (NEW.`rowid`, NEW.`remote_id`, NEW.`name`); END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_recipe_summaries_fts_AFTER_INSERT AFTER INSERT ON `recipe_summaries` BEGIN INSERT INTO `recipe_summaries_fts`(`docid`, `remote_id`, `name`) VALUES (NEW.`rowid`, NEW.`remote_id`, NEW.`name`); END"
],
"tableName": "recipe_summaries_fts",
"createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, content=`recipe_summaries`)",
"fields": [
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [],
"autoGenerate": false
},
"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, '1def22b22cb1f09a27de1b3188b857d2')"
]
}
}

View File

@@ -6,12 +6,13 @@ import gq.kirmanak.mealient.database.recipe.RecipeDao
import gq.kirmanak.mealient.database.recipe.entity.*
@Database(
version = 6,
version = 7,
entities = [
RecipeSummaryEntity::class,
RecipeEntity::class,
RecipeIngredientEntity::class,
RecipeInstructionEntity::class
RecipeInstructionEntity::class,
RecipeSummaryFtsEntity::class,
],
exportSchema = true,
autoMigrations = [
@@ -19,6 +20,7 @@ import gq.kirmanak.mealient.database.recipe.entity.*
AutoMigration(from = 3, to = 4),
AutoMigration(from = 4, to = 5, spec = AppDb.From4To5Migration::class),
AutoMigration(from = 5, to = 6, spec = AppDb.From5To6Migration::class),
AutoMigration(from = 6, to = 7),
]
)
@TypeConverters(RoomTypeConverters::class)

View File

@@ -9,6 +9,9 @@ interface RecipeDao {
@Query("SELECT * FROM recipe_summaries ORDER BY date_added DESC")
fun queryRecipesByPages(): PagingSource<Int, RecipeSummaryEntity>
@Query("SELECT * FROM recipe_summaries JOIN recipe_summaries_fts ON recipe_summaries_fts.remote_id == recipe_summaries.remote_id WHERE recipe_summaries_fts.name MATCH :query ORDER BY date_added DESC")
fun queryRecipesByPages(query: String): PagingSource<Int, RecipeSummaryEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertRecipe(recipeSummaryEntity: RecipeSummaryEntity)

View File

@@ -0,0 +1,13 @@
package gq.kirmanak.mealient.database.recipe.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Fts4
@Entity(tableName = "recipe_summaries_fts")
@Fts4(contentEntity = RecipeSummaryEntity::class)
data class RecipeSummaryFtsEntity(
@ColumnInfo(name = "remote_id") val remoteId: String,
@ColumnInfo(name = "name") val name: String,
)