Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit f015f06

Browse files
committed
update api
1 parent 4b989bb commit f015f06

File tree

4 files changed

+61
-114
lines changed

4 files changed

+61
-114
lines changed

sqlite-storage/src/commonMain/kotlin/org/asyncstorage/sqlitestorage/DefaultSqliteStorage.kt

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.asyncstorage.sqlitestorage
22

33
import app.cash.sqldelight.coroutines.asFlow
4+
import app.cash.sqldelight.coroutines.mapToList
45
import app.cash.sqldelight.db.SqlDriver
56
import kotlinx.coroutines.CoroutineDispatcher
67
import kotlinx.coroutines.flow.Flow
@@ -23,33 +24,33 @@ internal class DefaultSqliteStorage(
2324

2425
override suspend fun read(key: Key): Entry =
2526
withContext(dispatcher) {
26-
queries.getOne(key) { k, v -> Entry(k, v) }.executeAsOneOrNull() ?: Entry(key)
27+
queries.getOne(key, ::Entry).executeAsOneOrNull() ?: Entry(key)
2728
}
2829

29-
override fun readAsFlow(key: Key): Flow<Entry> {
30-
return queries.getOne(key) { k, v -> Entry(k, v) }
31-
.asFlow()
32-
.map { q ->
33-
q.executeAsOneOrNull() ?: Entry(key)
30+
override suspend fun readMany(keys: List<Key>): List<Entry> =
31+
withContext(dispatcher) {
32+
val found = queries.getMany(keys, ::Entry).executeAsList()
33+
keys.map { key ->
34+
found.find { it.key == key } ?: Entry(key)
3435
}
36+
}
37+
38+
override fun readAsFlow(keys: List<Key>): Flow<List<Entry>> {
39+
return queries.getMany(keys, ::Entry)
40+
.asFlow()
41+
.mapToList(dispatcher)
3542
}
3643

3744
override suspend fun write(entry: Entry) =
3845
withContext(dispatcher) {
3946
queries.insertOne(entry.key, entry.value)
4047
}
4148

42-
override suspend fun merge(entry: Entry) =
49+
override suspend fun writeMany(entries: List<Entry>) =
4350
withContext(dispatcher) {
44-
queries.transactionWithResult {
45-
val current = queries.getOne(entry.key).executeAsOneOrNull()
46-
if (current == null) {
51+
queries.transaction {
52+
entries.forEach { entry ->
4753
queries.insertOne(entry.key, entry.value)
48-
return@transactionWithResult entry
49-
} else {
50-
val merged = mergePossibleJsonValues(current.value_, entry.value)
51-
queries.insertOne(entry.key, merged)
52-
return@transactionWithResult Entry(entry.key, merged)
5354
}
5455
}
5556
}
@@ -59,30 +60,23 @@ internal class DefaultSqliteStorage(
5960
queries.deleteOne(key)
6061
}
6162

62-
override suspend fun readMany(keys: List<Key>): List<Entry> =
63+
override suspend fun removeMany(keys: List<Key>) =
6364
withContext(dispatcher) {
64-
val found = queries.getMany(keys) { k, v -> Entry(k, v) }.executeAsList()
65-
keys.map { key ->
66-
found.find { it.key == key } ?: Entry(key)
67-
}
65+
queries.deleteMany(keys)
6866
}
6967

70-
override fun readManyAsFlow(keys: List<Key>): Flow<List<Entry>> {
71-
return queries.getMany(keys) { k, v -> Entry(k, v) }
72-
.asFlow()
73-
.map { q ->
74-
val found = q.executeAsList()
75-
keys.map { key ->
76-
found.find { it.key == key } ?: Entry(key)
77-
}
78-
}
79-
}
8068

81-
override suspend fun writeMany(entries: List<Entry>) =
69+
override suspend fun merge(entry: Entry) =
8270
withContext(dispatcher) {
83-
queries.transaction {
84-
entries.forEach { entry ->
71+
queries.transactionWithResult {
72+
val current = queries.getOne(entry.key).executeAsOneOrNull()
73+
if (current == null) {
8574
queries.insertOne(entry.key, entry.value)
75+
return@transactionWithResult entry
76+
} else {
77+
val merged = mergePossibleJsonValues(current.value_, entry.value)
78+
queries.insertOne(entry.key, merged)
79+
return@transactionWithResult Entry(entry.key, merged)
8680
}
8781
}
8882
}
@@ -106,29 +100,24 @@ internal class DefaultSqliteStorage(
106100
}
107101
}
108102

109-
override suspend fun removeMany(keys: List<Key>) =
110-
withContext(dispatcher) {
111-
queries.deleteMany(keys)
112-
}
113-
114-
override suspend fun clear() =
115-
withContext(dispatcher) {
116-
queries.deleteAll()
117-
}
118-
119-
override suspend fun getKeys(): List<Key> =
103+
override suspend fun readKeys(): List<Key> =
120104
withContext(dispatcher) {
121105
queries.getAllKeys().executeAsList()
122106
}
123107

124-
override fun getKeysAsFlow(): Flow<List<Key>> {
108+
override fun readKeysAsFlow(): Flow<List<Key>> {
125109
return queries.getAllKeys()
126110
.asFlow()
127111
.map { q ->
128112
q.executeAsList()
129113
}
130114
}
131115

116+
override suspend fun clear() =
117+
withContext(dispatcher) {
118+
queries.deleteAll()
119+
}
120+
132121
override suspend fun closeConnection() =
133122
withContext(dispatcher) {
134123
driver.executePragmaOptimize()

sqlite-storage/src/commonMain/kotlin/org/asyncstorage/sqlitestorage/SqliteStorage.kt

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@ interface SqliteStorage {
1919
suspend fun read(key: Key): Entry
2020

2121
/**
22-
* Equivalent to [read] function, but returns a flow of Entry instead.
22+
* Returns a list of entries that match given key list.
23+
* If an entry is not found for selected key, the returned Entry will have `null` value.
2324
* Throws if DB connection is closed.
2425
*/
2526
@Throws(Throwable::class)
26-
fun readAsFlow(key: Key): Flow<Entry>
27+
suspend fun readMany(keys: List<Key>): List<Entry>
28+
29+
/**
30+
* Equivalent to [readMany] function, but returns a Flow of List of entries instead.
31+
* Throws if DB connection is closed.
32+
*/
33+
@Throws(Throwable::class)
34+
fun readAsFlow(keys: List<Key>): Flow<List<Entry>>
2735

2836
/**
2937
* Writes a single entry to database.
@@ -34,13 +42,12 @@ interface SqliteStorage {
3442
suspend fun write(entry: Entry)
3543

3644
/**
37-
* Merges given entry's value with stored entry, based on Merger Algorithm.
38-
* Creates the entry if not existing.
39-
* Returns merged entry.
45+
* Stores multiple entries in one transaction.
46+
* If an entry for matching key already exists, it will be overridden with new value.
4047
* Throws if DB connection is closed.
4148
*/
4249
@Throws(Throwable::class)
43-
suspend fun merge(entry: Entry): Entry
50+
suspend fun writeMany(entries: List<Entry>)
4451

4552
/**
4653
* Removes a single entry based on provided key.
@@ -51,27 +58,20 @@ interface SqliteStorage {
5158
suspend fun remove(key: Key)
5259

5360
/**
54-
* Returns a list of entries that match given key list.
55-
* If an entry is not found for selected key, the returned Entry will have `null` value.
56-
* Throws if DB connection is closed.
57-
*/
58-
@Throws(Throwable::class)
59-
suspend fun readMany(keys: List<Key>): List<Entry>
60-
61-
/**
62-
* Equivalent to [readMany] function, but returns a Flow of List of entries instead.
61+
* Removes multiple entries that match Key in provided key list.
6362
* Throws if DB connection is closed.
6463
*/
6564
@Throws(Throwable::class)
66-
fun readManyAsFlow(keys: List<Key>): Flow<List<Entry>>
65+
suspend fun removeMany(keys: List<Key>)
6766

6867
/**
69-
* Stores multiple entries in one transaction.
70-
* If an entry for matching key already exists, it will be overridden with new value.
68+
* Merges given entry's value with stored entry, based on Merger Algorithm.
69+
* Creates the entry if not existing.
70+
* Returns merged entry.
7171
* Throws if DB connection is closed.
7272
*/
7373
@Throws(Throwable::class)
74-
suspend fun writeMany(entries: List<Entry>)
74+
suspend fun merge(entry: Entry): Entry
7575

7676
/**
7777
* Merged multiple entries, with entries already existing.
@@ -82,26 +82,19 @@ interface SqliteStorage {
8282
@Throws(Throwable::class)
8383
suspend fun mergeMany(entries: List<Entry>): List<Entry>
8484

85-
/**
86-
* Removes multiple entries that match Key in provided key list.
87-
* Throws if DB connection is closed.
88-
*/
89-
@Throws(Throwable::class)
90-
suspend fun removeMany(keys: List<Key>)
91-
9285
/**
9386
* Returns a list of all Keys stored in db.
9487
* Throws if DB connection is closed.
9588
*/
9689
@Throws(Throwable::class)
97-
suspend fun getKeys(): List<Key>
90+
suspend fun readKeys(): List<Key>
9891

9992
/**
100-
* Equivalent to [getKeys], but returns a Flow of List of keys instead.
93+
* Equivalent to [readKeys], but returns a Flow of List of keys instead.
10194
* Throws if DB connection is closed.
10295
*/
10396
@Throws(Throwable::class)
104-
fun getKeysAsFlow(): Flow<List<Key>>
97+
fun readKeysAsFlow(): Flow<List<Key>>
10598

10699
/**
107100
* Clears every Entry from the database, effectively bringing it to empty state.

sqlite-storage/src/commonTest/kotlin/org/asyncstorage/sqlitestorage/SqliteStorageTest.kt

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -129,35 +129,6 @@ class SqliteStorageTest {
129129
savedEntries.forEach { assertNull(it.value, "Entry ${it.key} should cleared") }
130130
}
131131

132-
@Test
133-
fun reads_entry_on_change_as_flow() =
134-
runTest { db ->
135-
val entry = Entry("key1", "value123")
136-
137-
db.readAsFlow(entry.key).test {
138-
skipItems(1) // skip initial emit, where value is null
139-
db.write(entry)
140-
assertEquals(
141-
entry,
142-
awaitItem(),
143-
"entry item is different then emitted one",
144-
)
145-
val copy = entry.copy(value = "987entry")
146-
db.write(copy)
147-
assertEquals(
148-
copy,
149-
awaitItem(),
150-
"copied item is different than emitted",
151-
)
152-
db.write(Entry("different"))
153-
assertEquals(
154-
copy,
155-
awaitItem(),
156-
"copy value is changed after writing different value",
157-
)
158-
}
159-
}
160-
161132
@Test
162133
fun reads_many_entries_on_change_as_flow() =
163134
runTest { db ->
@@ -167,7 +138,7 @@ class SqliteStorageTest {
167138
Entry("2", "value2"),
168139
)
169140

170-
db.readManyAsFlow(entries.map { it.key }).test {
141+
db.readAsFlow(entries.map { it.key }).test {
171142
skipItems(1) // skip first where items are not available
172143
db.writeMany(entries)
173144
assertEquals(
@@ -197,7 +168,7 @@ class SqliteStorageTest {
197168
Entry("3", "entry_value_3"),
198169
Entry("4", "entry_value_4"),
199170
)
200-
db.getKeysAsFlow().test {
171+
db.readKeysAsFlow().test {
201172
skipItems(1) // skip first emit where default null values are emitted
202173
db.writeMany(entryList)
203174
assertEquals(

sqlite-storage/src/schema/org/asyncstorage/sqlitestorage/db/async_storage_entries.sq

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ CREATE TABLE async_storage_entries (
33
value TEXT
44
);
55

6-
7-
-- This statement causes Android driver to crash, therefore it needs to be executed on driver,
8-
-- before any other sql statement
9-
-- PRAGMA journal_mode=WAL;
10-
11-
-- Single entry operations
126
insertOne:
137
INSERT OR REPLACE INTO async_storage_entries (key, value) VALUES (:key, :value);
148

@@ -18,10 +12,10 @@ SELECT key, value FROM async_storage_entries WHERE key = :key;
1812
deleteOne:
1913
DELETE FROM async_storage_entries WHERE key = :key;
2014

21-
-- Batch insert will be supported in SQLDelight v2, for now, transaction will be used
22-
-- https://github.com/cashapp/sqldelight/discussions/2802
15+
-- Need to wait for batch operation support
16+
-- https://github.com/cashapp/sqldelight/issues/3260
2317
-- insertMany {
24-
-- UPDATE async_storage_entries
18+
-- UPDATE async_storage_entries SET key = ?
2519
-- }
2620

2721
getMany:

0 commit comments

Comments
 (0)