diff --git a/build.gradle b/build.gradle index c4adb6a..35dd69b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,19 +1,21 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.31' + ext.kotlin_version = '1.3.41' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.0' + classpath 'com.android.tools.build:gradle:3.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.novoda:bintray-release:0.9.1' } } +version = '0.9.0' + allprojects { repositories { google() diff --git a/library-android/.gitignore b/library-android/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/library-android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library-android/build.gradle b/library-android/build.gradle new file mode 100644 index 0000000..53b1325 --- /dev/null +++ b/library-android/build.gradle @@ -0,0 +1,57 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'com.novoda.bintray-release' + +android { + compileSdkVersion 28 + + defaultConfig { + versionCode 1 + versionName rootProject.version + minSdkVersion 14 + targetSdkVersion 28 + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } +} + +dependencies { + implementation project(':library') + implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + implementation "io.reactivex.rxjava2:rxjava:2.2.10" + implementation 'com.facebook.conceal:conceal:2.0.2' + + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.core:core-ktx:1.0.2' +} + +dependencies { + androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + androidTestImplementation "androidx.test:core:1.2.0" + androidTestImplementation "androidx.test:runner:1.2.0" + androidTestImplementation "androidx.test:rules:1.2.0" + androidTestImplementation "androidx.test.ext:junit-ktx:1.1.1" + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' +} + +def properties = project.rootProject.file('local.properties').withDataInputStream { stream -> + def props = new Properties() + props.load(stream) + props +} + +publish { + userOrg 'elementsinteractive' + groupId 'nl.elements.objectstore.android' + artifactId 'objectstore-android' + publishVersion rootProject.version + uploadName 'ObjectStore Android' + desc 'Android specific implementations for ObjectStore' + website 'https://github.com/elementsinteractive/ObjectStore' + + bintrayUser properties['BINTRAY_USER'] + bintrayKey properties['BINTRAY_KEY'] + + dryRun false + override true +} diff --git a/library/proguard-rules.pro b/library-android/proguard-rules.pro similarity index 100% rename from library/proguard-rules.pro rename to library-android/proguard-rules.pro diff --git a/library/src/androidTest/java/nl/elements/objectstore/PreferencesStoreTest.kt b/library-android/src/androidTest/java/nl/elements/objectstore/android/PreferencesStoreTest.kt similarity index 94% rename from library/src/androidTest/java/nl/elements/objectstore/PreferencesStoreTest.kt rename to library-android/src/androidTest/java/nl/elements/objectstore/android/PreferencesStoreTest.kt index e5a0aa8..3de922a 100644 --- a/library/src/androidTest/java/nl/elements/objectstore/PreferencesStoreTest.kt +++ b/library-android/src/androidTest/java/nl/elements/objectstore/android/PreferencesStoreTest.kt @@ -1,8 +1,9 @@ -package nl.elements.objectstore +package nl.elements.objectstore.android import android.content.Context import androidx.test.platform.app.InstrumentationRegistry -import nl.elements.objectstore.stores.PreferencesStore +import nl.elements.objectstore.ObjectStore +import nl.elements.objectstore.android.stores.PreferencesStore import org.junit.After import org.junit.Before import org.junit.Test diff --git a/library-android/src/main/AndroidManifest.xml b/library-android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8aa395b --- /dev/null +++ b/library-android/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/library/src/main/java/nl/elements/objectstore/stores/DatabaseStore.kt b/library-android/src/main/java/nl/elements/objectstore/android/stores/DatabaseStore.kt similarity index 98% rename from library/src/main/java/nl/elements/objectstore/stores/DatabaseStore.kt rename to library-android/src/main/java/nl/elements/objectstore/android/stores/DatabaseStore.kt index 2840922..1090c5b 100644 --- a/library/src/main/java/nl/elements/objectstore/stores/DatabaseStore.kt +++ b/library-android/src/main/java/nl/elements/objectstore/android/stores/DatabaseStore.kt @@ -1,4 +1,4 @@ -package nl.elements.objectstore.stores +package nl.elements.objectstore.android.stores import android.content.ContentValues import android.database.Cursor diff --git a/library/src/main/java/nl/elements/objectstore/stores/PreferencesStore.kt b/library-android/src/main/java/nl/elements/objectstore/android/stores/PreferencesStore.kt similarity index 94% rename from library/src/main/java/nl/elements/objectstore/stores/PreferencesStore.kt rename to library-android/src/main/java/nl/elements/objectstore/android/stores/PreferencesStore.kt index 5045807..d7c8fc9 100644 --- a/library/src/main/java/nl/elements/objectstore/stores/PreferencesStore.kt +++ b/library-android/src/main/java/nl/elements/objectstore/android/stores/PreferencesStore.kt @@ -1,4 +1,4 @@ -package nl.elements.objectstore.stores +package nl.elements.objectstore.android.stores import android.content.SharedPreferences import android.util.Base64 @@ -117,10 +117,11 @@ private class StorePreferencesEditor( override fun putFloat(key: String?, value: Float): SharedPreferences.Editor = put(key, value) - override fun putString(key: String?, value: String?): SharedPreferences.Editor = put(key, value) + override fun putString(key: String?, value: String?): SharedPreferences.Editor = put(key, value!!) - override fun putStringSet(key: String?, values: MutableSet?): SharedPreferences.Editor = put(key, values) + override fun putStringSet(key: String?, values: MutableSet?): SharedPreferences.Editor = + put(key, values ?: emptySet()) - private fun put(key: String?, value: T) = apply { key?.let { store[key] = value!! } } + private fun put(key: String?, value: T) = apply { key?.let { store[it] = value } } } diff --git a/library/src/main/java/nl/elements/objectstore/transformers/ConcealTransformer.kt b/library-android/src/main/java/nl/elements/objectstore/android/transformers/ConcealTransformer.kt similarity index 91% rename from library/src/main/java/nl/elements/objectstore/transformers/ConcealTransformer.kt rename to library-android/src/main/java/nl/elements/objectstore/android/transformers/ConcealTransformer.kt index 10b8801..5014f47 100644 --- a/library/src/main/java/nl/elements/objectstore/transformers/ConcealTransformer.kt +++ b/library-android/src/main/java/nl/elements/objectstore/android/transformers/ConcealTransformer.kt @@ -1,4 +1,4 @@ -package nl.elements.objectstore.transformers +package nl.elements.objectstore.android.transformers import com.facebook.crypto.Crypto import com.facebook.crypto.Entity @@ -18,4 +18,4 @@ class ConcealTransformer(private val crypto: Crypto) : Transformer { .encrypt(input.readBytes(), Entity.create(key)) .let(output::write) -} \ No newline at end of file +} diff --git a/library/src/main/res/drawable-v24/ic_launcher_foreground.xml b/library-android/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from library/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to library-android/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/library/src/main/res/drawable/ic_launcher_background.xml b/library-android/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from library/src/main/res/drawable/ic_launcher_background.xml rename to library-android/src/main/res/drawable/ic_launcher_background.xml diff --git a/library/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/library-android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from library/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to library-android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/library/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/library-android/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from library/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to library-android/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/library/src/main/res/mipmap-hdpi/ic_launcher.png b/library-android/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from library/src/main/res/mipmap-hdpi/ic_launcher.png rename to library-android/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/library/src/main/res/mipmap-hdpi/ic_launcher_round.png b/library-android/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from library/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to library-android/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/library/src/main/res/mipmap-mdpi/ic_launcher.png b/library-android/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from library/src/main/res/mipmap-mdpi/ic_launcher.png rename to library-android/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/library/src/main/res/mipmap-mdpi/ic_launcher_round.png b/library-android/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from library/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to library-android/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/library/src/main/res/mipmap-xhdpi/ic_launcher.png b/library-android/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from library/src/main/res/mipmap-xhdpi/ic_launcher.png rename to library-android/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/library/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/library-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from library/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to library-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/library/src/main/res/mipmap-xxhdpi/ic_launcher.png b/library-android/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from library/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to library-android/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/library/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/library-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from library/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to library-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/library/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/library-android/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from library/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to library-android/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/library/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/library-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from library/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to library-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/library/src/main/res/values/colors.xml b/library-android/src/main/res/values/colors.xml similarity index 100% rename from library/src/main/res/values/colors.xml rename to library-android/src/main/res/values/colors.xml diff --git a/library/src/main/res/values/strings.xml b/library-android/src/main/res/values/strings.xml similarity index 100% rename from library/src/main/res/values/strings.xml rename to library-android/src/main/res/values/strings.xml diff --git a/library/src/main/res/values/styles.xml b/library-android/src/main/res/values/styles.xml similarity index 100% rename from library/src/main/res/values/styles.xml rename to library-android/src/main/res/values/styles.xml diff --git a/library/src/test/java/nl/elements/objectstore/readme.kt b/library-android/src/test/java/nl/elements/objectstore/android/readme.kt similarity index 91% rename from library/src/test/java/nl/elements/objectstore/readme.kt rename to library-android/src/test/java/nl/elements/objectstore/android/readme.kt index cf13958..177ae57 100644 --- a/library/src/test/java/nl/elements/objectstore/readme.kt +++ b/library-android/src/test/java/nl/elements/objectstore/android/readme.kt @@ -1,4 +1,4 @@ -package nl.elements.objectstore +package nl.elements.objectstore.android import android.content.Context import android.content.SharedPreferences @@ -6,11 +6,11 @@ import android.graphics.Bitmap import com.facebook.android.crypto.keychain.AndroidConceal import com.facebook.android.crypto.keychain.SharedPrefsBackedKeyChain import com.facebook.crypto.CryptoConfig +import nl.elements.objectstore.* import nl.elements.objectstore.stores.DirectoryStore -import nl.elements.objectstore.stores.PreferencesStore -import nl.elements.objectstore.transformers.ConcealTransformer +import nl.elements.objectstore.android.stores.PreferencesStore +import nl.elements.objectstore.android.transformers.ConcealTransformer import java.io.File -import java.util.prefs.Preferences fun example(store: ObjectStore) { if ("id" !in store) diff --git a/library/build.gradle b/library/build.gradle index 8571963..d2606d0 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,42 +1,15 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' +apply plugin: 'java-library' +apply plugin: 'kotlin' apply plugin: 'com.novoda.bintray-release' -android { - compileSdkVersion 28 - - defaultConfig { - versionCode 1 - versionName '0.9.0' - minSdkVersion 14 - targetSdkVersion 28 - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } -} - dependencies { - implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' - implementation "io.reactivex.rxjava2:rxjava:2.2.9" - implementation 'com.facebook.conceal:conceal:2.0.2' - - implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.core:core-ktx:1.0.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "io.reactivex.rxjava2:rxjava:2.2.10" } dependencies { testImplementation 'junit:junit:4.12' - testImplementation "androidx.test:core:1.2.0" - testImplementation "org.jetbrains.kotlin:kotlin-test:1.3.31" - testImplementation "androidx.test.ext:junit-ktx:1.1.1" - - androidTestImplementation "org.jetbrains.kotlin:kotlin-test:1.3.31" - - androidTestImplementation "androidx.test:core:1.2.0" - androidTestImplementation "androidx.test:runner:1.2.0" - androidTestImplementation "androidx.test:rules:1.2.0" - androidTestImplementation "androidx.test.ext:junit-ktx:1.1.1" - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" } def properties = project.rootProject.file('local.properties').withDataInputStream { stream -> @@ -49,7 +22,7 @@ publish { userOrg 'elementsinteractive' groupId 'nl.elements.objectstore' artifactId 'objectstore' - publishVersion android.defaultConfig.versionName + publishVersion rootProject.version uploadName 'ObjectStore' desc 'Convenient interface for persisting objects.' website 'https://github.com/elementsinteractive/ObjectStore' @@ -60,3 +33,7 @@ publish { dryRun false override true } + + +sourceCompatibility = "7" +targetCompatibility = "7" diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml deleted file mode 100644 index 6e56dd9..0000000 --- a/library/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/library/src/main/java/nl/elements/objectstore/ObjectStore+utils.kt b/library/src/main/java/nl/elements/objectstore/ObjectStore+utils.kt new file mode 100644 index 0000000..2fc0ef8 --- /dev/null +++ b/library/src/main/java/nl/elements/objectstore/ObjectStore+utils.kt @@ -0,0 +1,44 @@ +package nl.elements.objectstore + +import nl.elements.objectstore.utils.unknownNamespaceObjectStore +import nl.elements.objectstore.utils.withNamespace + +private const val DEFAULT_DELIMITER = ":" + +/** + * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. + * + * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. + */ + +fun Array>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) = + asSequence().reduceWithNamespace(delimiter) + +/** + * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. + * + * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. + */ + +fun Map.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER): ObjectStore = + toList().asSequence().reduceWithNamespace(delimiter) + +/** + * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. + * + * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. + */ + +fun Iterable>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) = + asSequence().reduceWithNamespace(delimiter) + +/** + * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. + * + * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. + */ + +fun Sequence>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) = + fold(unknownNamespaceObjectStore) { next, (prefix, store) -> + store.withNamespace("$prefix$delimiter", next) + } diff --git a/library/src/main/java/nl/elements/objectstore/ObjectStore.kt b/library/src/main/java/nl/elements/objectstore/ObjectStore.kt index 8003ec5..f093367 100644 --- a/library/src/main/java/nl/elements/objectstore/ObjectStore.kt +++ b/library/src/main/java/nl/elements/objectstore/ObjectStore.kt @@ -4,6 +4,9 @@ import io.reactivex.Observable import io.reactivex.ObservableSource import io.reactivex.Observer import io.reactivex.subjects.PublishSubject +import nl.elements.objectstore.utils.UnknownNamespaceObjectStore +import nl.elements.objectstore.utils.unknownNamespaceObjectStore +import nl.elements.objectstore.utils.withNamespace import java.io.ByteArrayOutputStream import java.io.InputStream import java.io.OutputStream @@ -61,104 +64,3 @@ fun ObjectStore.writeToBytes(key: String, value: Any): ByteArray = ByteArrayOutputStream() .also { it.write(key, value) } .toByteArray() - -/// Utils for reducing `ObjectStore` which prefixes each key with the given `String` and delimiter - -private const val DEFAULT_DELIMITER = ":" - -/** - * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. - * - * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. - */ - -fun Array>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) = - asSequence().reduceWithNamespace(delimiter) - -/** - * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. - * - * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. - */ - -fun Map.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER): ObjectStore = - toList().asSequence().reduceWithNamespace(delimiter) - -/** - * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. - * - * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. - */ - -fun Iterable>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) = - asSequence().reduceWithNamespace(delimiter) - -/** - * Reduces all `ObjectStore`s (in sequence) into one store. Each `ObjectStore` his keys get prefixed with the given `Pair.first` and delimiter. - * - * Although it is not forbidden, it is not advised to have the `Pair.first` contain the delimiter. - */ - -fun Sequence>.reduceWithNamespace(delimiter: String = DEFAULT_DELIMITER) = - fold(unknownNamespaceObjectStore()) { next, (prefix, store) -> - store.withNamespace("$prefix$delimiter", next) - } - -private fun ObjectStore.withNamespace(namespace: String, next: ObjectStore): ObjectStore = - object : ObjectStore { - - val store = this@withNamespace - - override val converter: Converter = store.converter - override val transformer: Transformer = store.transformer - override val keys: Set - get() = store.keys.map { namespace + it }.toMutableSet().apply { addAll(next.keys) } - - override fun get(key: String): T = - key.removeNamespace()?.let(store::get) ?: next[key] - - override fun contains(key: String): Boolean = - key.removeNamespace()?.let(store::contains) ?: next.contains(key) - - override fun set(key: String, value: Any) = - key.removeNamespace()?.let { store[it] = value } ?: next.set(key, value) - - override fun remove(key: String) = key.removeNamespace()?.let(store::remove) ?: next.remove(key) - - override fun subscribe(observer: Observer) = - store - .toObservable() - .map(::prependNamespace) - .let { Observable.merge(it, next) } - .subscribe(observer) - - private fun String.removeNamespace(): String? = removePrefix(namespace).takeIf { it != this@removeNamespace } - - private fun prependNamespace(event: ObjectStore.Event): ObjectStore.Event = - when (event) { - is ObjectStore.Event.Updated -> ObjectStore.Event.Updated(namespace + event.key) - is ObjectStore.Event.Removed -> ObjectStore.Event.Removed(namespace + event.key) - } - - } - -private fun unknownNamespaceObjectStore(): ObjectStore = object : ObjectStore { - - override val converter: Converter = Converter.DEFAULT - override val transformer: Transformer = Transformer.DEFAULT - override val keys: Set = emptySet() - - override fun set(key: String, value: Any) = throw UnknownNamespaceException(key) - - override fun remove(key: String) = throw UnknownNamespaceException(key) - - override fun get(key: String): T = throw UnknownNamespaceException(key) - - override fun contains(key: String): Boolean = throw UnknownNamespaceException(key) - - override fun subscribe(observer: Observer) { - } - -} - -class UnknownNamespaceException internal constructor(key: String) : Exception(key) diff --git a/library/src/main/java/nl/elements/objectstore/ReadableObjectStore.kt b/library/src/main/java/nl/elements/objectstore/ReadableObjectStore.kt index f5870bb..b03fd29 100644 --- a/library/src/main/java/nl/elements/objectstore/ReadableObjectStore.kt +++ b/library/src/main/java/nl/elements/objectstore/ReadableObjectStore.kt @@ -9,42 +9,3 @@ interface ReadableObjectStore { operator fun contains(key: String): Boolean } - -/// Utils for reducing `ReadableObjectStore` - -/** - * Reduces all `ObjectStore`s (in sequence) into one `ObjectStore`. - */ - -fun Array.reduce() = asSequence().reduce() - -/** - * Reduces all `ObjectStore`s (in sequence) into one `ObjectStore`. - */ - -fun Iterable.reduce() = asSequence().reduce() - -/** - * Reduces all `ObjectStore`s (in sequence) into one `ObjectStore`. - */ - -fun Sequence.reduce(): ReadableObjectStore = reduce(::combine) - - -/// Utility functions - -private fun combine(l: ReadableObjectStore, r: ReadableObjectStore): ReadableObjectStore = - object : ReadableObjectStore { - - override val keys: Set - get() = l.keys.toMutableSet().apply { addAll(r.keys) } - - override fun get(key: String): T = - when (key) { - in l -> l[key] - else -> r[key] - } - - override fun contains(key: String): Boolean = key in l || key in r - - } diff --git a/library/src/main/java/nl/elements/objectstore/stores/DirectoryStore.kt b/library/src/main/java/nl/elements/objectstore/stores/DirectoryStore.kt index d0fc1cc..5548a9f 100644 --- a/library/src/main/java/nl/elements/objectstore/stores/DirectoryStore.kt +++ b/library/src/main/java/nl/elements/objectstore/stores/DirectoryStore.kt @@ -22,7 +22,7 @@ class DirectoryStore( } override val keys: Set - get() = directory.list().toSet() + get() = directory.list()!!.toSet() override fun set(key: String, value: Any) { fileOf(key) @@ -41,7 +41,7 @@ class DirectoryStore( override fun contains(key: String): Boolean = directory - .list { _, name -> name == key } + .list { _, name -> name == key }!! .isNotEmpty() override fun remove(key: String) { diff --git a/library/src/main/java/nl/elements/objectstore/utils/NamespaceObjectStore.kt b/library/src/main/java/nl/elements/objectstore/utils/NamespaceObjectStore.kt new file mode 100644 index 0000000..29f37f1 --- /dev/null +++ b/library/src/main/java/nl/elements/objectstore/utils/NamespaceObjectStore.kt @@ -0,0 +1,50 @@ +package nl.elements.objectstore.utils + +import io.reactivex.Observable +import io.reactivex.Observer +import nl.elements.objectstore.Converter +import nl.elements.objectstore.ObjectStore +import nl.elements.objectstore.Transformer +import nl.elements.objectstore.toObservable + +internal fun ObjectStore.withNamespace(namespace: String, next: ObjectStore): ObjectStore = + NamespaceStore(this, namespace, next) + +internal class NamespaceStore( + private val store: ObjectStore, + private val namespace: String, + private val next: ObjectStore +) : ObjectStore { + + override val converter: Converter = store.converter + override val transformer: Transformer = store.transformer + override val keys: Set + get() = store.keys.map { namespace + it }.toMutableSet().apply { addAll(next.keys) } + + override fun get(key: String): T = + key.removeNamespace()?.let(store::get) ?: next[key] + + override fun contains(key: String): Boolean = + key.removeNamespace()?.let(store::contains) ?: next.contains(key) + + override fun set(key: String, value: Any) = + key.removeNamespace()?.let { store[it] = value } ?: next.set(key, value) + + override fun remove(key: String) = key.removeNamespace()?.let(store::remove) ?: next.remove(key) + + override fun subscribe(observer: Observer) = + store + .toObservable() + .map(::prependNamespace) + .let { Observable.merge(it, next) } + .subscribe(observer) + + private fun String.removeNamespace(): String? = removePrefix(namespace).takeIf { it != this@removeNamespace } + + private fun prependNamespace(event: ObjectStore.Event): ObjectStore.Event = + when (event) { + is ObjectStore.Event.Updated -> ObjectStore.Event.Updated(namespace + event.key) + is ObjectStore.Event.Removed -> ObjectStore.Event.Removed(namespace + event.key) + } + +} diff --git a/library/src/main/java/nl/elements/objectstore/utils/UnknownNamespaceObjectStore.kt b/library/src/main/java/nl/elements/objectstore/utils/UnknownNamespaceObjectStore.kt new file mode 100644 index 0000000..dd09482 --- /dev/null +++ b/library/src/main/java/nl/elements/objectstore/utils/UnknownNamespaceObjectStore.kt @@ -0,0 +1,31 @@ +package nl.elements.objectstore.utils + +import io.reactivex.Observer +import nl.elements.objectstore.Converter +import nl.elements.objectstore.ObjectStore +import nl.elements.objectstore.Transformer + + +internal val unknownNamespaceObjectStore: ObjectStore = UnknownNamespaceObjectStore + +internal object UnknownNamespaceObjectStore : ObjectStore { + + override val converter: Converter = Converter.DEFAULT + override val transformer: Transformer = + Transformer.DEFAULT + override val keys: Set = emptySet() + + override fun set(key: String, value: Any) = throw UnknownNamespaceException(key) + + override fun remove(key: String) = throw UnknownNamespaceException(key) + + override fun get(key: String): T = throw UnknownNamespaceException(key) + + override fun contains(key: String): Boolean = throw UnknownNamespaceException(key) + + override fun subscribe(observer: Observer) { + } + +} + +class UnknownNamespaceException internal constructor(key: String) : Exception(key) \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index d8f14a1..3d1b47f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':library' +include ':library', ':library-android'