Skip to content

Instantly share code, notes, and snippets.

@rcketscientist
Created September 4, 2018 00:39
Show Gist options
  • Save rcketscientist/4e619aa75fd43ec9453af58f7c1add9a to your computer and use it in GitHub Desktop.
Save rcketscientist/4e619aa75fd43ec9453af58f7c1add9a to your computer and use it in GitHub Desktop.
import androidx.lifecycle.LiveData
import androidx.paging.DataSource
import androidx.room.*
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.sqlite.db.SupportSQLiteQuery
import com.anthonymandra.content.Meta
import com.anthonymandra.rawdroid.XmpFilter
import com.anthonymandra.util.DbUtil
import java.util.*
@Dao
abstract class MetadataDao {
@get:Query("SELECT uri, id FROM meta")
abstract val uriId: LiveData<List<UriIdResult>>
@get:Query("SELECT * FROM meta")
abstract val allImages: LiveData<List<MetadataEntity>>
val allMetadata: LiveData<List<MetadataTest>> = getImages()
@Query("SELECT COUNT(*) FROM meta")
abstract fun count(): Int
@RawQuery(observedEntities = [ MetadataEntity::class, SubjectJunction::class ])
internal abstract fun internalGetImages(query: SupportSQLiteQuery): LiveData<List<MetadataTest>>
@RawQuery(observedEntities = [ MetadataEntity::class, SubjectJunction::class ])
internal abstract fun internalGetImageFactory(query: SupportSQLiteQuery): DataSource.Factory<Int, MetadataTest>
@Transaction
@Query("SELECT * FROM meta WHERE id IN (:ids)")
internal abstract fun getImagesById(ids: List<Long>): DataSource.Factory<Int, MetadataTest>
@Transaction
@Query("SELECT * FROM meta WHERE uri = :uri")
abstract operator fun get(uri: String): LiveData<MetadataTest>
@Transaction
@Query("SELECT * FROM meta WHERE uri IN (:uris)")
abstract fun blocking(uris: List<String>): List<MetadataTest>
@Transaction
@Query("SELECT * FROM meta WHERE uri = :uri")
abstract fun blocking(uri: String): MetadataTest
@Transaction
@Query("SELECT * FROM meta WHERE uri IN (:uris)")
abstract fun stream(uris: List<String>): LiveData<List<MetadataTest>>
@Transaction
@Query("SELECT * FROM meta WHERE processed = 0") // 0 = true
abstract fun unprocessedImages() : List<MetadataTest> // TODO: maybe page this?
@Insert(onConflict = OnConflictStrategy.REPLACE)
internal abstract fun insert(datum: MetadataEntity): Long
@Insert(onConflict = OnConflictStrategy.REPLACE)
internal abstract fun insert(vararg datums: MetadataEntity): List<Long>
@Update
abstract fun update(vararg datums: MetadataEntity)
@Delete
abstract fun delete(vararg datums: MetadataEntity)
@Query("DELETE FROM meta WHERE id = :id")
abstract fun delete(id: Long)
@Query("DELETE FROM meta WHERE id IN (:ids)")
abstract fun delete(ids: List<Long>)
@Query("DELETE FROM meta")
abstract fun deleteAll()
// TODO: We could potentially use a static source in viewer to maintain order and update the
// appropriate meta tables when edited.
// fun getImageFactory(filter: XmpFilter) : PositionalDataSource<MetadataTest> {
// return internalGetImageFactory(this.createFilterQuery(filter)).create()
// }
fun getImageFactory(filter: XmpFilter) : DataSource.Factory<Int, MetadataTest> {
return internalGetImageFactory(this.createFilterQuery(filter))
}
fun getImageFactory() : DataSource.Factory<Int, MetadataTest> {
return getImageFactory(XmpFilter())
}
fun getImages(filter: XmpFilter) : LiveData<List<MetadataTest>> {
return internalGetImages(this.createFilterQuery(filter))
}
/**
* get with default filter will return all with default sorting
*/
private fun getImages() : LiveData<List<MetadataTest>> {
return getImages(XmpFilter())
}
private fun createFilterQuery(filter: XmpFilter): SupportSQLiteQuery {
val query = StringBuilder()
val selection = StringBuilder()
val order = StringBuilder()
val selectionArgs = ArrayList<Any>()
val and = " AND "
val or = " OR "
val joiner = if (filter.andTrueOrFalse) and else or
if (filter.xmp != null) {
// Special case, append to join query
if (filter.xmp.subject.isNotEmpty()) {
if (!selection.isEmpty())
selection.append(joiner)
selection.append(DbUtil.createIN("subjectId", filter.xmp.subject.size))
filter.xmp.subject.mapTo(selectionArgs) { it.id }
}
if (filter.xmp.label.isNotEmpty()) {
if (!selection.isEmpty())
selection.append(joiner)
selection.append(DbUtil.createIN(Meta.LABEL, filter.xmp.label.size))
selectionArgs.addAll(filter.xmp.label)
}
if (filter.xmp.rating.isNotEmpty()) {
if (!selection.isEmpty())
selection.append(joiner)
selection.append(DbUtil.createIN(Meta.RATING, filter.xmp.rating.size))
filter.xmp.rating.mapTo(selectionArgs) { java.lang.Double.toString(it.toDouble()) }
}
}
if (filter.hiddenFolders.isNotEmpty()) {
if (selection.isNotEmpty())
selection.append(and) // Always exclude the folders, don't OR
selection.append(DbUtil.createIN("parentId", filter.hiddenFolders, true))
}
order.append(" ORDER BY ")
val direction = if (filter.sortAscending) " ASC" else " DESC"
if (filter.segregateByType) {
order.append(Meta.TYPE).append(" COLLATE NOCASE").append(" ASC, ")
}
when (filter.sortColumn) {
XmpFilter.SortColumns.Date -> order.append(Meta.TIMESTAMP).append(direction)
XmpFilter.SortColumns.Name -> order.append(Meta.NAME).append(" COLLATE NOCASE").append(direction)
}
query.append(relationQuery)
if (selection.isNotEmpty()) {
query.append(" WHERE ")
query.append(selection)
}
query.append(groupBy)
query.append(order)
return SimpleSQLiteQuery(query.toString(), selectionArgs.toArray())
}
companion object {
/**
* If using a relation for subject this is a far simpler solution.
* Requires [groupBy]
*/
private const val relationQuery =
"SELECT *" +
" FROM meta" +
" LEFT JOIN meta_subject_junction ON meta_subject_junction.metaId = meta.id"
private const val groupBy = " GROUP BY meta.id"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment