filter cleanup

feature/top10
Razmig Sarkissian 7 years ago
parent c41b937933
commit ea728a1cf2
  1. 63
      app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt
  2. 59
      app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt
  3. 32
      app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt
  4. 8
      app/src/androidTest/java/net/pokeranalytics/android/filter/RealmFilterInstrumentedUnitTest.kt
  5. 134
      app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt
  6. 4
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  7. 2
      app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt
  8. 4
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  9. 4
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  10. 16
      app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt
  11. 106
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryType.kt
  12. 8
      app/src/main/java/net/pokeranalytics/android/model/interfaces/TimeFilterable.kt
  13. 35
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  14. 81
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterComponent.kt
  15. 144
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterElement.kt
  16. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterElementBlind.kt
  17. 16
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/ui/adapter/RowRepresentableDataSource.kt
  19. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt
  20. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt
  21. 110
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt
  22. 7
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt

@ -1,9 +1,9 @@
package net.pokeranalytics.android.filter package net.pokeranalytics.android.filter
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import java.util.* import java.util.*
@ -37,12 +37,11 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.BLINDS val filter = QueryType.BLINDS
filter.valueMap = mapOf("blinds" to arrayOf(mapOf( val blind = FilterElementRow.Blind(0.5, 1.0, null)
"sb" to 0.5, blind.filterSectionRow = FilterSectionRow.BLINDS
"bb" to 1.0, val filterElement = FilterElement(filterElementRows = arrayListOf(blind))
"code" to null filter.updateValueMap(filterElement)
)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -84,12 +83,12 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.BLINDS val filter = QueryType.BLINDS
filter.valueMap = mapOf("blinds" to arrayOf(mapOf( val blind = FilterElementRow.Blind(null, 1.0, null)
"sb" to null, blind.filterSectionRow = FilterSectionRow.BLINDS
"bb" to 1.0,
"code" to null val filterElement = FilterElement(filterElementRows = arrayListOf(blind))
))) filter.updateValueMap(filterElement)
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -131,12 +130,12 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.BLINDS val filter = QueryType.BLINDS
filter.valueMap = mapOf("blinds" to arrayOf(mapOf( val blind = FilterElementRow.Blind(1.0, 2.0, "AUD")
"sb" to 1.0, blind.filterSectionRow = FilterSectionRow.BLINDS
"bb" to 2.0,
"code" to "AUD" val filterElement = FilterElement(filterElementRows = arrayListOf(blind))
))) filter.updateValueMap(filterElement)
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -178,18 +177,14 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.BLINDS val filter = QueryType.BLINDS
filter.valueMap = mapOf("blinds" to arrayOf( val blind1 = FilterElementRow.Blind(1.0, 2.0, null)
mapOf( blind1.filterSectionRow = FilterSectionRow.BLINDS
"sb" to 1.0,
"bb" to 2.0, val blind2 = FilterElementRow.Blind(0.5, 1.0, null)
"code" to null blind2.filterSectionRow = FilterSectionRow.BLINDS
), val filterElement = FilterElement(filterElementRows = arrayListOf(blind1, blind2))
mapOf( filter.updateValueMap(filterElement)
"sb" to 0.5,
"bb" to 1.0,
"code" to null
)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,

@ -1,9 +1,13 @@
package net.pokeranalytics.android.filter package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import net.pokeranalytics.android.model.filter.FilterType import io.realm.RealmList
import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.FilterElement
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -25,9 +29,13 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(100.0, true, cal.time) Session.testInstance(100.0, true, cal.time)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.DAY_OF_WEEK val filter = QueryType.DAY_OF_WEEK
cal.time = s1.startDate cal.time = s1.startDate
filter.valueMap = mapOf("dayOfWeek" to cal.get(Calendar.DAY_OF_WEEK))
val filterElementRow = FilterElementRow.Day(cal.get(Calendar.DAY_OF_WEEK))
filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE
val filterElement = FilterElement(filterElementRow)
filter.updateValueMap(filterElement)
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -54,9 +62,13 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(100.0, true, cal.time) Session.testInstance(100.0, true, cal.time)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.MONTH val filter = QueryType.MONTH
cal.time = s1.startDate cal.time = s1.startDate
filter.valueMap = mapOf("month" to cal.get(Calendar.MONTH))
val filterElementRow = FilterElementRow.Month(cal.get(Calendar.MONTH))
filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE
val filterElement = FilterElement(filterElementRow)
filter.updateValueMap(filterElement)
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -83,9 +95,12 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(100.0, true, cal.time) Session.testInstance(100.0, true, cal.time)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.YEAR val filter = QueryType.YEAR
cal.time = s1.startDate cal.time = s1.startDate
filter.valueMap = mapOf("year" to cal.get(Calendar.YEAR)) val filterElementRow = FilterElementRow.Year(cal.get(Calendar.YEAR))
filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE
val filterElement = FilterElement(filterElementRow)
filter.updateValueMap(filterElement)
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -116,7 +131,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(FilterType.WEEK_END) arrayListOf(QueryType.WEEK_END)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
@ -141,7 +156,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(FilterType.WEEK_DAY) arrayListOf(QueryType.WEEK_DAY)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
@ -165,8 +180,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val s2 = Session.testInstance(100.0, true, cal.time, 1) val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.STARTED_FROM_DATE val filter = QueryType.STARTED_FROM_DATE
filter.valueMap = mapOf("date" to s2.startDate) val filterElementRow = FilterElementRow.From(s2.startDate!!)
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterElement(filterElementRow))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -195,8 +213,10 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.STARTED_TO_DATE val filter = QueryType.STARTED_TO_DATE
filter.valueMap = mapOf("date" to s1.startDate) val filterElementRow = FilterElementRow.From(s1.startDate!!)
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterElement(filterElementRow))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -226,8 +246,10 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.ENDED_FROM_DATE val filter = QueryType.ENDED_FROM_DATE
filter.valueMap = mapOf("date" to s2.endDate) val filterElementRow = FilterElementRow.From(s2.endDate())
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterElement(filterElementRow))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -257,8 +279,11 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.ENDED_TO_DATE val filter = QueryType.ENDED_TO_DATE
filter.valueMap = mapOf("date" to s1.endDate) val filterElementRow = FilterElementRow.From(s1.endDate())
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterElement(filterElementRow))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,

@ -1,10 +1,14 @@
package net.pokeranalytics.android.filter package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.RealmList
import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.FilterElement
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import java.util.* import java.util.*
@ -14,8 +18,9 @@ class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() {
@Test(expected = FilterValueMapException::class) @Test(expected = FilterValueMapException::class)
fun testValueKeyFilterException() { fun testValueKeyFilterException() {
val filter = FilterType.STARTED_FROM_DATE val filter = QueryType.STARTED_FROM_DATE
filter.valueMap = mapOf("bob" to Date()) val filterElement = FilterElement()
filter.updateValueMap(filterElement)
val realm = this.mockRealm val realm = this.mockRealm
Filter.queryOn( Filter.queryOn(
@ -26,29 +31,14 @@ class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() {
} }
@Test(expected = FilterValueMapException::class) @Test(expected = FilterValueMapException::class)
fun testSubValueKeyFilterException() { fun testFilterException() {
val filter = FilterType.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"bob" to 0.5,
"bb" to 1.0,
"code" to null
)))
val realm = this.mockRealm val realm = this.mockRealm
val filter = QueryType.BLINDS
filter.updateValueMap(FilterElement())
Filter.queryOn( Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(filter) arrayListOf(filter)
) )
} }
@Test(expected = FilterValueMapException::class)
fun testXFilterException() {
val realm = this.mockRealm
Filter.queryOn(
realm,
Session,
arrayListOf(FilterType.BLINDS)
)
}
} }

@ -1,7 +1,7 @@
package net.pokeranalytics.android.filter package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
@ -25,7 +25,7 @@ class RealmFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filterElement = FilterElementRow.Cash val filterElement = FilterElementRow.Cash
filterElement.filterSectionRow = FilterSectionRow.CASH_TOURNAMENT filterElement.filterSectionRow = FilterSectionRow.CASH_TOURNAMENT
filter.componentsFrom(arrayListOf(filterElement)) filter.createOrUpdateFilterElements(arrayListOf(filterElement))
val useCount = filter.countBy(FilterCategoryRow.GENERAL) val useCount = filter.countBy(FilterCategoryRow.GENERAL)
Assert.assertEquals(1, useCount) Assert.assertEquals(1, useCount)
@ -33,10 +33,10 @@ class RealmFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val isCash = filter.contains(filterElement) val isCash = filter.contains(filterElement)
Assert.assertEquals(true, isCash) Assert.assertEquals(true, isCash)
val filterComponent = filter.components.first() val filterComponent = filter.filterElements.first()
filterComponent?.let { filterComponent?.let {
Assert.assertEquals(FilterType.CASH, FilterType.valueOf(it.filterName)) Assert.assertEquals(QueryType.CASH, QueryType.valueOf(it.filterName))
} ?: run { } ?: run {
Assert.fail() Assert.fail()
} }

@ -2,8 +2,11 @@ package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.RealmList import io.realm.RealmList
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -25,7 +28,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(FilterType.CASH) arrayListOf(QueryType.CASH)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
@ -47,7 +50,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(FilterType.TOURNAMENT) arrayListOf(QueryType.TOURNAMENT)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
@ -74,7 +77,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(FilterType.LIVE) arrayListOf(QueryType.LIVE)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
@ -100,7 +103,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
Session, Session,
arrayListOf(FilterType.ONLINE) arrayListOf(QueryType.ONLINE)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
@ -121,8 +124,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(bankroll = b2) Session.testInstance(bankroll = b2)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.BANKROLL val filter = QueryType.BANKROLL
filter.valueMap = mapOf("ids" to arrayOf(b1.id)) val filterElementRow = FilterElementRow.Bankroll(b1)
filterElementRow.filterSectionRow = FilterSectionRow.BANKROLL
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -154,8 +159,13 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(bankroll = b3) Session.testInstance(bankroll = b3)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.BANKROLL val filter = QueryType.BANKROLL
filter.valueMap = mapOf("ids" to arrayOf(b1.id, b2.id)) val filterElementRow = FilterElementRow.Bankroll(b1)
filterElementRow.filterSectionRow = FilterSectionRow.BANKROLL
val filterElementRow2 = FilterElementRow.Bankroll(b2)
filterElementRow2.filterSectionRow = FilterSectionRow.BANKROLL
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -182,8 +192,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(game = g2) Session.testInstance(game = g2)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.GAME val filter = QueryType.GAME
filter.valueMap = mapOf("ids" to arrayOf(g2.id)) val filterElementRow = FilterElementRow.Game(g2)
filterElementRow.filterSectionRow = FilterSectionRow.GAME
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -215,8 +227,13 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(game = g3) Session.testInstance(game = g3)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.GAME val filter = QueryType.GAME
filter.valueMap = mapOf("ids" to arrayOf(g2.id, g3.id))
val filterElementRow = FilterElementRow.Game(g2)
filterElementRow.filterSectionRow = FilterSectionRow.GAME
val filterElementRow2 = FilterElementRow.Game(g3)
filterElementRow2.filterSectionRow = FilterSectionRow.GAME
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -243,8 +260,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(location = l2) Session.testInstance(location = l2)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.LOCATION val filter = QueryType.LOCATION
filter.valueMap = mapOf("ids" to arrayOf(l1.id)) val filterElementRow = FilterElementRow.Location(l1)
filterElementRow.filterSectionRow = FilterSectionRow.LOCATION
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -276,8 +295,14 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(location = l3) Session.testInstance(location = l3)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.LOCATION val filter = QueryType.LOCATION
filter.valueMap = mapOf("ids" to arrayOf(l1.id, l3.id))
val filterElementRow = FilterElementRow.Location(l1)
filterElementRow.filterSectionRow = FilterSectionRow.LOCATION
val filterElementRow2 = FilterElementRow.Location(l3)
filterElementRow2.filterSectionRow = FilterSectionRow.LOCATION
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -304,8 +329,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(tournamentName = t2) Session.testInstance(tournamentName = t2)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.TOURNAMENT_NAME val filter = QueryType.TOURNAMENT_NAME
filter.valueMap = mapOf("ids" to arrayOf(t1.id))
val filterElementRow = FilterElementRow.TournamentName(t1)
filterElementRow.filterSectionRow = FilterSectionRow.TOURNAMENT_NAME
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -337,8 +365,12 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(tournamentName = t3) Session.testInstance(tournamentName = t3)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.TOURNAMENT_NAME val filter = QueryType.TOURNAMENT_NAME
filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id)) val filterElementRow = FilterElementRow.TournamentName(t1)
filterElementRow.filterSectionRow = FilterSectionRow.TOURNAMENT_NAME
val filterElementRow2 = FilterElementRow.TournamentName(t2)
filterElementRow.filterSectionRow = FilterSectionRow.TOURNAMENT_NAME
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -373,8 +405,14 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(tournamentFeatures = RealmList(t1)) Session.testInstance(tournamentFeatures = RealmList(t1))
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.ALL_TOURNAMENT_FEATURES val filter = QueryType.ALL_TOURNAMENT_FEATURES
filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id)) val filterElementRow = FilterElementRow.AllTournamentFeature(t1)
filterElementRow.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
val filterElementRow2 = FilterElementRow.AllTournamentFeature(t2)
filterElementRow2.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
val filterElementRow3 = FilterElementRow.AllTournamentFeature(t4)
filterElementRow3.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2, filterElementRow3)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -406,8 +444,16 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(tournamentFeatures = RealmList(t1)) Session.testInstance(tournamentFeatures = RealmList(t1))
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.ANY_TOURNAMENT_FEATURES val filter = QueryType.ANY_TOURNAMENT_FEATURES
filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id)) val filterElementRow = FilterElementRow.AnyTournamentFeature(t1)
filterElementRow.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
val filterElementRow2 = FilterElementRow.AnyTournamentFeature(t2)
filterElementRow2.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
val filterElementRow3 = FilterElementRow.AnyTournamentFeature(t3)
filterElementRow3.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
val filterElementRow4 = FilterElementRow.AnyTournamentFeature(t4)
filterElementRow4.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2, filterElementRow3, filterElementRow4)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -436,8 +482,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(tournamentFeatures = RealmList(t1)) Session.testInstance(tournamentFeatures = RealmList(t1))
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.ANY_TOURNAMENT_FEATURES val filter = QueryType.ANY_TOURNAMENT_FEATURES
filter.valueMap = mapOf("ids" to arrayOf(t2.id)) val filterElementRow = FilterElementRow.AnyTournamentFeature(t2)
filterElementRow.filterSectionRow = FilterSectionRow.TOURNAMENT_FEATURE
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -463,8 +511,12 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(tableSize = 10) Session.testInstance(tableSize = 10)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.TABLE_SIZE val filter = QueryType.TABLE_SIZE
filter.valueMap = mapOf("values" to arrayOf(2,4)) val filterElementRow = FilterElementRow.TableSize(TableSize(2))
filterElementRow.filterSectionRow = FilterSectionRow.TABLE_SIZE
val filterElementRow2 = FilterElementRow.TableSize(TableSize(4))
filterElementRow.filterSectionRow = FilterSectionRow.TABLE_SIZE
filter.updateValueMap(FilterElement(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -490,8 +542,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val s2 = Session.testInstance(netResult = 570.0) val s2 = Session.testInstance(netResult = 570.0)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.MORE_THAN_NET_RESULT val filter = QueryType.MORE_THAN_NET_RESULT
filter.valueMap = mapOf("value" to 204.0) val filterElementRow = FilterElementRow.ResultMoreThan(204.0)
filterElementRow.filterSectionRow = FilterSectionRow.VALUE
filter.updateValueMap(FilterElement(filterElementRow))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -517,8 +571,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(netResult = 570.0) Session.testInstance(netResult = 570.0)
realm.commitTransaction() realm.commitTransaction()
val filter = FilterType.LESS_THAN_NET_RESULT val filter = QueryType.LESS_THAN_NET_RESULT
filter.valueMap = mapOf("value" to 540.0) val filterElementRow = FilterElementRow.ResultLessThan(540.0)
filterElementRow.filterSectionRow = FilterSectionRow.VALUE
filter.updateValueMap(FilterElement(filterElementRow))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,
@ -544,11 +600,15 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Session.testInstance(netResult = 570.0) Session.testInstance(netResult = 570.0)
realm.commitTransaction() realm.commitTransaction()
val filterMore = FilterType.MORE_THAN_NET_RESULT val filterMore = QueryType.MORE_THAN_NET_RESULT
filterMore.valueMap = mapOf("value" to 200.0) val filterElementRow = FilterElementRow.ResultMoreThan(200.0)
filterElementRow.filterSectionRow = FilterSectionRow.VALUE
filterMore.updateValueMap(FilterElement(filterElementRow))
val filterLess = FilterType.LESS_THAN_NET_RESULT val filterLess = QueryType.LESS_THAN_NET_RESULT
filterLess.valueMap = mapOf("value" to 400.0) val filterElementRow2 = FilterElementRow.ResultLessThan(400.0)
filterElementRow2.filterSectionRow = FilterSectionRow.VALUE
filterLess.updateValueMap(FilterElement(filterElementRow2))
val sessions = Filter.queryOn( val sessions = Filter.queryOn(
realm, realm,

@ -28,7 +28,7 @@ class Calculator {
} }
/** /**
* The type of evolution values * The type of evolution numericValues
*/ */
enum class EvolutionValues { enum class EvolutionValues {
NONE, NONE,
@ -82,7 +82,7 @@ class Calculator {
results.computeStatVariations(comparedResults) results.computeStatVariations(comparedResults)
} }
results.finalize(options) // later treatment, such as evolution values sorting results.finalize(options) // later treatment, such as evolution numericValues sorting
computedResults.add(results) computedResults.add(results)
val e = Date() val e = Date()

@ -51,7 +51,7 @@ class ComputedResults(group: ComputableGroup) {
// The computed stats of the sessionGroup // The computed stats of the sessionGroup
private var _computedStats: MutableMap<Stat, ComputedStat> = mutableMapOf() private var _computedStats: MutableMap<Stat, ComputedStat> = mutableMapOf()
// The map containing all evolution values for all stats // The map containing all evolution numericValues for all stats
private var _evolutionValues: MutableMap<Stat, MutableList<Point>> = mutableMapOf() private var _evolutionValues: MutableMap<Stat, MutableList<Point>> = mutableMapOf()
fun allStats() : Collection<ComputedStat> { fun allStats() : Collection<ComputedStat> {

@ -35,7 +35,7 @@ enum class Stat : RowRepresentable {
HANDS_PLAYED; HANDS_PLAYED;
/** /**
* Returns whether the stat evolution values requires a distribution sorting * Returns whether the stat evolution numericValues requires a distribution sorting
*/ */
fun hasDistributionSorting() : Boolean { fun hasDistributionSorting() : Boolean {
return when (this) { return when (this) {
@ -129,7 +129,7 @@ class ComputedStat(var stat: Stat, var value: Double, var currency: Currency? =
val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red
return TextFormat(numberFormat.format(this.value), color) return TextFormat(numberFormat.format(this.value), color)
} }
// Red/green values // Red/green numericValues
Stat.HOURLY_RATE_BB, Stat.AVERAGE_NET_BB, Stat.NET_BB_PER_100_HANDS -> { Stat.HOURLY_RATE_BB, Stat.AVERAGE_NET_BB, Stat.NET_BB_PER_100_HANDS -> {
val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red
return TextFormat(this.value.formatted(), color) return TextFormat(this.value.formatted(), color)

@ -13,5 +13,7 @@ class RowRepresentableEditDescriptorException(message: String) : Exception(messa
} }
class FilterValueMapException(message: String) : Exception(message) { class FilterValueMapException(message: String) : Exception(message) {
init {
println("FilterValueMapException(): $message")
}
} }

@ -21,21 +21,29 @@ import io.realm.RealmObject
* - multiple field filters should be handled as 'AND' * - multiple field filters should be handled as 'AND'
* - multiple '=' filters as 'OR' * - multiple '=' filters as 'OR'
* - multiple 'Greater than', 'less than' as 'AND' * - multiple 'Greater than', 'less than' as 'AND'
* - multiple values as 'OR' * - multiple numericValues as 'OR'
* *
* Also: * Also:
* A filter should be able to be converted into a Realm query * A filter should be able to be converted into a Realm query
* *
*/ */
interface FilterEntityDataSource {
/**
* Interface to set at companion object level of a realm object to provide the entity and the fieldName (eg: parameter's path)
*/
interface Filterable {
val relatedEntity: Class<out RealmObject> val relatedEntity: Class<out RealmObject>
fun fieldNameForQueryType(filterType: FilterType) : String?
/**
* return the path of the parameter used in the [QueryType] related to this entity
*/
fun fieldNameForQueryType(queryType: QueryType) : String?
} }
// //
//fun MutableList<Filterable>.filter(filter: FilterComponent) : List<Filterable> { //fun MutableList<Filterable>.filter(filter: FilterElement) : List<Filterable> {
// //
// return this.filter { f -> // return this.filter { f ->
// return@filter true // return@filter true

@ -1,39 +1,22 @@
package net.pokeranalytics.android.model.filter package net.pokeranalytics.android.model.filter
import io.realm.RealmList
import io.realm.RealmObject 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.FilterComponent import net.pokeranalytics.android.model.realm.FilterElementBlind
import net.pokeranalytics.android.model.realm.FilterElement
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import java.util.* import java.util.*
/** /**
* We want to be able to store filters in the database: * Enum describing the way a query should be handled
* - filters can be a combination of sub filters * Some queries requires a value to be checked upon through equals, in, more, less, between
* - filters can be applied to different type of objects: Sessions, Hands, Transactions... * To handle that, the enum has a public [valueMap] variable
* - filters can be applied to a list of different type of objects (feed) * A new type should also set the expected numericValues required in the [filterValuesExpectedKeys]
*
* A filter is described by the following:
* - a data type: Session, Hands...
* - a field: table size of a Session
* - an operator: equal, >=, <...
* - a value: an id, a number, a date...
*
* We can decide to have a collection of [operator, value] for a field
*
* Combination:
* - multiple datatype filters should be handled as 'OR'
* - multiple field filters should be handled as 'AND'
* - multiple '=' filters as 'OR'
* - multiple 'Greater than', 'less than' as 'AND'
* - multiple values as 'OR'
*
* Also:
* A filter should be able to be converted into a Realm query
*
*/ */
enum class QueryType(private var subType:SubType? = null) {
enum class FilterType(private var subType:SubType? = null) {
LIVE, LIVE,
CASH, CASH,
ONLINE, ONLINE,
@ -100,7 +83,7 @@ enum class FilterType(private var subType:SubType? = null) {
} }
} }
return when (this) { return when (this) {
BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids") BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES, TOURNAMENT_NAME -> arrayOf("ids")
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> arrayOf("values") LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> arrayOf("values")
BLINDS -> arrayOf("blinds") BLINDS -> arrayOf("blinds")
STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date")
@ -111,43 +94,37 @@ enum class FilterType(private var subType:SubType? = null) {
} }
} }
fun filter(realmQuery: RealmQuery<out RealmObject>, filterEntityDataSource: FilterEntityDataSource): RealmQuery<out RealmObject> { /**
* 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]
*/
fun filter(realmQuery: RealmQuery<out RealmObject>, filterable: Filterable): RealmQuery<out RealmObject> {
when { when {
this == BLINDS -> { this == BLINDS -> {
val smallBlindFieldName = filterEntityDataSource.fieldNameForQueryType(SMALL_BLIND) val smallBlindFieldName = filterable.fieldNameForQueryType(SMALL_BLIND)
val bigBlindFieldName = filterEntityDataSource.fieldNameForQueryType(BIG_BLIND) val bigBlindFieldName = filterable.fieldNameForQueryType(BIG_BLIND)
val currencyCodeFieldName = filterEntityDataSource.fieldNameForQueryType(CURRENCY_CODE) val currencyCodeFieldName = filterable.fieldNameForQueryType(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: Array<Map<String, Any?>> by valueMap val blinds: RealmList<FilterElementBlind> by valueMap
val expectedSubKeys = arrayOf("sb", "bb", "code") blinds.forEachIndexed {index, blind ->
blinds.forEachIndexed { index, subMap ->
val missingKeys = subMap.keys.filter { !expectedSubKeys.contains(it) }
if (subMap.keys.size == expectedSubKeys.size && missingKeys.isNotEmpty()) {
throw FilterValueMapException("subValueMap does not contain $missingKeys")
}
val sb: Double? by subMap
val bb: Double? by subMap
val code: String? by subMap
realmQuery realmQuery
.beginGroup() .beginGroup()
sb?.let { blind.sb?.let {
realmQuery realmQuery
.equalTo(smallBlindFieldName, sb) .equalTo(smallBlindFieldName, it)
.and() .and()
} }
realmQuery realmQuery
.equalTo(bigBlindFieldName, bb) .equalTo(bigBlindFieldName, blind.bb)
.and() .and()
code?.let { blind.code?.let {
realmQuery.equalTo(currencyCodeFieldName, code) realmQuery.equalTo(currencyCodeFieldName, it)
} ?: run { } ?: run {
realmQuery.isNull(currencyCodeFieldName) realmQuery.isNull(currencyCodeFieldName)
} }
@ -160,11 +137,11 @@ enum class FilterType(private var subType:SubType? = null) {
} }
return realmQuery return realmQuery
} }
this == ONLINE -> return LIVE.filter(realmQuery.not(), filterEntityDataSource) this == ONLINE -> return LIVE.filter(realmQuery.not(), filterable)
this == TOURNAMENT -> return CASH.filter(realmQuery.not(), filterEntityDataSource) this == TOURNAMENT -> return CASH.filter(realmQuery.not(), filterable)
this == WEEK_DAY -> return WEEK_END.filter(realmQuery.not(), filterEntityDataSource) this == WEEK_DAY -> return WEEK_END.filter(realmQuery.not(), filterable)
else -> { else -> {
val fieldName = filterEntityDataSource.fieldNameForQueryType(this) val fieldName = filterable.fieldNameForQueryType(this)
fieldName ?: throw FilterValueMapException("fieldName is missing") fieldName ?: throw FilterValueMapException("fieldName is missing")
this.subType?.let { subType -> this.subType?.let { subType ->
@ -247,7 +224,7 @@ enum class FilterType(private var subType:SubType? = null) {
} }
fun setValueFrom(filterComponent: FilterComponent) { fun updateValueMap(filterElement: FilterElement) {
if (filterValuesExpectedKeys == null) { if (filterValuesExpectedKeys == null) {
return return
} }
@ -255,38 +232,39 @@ enum class FilterType(private var subType:SubType? = null) {
this.subType?.let { subType -> this.subType?.let { subType ->
valueMap = when (subType) { valueMap = when (subType) {
SubType.LESS, SubType.MORE -> { SubType.LESS, SubType.MORE -> {
mapOf("value" to filterComponent.value) mapOf("value" to filterElement.value)
} }
SubType.BETWEEN -> { SubType.BETWEEN -> {
mapOf( mapOf(
"leftValue" to filterComponent.leftValue, "leftValue" to filterElement.leftValue,
"rightValue" to filterComponent.rightValue "rightValue" to filterElement.rightValue
) )
} }
} }
return
} }
when (this) { when (this) {
ALL_TOURNAMENT_FEATURES, ANY_TOURNAMENT_FEATURES, BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> { ALL_TOURNAMENT_FEATURES, ANY_TOURNAMENT_FEATURES, BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> {
valueMap = mapOf("ids" to filterComponent.ids) valueMap = mapOf("ids" to filterElement.ids)
} }
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> { LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> {
valueMap = mapOf("values" to filterComponent.values) valueMap = mapOf("values" to filterElement.values)
} }
BLINDS -> { BLINDS -> {
valueMap = mapOf("blinds" to filterComponent.blinds) valueMap = mapOf("blinds" to filterElement.blinds)
} }
STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> { STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> {
valueMap = mapOf("date" to filterComponent.date) valueMap = mapOf("date" to filterElement.date)
} }
DAY_OF_WEEK -> { DAY_OF_WEEK -> {
valueMap = mapOf("dayOfWeek" to filterComponent.dayOfWeek) valueMap = mapOf("dayOfWeek" to filterElement.dayOfWeek)
} }
MONTH -> { MONTH -> {
valueMap = mapOf("month" to filterComponent.month) valueMap = mapOf("month" to filterElement.month)
} }
YEAR -> { YEAR -> {
valueMap = mapOf("year" to filterComponent.year) valueMap = mapOf("year" to filterElement.year)
} }
else -> { else -> {
throw FilterValueMapException("filter type not handled") throw FilterValueMapException("filter type not handled")
@ -308,5 +286,7 @@ enum class FilterType(private var subType:SubType? = null) {
} }
return field return field
} }
private set
} }

@ -1,7 +1,10 @@
package net.pokeranalytics.android.model.filter.interfaces package net.pokeranalytics.android.model.interfaces
import java.util.* import java.util.*
/**
* Interface to let an object be filtered through specific time parameters
*/
interface TimeFilterable { interface TimeFilterable {
var dayOfWeek : Int? var dayOfWeek : Int?
@ -9,6 +12,9 @@ interface TimeFilterable {
var month : Int? var month : Int?
var year : Int? var year : Int?
/**
* Call this method whenever the date of the object is modified
*/
fun updateTimeParameter(startDate: Date?) { fun updateTimeParameter(startDate: Date?) {
startDate?.let { startDate?.let {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()

@ -2,17 +2,24 @@ 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.model.filter.FilterEntityDataSource import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.jetbrains.annotations.TestOnly
import java.util.* import java.util.*
/**
* A [Filter] is the top level representation of the filtering system
* It contains a list of [FilterElement] describing the complete query to launch
* The [Filter] is working closely with a [Filterable] interface providing the entity we want the query being launched on
*/
open class Filter : RealmObject() { open class Filter : RealmObject() {
companion object { companion object {
fun queryOn(realm: Realm, entity: FilterEntityDataSource, queries:List<FilterType>): RealmResults<*> { @TestOnly
fun queryOn(realm: Realm, entity: Filterable, queries:List<QueryType>): RealmResults<*> {
var realmQuery : RealmQuery<out RealmObject> = realm.where(entity.relatedEntity) var realmQuery : RealmQuery<out RealmObject> = realm.where(entity.relatedEntity)
queries.forEach { queries.forEach {
realmQuery = (it.filter(realmQuery, entity)) realmQuery = (it.filter(realmQuery, entity))
@ -31,11 +38,11 @@ open class Filter : RealmObject() {
// for MutableRealmInteger, see https://realm.io/docs/java/latest/#counters // for MutableRealmInteger, see https://realm.io/docs/java/latest/#counters
val usageCount: MutableRealmInteger = MutableRealmInteger.valueOf(0) val usageCount: MutableRealmInteger = MutableRealmInteger.valueOf(0)
var components: RealmList<FilterComponent> = RealmList() var filterElements: RealmList<FilterElement> = RealmList()
private set private set
fun componentsFrom(filterElementRows: ArrayList<FilterElementRow>) { fun createOrUpdateFilterElements(filterElementRows: ArrayList<FilterElementRow>) {
components.clear() filterElements.clear()
filterElementRows filterElementRows
.map { .map {
it.filterSectionRow it.filterSectionRow
@ -47,26 +54,28 @@ open class Filter : RealmObject() {
it.filterSectionRow == section it.filterSectionRow == section
} }
.apply { .apply {
if (this.size == 1) { if (this.size == 1) {
components.add(FilterComponent(this.first())) filterElements.add(FilterElement(this.first()))
} else { } else {
val casted = arrayListOf<FilterElementRow>() val casted = arrayListOf<FilterElementRow>()
casted.addAll(this) casted.addAll(this)
components.add(FilterComponent(casted)) filterElements.add(FilterElement(casted))
} }
} }
} }
} }
fun countBy(filterCategoryRow: FilterCategoryRow) : Int { fun countBy(filterCategoryRow: FilterCategoryRow) : Int {
val sections = filterCategoryRow.filterSectionRows val sections = filterCategoryRow.filterSectionRows
return components.count { return filterElements.count {
sections.contains(FilterSectionRow.valueOf(it.sectionName)) sections.contains(FilterSectionRow.valueOf(it.sectionName))
} }
} }
fun contains(filterElementRow:FilterElementRow) : Boolean { fun contains(filterElementRow:FilterElementRow) : Boolean {
val filtered = components.filter { val filtered = filterElements.filter {
it.filterName == filterElementRow.filterName it.filterName == filterElementRow.filterName
} }
if (filtered.isEmpty()) { if (filtered.isEmpty()) {
@ -75,10 +84,10 @@ open class Filter : RealmObject() {
return filterElementRow.contains(filtered) return filterElementRow.contains(filtered)
} }
fun queryOn(entity: FilterEntityDataSource) : RealmResults<*> { fun queryOn(entity: Filterable) : RealmResults<*> {
var realmQuery : RealmQuery<out RealmObject> = realm.where(entity.relatedEntity) var realmQuery : RealmQuery<out RealmObject> = realm.where(entity.relatedEntity)
this.components.map { this.filterElements.map {
it.filterType it.queryType
}.forEach { }.forEach {
realmQuery = (it.filter(realmQuery, entity)) realmQuery = (it.filter(realmQuery, entity))
} }

@ -1,81 +0,0 @@
package net.pokeranalytics.android.model.realm
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.Ignore
import net.pokeranalytics.android.model.filter.FilterType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow.*
import java.util.*
import kotlin.collections.ArrayList
open class FilterComponent(var filterName : String = "", var sectionName: String = "") : RealmObject() {
constructor(filterElementRows: ArrayList<FilterElementRow>) : this(filterElementRows.first().filterName, filterElementRows.first().filterSectionRow.name) {
this.ids = when (FilterType.valueOf(this.filterName)) {
FilterType.GAME -> {
RealmList<String>().apply {
this.addAll(filterElementRows.map {
(it as FilterElementRow.Game).game.id
})
}
}
else -> null
}
this.values = when (FilterType.valueOf(filterName)) {
FilterType.LIMIT -> {
RealmList<Int>().apply {
this.addAll(filterElementRows.map {
(it as FilterElementRow.Limit).limit.ordinal
})
}
}
else -> null
}
}
constructor(filterElementRow:FilterElementRow) : this(filterElementRow.filterName, filterElementRow.filterSectionRow.name) {
when (filterElementRow) {
is From -> date = filterElementRow.date
is To -> date = filterElementRow.date
}
}
val filterType : FilterType
get() = FilterType.valueOf(filterName)
.apply {
this.setValueFrom(this@FilterComponent)
}
var date : Date? = null
var values : RealmList<Int>? = null
var ids : RealmList<String>? = null
@Ignore
val value : Double? = null
@Ignore
val leftValue : Double? = null
@Ignore
val rightValue : Double? = null
@Ignore
val blinds : Array<Map<String,Any?>>? = null
@Ignore
val dayOfWeek : Int? = null
@Ignore
val month : Int? = null
@Ignore
val year : Int? = null
}
open class BlindFilterComponent : RealmObject() {
var sb : Double? = null
var bb : Double? = null
var code : String? = null
}

@ -0,0 +1,144 @@
package net.pokeranalytics.android.model.realm
import io.realm.RealmList
import io.realm.RealmObject
import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow.*
import java.util.*
import kotlin.collections.ArrayList
open class FilterElement(var filterName : String = "", var sectionName: String = "") : RealmObject() {
constructor(filterElementRows: ArrayList<FilterElementRow>) : this(filterElementRows.first().filterName, filterElementRows.first().filterSectionRow.name) {
this.stringValues = when (QueryType.valueOf(this.filterName)) {
QueryType.GAME, QueryType.BANKROLL, QueryType.TOURNAMENT_NAME, QueryType.ALL_TOURNAMENT_FEATURES, QueryType.ANY_TOURNAMENT_FEATURES, QueryType.LOCATION -> {
RealmList<String>().apply {
this.addAll(filterElementRows.map {
(it as DataFilterElementRow).id
})
}
}
else -> null
}
this.numericValues = when (QueryType.valueOf(filterName)) {
QueryType.LIMIT -> {
RealmList<Double>().apply {
this.addAll(filterElementRows.map {
(it as FilterElementRow.Limit).limit.ordinal.toDouble()
})
}
}
QueryType.TABLE_SIZE -> {
RealmList<Double>().apply {
this.addAll(filterElementRows.map {
(it as FilterElementRow.TableSize).tableSize.numberOfPlayer.toDouble()
})
}
}
QueryType.YEAR, QueryType.MONTH, QueryType.DAY_OF_WEEK -> {
RealmList<Double>().apply {
this.addAll(filterElementRows.map {
(it as SingleValueFilterElementRow).value.toDouble()
})
}
}
QueryType.LESS_THAN_NET_RESULT -> {
RealmList<Double>().apply {
this.addAll(filterElementRows.map {
(it as ResultLessThan).value
})
}
}
QueryType.MORE_THAN_NET_RESULT -> {
RealmList<Double>().apply {
this.addAll(filterElementRows.map {
(it as ResultMoreThan).value
})
}
}
else -> null
}
this.blindValues = when (QueryType.valueOf(filterName)) {
QueryType.BLINDS -> {
RealmList<FilterElementBlind>().apply {
this.addAll(filterElementRows.map {
FilterElementBlind((it as FilterElementRow.Blind).sb, it.bb, it.code)
})
}
}
else -> null
}
}
constructor(filterElementRow:FilterElementRow) : this(arrayListOf(filterElementRow)) {
when (filterElementRow) {
is From -> dateValue = filterElementRow.date
is To -> dateValue= filterElementRow.date
}
}
val queryType : QueryType
get() = QueryType.valueOf(filterName)
.apply {
this.updateValueMap(this@FilterElement)
}
private var numericValues: RealmList<Double>? = null
private var dateValue : Date? = null
private var stringValues : RealmList<String>? = null
private var blindValues : RealmList<FilterElementBlind>? = null
val ids : Array<String>
get() = stringValues?.toTypedArray()?: throw FilterValueMapException("filter type not handled")
val blinds : RealmList<FilterElementBlind>
get() {
blindValues?.let {
if (it.isNotEmpty()) {
return it
} else {
throw FilterValueMapException("filter is empty or null")
}
}
throw FilterValueMapException("filter is empty or null")
}
val date : Date
get() = dateValue?: throw FilterValueMapException("filter type not handled")
val values : Array<Int>
get() = numericValues?.map {
it.toInt()
}?.toTypedArray()?: throw FilterValueMapException("filter type not handled")
val value : Double
get() = numericValues?.first()?: throw FilterValueMapException("filter type not handled")
val leftValue : Double
get() = numericValues?.first()?: throw FilterValueMapException("filter type not handled")
val rightValue : Double
get() = numericValues?.last()?: throw FilterValueMapException("filter type not handled")
val dayOfWeek : Int
get() = numericValues?.first()?.toInt()?: throw FilterValueMapException("filter type not handled")
val month : Int
get() = numericValues?.first()?.toInt()?: throw FilterValueMapException("filter type not handled")
val year : Int
get() = numericValues?.first()?.toInt()?: throw FilterValueMapException("filter type not handled")
}

@ -0,0 +1,8 @@
package net.pokeranalytics.android.model.realm
import io.realm.RealmObject
open class FilterElementBlind(var sb : Double? = null,
var bb : Double? = null,
var code : String? = null
) : RealmObject()

@ -20,10 +20,10 @@ import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.filter.FilterEntityDataSource import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.filter.FilterType.* import net.pokeranalytics.android.model.filter.QueryType.*
import net.pokeranalytics.android.model.filter.interfaces.TimeFilterable import net.pokeranalytics.android.model.interfaces.TimeFilterable
import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.interfaces.Timed
import net.pokeranalytics.android.model.utils.SessionSetManager import net.pokeranalytics.android.model.utils.SessionSetManager
@ -43,14 +43,14 @@ import java.util.Currency
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed, open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed,
TimeFilterable { TimeFilterable {
enum class Type { enum class Type {
CASH_GAME, CASH_GAME,
TOURNAMENT TOURNAMENT
} }
companion object : FilterEntityDataSource { companion object : Filterable {
fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null): Session { fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null): Session {
val session = Session() val session = Session()
session.result = Result() session.result = Result()
@ -65,8 +65,8 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
override val relatedEntity: Class<out RealmObject> = Session::class.java override val relatedEntity: Class<out RealmObject> = Session::class.java
override fun fieldNameForQueryType(filterType: FilterType): String? { override fun fieldNameForQueryType(queryType: QueryType): String? {
return when (filterType) { return when (queryType) {
LIVE -> "bankroll.live" LIVE -> "bankroll.live"
CASH -> "type" CASH -> "type"
BANKROLL -> "bankroll.id" BANKROLL -> "bankroll.id"

@ -102,7 +102,7 @@ class UnmanagedRowRepresentableException(message: String) : Exception(message) {
* - string * - string
* - booleans * - booleans
* - actionIcon * - actionIcon
* to display the appropriate values in graphical components, such as labels, textfields, switchs... * to display the appropriate numericValues in graphical filterElements, such as labels, textfields, switchs...
*/ */
interface DisplayableDataSource { interface DisplayableDataSource {

@ -199,7 +199,7 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta
/* /*
this.dataType = dataType this.dataType = dataType
this.liveDataType = LiveData.values()[dataType] this.liveDataType = LiveData.numericValues()[dataType]
this.primaryKey = primaryKey this.primaryKey = primaryKey
*/ */
} }

@ -29,7 +29,7 @@ interface DefaultEditable : Editable, Localizable {
} }
/** /**
* An interface used so that enums values can be represented visually * An interface used so that enums numericValues can be represented visually
* as rows in RecyclerViews * as rows in RecyclerViews
*/ */
interface Displayable : Localizable { interface Displayable : Localizable {

@ -2,8 +2,9 @@ package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.FilterValueMapException import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.filter.FilterType import net.pokeranalytics.android.model.filter.QueryType
import net.pokeranalytics.android.model.realm.FilterComponent import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.realm.FilterElement
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
@ -24,76 +25,78 @@ sealed class FilterElementRow : RowRepresentable {
object Weekday: FilterElementRow() object Weekday: FilterElementRow()
object Weekend : FilterElementRow() object Weekend : FilterElementRow()
open class DataFilterElementRow(data:Manageable) : FilterElementRow() {
val id : String = data.id
val name : String = (data as RowRepresentable).getDisplayName()
}
open class SingleValueFilterElementRow(val value:Int) : FilterElementRow()
data class Blind(var sb: Double? = null, var bb: Double? = null, var code: String? = null) : FilterElementRow()
data class From(var date: Date = Date()) : FilterElementRow() data class From(var date: Date = Date()) : FilterElementRow()
data class To(var date: Date = Date()) : FilterElementRow() data class To(var date: Date = Date()) : FilterElementRow()
data class Year(val day: Int) : FilterElementRow() data class Year(val year: Int) : SingleValueFilterElementRow(year)
data class Month(val day: Int) : FilterElementRow() data class Month(val month: Int) : SingleValueFilterElementRow(month)
data class Day(val day: Int) : FilterElementRow() data class Day(val day: Int) : SingleValueFilterElementRow(day)
data class PastDays(var lastDays : Int = 0) : FilterElementRow() data class PastDays(var lastDays : Int = 0) : FilterElementRow()
data class Limit(val limit : net.pokeranalytics.android.model.Limit) : FilterElementRow() data class Limit(val limit : net.pokeranalytics.android.model.Limit) : FilterElementRow()
data class TableSize(val tableSize : net.pokeranalytics.android.model.TableSize) : FilterElementRow() data class TableSize(val tableSize : net.pokeranalytics.android.model.TableSize) : FilterElementRow()
data class Bankroll(val bankroll: net.pokeranalytics.android.model.realm.Bankroll) : FilterElementRow() data class Bankroll(val bankroll: Manageable) : DataFilterElementRow(bankroll)
data class Game(val game: net.pokeranalytics.android.model.realm.Game) : FilterElementRow() data class Game(val game: Manageable) : DataFilterElementRow(game)
data class Location(val location: net.pokeranalytics.android.model.realm.Location) : FilterElementRow() data class Location(val location: Manageable) : DataFilterElementRow(location)
data class TournamentName(val tournamentName: net.pokeranalytics.android.model.realm.TournamentName) : FilterElementRow() data class TournamentName(val tournamentName: Manageable) : DataFilterElementRow(tournamentName)
data class TournamentFeature(val tournamentFeature: net.pokeranalytics.android.model.realm.TournamentFeature) : FilterElementRow() data class AllTournamentFeature(val tournamentFeature: Manageable) : DataFilterElementRow(tournamentFeature)
data class AnyTournamentFeature(val tournamentFeature: Manageable) : DataFilterElementRow(tournamentFeature)
data class ResultMoreThan(var value:Double) : FilterElementRow()
data class ResultLessThan(var value:Double) : FilterElementRow()
lateinit var filterSectionRow: FilterSectionRow lateinit var filterSectionRow: FilterSectionRow
val filterName : String = this.filterType.name val filterName : String = this.queryType.name
private val filterType : FilterType private val queryType : QueryType
get() { get() {
return when (this) { return when (this) {
is Cash -> FilterType.CASH is Cash -> QueryType.CASH
is Tournament -> FilterType.TOURNAMENT is Tournament -> QueryType.TOURNAMENT
/* is Today -> FilterType. is Blind -> QueryType.BLINDS
is From -> QueryType.STARTED_FROM_DATE
is To -> QueryType.ENDED_TO_DATE
is Month -> QueryType.MONTH
is Day -> QueryType.DAY_OF_WEEK
is Year -> QueryType.YEAR
is Live -> QueryType.LIVE
is Online -> QueryType.ONLINE
is Weekday -> QueryType.WEEK_DAY
is Weekend-> QueryType.WEEK_END
/* is Today -> QueryType.
is Yesterday -> R.string.yesterday is Yesterday -> R.string.yesterday
is TodayAndYesterday -> R.string.yesterday_and_today is TodayAndYesterday -> R.string.yesterday_and_today
is CurrentWeek -> R.string.current_week is CurrentWeek -> R.string.current_week
is CurrentMonth -> R.string.current_month is CurrentMonth -> R.string.current_month
is CurrentYear -> R.string.current_year is CurrentYear -> R.string.current_year
is From -> R.string.from
is To -> R.string.to
is Live -> R.string.live
is Online -> R.string.online
is Weekday -> R.string.week_days
is Weekend-> R.string.weekend
is Year-> R.string.year
is Month-> R.string.month_of_the_year
is Day -> R.string.day_of_the_week
is PastDays -> R.string.period_in_days is PastDays -> R.string.period_in_days
is Limit -> R.string.limit is Limit -> R.string.limit
is TableSize -> R.string.table_size
is Bankroll -> R.string.bankroll
*/
is Game -> FilterType.GAME
/*
is Location -> R.string.location
is TournamentName -> R.string.tournament_name
is TournamentFeature -> R.string.tournament_feature
*/ */
else -> throw FilterValueMapException("no filter type for filter element") //TODO create exception is TableSize -> QueryType.TABLE_SIZE
is Game -> QueryType.GAME
is Bankroll -> QueryType.BANKROLL
is Location -> QueryType.LOCATION
is TournamentName -> QueryType.TOURNAMENT_NAME
is AnyTournamentFeature -> QueryType.ANY_TOURNAMENT_FEATURES
is AllTournamentFeature -> QueryType.ALL_TOURNAMENT_FEATURES
is ResultMoreThan -> QueryType.MORE_THAN_NET_RESULT
is ResultLessThan -> QueryType.LESS_THAN_NET_RESULT
else -> throw FilterValueMapException("no filter type for $this") //TODO create exception
} }
} }
fun contains(filterComponents: List<FilterComponent>) : Boolean { fun contains(filterElements: List<FilterElement>) : Boolean {
return when (this) { return when (this) {
is Game -> filterComponents.any { is DataFilterElementRow -> filterElements.any {
it.ids?.contains(this.game.id) ?: false it.ids.contains(this.id)
} }
is From -> TODO()
is To -> TODO()
is Year -> TODO()
is Month -> TODO()
is Day -> TODO()
is PastDays -> TODO()
is Limit -> TODO()
is TableSize -> TODO()
is Bankroll -> TODO()
is Location -> TODO()
is TournamentName -> TODO()
is TournamentFeature -> TODO()
else -> return true else -> return true
} }
} }
@ -122,17 +125,16 @@ sealed class FilterElementRow : RowRepresentable {
is PastDays -> R.string.period_in_days is PastDays -> R.string.period_in_days
is Limit -> R.string.limit is Limit -> R.string.limit
is TableSize -> R.string.table_size is TableSize -> R.string.table_size
is Bankroll -> R.string.bankroll is Blind -> TODO()
is Game -> R.string.game is ResultMoreThan -> TODO()
is Location -> R.string.location is ResultLessThan -> TODO()
is TournamentName -> R.string.tournament_name else -> null
is TournamentFeature -> R.string.tournament_feature
} }
} }
override fun getDisplayName(): String { override fun getDisplayName(): String {
return when (this) { return when (this) {
is Game -> game.getDisplayName() is DataFilterElementRow -> this.name
else -> return super.getDisplayName() else -> return super.getDisplayName()
} }
} }

@ -24,6 +24,8 @@ enum class FilterSectionRow(override val resId: Int?): RowRepresentable {
BLINDS(net.pokeranalytics.android.R.string.blinds), BLINDS(net.pokeranalytics.android.R.string.blinds),
CASH_RE_BUY_COUNT(net.pokeranalytics.android.R.string.cash_game), CASH_RE_BUY_COUNT(net.pokeranalytics.android.R.string.cash_game),
TOURNAMENT_TYPE(net.pokeranalytics.android.R.string.tournament_types), TOURNAMENT_TYPE(net.pokeranalytics.android.R.string.tournament_types),
TOURNAMENT_NAME(net.pokeranalytics.android.R.string.tournament_name),
TOURNAMENT_FEATURE(net.pokeranalytics.android.R.string.tournament_feature),
COMPLETION_PERCENTAGE(net.pokeranalytics.android.R.string.tournament_completion_percentage_interval), COMPLETION_PERCENTAGE(net.pokeranalytics.android.R.string.tournament_completion_percentage_interval),
PLACE(net.pokeranalytics.android.R.string.final_position), PLACE(net.pokeranalytics.android.R.string.final_position),
PLAYERS_COUNT(net.pokeranalytics.android.R.string.players_count), PLAYERS_COUNT(net.pokeranalytics.android.R.string.players_count),
@ -67,7 +69,8 @@ enum class FilterSectionRow(override val resId: Int?): RowRepresentable {
} }
tableSizes tableSizes
} }
TOURNAMENT_NAME -> arrayListOf()
TOURNAMENT_FEATURE -> arrayListOf()
DYNAMIC_DATE -> arrayListOf( DYNAMIC_DATE -> arrayListOf(
Today, Today,
Yesterday, Yesterday,
@ -175,7 +178,7 @@ enum class FilterSectionRow(override val resId: Int?): RowRepresentable {
val games = realm.copyFromRealm(LiveData.GAME.items(realm) as RealmResults<Game>) val games = realm.copyFromRealm(LiveData.GAME.items(realm) as RealmResults<Game>)
rows.addAll(games) rows.addAll(games)
} }
LIMIT_TYPE -> rows.addAll(Limit.values()) LIMIT_TYPE -> rows.addAll(Limit.numericValues())
TABLE_SIZE -> { TABLE_SIZE -> {
val sessions = realm.where<Session>().sort("tableSize").distinct("tableSize").findAll() val sessions = realm.where<Session>().sort("tableSize").distinct("tableSize").findAll()
for (session in sessions) { for (session in sessions) {

Loading…
Cancel
Save