Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ class LibraryRepositoryImpl @Inject constructor(
override suspend fun getLibraryListForUser(userId: String?): List<RealmMyLibrary> {
if (userId == null) return emptyList()

// OPTIMIZATION: Filter by userId in the query first, then check needToUpdate
// This is faster than loading all libraries and filtering in memory
val results = queryList(RealmMyLibrary::class.java) {
equalTo("isPrivate", false)
contains("userId", userId)
}
return filterLibrariesNeedingUpdate(results)
.filter { it.userId?.contains(userId) == true }
}

override suspend fun getStepResources(stepId: String?, resourceOffline: Boolean): List<RealmMyLibrary> {
Expand All @@ -61,11 +63,31 @@ class LibraryRepositoryImpl @Inject constructor(
override suspend fun countLibrariesNeedingUpdate(userId: String?): Int {
if (userId == null) return 0

val results = queryList(RealmMyLibrary::class.java) {
equalTo("isPrivate", false)
// OPTIMIZATION: Use Realm query to filter directly in database instead of loading all into memory
// This is much faster than loading all libraries and filtering in Kotlin
return withRealm { realm ->
// Count resources that need update and belong to this user
// needToUpdate() logic: !resourceOffline OR (resourceLocalAddress != null AND _rev != downloadedRev)

// Case 1: Resources that are not offline
val notOfflineCount = realm.where(RealmMyLibrary::class.java)
.equalTo("isPrivate", false)
.equalTo("resourceOffline", false)
.contains("userId", userId)
.count()

// Case 2: Resources that have local address but need update (_rev != downloadedRev)
val needsUpdateCount = realm.where(RealmMyLibrary::class.java)
.equalTo("isPrivate", false)
.equalTo("resourceOffline", true)
.isNotNull("resourceLocalAddress")
.notEqualTo("_rev", "") // Has a revision
.contains("userId", userId)
.findAll()
.count { it._rev != it.downloadedRev } // Only count if revisions don't match

(notOfflineCount + needsUpdateCount).toInt()
}
return filterLibrariesNeedingUpdate(results)
.count { it.userId?.contains(userId) == true }
}

override suspend fun saveLibraryItem(item: RealmMyLibrary) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,14 @@ interface NotificationRepository {
relatedId: String?,
userId: String?,
)
suspend fun createNotificationsIfMissing(
notifications: List<NotificationData>,
userId: String?,
)

data class NotificationData(
val type: String,
val message: String,
val relatedId: String?,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,67 @@ class NotificationRepositoryImpl @Inject constructor(
}
}

override suspend fun createNotificationsIfMissing(
notifications: List<NotificationRepository.NotificationData>,
userId: String?,
) {
val actualUserId = userId ?: ""
if (notifications.isEmpty()) return

val startTime = System.currentTimeMillis()
android.util.Log.d("NotificationRepository", "createNotificationsIfMissing: Starting batch create for ${notifications.size} notifications")

executeTransaction { realm ->
// OPTIMIZATION: Query only UNREAD notifications (old read ones don't matter)
// This is much faster than searching through all historical notifications
val queryStartTime = System.currentTimeMillis()
val existingUnreadNotifications = realm.where(RealmNotification::class.java)
.equalTo("userId", actualUserId)
.equalTo("isRead", false)
.findAll()

android.util.Log.d("NotificationRepository", "createNotificationsIfMissing: Found ${existingUnreadNotifications.size} unread notifications in ${System.currentTimeMillis() - queryStartTime}ms")

// Create a set of existing notification keys for O(1) lookup
val existingKeys = existingUnreadNotifications.mapNotNull { existing ->
if (existing.relatedId != null) {
"${existing.type}:${existing.relatedId}"
} else {
"${existing.type}:null"
}
}.toSet()

val now = Date()
var createdCount = 0
var skippedCount = 0

// Batch create all missing notifications in a single transaction
notifications.forEach { notification ->
val key = if (notification.relatedId != null) {
"${notification.type}:${notification.relatedId}"
} else {
"${notification.type}:null"
}

if (key !in existingKeys) {
realm.createObject(RealmNotification::class.java, UUID.randomUUID().toString()).apply {
this.userId = actualUserId
this.type = notification.type
this.message = notification.message
this.relatedId = notification.relatedId
this.createdAt = now
}
createdCount++
} else {
skippedCount++
}
}

val endTime = System.currentTimeMillis()
android.util.Log.d("NotificationRepository", "createNotificationsIfMissing: Created $createdCount new, skipped $skippedCount existing in ${endTime - startTime}ms total")
}
}

override suspend fun getUnreadCount(userId: String?): Int {
if (userId == null) return 0

Expand Down
Loading