From c99c1be8dd0a058d25de742188b184fceaf651e6 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Thu, 28 Oct 2021 01:12:16 +0200 Subject: [PATCH] Update: Migrate Product.query (4.2/5 in replacing SQLite with Room) --- src/main/kotlin/com/looker/droidify/Common.kt | 25 +++++ .../com/looker/droidify/database/DAOs.kt | 98 +++++++++++++++++++ .../com/looker/droidify/database/Database.kt | 2 +- .../looker/droidify/database/QueryBuilder.kt | 4 +- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/looker/droidify/Common.kt b/src/main/kotlin/com/looker/droidify/Common.kt index d520b4d4..6dca68af 100644 --- a/src/main/kotlin/com/looker/droidify/Common.kt +++ b/src/main/kotlin/com/looker/droidify/Common.kt @@ -8,5 +8,30 @@ const val NOTIFICATION_ID_SYNCING = 1 const val NOTIFICATION_ID_UPDATES = 2 const val NOTIFICATION_ID_DOWNLOADING = 3 +const val ROW_REPOSITORY_ID = "repository_id" +const val ROW_PACKAGE_NAME = "package_name" +const val ROW_NAME = "name" +const val ROW_SUMMARY = "summary" +const val ROW_DESCRIPTION = "description" +const val ROW_ADDED = "added" +const val ROW_UPDATED = "updated" +const val ROW_VERSION_CODE = "version_code" +const val ROW_SIGNATURES = "signatures" +const val ROW_COMPATIBLE = "compatible" +const val ROW_DATA = "data" +const val ROW_DATA_ITEM = "data_item" +const val ROW_VERSION = "version" +const val ROW_SIGNATURE = "signature" +const val ROW_ID = "_id" +const val ROW_ENABLED = "enabled" +const val ROW_DELETED = "deleted" +const val ROW_CAN_UPDATE = "can_update" +const val ROW_MATCH_RANK = "match_rank" +const val ROW_REPOSITORY_NAME = "repository" +const val ROW_PRODUCT_NAME = "product" +const val ROW_CATEGORY_NAME = "category" +const val ROW_INSTALLED_NAME = "memory.installed" +const val ROW_LOCK_NAME = "memory.lock" + const val JOB_ID_SYNC = 1 diff --git a/src/main/kotlin/com/looker/droidify/database/DAOs.kt b/src/main/kotlin/com/looker/droidify/database/DAOs.kt index 5cf589de..e43a48da 100644 --- a/src/main/kotlin/com/looker/droidify/database/DAOs.kt +++ b/src/main/kotlin/com/looker/droidify/database/DAOs.kt @@ -1,6 +1,13 @@ package com.looker.droidify.database +import android.database.Cursor +import android.os.CancellationSignal import androidx.room.* +import androidx.sqlite.db.SimpleSQLiteQuery +import androidx.sqlite.db.SupportSQLiteQuery +import com.looker.droidify.* +import com.looker.droidify.entity.ProductItem + interface BaseDao { @Insert @@ -48,6 +55,97 @@ interface ProductDao : BaseDao { @Query("DELETE FROM product WHERE repository_id = :id") fun deleteById(vararg id: Long): Int + + @RawQuery + fun query( + query: SupportSQLiteQuery + ): Cursor + + // TODO optimize and simplify + @Transaction + fun query( + installed: Boolean, updates: Boolean, searchQuery: String, + section: ProductItem.Section, order: ProductItem.Order, signal: CancellationSignal? + ): Cursor { + val builder = QueryBuilder() + + val signatureMatches = """installed.${ROW_SIGNATURE} IS NOT NULL AND + product.${ROW_SIGNATURES} LIKE ('%.' || installed.${ROW_SIGNATURE} || '.%') AND + product.${ROW_SIGNATURES} != ''""" + + builder += """SELECT product.rowid AS _id, product.${ROW_REPOSITORY_ID}, + product.${ROW_PACKAGE_NAME}, product.${ROW_NAME}, + product.${ROW_SUMMARY}, installed.${ROW_VERSION}, + (COALESCE(lock.${ROW_VERSION_CODE}, -1) NOT IN (0, product.${ROW_VERSION_CODE}) AND + product.${ROW_COMPATIBLE} != 0 AND product.${ROW_VERSION_CODE} > + COALESCE(installed.${ROW_VERSION_CODE}, 0xffffffff) AND $signatureMatches) + AS ${ROW_CAN_UPDATE}, product.${ROW_COMPATIBLE}, + product.${ROW_DATA_ITEM},""" + + if (searchQuery.isNotEmpty()) { + builder += """(((product.${ROW_NAME} LIKE ? OR + product.${ROW_SUMMARY} LIKE ?) * 7) | + ((product.${ROW_PACKAGE_NAME} LIKE ?) * 3) | + (product.${ROW_DESCRIPTION} LIKE ?)) AS ${ROW_MATCH_RANK},""" + builder %= List(4) { "%$searchQuery%" } + } else { + builder += "0 AS ${ROW_MATCH_RANK}," + } + + builder += """MAX((product.${ROW_COMPATIBLE} AND + (installed.${ROW_SIGNATURE} IS NULL OR $signatureMatches)) || + PRINTF('%016X', product.${ROW_VERSION_CODE})) FROM $ROW_PRODUCT_NAME AS product""" + builder += """JOIN $ROW_REPOSITORY_NAME AS repository + ON product.${ROW_REPOSITORY_ID} = repository.${ROW_ID}""" + builder += """LEFT JOIN $ROW_LOCK_NAME AS lock + ON product.${ROW_PACKAGE_NAME} = lock.${ROW_PACKAGE_NAME}""" + + if (!installed && !updates) { + builder += "LEFT" + } + builder += """JOIN $ROW_INSTALLED_NAME AS installed + ON product.${ROW_PACKAGE_NAME} = installed.${ROW_PACKAGE_NAME}""" + + if (section is ProductItem.Section.Category) { + builder += """JOIN $ROW_CATEGORY_NAME AS category + ON product.${ROW_PACKAGE_NAME} = category.${ROW_PACKAGE_NAME}""" + } + + builder += """WHERE repository.${ROW_ENABLED} != 0 AND + repository.${ROW_DELETED} == 0""" + + if (section is ProductItem.Section.Category) { + builder += "AND category.${ROW_NAME} = ?" + builder %= section.name + } else if (section is ProductItem.Section.Repository) { + builder += "AND product.${ROW_REPOSITORY_ID} = ?" + builder %= section.id.toString() + } + + if (searchQuery.isNotEmpty()) { + builder += """AND $ROW_MATCH_RANK > 0""" + } + + builder += "GROUP BY product.${ROW_PACKAGE_NAME} HAVING 1" + + if (updates) { + builder += "AND $ROW_CAN_UPDATE" + } + builder += "ORDER BY" + + if (searchQuery.isNotEmpty()) { + builder += """$ROW_MATCH_RANK DESC,""" + } + + when (order) { + ProductItem.Order.NAME -> Unit + ProductItem.Order.DATE_ADDED -> builder += "product.${ROW_ADDED} DESC," + ProductItem.Order.LAST_UPDATE -> builder += "product.${ROW_UPDATED} DESC," + }::class + builder += "product.${ROW_NAME} COLLATE LOCALIZED ASC" + + return query(SimpleSQLiteQuery(builder.build())) + } } @Dao diff --git a/src/main/kotlin/com/looker/droidify/database/Database.kt b/src/main/kotlin/com/looker/droidify/database/Database.kt index b514bfea..e266832c 100644 --- a/src/main/kotlin/com/looker/droidify/database/Database.kt +++ b/src/main/kotlin/com/looker/droidify/database/Database.kt @@ -515,7 +515,7 @@ object Database { .use { it.firstOrNull()?.getInt(0) ?: 0 } } - // TODO Too complex left to wiring phase + // Done fun query( installed: Boolean, updates: Boolean, searchQuery: String, section: ProductItem.Section, order: ProductItem.Order, signal: CancellationSignal? diff --git a/src/main/kotlin/com/looker/droidify/database/QueryBuilder.kt b/src/main/kotlin/com/looker/droidify/database/QueryBuilder.kt index c81618dd..86d3bcb1 100644 --- a/src/main/kotlin/com/looker/droidify/database/QueryBuilder.kt +++ b/src/main/kotlin/com/looker/droidify/database/QueryBuilder.kt @@ -33,6 +33,8 @@ class QueryBuilder { this.arguments += arguments } + fun build() = builder.toString() + fun query(db: SQLiteDatabase, signal: CancellationSignal?): Cursor { val query = builder.toString() val arguments = arguments.toTypedArray() @@ -47,4 +49,4 @@ class QueryBuilder { } return db.rawQuery(query, arguments, signal) } -} +} \ No newline at end of file