feat(cache): Add conflict strategy

This commit is contained in:
sweetbread
2024-05-26 15:58:07 +03:00
committed by Sweetbread
parent 3138afb0de
commit 46987c6fa5
2 changed files with 188 additions and 116 deletions
+4 -2
View File
@@ -10,9 +10,10 @@ import io.ktor.http.parameters
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import ru.sweetbread.unn.db.cacheScheduleItems import ru.sweetbread.unn.db.cacheSchedule
import ru.sweetbread.unn.db.cacheUser import ru.sweetbread.unn.db.cacheUser
import ru.sweetbread.unn.db.loadSchedule import ru.sweetbread.unn.db.loadSchedule
import ru.sweetbread.unn.db.loadUserByBitrixId import ru.sweetbread.unn.db.loadUserByBitrixId
@@ -207,6 +208,7 @@ suspend fun getScheduleDay(
if ((type == ME.type) and (id == ME.unnId!!)) { if ((type == ME.type) and (id == ME.unnId!!)) {
val schedule = withContext(Dispatchers.IO) { loadSchedule(date) } val schedule = withContext(Dispatchers.IO) { loadSchedule(date) }
Log.d("Schedule", schedule.joinToString())
if (schedule.size != 0) { if (schedule.size != 0) {
return schedule return schedule
} }
@@ -294,7 +296,7 @@ suspend fun getSchedule(
} }
if ((type == ME.type) and (id == ME.unnId!!)) { if ((type == ME.type) and (id == ME.unnId!!)) {
cacheScheduleItems(out) cacheSchedule(out)
} }
return out return out
} }
+184 -114
View File
@@ -1,10 +1,12 @@
package ru.sweetbread.unn.db package ru.sweetbread.unn.db
import android.util.Log
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import androidx.room.Query import androidx.room.Query
import ru.sweetbread.unn.Auditorium import ru.sweetbread.unn.Auditorium
@@ -16,6 +18,7 @@ import ru.sweetbread.unn.LecturerRank
import ru.sweetbread.unn.ScheduleUnit import ru.sweetbread.unn.ScheduleUnit
import ru.sweetbread.unn.ui.layout.db import ru.sweetbread.unn.ui.layout.db
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime import java.time.LocalTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -23,15 +26,16 @@ import java.time.format.DateTimeFormatter
data class BuildingDB( data class BuildingDB(
@PrimaryKey val oid: Int, @PrimaryKey val oid: Int,
@ColumnInfo val name: String, @ColumnInfo val name: String,
@ColumnInfo val gid: Int @ColumnInfo val gid: Int,
@ColumnInfo val expiredAt: String
) )
@Dao @Dao
interface BuildingDao { interface BuildingDao {
@Query("SELECT * FROM buildingdb WHERE oid = :oid LIMIT 1") @Query("SELECT * FROM buildingdb WHERE oid = :oid LIMIT 1")
fun get(oid: Int): BuildingDB fun get(oid: Int): BuildingDB?
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(building: BuildingDB) fun insert(building: BuildingDB)
@Delete @Delete
@@ -39,20 +43,26 @@ interface BuildingDao {
} }
fun cacheBuilding(building: Building) { fun cacheBuilding(building: Building) {
try { db.buildingDao().insert(
db.buildingDao().insert( BuildingDB(
BuildingDB( building.oid,
building.oid, building.name,
building.name, building.gid,
building.gid LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
) )
} catch (_: android.database.sqlite.SQLiteConstraintException) { )
}
} }
fun loadBuilding(oid: Int): Building { fun loadBuilding(oid: Int): Building? {
return db.buildingDao().get(oid).let { return db.buildingDao().get(oid)?.let {
if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.buildingDao().delete(it)
return null
}
Building( Building(
it.name, it.name,
it.gid, it.gid,
@@ -66,15 +76,16 @@ data class AuditoriumDB(
@PrimaryKey val oid: Int, @PrimaryKey val oid: Int,
@ColumnInfo val name: String, @ColumnInfo val name: String,
@ColumnInfo val floor: Int?, @ColumnInfo val floor: Int?,
@ColumnInfo val buildingOid: Int @ColumnInfo val buildingOid: Int,
@ColumnInfo val expiredAt: String
) )
@Dao @Dao
interface AuditoriumDao { interface AuditoriumDao {
@Query("SELECT * FROM auditoriumdb WHERE oid = :oid LIMIT 1") @Query("SELECT * FROM auditoriumdb WHERE oid = :oid LIMIT 1")
fun get(oid: Int): AuditoriumDB fun get(oid: Int): AuditoriumDB?
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(auditorium: AuditoriumDB) fun insert(auditorium: AuditoriumDB)
@Delete @Delete
@@ -82,27 +93,34 @@ interface AuditoriumDao {
} }
fun cacheAuditorium(auditorium: Auditorium) { fun cacheAuditorium(auditorium: Auditorium) {
try { cacheBuilding(auditorium.building)
cacheBuilding(auditorium.building) db.auditoriumDao().insert(
db.auditoriumDao().insert( AuditoriumDB(
AuditoriumDB( auditorium.oid,
auditorium.oid, auditorium.name,
auditorium.name, auditorium.floor,
auditorium.floor, auditorium.building.oid,
auditorium.building.oid LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
) )
} catch (_: android.database.sqlite.SQLiteConstraintException) { )
}
} }
fun loadAuditorium(oid: Int): Auditorium { fun loadAuditorium(oid: Int): Auditorium? {
return db.auditoriumDao().get(oid).let { return db.auditoriumDao().get(oid)?.let {
Auditorium( if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.auditoriumDao().delete(it)
return null
}
val building = loadBuilding(it.buildingOid) ?: return null
return Auditorium(
it.name, it.name,
it.oid, it.oid,
it.floor ?: 0, it.floor ?: 0,
loadBuilding(it.buildingOid) building
) )
} }
} }
@@ -111,15 +129,16 @@ fun loadAuditorium(oid: Int): Auditorium {
data class DisciplineDB( data class DisciplineDB(
@PrimaryKey val oid: Int, @PrimaryKey val oid: Int,
@ColumnInfo val name: String, @ColumnInfo val name: String,
@ColumnInfo val type: Int @ColumnInfo val type: Int,
@ColumnInfo val expiredAt: String
) )
@Dao @Dao
interface DisciplineDao { interface DisciplineDao {
@Query("SELECT * FROM disciplinedb WHERE oid = :oid LIMIT 1") @Query("SELECT * FROM disciplinedb WHERE oid = :oid LIMIT 1")
fun get(oid: Int): DisciplineDB fun get(oid: Int): DisciplineDB?
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(discipline: DisciplineDB) fun insert(discipline: DisciplineDB)
@Delete @Delete
@@ -127,21 +146,28 @@ interface DisciplineDao {
} }
fun cacheDiscipline(discipline: Discipline) { fun cacheDiscipline(discipline: Discipline) {
try { db.disciplineDao().insert(
db.disciplineDao().insert( DisciplineDB(
DisciplineDB( discipline.oid,
discipline.oid, discipline.name,
discipline.name, discipline.type,
discipline.type LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
) )
} catch (_: android.database.sqlite.SQLiteConstraintException) { )
}
} }
fun loadDiscipline(oid: Int): Discipline { fun loadDiscipline(oid: Int): Discipline? {
return db.disciplineDao().get(oid).let { return db.disciplineDao().get(oid)?.let {
Discipline( if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.disciplineDao().delete(it)
return null
}
return Discipline(
it.name, it.name,
it.oid, it.oid,
it.type it.type
@@ -154,15 +180,16 @@ data class KindOfWorkDB(
@PrimaryKey val oid: Int, @PrimaryKey val oid: Int,
@ColumnInfo val name: String, @ColumnInfo val name: String,
@ColumnInfo val uid: String, @ColumnInfo val uid: String,
@ColumnInfo val complexity: Int @ColumnInfo val complexity: Int,
@ColumnInfo val expiredAt: String
) )
@Dao @Dao
interface KindOfWorkDao { interface KindOfWorkDao {
@Query("SELECT * FROM kindofworkdb WHERE oid = :oid LIMIT 1") @Query("SELECT * FROM kindofworkdb WHERE oid = :oid LIMIT 1")
fun get(oid: Int): KindOfWorkDB fun get(oid: Int): KindOfWorkDB?
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(kindOfWork: KindOfWorkDB) fun insert(kindOfWork: KindOfWorkDB)
@Delete @Delete
@@ -170,22 +197,29 @@ interface KindOfWorkDao {
} }
fun cacheKindOfWork(kindOfWork: KindOfWork) { fun cacheKindOfWork(kindOfWork: KindOfWork) {
try { db.kindOfWorkDao().insert(
db.kindOfWorkDao().insert( KindOfWorkDB(
KindOfWorkDB( kindOfWork.oid,
kindOfWork.oid, kindOfWork.name,
kindOfWork.name, kindOfWork.uid,
kindOfWork.uid, kindOfWork.complexity,
kindOfWork.complexity LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
) )
} catch (_: android.database.sqlite.SQLiteConstraintException) { )
}
} }
fun loadKindOfWork(oid: Int): KindOfWork { fun loadKindOfWork(oid: Int): KindOfWork? {
return db.kindOfWorkDao().get(oid).let { return db.kindOfWorkDao().get(oid)?.let {
KindOfWork( if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.kindOfWorkDao().delete(it)
return null
}
return KindOfWork(
it.name, it.name,
it.oid, it.oid,
it.uid, it.uid,
@@ -200,15 +234,16 @@ data class LecturerDB(
@ColumnInfo val name: String, @ColumnInfo val name: String,
@ColumnInfo val rank: LecturerRank, @ColumnInfo val rank: LecturerRank,
@ColumnInfo val email: String, @ColumnInfo val email: String,
@ColumnInfo val uid: String @ColumnInfo val uid: String,
@ColumnInfo val expiredAt: String
) )
@Dao @Dao
interface LecturerDao { interface LecturerDao {
@Query("SELECT * FROM lecturerdb WHERE unnId = :unnId LIMIT 1") @Query("SELECT * FROM lecturerdb WHERE unnId = :unnId LIMIT 1")
fun get(unnId: Int): LecturerDB fun get(unnId: Int): LecturerDB?
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(lecturer: LecturerDB) fun insert(lecturer: LecturerDB)
@Delete @Delete
@@ -216,23 +251,30 @@ interface LecturerDao {
} }
fun cacheLecturer(lecturer: Lecturer) { fun cacheLecturer(lecturer: Lecturer) {
try { db.lecturerDao().insert(
db.lecturerDao().insert( LecturerDB(
LecturerDB( lecturer.unnId,
lecturer.unnId, lecturer.name,
lecturer.name, lecturer.rank,
lecturer.rank, lecturer.email,
lecturer.email, lecturer.uid,
lecturer.uid LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
) )
} catch (_: android.database.sqlite.SQLiteConstraintException) { )
}
} }
fun loadLecturer(unnId: Int): Lecturer { fun loadLecturer(unnId: Int): Lecturer? {
return db.lecturerDao().get(unnId).let { return db.lecturerDao().get(unnId)?.let {
Lecturer( if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.lecturerDao().delete(it)
return null
}
return Lecturer(
it.name, it.name,
it.rank, it.rank,
it.email, it.email,
@@ -253,62 +295,90 @@ data class ScheduleUnitDB(
@ColumnInfo val auditoriumOid: Int, @ColumnInfo val auditoriumOid: Int,
@ColumnInfo val disciplineOid: Int, @ColumnInfo val disciplineOid: Int,
@ColumnInfo val kindOfWorkOid: Int, @ColumnInfo val kindOfWorkOid: Int,
@ColumnInfo val lecturerId: Int // TODO: many-to-many @ColumnInfo val lecturerId: Int, // TODO: many-to-many
@ColumnInfo val expiredAt: String
) )
@Dao @Dao
interface ScheduleItemDao { interface ScheduleItemDao {
@Query("SELECT * FROM scheduleUnitDB WHERE oid = :oid LIMIT 1") @Query("SELECT * FROM scheduleUnitDB WHERE oid = :oid LIMIT 1")
fun getScheduleItem(oid: Int): ScheduleUnitDB? fun getSchedule(oid: Int): ScheduleUnitDB?
@Query("SELECT * FROM scheduleUnitDB WHERE date = :date ORDER BY `begin`") @Query("SELECT * FROM scheduleUnitDB WHERE date = :date ORDER BY `begin`")
fun getSchedule(date: String): List<ScheduleUnitDB> fun getSchedule(date: String): List<ScheduleUnitDB>
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(user: ScheduleUnitDB) fun insert(user: ScheduleUnitDB)
@Delete @Delete
fun delete(user: ScheduleUnitDB) fun delete(user: ScheduleUnitDB)
} }
fun cacheScheduleItems(items: ArrayList<ScheduleUnit>) { fun cacheSchedule(item: ScheduleUnit) {
for (item in items) { cacheAuditorium(item.auditorium)
try { cacheDiscipline(item.discipline)
cacheAuditorium(item.auditorium) cacheKindOfWork(item.kindOfWork)
cacheDiscipline(item.discipline) cacheLecturer(item.lecturers[0])
cacheKindOfWork(item.kindOfWork)
cacheLecturer(item.lecturers[0])
db.scheduleDao().insert( db.scheduleDao().insert(
ScheduleUnitDB( ScheduleUnitDB(
item.oid, item.oid,
item.date.format(DateTimeFormatter.ISO_DATE), item.date.format(DateTimeFormatter.ISO_DATE),
item.stream, item.stream,
item.begin.format(DateTimeFormatter.ISO_TIME), item.begin.format(DateTimeFormatter.ISO_TIME),
item.end.format(DateTimeFormatter.ISO_TIME), item.end.format(DateTimeFormatter.ISO_TIME),
item.auditorium.oid, item.auditorium.oid,
item.discipline.oid, item.discipline.oid,
item.kindOfWork.oid, item.kindOfWork.oid,
item.lecturers[0].unnId item.lecturers[0].unnId,
) when {
) (LocalDate.now() > item.date) -> LocalDateTime.now().plusWeeks(2)
} catch (_: android.database.sqlite.SQLiteConstraintException) { (LocalDate.now().plusWeeks(1) > item.date) -> LocalDateTime.now().plusDays(1)
} (LocalDate.now().plusWeeks(2) > item.date) -> LocalDateTime.now().plusWeeks(1)
} else -> LocalDateTime.now().plusWeeks(2)
}.format(DateTimeFormatter.ISO_DATE_TIME)
)
)
} }
fun loadSchedule(date: LocalDate): ArrayList<ScheduleUnit> { fun cacheSchedule(items: ArrayList<ScheduleUnit>) {
return ArrayList(db.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE)).map { for (item in items)
ScheduleUnit( cacheSchedule(item)
}
fun loadSchedule(oid: Int): ScheduleUnit? {
db.scheduleDao().getSchedule(oid)?.let {
Log.d("load", it.oid.toString())
if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) < LocalDateTime.now()
) {
Log.d("delete", it.oid.toString())
db.scheduleDao().delete(it)
return null
}
return ScheduleUnit(
it.oid, it.oid,
loadAuditorium(it.auditoriumOid), loadAuditorium(it.auditoriumOid) ?: return null,
LocalDate.parse(it.date, DateTimeFormatter.ISO_DATE), LocalDate.parse(it.date, DateTimeFormatter.ISO_DATE),
loadDiscipline(it.disciplineOid), loadDiscipline(it.disciplineOid) ?: return null,
loadKindOfWork(it.kindOfWorkOid), loadKindOfWork(it.kindOfWorkOid) ?: return null,
arrayListOf(loadLecturer(it.lecturerId)), arrayListOf(loadLecturer(it.lecturerId) ?: return null),
it.stream, it.stream,
LocalTime.parse(it.begin, DateTimeFormatter.ISO_TIME), LocalTime.parse(it.begin, DateTimeFormatter.ISO_TIME),
LocalTime.parse(it.end, DateTimeFormatter.ISO_TIME) LocalTime.parse(it.end, DateTimeFormatter.ISO_TIME)
) )
}) }
return null
}
fun loadSchedule(date: LocalDate): ArrayList<ScheduleUnit> {
db.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE))
.mapNotNull { Log.d("meow", "${it.oid}: ${loadSchedule(it.oid)}") }
return ArrayList(
db.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE))
.mapNotNull { loadSchedule(it.oid) }
)
} }