diff --git a/README.md b/README.md index 844a1ba7..747f6608 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,9 @@ To check if an MMKV instance exists, use `existsMMKV(...)`: import { existsMMKV } from 'react-native-mmkv' const exists = existsMMKV('my-instance') + +// For instances created with a custom path: +const existsAtPath = existsMMKV('my-instance', '/custom/mmkv/path') ``` ### Delete an MMKV instance @@ -251,6 +254,19 @@ To delete an MMKV instance, use `deleteMMKV(...)`: import { deleteMMKV } from 'react-native-mmkv' const wasDeleted = deleteMMKV('my-instance') + +// For instances created with a custom path: +const wasDeletedAtPath = deleteMMKV('my-instance', '/custom/mmkv/path') +``` + +### Get the default MMKV base directory + +To get the default native MMKV base directory, use `getBaseDirectory()`: + +```ts +import { getBaseDirectory } from 'react-native-mmkv' + +const baseDirectory = getBaseDirectory() ``` ### Log Level diff --git a/example/__tests__/MMKV.harness.ts b/example/__tests__/MMKV.harness.ts index 59718dca..9dbb74bb 100644 --- a/example/__tests__/MMKV.harness.ts +++ b/example/__tests__/MMKV.harness.ts @@ -6,7 +6,13 @@ import { afterEach, } from 'react-native-harness'; import { Platform } from 'react-native'; -import { MMKV, createMMKV, deleteMMKV, existsMMKV } from 'react-native-mmkv'; +import { + MMKV, + createMMKV, + deleteMMKV, + existsMMKV, + getBaseDirectory, +} from 'react-native-mmkv'; const skipOnWeb = (reason: string): boolean => { if (Platform.OS === 'web') { @@ -20,6 +26,12 @@ const waitForNextTick = async () => { await new Promise((resolve) => setTimeout(resolve, 0)); }; +const getNativeCustomPath = (name: string): string | undefined => { + if (skipOnWeb('custom paths are not supported on Web')) return undefined; + const baseDirectory = getBaseDirectory(); + return `${baseDirectory}/${name}`; +}; + describe('MMKV Core Functionality', () => { let storage: MMKV; @@ -1186,6 +1198,27 @@ describe('Deleting instances and checking if they exist', () => { const exists = existsMMKV('some-non-existing-instance'); expect(exists).toStrictEqual(false); }); + + it('should accept an explicit undefined path argument', () => { + const id = `some-location-instance-${Date.now()}`; + const storage = createMMKV({ id }); + storage.set('value', 'stored'); + + const exists = existsMMKV(id, undefined); + expect(exists).toStrictEqual(true); + }); + + it('should check custom path instances with their path', () => { + const id = `some-path-instance-${Date.now()}`; + const path = getNativeCustomPath(`path-aware-exists-${Date.now()}`); + if (path == null) return; + + const storage = createMMKV({ id, path }); + storage.set('value', 'stored'); + + expect(existsMMKV(id)).toStrictEqual(false); + expect(existsMMKV(id, path)).toStrictEqual(true); + }); }); describe('Deleting an instance', () => { @@ -1214,6 +1247,29 @@ describe('Deleting instances and checking if they exist', () => { const wasDeleted = deleteMMKV('some-non-existing-instance'); expect(wasDeleted).toStrictEqual(false); }); + + it('should accept an explicit undefined path argument', () => { + const id = `some-location-instance-${Date.now()}`; + const storage = createMMKV({ id }); + storage.set('value', 'stored'); + + const wasDeleted = deleteMMKV(id, undefined); + expect(wasDeleted).toStrictEqual(true); + expect(existsMMKV(id, undefined)).toStrictEqual(false); + }); + + it('should delete custom path instances with their path', () => { + const id = `some-path-instance-${Date.now()}`; + const path = getNativeCustomPath(`path-aware-delete-${Date.now()}`); + if (path == null) return; + + const storage = createMMKV({ id, path }); + storage.set('value', 'stored'); + + expect(existsMMKV(id, path)).toStrictEqual(true); + expect(deleteMMKV(id, path)).toStrictEqual(true); + expect(existsMMKV(id, path)).toStrictEqual(false); + }); }); }); diff --git a/packages/react-native-mmkv/cpp/HybridMMKVFactory.cpp b/packages/react-native-mmkv/cpp/HybridMMKVFactory.cpp index e93be0b7..d71366ca 100644 --- a/packages/react-native-mmkv/cpp/HybridMMKVFactory.cpp +++ b/packages/react-native-mmkv/cpp/HybridMMKVFactory.cpp @@ -26,12 +26,16 @@ std::shared_ptr HybridMMKVFactory::createMMKV(const Configuratio return std::make_shared(configuration); } -bool HybridMMKVFactory::deleteMMKV(const std::string& id) { - return MMKV::removeStorage(id); +bool HybridMMKVFactory::deleteMMKV(const std::string& id, const std::optional& path) { + std::string rootPath = path.value_or(""); + std::string* rootPathPtr = rootPath.empty() ? nullptr : &rootPath; + return MMKV::removeStorage(id, rootPathPtr); } -bool HybridMMKVFactory::existsMMKV(const std::string& id) { - return MMKV::checkExist(id); +bool HybridMMKVFactory::existsMMKV(const std::string& id, const std::optional& path) { + std::string rootPath = path.value_or(""); + std::string* rootPathPtr = rootPath.empty() ? nullptr : &rootPath; + return MMKV::checkExist(id, rootPathPtr); } } // namespace margelo::nitro::mmkv diff --git a/packages/react-native-mmkv/cpp/HybridMMKVFactory.hpp b/packages/react-native-mmkv/cpp/HybridMMKVFactory.hpp index b763f716..b5e99440 100644 --- a/packages/react-native-mmkv/cpp/HybridMMKVFactory.hpp +++ b/packages/react-native-mmkv/cpp/HybridMMKVFactory.hpp @@ -20,8 +20,8 @@ class HybridMMKVFactory final : public HybridMMKVFactorySpec { void initializeMMKV(const std::string& rootPath) override; std::shared_ptr createMMKV(const Configuration& configuration) override; - bool deleteMMKV(const std::string& id) override; - bool existsMMKV(const std::string& id) override; + bool deleteMMKV(const std::string& id, const std::optional& path) override; + bool existsMMKV(const std::string& id, const std::optional& path) override; }; } // namespace margelo::nitro::mmkv diff --git a/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVFactorySpec.hpp b/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVFactorySpec.hpp index 4fb51831..65eed233 100644 --- a/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVFactorySpec.hpp +++ b/packages/react-native-mmkv/nitrogen/generated/shared/c++/HybridMMKVFactorySpec.hpp @@ -22,6 +22,7 @@ namespace margelo::nitro::mmkv { struct Configuration; } #include #include "HybridMMKVSpec.hpp" #include "Configuration.hpp" +#include namespace margelo::nitro::mmkv { @@ -56,8 +57,8 @@ namespace margelo::nitro::mmkv { // Methods virtual void initializeMMKV(const std::string& rootPath) = 0; virtual std::shared_ptr createMMKV(const Configuration& configuration) = 0; - virtual bool deleteMMKV(const std::string& id) = 0; - virtual bool existsMMKV(const std::string& id) = 0; + virtual bool deleteMMKV(const std::string& id, const std::optional& path) = 0; + virtual bool existsMMKV(const std::string& id, const std::optional& path) = 0; protected: // Hybrid Setup diff --git a/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.ts b/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.ts index c923b098..83d0710a 100644 --- a/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.ts +++ b/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.ts @@ -1,11 +1,11 @@ import { getMMKVFactory } from '../getMMKVFactory' import { isTest } from '../isTest' -export function deleteMMKV(id: string): boolean { +export function deleteMMKV(id: string, path?: string): boolean { if (isTest()) { return true } const factory = getMMKVFactory() - return factory.deleteMMKV(id) + return factory.deleteMMKV(id, path) } diff --git a/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.web.ts b/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.web.ts index 0f32d7a8..193d8556 100644 --- a/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.web.ts +++ b/packages/react-native-mmkv/src/deleteMMKV/deleteMMKV.web.ts @@ -3,7 +3,11 @@ import { LOCAL_STORAGE_KEY_WILDCARD, } from '../web/getLocalStorage' -export function deleteMMKV(id: string): boolean { +export function deleteMMKV(id: string, path?: string): boolean { + if (path != null) { + throw new Error("MMKV: 'path' is not supported on Web!") + } + const storage = getLocalStorage() const prefix = id + LOCAL_STORAGE_KEY_WILDCARD let wasRemoved = false diff --git a/packages/react-native-mmkv/src/existsMMKV/existsMMKV.ts b/packages/react-native-mmkv/src/existsMMKV/existsMMKV.ts index 7ef6d0b8..b6484b24 100644 --- a/packages/react-native-mmkv/src/existsMMKV/existsMMKV.ts +++ b/packages/react-native-mmkv/src/existsMMKV/existsMMKV.ts @@ -1,11 +1,11 @@ import { getMMKVFactory } from '../getMMKVFactory' import { isTest } from '../isTest' -export function existsMMKV(id: string): boolean { +export function existsMMKV(id: string, path?: string): boolean { if (isTest()) { return true } const factory = getMMKVFactory() - return factory.existsMMKV(id) + return factory.existsMMKV(id, path) } diff --git a/packages/react-native-mmkv/src/existsMMKV/existsMMKV.web.ts b/packages/react-native-mmkv/src/existsMMKV/existsMMKV.web.ts index b55416e5..ef369563 100644 --- a/packages/react-native-mmkv/src/existsMMKV/existsMMKV.web.ts +++ b/packages/react-native-mmkv/src/existsMMKV/existsMMKV.web.ts @@ -3,7 +3,11 @@ import { LOCAL_STORAGE_KEY_WILDCARD, } from '../web/getLocalStorage' -export function existsMMKV(id: string): boolean { +export function existsMMKV(id: string, path?: string): boolean { + if (path != null) { + throw new Error("MMKV: 'path' is not supported on Web!") + } + const storage = getLocalStorage() const prefix = id + LOCAL_STORAGE_KEY_WILDCARD const keys = Object.keys(storage) diff --git a/packages/react-native-mmkv/src/getBaseDirectory/getBaseDirectory.ts b/packages/react-native-mmkv/src/getBaseDirectory/getBaseDirectory.ts new file mode 100644 index 00000000..4a4baf67 --- /dev/null +++ b/packages/react-native-mmkv/src/getBaseDirectory/getBaseDirectory.ts @@ -0,0 +1,9 @@ +import { getPlatformContext } from '../getMMKVFactory' + +/** + * Get the default native MMKV base directory. + */ +export function getBaseDirectory(): string { + const platformContext = getPlatformContext() + return platformContext.getBaseDirectory() +} diff --git a/packages/react-native-mmkv/src/getBaseDirectory/getBaseDirectory.web.ts b/packages/react-native-mmkv/src/getBaseDirectory/getBaseDirectory.web.ts new file mode 100644 index 00000000..c34aa82d --- /dev/null +++ b/packages/react-native-mmkv/src/getBaseDirectory/getBaseDirectory.web.ts @@ -0,0 +1,6 @@ +/** + * Get the default native MMKV base directory. + */ +export function getBaseDirectory(): string { + throw new Error("MMKV: 'getBaseDirectory()' is not supported on Web!") +} diff --git a/packages/react-native-mmkv/src/index.ts b/packages/react-native-mmkv/src/index.ts index f059d8aa..11426e76 100644 --- a/packages/react-native-mmkv/src/index.ts +++ b/packages/react-native-mmkv/src/index.ts @@ -5,6 +5,9 @@ export type { Configuration, Mode } from './specs/MMKVFactory.nitro' // The create function export { createMMKV } from './createMMKV/createMMKV' +// Path utilities +export { getBaseDirectory } from './getBaseDirectory/getBaseDirectory' + // Exists + Delete export { existsMMKV } from './existsMMKV/existsMMKV' export { deleteMMKV } from './deleteMMKV/deleteMMKV' diff --git a/packages/react-native-mmkv/src/specs/MMKVFactory.nitro.ts b/packages/react-native-mmkv/src/specs/MMKVFactory.nitro.ts index 734f1558..40ac7d0d 100644 --- a/packages/react-native-mmkv/src/specs/MMKVFactory.nitro.ts +++ b/packages/react-native-mmkv/src/specs/MMKVFactory.nitro.ts @@ -112,16 +112,17 @@ export interface MMKVFactory extends HybridObject<{ createMMKV(configuration: Configuration): MMKV /** - * Deletes the MMKV instance with the - * given {@linkcode id}. + * Deletes the MMKV instance with the given `id`. + * If the instance was created with a custom `path`, pass the same path here. */ - deleteMMKV(id: string): boolean + deleteMMKV(id: string, path?: string): boolean /** - * Returns `true` if an MMKV instance with the - * given {@linkcode id} exists, `false` otherwise. + * Returns `true` if an MMKV instance with the given `id` exists, `false` + * otherwise. If the instance was created with a custom `path`, pass the same + * path here. */ - existsMMKV(id: string): boolean + existsMMKV(id: string, path?: string): boolean /** * Get the default MMKV instance's ID.