Simple key-value storage (a persistent data structure) directly on file system, maps each key to a separate file.
- Simple key-value storage model
- Very easy to learn and use
- Both Synchronous and Asynchronous APIs
- One JSON containing file per each key
- Built-in configurable cache
- Both Promise and Callback support
const store = require("key-file-storage")('my/storage/path')
// Write something to file 'my/storage/path/myfile'
store.myfile = { x: 123 }
// Read contents of file 'my/storage/path/myfile'
const x = store.myfile.x
// Delete file 'my/storage/path/myfile'
delete store.myfile
A nice alternative for any of these libraries: node-persist, configstore, flat-cache, conf, simple-store, and more...
Installing package on Node.js:
$ npm install key-file-storage
Initializing a key-file storage:
// ES Modules import style:
import kfs from 'key-file-storage'
// CommonJS import style:
const kfs = require("key-file-storage")
const store = kfs('/storage/directory/path', caching)
The value of caching
can be
-
true
(By default, if not specified) : Unlimited cache, anything will be cached on memory, good for small data volumes. -
false
: No cache, read the files from disk every time, good when other applications can modify the files' contents arbitrarily. -
n
(An integer number) : Limited cache, only then
latest referred key-values will be cached, good for large data volumes where only a fraction of data is being used frequently .
As simple as native javascript objects:
store['key'] = value // Writes file
store['key'] // Reads file
delete store['key'] // Deletes file
delete store['*'] // Deletes all storage files
'key' in store // Checks for file existence
//=> true or false
-
You can use
store.keyName
instead ofstore['keyName']
anywhere if the key name allows. -
undefined
is not supported as a savable value, butnull
is. Saving a key with valueundefined
is equivalent to removing it. So, you can usestore['key'] = undefined
or evenstore['*'] = undefined
to delete files. -
Synchronous API will throw an exception if any errors happen, so you shall handle it your way.
Every one of the following calls returns a promise:
store('key', value) // Writes file
store('key') // Reads file
new store('key') // Resets/deletes file
new store('*') /* or */
new store() /* or */
new store // Deletes all storage files
('key' in store(), store()) // Checks for file existence
// Resolves to true or false
- Once again,
undefined
is not supported as a savable value, butnull
is. Saving a key with valueundefined
is equivalent to removing it. So, you can usestore('key', undefined)
or evenstore('*', undefined)
to delete files.
The same as asynchronous with promises, but with callback function as the last input parameter of store()
:
store('key', value, cb) // Writes file
store('key', cb) // Reads file
new store('key', cb) // Resets/Deletes file
new store('*', cb) /* or */
new store(cb) // Deletes all storage files
'key' in store(cb) // Checks for file existence
// without promise output
/* or */
('key' in store(), store(cb))
// Checks for file existence
// with promise output
-
These calls still return a promise on their output (except for
'key' in store(callback)
form of existence check). -
The first input parameter of all callback functions is
err
, so you shall handle it within the callback. Reading and Existence checking callbacks provide the return values as their second input parameter.
Every folder in the storage can be treated as a collection of key-values.
You can query the list of all containing keys (filenames) within a collection (folder) like this (Note that a collection path must end with a forward slash '/'
):
try {
const keys = store['col/path/']
// keys = ['col/path/key1', 'col/path/sub/key2', ... ]
} catch (error) {
// Handle error...
}
store('col/path/')
.then(keys => {
// keys = ['col/path/key1', 'col/path/sub/key2', ... ]
})
.catch(error => {
// Handle error...
})
store('col/path/', (error, keys) => {
if (error) {
// Handle error...
}
// keys = ['col/path/key1', 'col/path/sub/key2', ... ]
})
-
NOTE 1 : Each key will map to a separate file (using the key itself as its relative path). Therefore, keys may be relative paths, e.g:
'data.json'
,'/my/key/01'
or'any/other/relative/path/to/a/file'
. The only exceptions are the strings including'..'
(double dot) which will not be accepted for security reasons. -
NOTE 2 : You may have hidden key files by simply add a
'.'
before the filename in the key path. -
NOTE 3 : If a key's relative path ends with a forward slash
'/'
, it will be considered to be a collection (folder) name. So,'data/set/'
is a collection and'data/set/key'
is a key in that collection. -
NOTE 4 : This module has a built-in implemented cache, so, when activated, accessing a certain key more than once won't require file-system level operations again for that file.
-
NOTE 5 : When activated, caching will include queries on collections too.
import kfs from "key-file-storage"
// Locate 'db' folder in the current directory as the storage path,
// Require 100 latest accessed key-values to be cached:
const store = kfs('./db', 100)
// Create file './db/users/hessam' containing this user data, synchronously:
store['users/hessam'] = ({
name: "Hessam",
skills: {
java: 10,
csharp: 15
}
})
// Read file './db/users/hessam' as a JSON object, asynchronously:
store('users/hessam').then(hessam => {
console.log(`Hessam's java skill is ${hessam.skills.java}.`)
})
// Check whether file './db/users/mahdiar' exists or not, asynchronously:
'users/mahdiar' in store((error, exists) => {
if (exists) {
console.log("User Mahdiar exists!")
}
})
// List all the keys in './db/users/', synchronously:
const allUsers = store['users/']
//=> ['users/hessam', 'users/mahdiar', ... ]
It would be very appreciated if you had any suggestions or contribution on this repository or submitted any issue.
- See the code on GitHub
- Contact me by my gmail address (Hessamoddin A Shokravi)