Skip to content

Commit cf86924

Browse files
committed
fix(async-storage): always return what requested
1 parent 21f2a8a commit cf86924

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

shared-storage/src/commonMain/kotlin/org/asyncstorage/shared_storage/SharedStorageImpl.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import org.asyncstorage.shared_storage.database.StorageEntry
1111
/**
1212
* Default implementation of [SharedStorage] interface.
1313
*
14+
* Storage always returns entries that were requested - if requested `key` is not in database
15+
* the result is not omitted and Entry(`key`, null) is returned.
16+
*
1417
* Note about [getValuesFlow]: Since SQLite database trigger notifications only on table level, not
1518
* row level, non-observed requested keys will trigger emits. Therefor, flow returned has
1619
* .distinctUntilChanged to mimic row level update.
@@ -26,19 +29,19 @@ internal class SharedStorageImpl(val database: StorageDatabase, files: DatabaseF
2629
}
2730

2831
override suspend fun getValues(keys: List<String>): List<Entry> =
29-
catchStorageException(log) { storage.getValues(keys).map(StorageEntry::toEntry) }
32+
catchStorageException(log) { storage.getValues(keys).toRequestedEntry(keys) }
3033

3134
override fun getValuesFlow(keys: List<String>): Flow<List<Entry>> =
3235
storage
3336
.getValuesFlow(keys)
34-
.map { list -> list.map(StorageEntry::toEntry) }
37+
.map { list -> list.toRequestedEntry(keys) }
3538
.distinctUntilChanged()
3639
.catchStorageException(log)
3740

3841
override suspend fun setValues(entries: List<Entry>): List<Entry> =
3942
catchStorageException(log) {
4043
val values = entries.map(Entry::toStorageEntry)
41-
storage.setValuesAndGet(values).map(StorageEntry::toEntry)
44+
storage.setValuesAndGet(values).toRequestedEntry(entries.map { it.key })
4245
}
4346

4447
override suspend fun removeValues(keys: List<String>) =
@@ -50,4 +53,13 @@ internal class SharedStorageImpl(val database: StorageDatabase, files: DatabaseF
5053
storage.getKeysFlow().catchStorageException(log)
5154

5255
override suspend fun clear() = catchStorageException(log) { storage.clear() }
56+
57+
58+
private fun List<StorageEntry>.toRequestedEntry(keys: List<String>): List<Entry> {
59+
val lookup = associateBy { it.key }
60+
return keys.map { key ->
61+
lookup[key]?.toEntry() ?: Entry(key, null)
62+
}
63+
}
64+
5365
}

shared-storage/src/commonTest/kotlin/tests/StorageTests.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,28 @@ class SharedStorageTest : TestRunner() {
176176
assertEquals(0, awaitItem().size)
177177
}
178178
}
179+
180+
@Test
181+
fun `returns requested values, even if not existing`() = runTest {
182+
val entry1 = Entry("key1", "value1")
183+
val result = storage.setValues(listOf(entry1))
184+
assertEquals(entry1, result.first())
185+
186+
187+
val entries = storage.getValues(listOf("key1", "key2", "key3")).sortedBy { it.key }
188+
189+
assertEquals(3, entries.size)
190+
191+
assertContentEquals(
192+
listOf(entry1, Entry("key2", null), Entry("key3", null)).sortedBy { it.key },
193+
entries
194+
)
195+
196+
197+
assertContentEquals(
198+
listOf(Entry("non-existing", null), Entry("another-null", null)),
199+
storage.getValues(listOf("non-existing", "another-null"))
200+
)
201+
202+
}
179203
}

0 commit comments

Comments
 (0)