Skip to content

Commit

Permalink
feat(keyv-local-sync): init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSharpieOne committed Mar 27, 2018
1 parent e02aabd commit 9a3d400
Show file tree
Hide file tree
Showing 8 changed files with 444 additions and 70 deletions.
2 changes: 2 additions & 0 deletions packages/keyv-local-sync/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!src
8 changes: 8 additions & 0 deletions packages/keyv-local-sync/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
dist: trusty
language: node_js
node_js:
- '8'
- '6'
- '4'
script: npm run test:full
after_success: npm run coverage
22 changes: 22 additions & 0 deletions packages/keyv-local-sync/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
MIT License

Copyright (c) 2017 Luke Childs
Modifications Copyright (c) 2018 Availity

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
195 changes: 195 additions & 0 deletions packages/keyv-local-sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# @availity/keyv-local-sync

> Simple local real-time key-value storage with support for TTL
[![Build Status](https://travis-ci.org/availity/keyv-local-sync.svg?branch=master)](https://travis-ci.org/availity/keyv-local-sync)
[![Coverage Status](https://coveralls.io/repos/github/availity/keyv-local-sync/badge.svg?branch=master)](https://coveralls.io/github/availity/keyv-local-sync?branch=master)
[![npm](https://img.shields.io/npm/dm/keyv-local-sync.svg)](https://www.npmjs.com/package/keyv-local-sync)
[![npm](https://img.shields.io/npm/v/keyv-local-sync.svg)](https://www.npmjs.com/package/keyv-local-sync)

keyv-local-sync provides a consistent interface for key-value. It supports TTL based expiry, making it suitable as a cache key-value store.

## Features

There are a few existing modules similar to keyv-local-sync, however keyv-local-sync is different because it:

- Isn't bloated
- Isn't async, uses local memory-based storage for real-time lookups and storage
- Cache promises or anything, it's not serialized so you get back exactly what you put in
- Suitable as a TTL based cache key-value store
- [Easily embeddable](#add-cache-support-to-your-module) inside another module
- Works with any storage that implements the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) API
- Supports namespaces
- Supports the current active LTS version of Node.js or higher

## Usage

Install keyv-local-sync.

```
npm install --save @availity/keyv-local-sync
```

Create a new keyv-local-sync instance. keyv-local-sync will automatically load the correct storage adapter.

```js
const KeyvLocalSync = require('@availity/keyv-local-sync');

// One of the following
const keyvLocalSync = new KeyvLocalSync(); // the default store uses quick-lru
const keyvLocalSync = new KeyvLocalSync({ store: new Map() });


keyvLocalSync.set('foo', 'expires in 1 second', 1000); // true
keyvLocalSync.set('foo', 'never expires'); // true
keyvLocalSync.get('foo'); // 'never expires'
keyvLocalSync.delete('foo'); // true
keyvLocalSync.clear(); // undefined
```

### Namespaces
keyv-local-sync instance to avoid key collisions and allow you to clear only a certain namespace while u
You can namespace your keyv-local-sync instance to avoid key collisions and allow you to clear only a certain namespace.

```js
const users = new KeyvLocalSync({ namespace: 'users' });
const cache = new KeyvLocalSync({ namespace: 'cache' });

users.set('foo', 'users'); // true
cache.set('foo', 'cache'); // true
users.get('foo'); // 'users'
cache.get('foo'); // 'cache'
users.clear(); // undefined
users.get('foo'); // undefined
cache.get('foo'); // 'cache'
```

## Third-party Storage Adapters

You can also use third-party storage adapters or build your own. keyv-local-sync will wrap these storage adapters in TTL functionality and handle complex types internally.

```js
const KeyvLocalSync = require('@availity/keyv-local-sync');
const myAdapter = require('./my-storage-adapter');

const keyvLocalSync = new KeyvLocalSync({ store: myAdapter });
```

Any store that follows the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) api will work.

```js
new KeyvLocalSync({ store: new Map() });
```

For example, [`quick-lru`](https://github.com/sindresorhus/quick-lru) is a module that implements the Map API, it is used by default is no store is provided.

```js
const KeyvLocalSync = require('@availity/keyv-local-sync');

const keyvLocalSync = new KeyvLocalSync({ size: 1000 });
```

The following are third-party storage adapters compatible with keyv-local-sync:

- [quick-lru](https://github.com/sindresorhus/quick-lru) - Simple "Least Recently Used" (LRU) cache
- [keyv-local-sync-file](https://github.com/zaaack/keyv-local-sync-file) - File system storage adapter for keyv-local-sync

## Add Cache Support to your Module

keyv-local-sync is designed to be easily embedded into other modules to add cache support. The recommended pattern is to expose a `cache` option in your modules options which is passed through to keyv-local-sync. Caching will work in memory by default and users have the option to also install a keyv-local-sync storage adapter and pass in a connection string, or any other storage that implements the `Map` API.

You should also set a namespace for your module so you can safely call `.clear()` without clearing unrelated app data.

Inside your module:

```js
class AwesomeModule {
constructor(opts) {
this.cache = new KeyvLocalSync({
store: opts.cache,
namespace: 'awesome-module'
});
}
}
```

Now it can be consumed like this:

```js
const AwesomeModule = require('awesome-module');

// Caches stuff in memory by default
const awesomeModule = new AwesomeModule();

// After npm install --save keyv-local-sync-redis
const awesomeModule = new AwesomeModule({ cache: new Map() });

// Some third-party module that implements the Map API
const awesomeModule = new AwesomeModule({ cache: some3rdPartyStore });
```

## API

### new keyv-local-sync([options])

Returns a new keyv-local-sync instance.

### options

Type: `Object`

The options object is also passed through to the storage adapter. Check your storage adapter docs for any extra options.

#### options.namespace

Type: `String`<br>
Default: `'keyv-local-sync'`

Namespace for the current instance.

#### options.ttl

Type: `Number`<br>
Default: `undefined`

Default TTL. Can be overridden by specififying a TTL on `.set()`.

#### options.store

Type: `Storage adapter instance`<br>
Default: `new QuickLRU({maxSize: this.opts.maxSize || 1000})`

The storage adapter instance to be used by keyv-local-sync.

### Instance

Keys must always be strings. Values can be of any type.

#### .set(key, value, [ttl])

Set a value.

By default keys are persistent. You can set an expiry TTL in milliseconds.

Returns `true`.

#### .get(key)

Returns the value.

#### .delete(key)

Deletes an entry.

Returns `true` if the key existed, `false` if not.

#### .clear()

Delete all entries in the current namespace.

Returns `undefined`.

## License

Original work: MIT © Luke Childs
Modifications: MIT © Availity
42 changes: 42 additions & 0 deletions packages/keyv-local-sync/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "@availity/keyv-local-sync",
"version": "1.0.0",
"description": "Simple key-value storage for local in memory caches in a synchros fashion",
"main": "src/index.js",
"scripts": {
"test": "nyc ava test/test.js",
"test:full": "nyc ava --serial",
"coverage": "nyc report --reporter=text-lcov | coveralls"
},
"repository": {
"type": "git",
"url": "git+https://github.com/availity/sdk-js.git"
},
"keywords": [
"key",
"value",
"store",
"cache",
"ttl",
"sync"
],
"contributors": [
"Luke Childs <lukechilds123@gmail.com> (http://lukechilds.co.uk)",
"Evan Sharp <evan.sharp@availity.com> (https://github.com/TheSharpieOne)"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/availity/sdk-js/issues"
},
"homepage": "https://github.com/availity/sdk-js",
"dependencies": {
"quick-lru": "^1.1.0"
},
"devDependencies": {
"ava": "^0.25.0",
"coveralls": "^3.0.0",
"nyc": "^11.0.3",
"this": "^1.0.2",
"timekeeper": "^2.0.0"
}
}
58 changes: 58 additions & 0 deletions packages/keyv-local-sync/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict';

const QuickLRU = require('quick-lru');

class KeyvLocalSync {
constructor(opts) {
this.opts = Object.assign(
{
namespace: 'keyv-local-sync',
maxSize: 1000,
},
opts
);

if (!this.opts.store) {
this.opts.store = new QuickLRU({ maxSize: this.opts.maxSize });
}
}

getKeyPrefix(key) {
return `${this.opts.namespace}:${key}`;
}

get(key) {
key = this.getKeyPrefix(key);
const data = this.opts.store.get(key);
if (data === undefined) {
return undefined;
}
if (typeof data.expires === 'number' && Date.now() > data.expires) {
this.delete(key);
return undefined;
}
return data.value;
}

set(key, value, ttl) {
if (typeof ttl === 'undefined') {
({ ttl } = this.opts);
}
if (ttl === 0) {
ttl = undefined;
}
const expires = typeof ttl === 'number' ? Date.now() + ttl : null;
this.opts.store.set(this.getKeyPrefix(key), { value, expires }, ttl);
return true;
}

delete(key) {
return this.opts.store.delete(this.getKeyPrefix(key));
}

clear() {
return this.opts.store.clear();
}
}

module.exports = KeyvLocalSync;
Loading

0 comments on commit 9a3d400

Please sign in to comment.