Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@programmerr47
Created December 22, 2018 13:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save programmerr47/8c138b1974092b0bda76a36a0e26bc97 to your computer and use it in GitHub Desktop.
Save programmerr47/8c138b1974092b0bda76a36a0e26bc97 to your computer and use it in GitHub Desktop.
Simple implementation for CacheProvider interface
interface TimeProvider {
val currentMs: Long
}
object SystemTimeProvider : TimeProvider {
override val currentMs: Long get() = System.currentTimeMillis()
}
interface CacheProvider {
fun obtainFresh(key: String): String?
fun obtain(key: String): String?
fun store(key: String, value: String, stalesAfterMs: Long, expiresAfterMs: Long)
}
class SqliteCacheProvider(context: Context, name: String, version: Int, private val timeProvider: TimeProvider = SystemTimeProvider) :
SQLiteOpenHelper(context, name, null, version), CacheProvider {
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("DROP TABLE IF EXISTS $T_CACHE")
onCreate(db)
}
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $T_CACHE ($C_KEY TEXT PRIMARY KEY, $C_VALUE TEXT, $C_STALES INTEGER, $C_EXPIRES INTEGER);")
}
override fun obtainFresh(key: String) =
obtainBy("SELECT $C_VALUE FROM $T_CACHE WHERE $C_KEY = ? AND $C_STALES > ${timeProvider.currentMs} LIMIT 1", arrayOf(key))
override fun obtain(key: String) =
obtainBy("SELECT $C_VALUE FROM $T_CACHE WHERE $C_KEY = ? AND $C_EXPIRES > ${timeProvider.currentMs} LIMIT 1", arrayOf(key))
private fun obtainBy(query: String, args: Array<String>): String? {
return try {
readableDatabase.rawQuery(query, args).use {
if (it.count == 0) null
else {
it.moveToFirst()
it.getString(C_VALUE)
}
}
} catch (e: SQLiteException) {
null
}
}
override fun store(key: String, value: String, stalesAfterMs: Long, expiresAfterMs: Long) {
val currentTime = timeProvider.currentMs
val values = ContentValues(4).also {
it[C_KEY] = key
it[C_VALUE] = value
it[C_STALES] = correctTime(currentTime, stalesAfterMs)
it[C_EXPIRES] = correctTime(currentTime, expiresAfterMs)
}
writableDatabase.insertWithOnConflict(T_CACHE, "", values, SQLiteDatabase.CONFLICT_REPLACE)
}
fun clean() = writableDatabase.execSQL("DELETE FROM $T_CACHE WHERE $C_EXPIRES < ${timeProvider.currentMs}")
fun clear() = writableDatabase.execSQL("DELETE FROM $T_CACHE")
private fun correctTime(time: Long, addend: Long) = (time + addend).let {
if (it < time) Long.MAX_VALUE
else it
}
companion object {
private const val T_CACHE = "cache"
private const val C_KEY = "c_key"
private const val C_VALUE = "c_value"
private const val C_STALES = "c_stales"
private const val C_EXPIRES = "c_expires"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment