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.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray
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.loadSchedule
import ru.sweetbread.unn.db.loadUserByBitrixId
@@ -207,6 +208,7 @@ suspend fun getScheduleDay(
if ((type == ME.type) and (id == ME.unnId!!)) {
val schedule = withContext(Dispatchers.IO) { loadSchedule(date) }
Log.d("Schedule", schedule.joinToString())
if (schedule.size != 0) {
return schedule
}
@@ -294,7 +296,7 @@ suspend fun getSchedule(
}
if ((type == ME.type) and (id == ME.unnId!!)) {
cacheScheduleItems(out)
cacheSchedule(out)
}
return out
}
+184 -114
View File
@@ -1,10 +1,12 @@
package ru.sweetbread.unn.db
import android.util.Log
import androidx.room.ColumnInfo
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey
import androidx.room.Query
import ru.sweetbread.unn.Auditorium
@@ -16,6 +18,7 @@ import ru.sweetbread.unn.LecturerRank
import ru.sweetbread.unn.ScheduleUnit
import ru.sweetbread.unn.ui.layout.db
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
@@ -23,15 +26,16 @@ import java.time.format.DateTimeFormatter
data class BuildingDB(
@PrimaryKey val oid: Int,
@ColumnInfo val name: String,
@ColumnInfo val gid: Int
@ColumnInfo val gid: Int,
@ColumnInfo val expiredAt: String
)
@Dao
interface BuildingDao {
@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)
@Delete
@@ -39,20 +43,26 @@ interface BuildingDao {
}
fun cacheBuilding(building: Building) {
try {
db.buildingDao().insert(
BuildingDB(
building.oid,
building.name,
building.gid
)
db.buildingDao().insert(
BuildingDB(
building.oid,
building.name,
building.gid,
LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
} catch (_: android.database.sqlite.SQLiteConstraintException) {
}
)
}
fun loadBuilding(oid: Int): Building {
return db.buildingDao().get(oid).let {
fun loadBuilding(oid: Int): Building? {
return db.buildingDao().get(oid)?.let {
if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.buildingDao().delete(it)
return null
}
Building(
it.name,
it.gid,
@@ -66,15 +76,16 @@ data class AuditoriumDB(
@PrimaryKey val oid: Int,
@ColumnInfo val name: String,
@ColumnInfo val floor: Int?,
@ColumnInfo val buildingOid: Int
@ColumnInfo val buildingOid: Int,
@ColumnInfo val expiredAt: String
)
@Dao
interface AuditoriumDao {
@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)
@Delete
@@ -82,27 +93,34 @@ interface AuditoriumDao {
}
fun cacheAuditorium(auditorium: Auditorium) {
try {
cacheBuilding(auditorium.building)
db.auditoriumDao().insert(
AuditoriumDB(
auditorium.oid,
auditorium.name,
auditorium.floor,
auditorium.building.oid
)
cacheBuilding(auditorium.building)
db.auditoriumDao().insert(
AuditoriumDB(
auditorium.oid,
auditorium.name,
auditorium.floor,
auditorium.building.oid,
LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
} catch (_: android.database.sqlite.SQLiteConstraintException) {
}
)
}
fun loadAuditorium(oid: Int): Auditorium {
return db.auditoriumDao().get(oid).let {
Auditorium(
fun loadAuditorium(oid: Int): Auditorium? {
return db.auditoriumDao().get(oid)?.let {
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.oid,
it.floor ?: 0,
loadBuilding(it.buildingOid)
building
)
}
}
@@ -111,15 +129,16 @@ fun loadAuditorium(oid: Int): Auditorium {
data class DisciplineDB(
@PrimaryKey val oid: Int,
@ColumnInfo val name: String,
@ColumnInfo val type: Int
@ColumnInfo val type: Int,
@ColumnInfo val expiredAt: String
)
@Dao
interface DisciplineDao {
@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)
@Delete
@@ -127,21 +146,28 @@ interface DisciplineDao {
}
fun cacheDiscipline(discipline: Discipline) {
try {
db.disciplineDao().insert(
DisciplineDB(
discipline.oid,
discipline.name,
discipline.type
)
db.disciplineDao().insert(
DisciplineDB(
discipline.oid,
discipline.name,
discipline.type,
LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
} catch (_: android.database.sqlite.SQLiteConstraintException) {
}
)
}
fun loadDiscipline(oid: Int): Discipline {
return db.disciplineDao().get(oid).let {
Discipline(
fun loadDiscipline(oid: Int): Discipline? {
return db.disciplineDao().get(oid)?.let {
if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.disciplineDao().delete(it)
return null
}
return Discipline(
it.name,
it.oid,
it.type
@@ -154,15 +180,16 @@ data class KindOfWorkDB(
@PrimaryKey val oid: Int,
@ColumnInfo val name: String,
@ColumnInfo val uid: String,
@ColumnInfo val complexity: Int
@ColumnInfo val complexity: Int,
@ColumnInfo val expiredAt: String
)
@Dao
interface KindOfWorkDao {
@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)
@Delete
@@ -170,22 +197,29 @@ interface KindOfWorkDao {
}
fun cacheKindOfWork(kindOfWork: KindOfWork) {
try {
db.kindOfWorkDao().insert(
KindOfWorkDB(
kindOfWork.oid,
kindOfWork.name,
kindOfWork.uid,
kindOfWork.complexity
)
db.kindOfWorkDao().insert(
KindOfWorkDB(
kindOfWork.oid,
kindOfWork.name,
kindOfWork.uid,
kindOfWork.complexity,
LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
} catch (_: android.database.sqlite.SQLiteConstraintException) {
}
)
}
fun loadKindOfWork(oid: Int): KindOfWork {
return db.kindOfWorkDao().get(oid).let {
KindOfWork(
fun loadKindOfWork(oid: Int): KindOfWork? {
return db.kindOfWorkDao().get(oid)?.let {
if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.kindOfWorkDao().delete(it)
return null
}
return KindOfWork(
it.name,
it.oid,
it.uid,
@@ -200,15 +234,16 @@ data class LecturerDB(
@ColumnInfo val name: String,
@ColumnInfo val rank: LecturerRank,
@ColumnInfo val email: String,
@ColumnInfo val uid: String
@ColumnInfo val uid: String,
@ColumnInfo val expiredAt: String
)
@Dao
interface LecturerDao {
@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)
@Delete
@@ -216,23 +251,30 @@ interface LecturerDao {
}
fun cacheLecturer(lecturer: Lecturer) {
try {
db.lecturerDao().insert(
LecturerDB(
lecturer.unnId,
lecturer.name,
lecturer.rank,
lecturer.email,
lecturer.uid
)
db.lecturerDao().insert(
LecturerDB(
lecturer.unnId,
lecturer.name,
lecturer.rank,
lecturer.email,
lecturer.uid,
LocalDateTime.now().plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME)
)
} catch (_: android.database.sqlite.SQLiteConstraintException) {
}
)
}
fun loadLecturer(unnId: Int): Lecturer {
return db.lecturerDao().get(unnId).let {
Lecturer(
fun loadLecturer(unnId: Int): Lecturer? {
return db.lecturerDao().get(unnId)?.let {
if (LocalDateTime.parse(
it.expiredAt,
DateTimeFormatter.ISO_DATE_TIME
) > LocalDateTime.now()
) {
db.lecturerDao().delete(it)
return null
}
return Lecturer(
it.name,
it.rank,
it.email,
@@ -253,62 +295,90 @@ data class ScheduleUnitDB(
@ColumnInfo val auditoriumOid: Int,
@ColumnInfo val disciplineOid: 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
interface ScheduleItemDao {
@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`")
fun getSchedule(date: String): List<ScheduleUnitDB>
@Insert
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(user: ScheduleUnitDB)
@Delete
fun delete(user: ScheduleUnitDB)
}
fun cacheScheduleItems(items: ArrayList<ScheduleUnit>) {
for (item in items) {
try {
cacheAuditorium(item.auditorium)
cacheDiscipline(item.discipline)
cacheKindOfWork(item.kindOfWork)
cacheLecturer(item.lecturers[0])
fun cacheSchedule(item: ScheduleUnit) {
cacheAuditorium(item.auditorium)
cacheDiscipline(item.discipline)
cacheKindOfWork(item.kindOfWork)
cacheLecturer(item.lecturers[0])
db.scheduleDao().insert(
ScheduleUnitDB(
item.oid,
item.date.format(DateTimeFormatter.ISO_DATE),
item.stream,
item.begin.format(DateTimeFormatter.ISO_TIME),
item.end.format(DateTimeFormatter.ISO_TIME),
item.auditorium.oid,
item.discipline.oid,
item.kindOfWork.oid,
item.lecturers[0].unnId
)
)
} catch (_: android.database.sqlite.SQLiteConstraintException) {
}
}
db.scheduleDao().insert(
ScheduleUnitDB(
item.oid,
item.date.format(DateTimeFormatter.ISO_DATE),
item.stream,
item.begin.format(DateTimeFormatter.ISO_TIME),
item.end.format(DateTimeFormatter.ISO_TIME),
item.auditorium.oid,
item.discipline.oid,
item.kindOfWork.oid,
item.lecturers[0].unnId,
when {
(LocalDate.now() > item.date) -> LocalDateTime.now().plusWeeks(2)
(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> {
return ArrayList(db.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE)).map {
ScheduleUnit(
fun cacheSchedule(items: ArrayList<ScheduleUnit>) {
for (item in items)
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,
loadAuditorium(it.auditoriumOid),
loadAuditorium(it.auditoriumOid) ?: return null,
LocalDate.parse(it.date, DateTimeFormatter.ISO_DATE),
loadDiscipline(it.disciplineOid),
loadKindOfWork(it.kindOfWorkOid),
arrayListOf(loadLecturer(it.lecturerId)),
loadDiscipline(it.disciplineOid) ?: return null,
loadKindOfWork(it.kindOfWorkOid) ?: return null,
arrayListOf(loadLecturer(it.lecturerId) ?: return null),
it.stream,
LocalTime.parse(it.begin, 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) }
)
}