5

I know Anko provides the functions parseSingle, parseOpt and parseList , I don't understand why the code of Android Developers (the book) need to design extensions parseList again.

Could you tell me? Thanks!

https://github.com/antoniolg/Kotlin-for-Android-Developers/blob/master/app/src/main/java/com/antonioleiva/weatherapp/data/db/ForecastDb.kt

override fun requestForecastByZipCode(zipCode: Long, date: Long) = forecastDbHelper.use {

        val dailyRequest = "${DayForecastTable.CITY_ID} = ? AND ${DayForecastTable.DATE} >= ?"
        val dailyForecast = select(DayForecastTable.NAME)
                .whereSimple(dailyRequest, zipCode.toString(), date.toString())
                .parseList { DayForecast(HashMap(it)) }

}

https://github.com/antoniolg/Kotlin-for-Android-Developers/blob/master/app/src/main/java/com/antonioleiva/weatherapp/extensions/DatabaseExtensions.kt

fun <T : Any> SelectQueryBuilder.parseList(parser: (Map<String, Any?>) -> T): List<T> =
        parseList(object : MapRowParser<T> {
            override fun parseRow(columns: Map<String, Any?>): T = parser(columns)
})
Zoe
  • 27,060
  • 21
  • 118
  • 148
HelloCW
  • 843
  • 22
  • 125
  • 310

2 Answers2

3

Anko's parseList takes a MapRowParser, not a function. This simplifies usage. With Anko version you'd write

.parseList { mapRowParser { DayForecast(HashMap(it)) } }

instead. That's assuming there is a constructor function like mapRowParser which I can't find in their sources; otherwise, you could write it quite trivially.

Or rather, it's already written for you in the example code, just not as a separate function:

fun <T> mapRowParser(parser: (Map<String, Any?>) -> T): MapRowParser<T> = 
    object : MapRowParser<T> {
        override fun parseRow(columns: Map<String, Any?>): T = parser(columns)
    }

I am honestly really surprised if this function doesn't exist already (maybe called something else, but what?). OTOH, if it does exist, Leiva should have used it.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Thanks! What does HashMap(it) mean? – HelloCW Nov 02 '17 at 14:18
  • It's how constructors are called in Kotlin. It copies the input map into a new `HashMap` (I don't know why, instead of just `DayForecast(it)`). – Alexey Romanov Nov 02 '17 at 19:50
  • Thanks! but .parseList { mapRowParser { DayForecast(HashMap(it)) } } don't work, and .parseList { MapRowParser { DayForecast(HashMap(it)) } } don't work too! Could you give me a full code? – HelloCW Nov 03 '17 at 02:00
  • Edited to insert the function. – Alexey Romanov Nov 05 '17 at 18:11
  • Sorry, but your code don't work yet, I get the error Error:(28, 19) None of the following functions can be called with the arguments supplied: public final inline fun parseList(parser: MapRowParser??>): List??> defined in org.jetbrains.anko.db.SelectQueryBuilder public final inline fun parseList(parser: RowParser??>): List??> defined in org.jetbrains.anko.db.SelectQueryBuilder – HelloCW Nov 07 '17 at 02:06
  • I guest that there are some problems with your codre fun mapRowParser(parser: (Map) -> T): MapRowParser = ... – HelloCW Nov 07 '17 at 02:07
0

If you expected simple single column rows result, you can use ready-made Anko parsers:

  • ShortParser
  • IntParser
  • LongParser
  • FloatParser
  • DoubleParser
  • StringParser
  • BlobParser

Your code might be:

val dailyForecast = select(DayForecastTable.NAME)
                .whereSimple(dailyRequest, zipCode.toString(), date.toString())
                .parseList(StringParser)

Or you can implement your own parser. Here below sample for three columns result (Int, String, String):

val userParser = rowParser { id: Int, name: String, email: String ->
    Triple(id, name, email)
}
andrekot
  • 21
  • 2