diff --git a/packages/react-native-mmkv/cpp/HybridMMKV.cpp b/packages/react-native-mmkv/cpp/HybridMMKV.cpp index 8ff2505d..5a26a5e0 100644 --- a/packages/react-native-mmkv/cpp/HybridMMKV.cpp +++ b/packages/react-native-mmkv/cpp/HybridMMKV.cpp @@ -13,7 +13,7 @@ namespace margelo::nitro::mmkv { -HybridMMKV::HybridMMKV(const Configuration& config) : HybridObject(TAG) { +HybridMMKV::HybridMMKV(const Configuration& config) : _config(config), HybridObject(TAG) { std::string path = config.path.has_value() ? config.path.value() : ""; std::string encryptionKey = config.encryptionKey.has_value() ? config.encryptionKey.value() : ""; bool hasEncryptionKey = encryptionKey.size() > 0; @@ -29,12 +29,12 @@ HybridMMKV::HybridMMKV(const Configuration& config) : HybridObject(TAG) { } #ifdef __APPLE__ - instance = MMKV::mmkvWithID(config.id, mode, encryptionKeyPtr, pathPtr); + _instance = MMKV::mmkvWithID(config.id, mode, encryptionKeyPtr, pathPtr); #else - instance = MMKV::mmkvWithID(config.id, DEFAULT_MMAP_SIZE, mode, encryptionKeyPtr, pathPtr); + _instance = MMKV::mmkvWithID(config.id, DEFAULT_MMAP_SIZE, mode, encryptionKeyPtr, pathPtr); #endif - if (instance == nullptr) [[unlikely]] { + if (_instance == nullptr) [[unlikely]] { // Check if instanceId is invalid if (config.id.empty()) [[unlikely]] { throw std::runtime_error("Failed to create MMKV instance! `id` cannot be empty!"); @@ -55,11 +55,14 @@ HybridMMKV::HybridMMKV(const Configuration& config) : HybridObject(TAG) { } } +Configuration HybridMMKV::getConfig() { + return _config; +} double HybridMMKV::getSize() { - return instance->actualSize(); + return _instance->actualSize(); } bool HybridMMKV::getIsReadOnly() { - return instance->isReadOnly(); + return _instance->isReadOnly(); } // helper: overload pattern matching for lambdas @@ -78,20 +81,20 @@ void HybridMMKV::set(const std::string& key, const std::variantset(b, key); + return _instance->set(b, key); }, [&](const std::shared_ptr& buf) { // ArrayBuffer MMBuffer buffer(buf->data(), buf->size(), MMBufferCopyFlag::MMBufferNoCopy); - return instance->set(std::move(buffer), key); + return _instance->set(std::move(buffer), key); }, [&](const std::string& string) { // string - return instance->set(string, key); + return _instance->set(string, key); }, [&](double number) { // number - return instance->set(number, key); + return _instance->set(number, key); }}, value); if (!didSet) { @@ -99,11 +102,11 @@ void HybridMMKV::set(const std::string& key, const std::variantmmapID(), key); + MMKVValueChangedListenerRegistry::notifyOnValueChanged(_instance->mmapID(), key); } std::optional HybridMMKV::getBoolean(const std::string& key) { bool hasValue; - bool result = instance->getBool(key, /* defaultValue */ false, &hasValue); + bool result = _instance->getBool(key, /* defaultValue */ false, &hasValue); if (hasValue) { return result; } else { @@ -112,7 +115,7 @@ std::optional HybridMMKV::getBoolean(const std::string& key) { } std::optional HybridMMKV::getString(const std::string& key) { std::string result; - bool hasValue = instance->getString(key, result, /* inplaceModification */ true); + bool hasValue = _instance->getString(key, result, /* inplaceModification */ true); if (hasValue) { return result; } else { @@ -121,7 +124,7 @@ std::optional HybridMMKV::getString(const std::string& key) { } std::optional HybridMMKV::getNumber(const std::string& key) { bool hasValue; - double result = instance->getDouble(key, /* defaultValue */ 0.0, &hasValue); + double result = _instance->getDouble(key, /* defaultValue */ 0.0, &hasValue); if (hasValue) { return result; } else { @@ -132,11 +135,11 @@ std::optional> HybridMMKV::getBuffer(const std::str MMBuffer result; #ifdef __APPLE__ // iOS: Convert std::string to NSString* for MMKVCore pod compatibility - bool hasValue = instance->getBytes(@(key.c_str()), result); + bool hasValue = _instance->getBytes(@(key.c_str()), result); #else // Android/other platforms: Use std::string directly (converts to // std::string_view) - bool hasValue = instance->getBytes(key, result); + bool hasValue = _instance->getBytes(key, result); #endif if (hasValue) { return std::make_shared(std::move(result)); @@ -145,49 +148,49 @@ std::optional> HybridMMKV::getBuffer(const std::str } } bool HybridMMKV::contains(const std::string& key) { - return instance->containsKey(key); + return _instance->containsKey(key); } bool HybridMMKV::remove(const std::string& key) { - bool wasRemoved = instance->removeValueForKey(key); + bool wasRemoved = _instance->removeValueForKey(key); if (wasRemoved) { // Notify on changed - MMKVValueChangedListenerRegistry::notifyOnValueChanged(instance->mmapID(), key); + MMKVValueChangedListenerRegistry::notifyOnValueChanged(_instance->mmapID(), key); } return wasRemoved; } std::vector HybridMMKV::getAllKeys() { - return instance->allKeys(); + return _instance->allKeys(); } void HybridMMKV::clearAll() { auto keysBefore = getAllKeys(); - instance->clearAll(); + _instance->clearAll(); for (const auto& key : keysBefore) { // Notify on changed - MMKVValueChangedListenerRegistry::notifyOnValueChanged(instance->mmapID(), key); + MMKVValueChangedListenerRegistry::notifyOnValueChanged(_instance->mmapID(), key); } } void HybridMMKV::recrypt(const std::optional& key) { bool successful = false; if (key.has_value()) { // Encrypt with the given key - successful = instance->reKey(key.value()); + successful = _instance->reKey(key.value()); } else { // Remove the encryption key by setting it to a blank string - successful = instance->reKey(std::string()); + successful = _instance->reKey(std::string()); } if (!successful) { throw std::runtime_error("Failed to recrypt MMKV instance!"); } } void HybridMMKV::trim() { - instance->trim(); - instance->clearMemoryCache(); + _instance->trim(); + _instance->clearMemoryCache(); } Listener HybridMMKV::addOnValueChangedListener(const std::function& onValueChanged) { // Add listener - auto mmkvID = instance->mmapID(); - auto listenerID = MMKVValueChangedListenerRegistry::addListener(instance->mmapID(), onValueChanged); + auto mmkvID = _instance->mmapID(); + auto listenerID = MMKVValueChangedListenerRegistry::addListener(_instance->mmapID(), onValueChanged); return Listener([=]() { // remove() diff --git a/packages/react-native-mmkv/cpp/HybridMMKV.hpp b/packages/react-native-mmkv/cpp/HybridMMKV.hpp index 946be28b..d5494e8c 100644 --- a/packages/react-native-mmkv/cpp/HybridMMKV.hpp +++ b/packages/react-native-mmkv/cpp/HybridMMKV.hpp @@ -19,6 +19,7 @@ class HybridMMKV final : public HybridMMKVSpec { public: // Properties + Configuration getConfig() override; double getSize() override; bool getIsReadOnly() override; @@ -41,7 +42,8 @@ class HybridMMKV final : public HybridMMKVSpec { static MMKVMode getMMKVMode(const Configuration& config); private: - MMKV* instance; + MMKV* _instance; + Configuration _config; }; } // namespace margelo::nitro::mmkv diff --git a/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.cpp b/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.cpp index abd7b66d..f5140a36 100644 --- a/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.cpp +++ b/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.cpp @@ -14,6 +14,7 @@ namespace margelo::nitro::mmkv { HybridObject::loadHybridMethods(); // load custom methods/properties registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridGetter("config", &HybridMMKVSpec::getConfig); prototype.registerHybridGetter("size", &HybridMMKVSpec::getSize); prototype.registerHybridGetter("isReadOnly", &HybridMMKVSpec::getIsReadOnly); prototype.registerHybridMethod("set", &HybridMMKVSpec::set); diff --git a/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.hpp b/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.hpp index 9952d908..2b87bd4a 100644 --- a/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.hpp +++ b/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVSpec.hpp @@ -13,9 +13,12 @@ #error NitroModules cannot be found! Are you sure you installed NitroModules properly? #endif +// Forward declaration of `Configuration` to properly resolve imports. +namespace margelo::nitro::mmkv { struct Configuration; } // Forward declaration of `Listener` to properly resolve imports. namespace margelo::nitro::mmkv { struct Listener; } +#include "Configuration.hpp" #include #include #include @@ -51,6 +54,7 @@ namespace margelo::nitro::mmkv { public: // Properties + virtual Configuration getConfig() = 0; virtual double getSize() = 0; virtual bool getIsReadOnly() = 0; diff --git a/packages/react-native-mmkv/src/createMMKV/createMMKV.ts b/packages/react-native-mmkv/src/createMMKV/createMMKV.ts index 8a77e953..83c8633c 100644 --- a/packages/react-native-mmkv/src/createMMKV/createMMKV.ts +++ b/packages/react-native-mmkv/src/createMMKV/createMMKV.ts @@ -13,7 +13,7 @@ let platformContext: MMKVPlatformContext | undefined export function createMMKV(configuration?: Configuration): MMKV { if (isTest()) { // In a test environment, we mock the MMKV instance. - return createMockMMKV() + return createMockMMKV(configuration) } if (platformContext == null) { diff --git a/packages/react-native-mmkv/src/createMMKV/createMMKV.web.ts b/packages/react-native-mmkv/src/createMMKV/createMMKV.web.ts index 790b543b..0be0094d 100644 --- a/packages/react-native-mmkv/src/createMMKV/createMMKV.web.ts +++ b/packages/react-native-mmkv/src/createMMKV/createMMKV.web.ts @@ -85,6 +85,7 @@ export function createMMKV( } return { + config: config, clearAll: () => { const keys = Object.keys(storage()) for (const key of keys) { diff --git a/packages/react-native-mmkv/src/createMMKV/createMockMMKV.ts b/packages/react-native-mmkv/src/createMMKV/createMockMMKV.ts index 66453961..5cc90534 100644 --- a/packages/react-native-mmkv/src/createMMKV/createMockMMKV.ts +++ b/packages/react-native-mmkv/src/createMMKV/createMockMMKV.ts @@ -1,9 +1,13 @@ import type { MMKV } from '../specs/MMKV.nitro' +import type { Configuration } from '../specs/MMKVFactory.nitro' /** * Mock MMKV instance when used in a Jest/Test environment. */ -export function createMockMMKV(): MMKV { +export function createMockMMKV( + configuration: Configuration = { id: 'mmkv.default' } +): MMKV { + const config = configuration const storage = new Map() const listeners = new Set<(key: string) => void>() @@ -14,6 +18,7 @@ export function createMockMMKV(): MMKV { } return { + config: config, clearAll: () => { const keysBefore = storage.keys() storage.clear() diff --git a/packages/react-native-mmkv/src/specs/MMKV.nitro.ts b/packages/react-native-mmkv/src/specs/MMKV.nitro.ts index 1c922e34..2412a51b 100644 --- a/packages/react-native-mmkv/src/specs/MMKV.nitro.ts +++ b/packages/react-native-mmkv/src/specs/MMKV.nitro.ts @@ -1,10 +1,25 @@ import type { HybridObject } from 'react-native-nitro-modules' +import type { Configuration } from './MMKVFactory.nitro' export interface Listener { remove: () => void } export interface MMKV extends HybridObject<{ ios: 'c++'; android: 'c++' }> { + /** + * The {@linkcode Configuration} that was used to create this {@linkcode MMKV} + * instance. + */ + readonly config: Configuration + /** + * Get the current total size of the storage, in bytes. + */ + readonly size: number + /** + * Returns whether this instance is in read-only mode or not. + * If this is `true`, you can only use "get"-functions. + */ + readonly isReadOnly: boolean /** * Set a {@linkcode value} for the given {@linkcode key}. * @@ -75,15 +90,6 @@ export interface MMKV extends HybridObject<{ ios: 'c++'; android: 'c++' }> { * In most applications, this is not needed at all. */ trim(): void - /** - * Get the current total size of the storage, in bytes. - */ - readonly size: number - /** - * Returns whether this instance is in read-only mode or not. - * If this is `true`, you can only use "get"-functions. - */ - readonly isReadOnly: boolean /** * Adds a value changed listener. The Listener will be called whenever any value * in this storage instance changes (set or delete).