make filtering functions generic

feature/top10
Laurent 7 years ago
parent 755b821f42
commit e549ab0798
  1. 27
      app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt
  2. 34
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryType.kt
  3. 18
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt

@ -1,6 +1,7 @@
package net.pokeranalytics.android.model.filter package net.pokeranalytics.android.model.filter
import io.realm.RealmObject import io.realm.RealmModel
import net.pokeranalytics.android.model.realm.Session
/** /**
* We want to be able to store filters in the database: * We want to be able to store filters in the database:
@ -28,15 +29,37 @@ import io.realm.RealmObject
* *
*/ */
class UnmanagedFilterField(message: String) : Exception(message) {
}
/** /**
* Companion-level Interface to indicate an RealmObject class can be filtered and to provide all the fieldNames (eg: parameter's path) needed to be query on. * Companion-level Interface to indicate an RealmObject class can be filtered and to provide all the fieldNames (eg: parameter's path) needed to be query on.
*/ */
interface Filterable { interface Filterable : RealmModel {
/** /**
* return the path of the parameter used in the [QueryType] related to this entity * return the path of the parameter used in the [QueryType] related to this entity
*/ */
fun fieldNameForQueryType(queryType: QueryType) : String? fun fieldNameForQueryType(queryType: QueryType) : String?
}
class FilterHelper {
companion object {
inline fun <reified T : Filterable> fieldNameForQueryType(queryType: QueryType) : String? {
when (T::class) {
is Session -> {
Session.fieldNameForQueryType(queryType)
}
}
throw UnmanagedFilterField("Filterable type fields are not defined")
}
}
} }
// //

@ -1,12 +1,10 @@
package net.pokeranalytics.android.model.filter package net.pokeranalytics.android.model.filter
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmQuery import io.realm.RealmQuery
import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.realm.FilterElementBlind
import net.pokeranalytics.android.model.realm.FilterElement import net.pokeranalytics.android.model.realm.FilterElement
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.FilterElementBlind
import java.util.* import java.util.*
@ -16,7 +14,7 @@ import java.util.*
* To handle that, the enum has a public [valueMap] variable * To handle that, the enum has a public [valueMap] variable
* A new type should also set the expected numericValues required in the [filterValuesExpectedKeys] * A new type should also set the expected numericValues required in the [filterValuesExpectedKeys]
*/ */
enum class QueryType(private var subType:SubType? = null) { enum class QueryType(var subType:SubType? = null) {
LIVE, LIVE,
CASH, CASH,
ONLINE, ONLINE,
@ -68,7 +66,7 @@ enum class QueryType(private var subType:SubType? = null) {
; ;
private enum class SubType { enum class SubType {
BETWEEN, BETWEEN,
MORE, MORE,
LESS; LESS;
@ -98,18 +96,19 @@ enum class QueryType(private var subType:SubType? = null) {
* main method of the enum * main method of the enum
* providing a base RealmQuery [realmQuery], the method is able to attached the corresponding query and returns the newly formed [RealmQuery] * providing a base RealmQuery [realmQuery], the method is able to attached the corresponding query and returns the newly formed [RealmQuery]
*/ */
fun filter(realmQuery: RealmQuery<out RealmObject>, filterable: Filterable): RealmQuery<out RealmObject> { inline fun <reified T : Filterable> filter(realmQuery: RealmQuery<T>): RealmQuery<T> {
when { when {
this == BLINDS -> { this == BLINDS -> {
val smallBlindFieldName = filterable.fieldNameForQueryType(SMALL_BLIND)
val bigBlindFieldName = filterable.fieldNameForQueryType(BIG_BLIND) val smallBlindFieldName = FilterHelper.fieldNameForQueryType<T>(queryType = SMALL_BLIND)
val currencyCodeFieldName = filterable.fieldNameForQueryType(CURRENCY_CODE) val bigBlindFieldName = FilterHelper.fieldNameForQueryType<T>(queryType = BIG_BLIND)
val currencyCodeFieldName = FilterHelper.fieldNameForQueryType<T>(CURRENCY_CODE)
smallBlindFieldName ?: throw FilterValueMapException("fieldName is missing") smallBlindFieldName ?: throw FilterValueMapException("fieldName is missing")
bigBlindFieldName ?: throw FilterValueMapException("fieldName is missing") bigBlindFieldName ?: throw FilterValueMapException("fieldName is missing")
currencyCodeFieldName ?: throw FilterValueMapException("fieldName is missing") currencyCodeFieldName ?: throw FilterValueMapException("fieldName is missing")
val blinds: RealmList<FilterElementBlind> by valueMap val blinds: RealmList<FilterElementBlind> by valueMap
blinds.forEachIndexed {index, blind -> blinds.forEachIndexed { index, blind ->
realmQuery realmQuery
.beginGroup() .beginGroup()
@ -137,11 +136,8 @@ enum class QueryType(private var subType:SubType? = null) {
} }
return realmQuery return realmQuery
} }
this == ONLINE -> return LIVE.filter(realmQuery.not(), filterable)
this == TOURNAMENT -> return CASH.filter(realmQuery.not(), filterable)
this == WEEK_DAY -> return WEEK_END.filter(realmQuery.not(), filterable)
else -> { else -> {
val fieldName = filterable.fieldNameForQueryType(this) val fieldName = FilterHelper.fieldNameForQueryType<T>(this)
fieldName ?: throw FilterValueMapException("fieldName is missing") fieldName ?: throw FilterValueMapException("fieldName is missing")
this.subType?.let { subType -> this.subType?.let { subType ->
@ -163,8 +159,8 @@ enum class QueryType(private var subType:SubType? = null) {
} }
return when (this) { return when (this) {
LIVE -> realmQuery.equalTo(fieldName, true) LIVE, ONLINE -> realmQuery.equalTo(fieldName, this == LIVE)
CASH -> realmQuery.equalTo(fieldName, Session.Type.CASH_GAME.ordinal) CASH, TOURNAMENT -> realmQuery.equalTo(fieldName, this.ordinal)
ALL_TOURNAMENT_FEATURES -> { ALL_TOURNAMENT_FEATURES -> {
val ids: Array<String> by valueMap val ids: Array<String> by valueMap
ids.forEach { ids.forEach {
@ -212,8 +208,10 @@ enum class QueryType(private var subType:SubType? = null) {
val year: Int by valueMap val year: Int by valueMap
realmQuery.equalTo(fieldName, year) realmQuery.equalTo(fieldName, year)
} }
WEEK_END -> { WEEK_END, WEEK_DAY -> {
realmQuery.`in`(fieldName, arrayOf(Calendar.SATURDAY, Calendar.SUNDAY)) var query = realmQuery.`in`(fieldName, arrayOf(Calendar.SATURDAY, Calendar.SUNDAY))
if (this == WEEK_DAY) { query.not() }
query
} }
else -> { else -> {
throw FilterValueMapException("filter type not handled") throw FilterValueMapException("filter type not handled")

@ -2,7 +2,7 @@ package net.pokeranalytics.android.model.realm
import io.realm.* import io.realm.*
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.exceptions.FilterMissingEntityException import io.realm.kotlin.where
import net.pokeranalytics.android.exceptions.FilterUnhandledEntityException import net.pokeranalytics.android.exceptions.FilterUnhandledEntityException
import net.pokeranalytics.android.model.filter.Filterable import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryType import net.pokeranalytics.android.model.filter.QueryType
@ -64,11 +64,10 @@ open class Filter(entity:Filterable) : RealmObject() {
companion object { companion object {
@TestOnly @TestOnly
fun queryOn(realm: Realm, entity: Filterable, queries:List<QueryType>): RealmResults<*> { inline fun <reified T : Filterable> queryOn(realm: Realm, queries: List<QueryType>): RealmResults<T> {
val realmEntity : Class < out RealmObject > = FilterableClass.filterableClass(entity).relatedEntity var realmQuery = realm.where<T>()
var realmQuery : RealmQuery<out RealmObject> = realm.where(realmEntity)
queries.forEach { queries.forEach {
realmQuery = (it.filter(realmQuery, entity)) realmQuery = (it.filter<T>(realmQuery))
} }
return realmQuery.findAll() return realmQuery.findAll()
} }
@ -130,16 +129,15 @@ open class Filter(entity:Filterable) : RealmObject() {
return filterElementRow.contains(filtered) return filterElementRow.contains(filtered)
} }
fun results(): RealmResults<*> { inline fun <reified T : Filterable> results(): RealmResults<T> {
val filterableClass : FilterableClass = this.filterableClass ?: throw FilterMissingEntityException("this filter has no entity initialized") var realmQuery : RealmQuery<T> = realm.where<T>()
val realmEntity : Class < out RealmObject > = filterableClass.relatedEntity
var realmQuery : RealmQuery<out RealmObject> = realm.where(realmEntity)
this.filterElements.map { this.filterElements.map {
it.queryType it.queryType
}.forEach { }.forEach {
realmQuery = (it.filter(realmQuery, filterableClass.filterable)) realmQuery = it.filter(realmQuery)
} }
return realmQuery.findAll() return realmQuery.findAll()
} }
} }

Loading…
Cancel
Save