Skip to content

Commit 72db82c

Browse files
Danny Lamartijeffreydelooff
authored andcommitted
Fixes package naming, add ReadableObjectStore and add aggregating functions
1 parent 1da070e commit 72db82c

File tree

6 files changed

+173
-28
lines changed

6 files changed

+173
-28
lines changed

library/src/main/java/nl/elements/objectstore/ObjectStore.kt

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
package nl.elements.objectstore
2+
13
import io.reactivex.Observable
24
import io.reactivex.ObservableSource
35
import io.reactivex.Observer
46
import io.reactivex.subjects.PublishSubject
5-
import nl.elements.objectstore.Converter
6-
import nl.elements.objectstore.Transformer
77
import java.io.ByteArrayOutputStream
88
import java.io.InputStream
99
import java.io.OutputStream
@@ -13,19 +13,13 @@ import java.io.OutputStream
1313
* Supplies a basic abstraction for CRUD operations.
1414
*/
1515

16-
interface ObjectStore : ObservableSource<ObjectStore.Event> {
16+
interface ObjectStore : ReadableObjectStore, ObservableSource<ObjectStore.Event> {
1717

1818
val converter: Converter
1919
val transformer: Transformer
2020

21-
val keys: Set<String>
22-
23-
operator fun <T : Any> get(key: String): T
24-
2521
operator fun set(key: String, value: Any)
2622

27-
operator fun contains(key: String): Boolean
28-
2923
fun remove(key: String)
3024

3125
fun OutputStream.write(key: String, value: Any) =
@@ -61,7 +55,110 @@ interface ObjectStore : ObservableSource<ObjectStore.Event> {
6155

6256
fun ObjectStore.toObservable(): Observable<ObjectStore.Event> = Observable.defer { this }
6357

58+
fun ObjectStore.toReadableObjectStore(): ReadableObjectStore = this
59+
6460
fun ObjectStore.writeToBytes(key: String, value: Any): ByteArray =
6561
ByteArrayOutputStream()
6662
.also { it.write(key, value) }
6763
.toByteArray()
64+
65+
/// Utils for reducing `ObjectStore` which prefixes each key with the given `String` and delimiter
66+
67+
private const val DEFAULT_DELIMITER = ":"
68+
69+
/**
70+
* Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter.
71+
*
72+
* Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter.
73+
*/
74+
75+
fun Array<Pair<String, ObjectStore>>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) =
76+
asSequence().reduceWithNamespace(delimiter)
77+
78+
/**
79+
* Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter.
80+
*
81+
* Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter.
82+
*/
83+
84+
fun Map<String, ObjectStore>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER): ObjectStore =
85+
toList().asSequence().reduceWithNamespace(delimiter)
86+
87+
/**
88+
* Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter.
89+
*
90+
* Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter.
91+
*/
92+
93+
fun Iterable<Pair<String, ObjectStore>>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) =
94+
asSequence().reduceWithNamespace(delimiter)
95+
96+
/**
97+
* Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter.
98+
*
99+
* Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter.
100+
*/
101+
102+
fun Sequence<Pair<String, ObjectStore>>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) =
103+
fold(unknownNamespaceObjectStore()) { next, (prefix, store) ->
104+
store.withNamespace("$prefix$delimiter", next)
105+
}
106+
107+
private fun ObjectStore.withNamespace(namespace: String, next: ObjectStore): ObjectStore =
108+
object : ObjectStore {
109+
110+
val store = this@withNamespace
111+
112+
override val converter: Converter = store.converter
113+
override val transformer: Transformer = store.transformer
114+
override val keys: Set<String>
115+
get() = store.keys.map { namespace + it }.toMutableSet().apply { addAll(next.keys) }
116+
117+
override fun <T : Any> get(key: String): T =
118+
key.removeNamespace()?.let(store::get) ?: next[key]
119+
120+
override fun contains(key: String): Boolean =
121+
key.removeNamespace()?.let(store::contains) ?: next.contains(key)
122+
123+
override fun set(key: String, value: Any) =
124+
key.removeNamespace()?.let { store[it] = value } ?: next.set(key, value)
125+
126+
override fun remove(key: String) = key.removeNamespace()?.let(store::remove) ?: next.remove(key)
127+
128+
override fun subscribe(observer: Observer<in ObjectStore.Event>) =
129+
store
130+
.toObservable()
131+
.map(::prependNamespace)
132+
.let { Observable.merge(it, next) }
133+
.subscribe(observer)
134+
135+
private fun String.removeNamespace(): String? = removePrefix(namespace).takeIf { it != this@removeNamespace }
136+
137+
private fun prependNamespace(event: ObjectStore.Event): ObjectStore.Event =
138+
when (event) {
139+
is ObjectStore.Event.Updated -> ObjectStore.Event.Updated(namespace + event.key)
140+
is ObjectStore.Event.Removed -> ObjectStore.Event.Removed(namespace + event.key)
141+
}
142+
143+
}
144+
145+
private fun unknownNamespaceObjectStore(): ObjectStore = object : ObjectStore {
146+
147+
override val converter: Converter = Converter.DEFAULT
148+
override val transformer: Transformer = Transformer.DEFAULT
149+
override val keys: Set<String> = emptySet()
150+
151+
override fun set(key: String, value: Any) = throw UnknownNamespaceException(key)
152+
153+
override fun remove(key: String) = throw UnknownNamespaceException(key)
154+
155+
override fun <T : Any> get(key: String): T = throw UnknownNamespaceException(key)
156+
157+
override fun contains(key: String): Boolean = throw UnknownNamespaceException(key)
158+
159+
override fun subscribe(observer: Observer<in ObjectStore.Event>) {
160+
}
161+
162+
}
163+
164+
class UnknownNamespaceException internal constructor(key: String) : Exception(key)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package nl.elements.objectstore
2+
3+
interface ReadableObjectStore {
4+
5+
val keys: Set<String>
6+
7+
operator fun <T : Any> get(key: String): T
8+
9+
operator fun contains(key: String): Boolean
10+
11+
}
12+
13+
/// Utils for reducing `ReadableObjectStore`
14+
15+
/**
16+
* Reduces all `ObjectStore`s (in sequence) into one `ObjectStore`.
17+
*/
18+
19+
fun Array<ReadableObjectStore>.reduce() = asSequence().reduce()
20+
21+
/**
22+
* Reduces all `ObjectStore`s (in sequence) into one `ObjectStore`.
23+
*/
24+
25+
fun Iterable<ReadableObjectStore>.reduce() = asSequence().reduce()
26+
27+
/**
28+
* Reduces all `ObjectStore`s (in sequence) into one `ObjectStore`.
29+
*/
30+
31+
fun Sequence<ReadableObjectStore>.reduce(): ReadableObjectStore = reduce(::combine)
32+
33+
34+
/// Utility functions
35+
36+
private fun combine(l: ReadableObjectStore, r: ReadableObjectStore): ReadableObjectStore =
37+
object : ReadableObjectStore {
38+
39+
override val keys: Set<String>
40+
get() = l.keys.toMutableSet().apply { addAll(r.keys) }
41+
42+
override fun <T : Any> get(key: String): T =
43+
when (key) {
44+
in l -> l[key]
45+
else -> r[key]
46+
}
47+
48+
override fun contains(key: String): Boolean = key in l || key in r
49+
50+
}

library/src/main/java/nl/elements/objectstore/stores/DatabaseStore.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package nl.elements.objectstore.stores
22

3-
import ObjectStore
4-
import ObjectStore.Event.Removed
5-
import ObjectStore.Event.Updated
63
import android.content.ContentValues
74
import android.database.Cursor
85
import android.database.sqlite.SQLiteDatabase
96
import android.provider.BaseColumns._ID
107
import nl.elements.objectstore.Converter
8+
import nl.elements.objectstore.ObjectStore
9+
import nl.elements.objectstore.ObjectStore.Event.Removed
10+
import nl.elements.objectstore.ObjectStore.Event.Updated
1111
import nl.elements.objectstore.Transformer
12-
import writeToBytes
12+
import nl.elements.objectstore.writeToBytes
1313

1414
/**
1515
* A store that maintains its own table for storing key-value pairs.
@@ -40,9 +40,7 @@ class DatabaseStore(
4040
)
4141
"""
4242

43-
database
44-
.rawQuery(query, null)
45-
.close()
43+
database.rawQuery(query, null).close()
4644
}
4745

4846
override fun set(key: String, value: Any) {

library/src/main/java/nl/elements/objectstore/stores/DirectoryStore.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package nl.elements.objectstore.stores
22

3-
import ObjectStore
4-
import ObjectStore.Event.Removed
5-
import ObjectStore.Event.Updated
63
import nl.elements.objectstore.Converter
4+
import nl.elements.objectstore.ObjectStore
5+
import nl.elements.objectstore.ObjectStore.Event.Removed
6+
import nl.elements.objectstore.ObjectStore.Event.Updated
77
import nl.elements.objectstore.Transformer
88
import java.io.File
99

library/src/main/java/nl/elements/objectstore/stores/MemoryStore.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package nl.elements.objectstore.stores
22

3-
import ObjectStore
4-
import ObjectStore.Event.Removed
5-
import ObjectStore.Event.Updated
63
import nl.elements.objectstore.Converter
4+
import nl.elements.objectstore.ObjectStore
5+
import nl.elements.objectstore.ObjectStore.Event.*
76
import nl.elements.objectstore.Transformer
8-
import writeToBytes
7+
import nl.elements.objectstore.writeToBytes
98
import java.io.ByteArrayInputStream
109

1110
class MemoryStore(
@@ -20,7 +19,7 @@ class MemoryStore(
2019

2120
override fun <T : Any> get(key: String): T =
2221
synchronized { data[key]!! }
23-
.let(::ByteArrayInputStream)
22+
.inputStream()
2423
.read(key)
2524

2625
override fun set(key: String, value: Any) {

library/src/main/java/nl/elements/objectstore/stores/PreferencesStore.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package nl.elements.objectstore.stores
22

3-
import ObjectStore
4-
import ObjectStore.Event.Removed
5-
import ObjectStore.Event.Updated
3+
64
import android.content.SharedPreferences
75
import io.reactivex.Observable
86
import io.reactivex.disposables.Disposable
97
import nl.elements.objectstore.Converter
8+
import nl.elements.objectstore.ObjectStore
9+
import nl.elements.objectstore.ObjectStore.Event.Removed
10+
import nl.elements.objectstore.ObjectStore.Event.Updated
1011
import nl.elements.objectstore.Transformer
11-
import writeToBytes
12+
import nl.elements.objectstore.writeToBytes
1213

1314
/**
1415
* A store that reads and writes its values from the given `SharedPreferences`. All values are stored as `String`.

0 commit comments

Comments
 (0)