174 lines
7.0 KiB
Kotlin
174 lines
7.0 KiB
Kotlin
package jp.juggler.subwaytooter.table
|
|
|
|
import android.content.ContentValues
|
|
import android.database.sqlite.SQLiteDatabase
|
|
import android.provider.BaseColumns
|
|
import jp.juggler.subwaytooter.api.entity.Acct
|
|
import jp.juggler.subwaytooter.api.entity.EntityId
|
|
import jp.juggler.util.data.MetaColumns
|
|
import jp.juggler.util.data.TableCompanion
|
|
import jp.juggler.util.data.replaceTo
|
|
import jp.juggler.util.log.LogCategory
|
|
import kotlin.math.min
|
|
|
|
class NotificationShown(
|
|
var id: Long = 0L,
|
|
var acct: String = "",
|
|
var notificationId: String = "",
|
|
var timeCreate: Long = System.currentTimeMillis(),
|
|
) {
|
|
companion object : TableCompanion {
|
|
private val log = LogCategory("NotificationShown")
|
|
override val table = "notification_shown"
|
|
private const val COL_ID = BaseColumns._ID
|
|
private const val COL_ACCT = "a"
|
|
private const val COL_NOTIFICATION_ID = "ni"
|
|
private const val COL_TIME_CREATE = "tc"
|
|
private val columnList = MetaColumns(table, initialVersion = 65).apply {
|
|
column(0, COL_ID, MetaColumns.TS_INT_PRIMARY_KEY_NOT_NULL)
|
|
column(0, COL_ACCT, MetaColumns.TS_EMPTY_NOT_NULL)
|
|
column(0, COL_NOTIFICATION_ID, MetaColumns.TS_EMPTY_NOT_NULL)
|
|
column(0, COL_TIME_CREATE, MetaColumns.TS_ZERO_NOT_NULL)
|
|
createExtra = {
|
|
arrayOf(
|
|
"create unique index if not exists ${table}_a on $table($COL_ACCT,$COL_NOTIFICATION_ID)",
|
|
"create index if not exists ${table}_at on $table($COL_ACCT,$COL_TIME_CREATE)",
|
|
)
|
|
}
|
|
}
|
|
|
|
override fun onDBCreate(db: SQLiteDatabase) {
|
|
columnList.onDBCreate(db)
|
|
}
|
|
|
|
override fun onDBUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
|
if (oldVersion < 65 && newVersion >= 65) {
|
|
onDBCreate(db)
|
|
}
|
|
}
|
|
}
|
|
|
|
class Access(val db: SQLiteDatabase) {
|
|
fun deleteOld() {
|
|
try {
|
|
val list = db.rawQuery(
|
|
"select $COL_ACCT,count(*) from $table GROUP BY $COL_ACCT",
|
|
emptyArray(),
|
|
)?.use { cursor ->
|
|
buildList {
|
|
while (cursor.moveToNext()) {
|
|
add(
|
|
Pair(
|
|
cursor.getString(0),
|
|
cursor.getInt(1),
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
list ?: error("can't get usage count group by $COL_ACCT")
|
|
// ある程度の量は残したい
|
|
val keep = 200
|
|
for (pair in list) {
|
|
val acct = pair.first
|
|
var size = pair.second
|
|
log.i("$acct size=$size")
|
|
// 掃除する頻度を下げるため、ここのしきい値は倍にする
|
|
if (size <= keep * 2) continue
|
|
while (true) {
|
|
// 一度に削除したい数
|
|
val step = min(100, size - keep)
|
|
if (step <= 0) continue
|
|
// 古いものからstep件目の時刻を読む
|
|
val time = db.rawQuery(
|
|
"select $COL_TIME_CREATE from $table where $COL_ACCT=? order by $COL_TIME_CREATE asc limit ?",
|
|
arrayOf(acct, step.toString())
|
|
)?.use { cursor ->
|
|
when (cursor.moveToLast()) {
|
|
true -> cursor.getLong(0)
|
|
else -> null
|
|
}
|
|
}
|
|
if (time == null || time <= 0L) {
|
|
log.e("can't get time of position $step")
|
|
break
|
|
}
|
|
// 時刻がそれ以下のデータを削除する
|
|
db.execSQL(
|
|
"delete from $table where $COL_ACCT=? and $COL_TIME_CREATE<=?",
|
|
arrayOf(acct, time.toString())
|
|
)
|
|
// 件数を読み直す
|
|
size = db.rawQuery(
|
|
"select count(*) from $table where $COL_ACCT=?",
|
|
arrayOf(acct),
|
|
)?.use { cursor ->
|
|
when (cursor.moveToNext()) {
|
|
true -> cursor.getInt(0)
|
|
else -> null
|
|
}
|
|
} ?: -1
|
|
log.i("$acct size=$size")
|
|
if (size < 0) {
|
|
log.e("can't get size for $acct")
|
|
break
|
|
}
|
|
}
|
|
}
|
|
} catch (ex: Throwable) {
|
|
log.e(ex, "deleteOld failed.")
|
|
}
|
|
}
|
|
|
|
fun cleayByAcct(acct: Acct) {
|
|
db.execSQL(
|
|
"delete from $table where $COL_ACCT=?",
|
|
arrayOf(acct)
|
|
)
|
|
}
|
|
|
|
fun duplicateOrPut(acct: Acct, notificationId: String): Boolean {
|
|
try {
|
|
// 有効なIDがない場合は重複排除しない
|
|
when (notificationId) {
|
|
"", EntityId.DEFAULT.toString() -> return false
|
|
}
|
|
|
|
db.rawQuery(
|
|
"select $COL_ID from $table where $COL_ACCT=? and $COL_NOTIFICATION_ID=? limit 1",
|
|
arrayOf(acct.ascii, notificationId)
|
|
)?.use {
|
|
if (it.count > 0) return true
|
|
}
|
|
ContentValues().apply {
|
|
put(COL_TIME_CREATE, System.currentTimeMillis())
|
|
put(COL_ACCT, acct.ascii)
|
|
put(COL_NOTIFICATION_ID, notificationId)
|
|
}.replaceTo(db, table)
|
|
} catch (ex: Throwable) {
|
|
log.e(ex, "duplicateOrPut failed.")
|
|
}
|
|
return false
|
|
}
|
|
|
|
fun isDuplicate(acct: Acct, notificationId: String): Boolean {
|
|
try {
|
|
// 有効なIDがない場合は重複排除しない
|
|
when (notificationId) {
|
|
"", EntityId.DEFAULT.toString() -> return false
|
|
}
|
|
|
|
db.rawQuery(
|
|
"select $COL_ID from $table where $COL_ACCT=? and $COL_NOTIFICATION_ID=? limit 1",
|
|
arrayOf(acct.ascii, notificationId)
|
|
)?.use {
|
|
if (it.count > 0) return true
|
|
}
|
|
} catch (ex: Throwable) {
|
|
log.e(ex, "isDuplicate failed.")
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
}
|