Skip to content

Instantly share code, notes, and snippets.

@dmz9
Last active May 28, 2018 14:21
Show Gist options
  • Save dmz9/59bc8a87029b20fdf5090186362eb31e to your computer and use it in GitHub Desktop.
Save dmz9/59bc8a87029b20fdf5090186362eb31e to your computer and use it in GitHub Desktop.
class CityRepository @Inject constructor(
private val publicApi: PublicApi,
private val pool: SchedulersPool
) {
protected val parser = CriteriaParser()
fun getCities(criteria: Criteria): Single<CityCollection> {
return publicApi
.let {
if (criteria.page.isEmpty()) {
it.getCities(toQueryMap(criteria))
} else {
it.getCities(criteria.page)
}
}
.observeOn(pool.android())
.subscribeOn(pool.compute())
.map(this::mapCollection)
}
fun mapCollection(response: Response<Collection>): Collection { ... }
fun toQueryMap(criteria: Criteria): Map<String, String> = parser.toQueryMap(criteria)
}
data class CompositeFilter(
@SerializedName("composite")
val composite: List<Filter> = ArrayList()
) {
fun isEmpty(): Boolean = composite.isEmpty()
fun isNotEmpty(): Boolean = composite.isNotEmpty()
fun add(filter: Filter): CompositeFilter = CompositeFilter(composite + listOf(filter))
}
data class Criteria(
@SerializedName("isAnon") var isAnon: Boolean = true,
@SerializedName("limit") var limit: Int = 100,
@SerializedName("page") var page: String = "",
@SerializedName("sortBy") var sortBy: String = "id",
@SerializedName("sortDir") var sortDir: String = SORT_ASC,
@SerializedName("search") var search: String = "",
@SerializedName("filter") val filter: CompositeFilter = CompositeFilter()
) {
companion object {
const val MAX_LIMIT = 100
const val NO_LIMIT = -1
const val SORT_ASC = "asc"
const val SORT_DESC = "desc"
}
}
class CriteriaParser {
fun getSort(criteria: Criteria) = "${criteria.sortBy}:${criteria.sortDir}"
fun getLimit(criteria: Criteria) = when {
criteria.limit <= 0 || criteria.limit > Criteria.MAX_LIMIT -> Criteria.MAX_LIMIT
else -> criteria.limit
}.toString()
fun toQueryMap(criteria: Criteria): Map<String, String> {
val map = mutableMapOf<String, String>()
map["limit"] = getLimit(criteria)
if (criteria.sortBy.isNotEmpty()) {
map["sort"] = getSort(criteria)
}
if (criteria.filter.isNotEmpty()) {
criteria.filter.composite.forEach {
when (it) {
// builds url like /route?param=in:a,b,c
is Filter.In -> map[it.param] = "in:" + it.range.joinToString(",")
}
}
}
return map
}
}
sealed class Filter {
class In(val param: String, val range: List<String>) : Filter()
class GreaterThan(val param: String, val value: String):Filter()
class LessThan(val param:String, val value: String):Filter()
}
class Interactor @Inject constructor(
private val repository: CityRepository,
private val settings: ISettingsRepository
) {
fun getCities(criteria: Criteria): Observable<CityCollection> {
criteria.isAnon = !settings.isSignedIn()
return repository
.getCities(criteria)
.toObservable()
.concatMap {
val obs = Observable.fromCallable { it }
when {
it.isLast() -> obs
else->obs.concatWith(getCities(Criteria(page = it.nextPage)))
}
}
}
}
interface PublicApi {
/**
* cities by params, first page
*/
@GET("/cities")
fun getCities(@QueryMap queryMap: Map<String, String>): Single<Response<CityCollection>>
/**
* cities by direct page url
*/
@GET
fun getCities(@Url url: String): Single<Response<CityCollection>>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment