npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@wirelineio/store-client

v0.1.48

Published

Wireline Store Client.

Downloads

7

Readme


id: tutorial-store title: Wireline Key/Value Store

A simple key/value storage service. Supported operations are:

  • set
  • get
  • inc
  • del
  • scan
  • clear
  • format

Quick Start

Add the Wireline key/value store API client to your project:

$ yarn add @wirelineio/store-client

Then import it in your code and create the Store client object by passing it the context:

import Wireline from '@wirelineio/sdk';
import Store from '@wirelineio/store-client';

module.exports = {
  test: Wireline.exec(async (event, context) => {
    let store = new Store(context);

    // The rest of your code here...
  })
};

The last step is to indicate which deployment of the wireline.io/store service you would like to use, either a new one or an existing one. The HTTP endpoint details for whichever wireline.io/store you choose will be infused automatically into the context object by Wireline.exec(), providing everything needed to configure your Store client object.

In this example, we will use one that already exists by adding it as a reference to our stack.yml. Use the wire CLI to list active deployments of the wireline.io/store service.

$ wire svc list-deployments --service 'wireline.io/store'
# NOTE: Some columns omitted for clarity.

Domain        Stack         Service               WRN                                 Version
---------------------------------------------------------------------------------------------
wireline.io   wireline      wireline.io/store     wrn::wireline.io/wireline/store     0.0.1
...

Add a reference to it at the bottom of the stack.yml of your Wireline project using its name, wireline.io/store, and the WRN of the deployment you wish to use, wrn::wireline.io/wireline/store.

  wireline.io/store:
    reference:
      endpointUrl: wrn::wireline.io/wireline/store

Get/Set

The most basic operations are set and get, storing or retrieving a key/value pair (respectively). The key must be a string. The value may be a string, number. boolean, or an object.

    await store.set('key', 'value'));
    let value = await store.get('key');

Inc

This provides an atomically incrementing counter. If the counter does not exist, it will be created and set to a value of 1.

    let value = await store.inc('counterA');

Del

Removes a single key/value pair, if it exists. No value is returned, and there is no indication as to whether the key existed.

    await store.del('counterA');

Scan

Scan for key/value pairs in the bucket. If provided, prefix restricts the results to keys which equal or begin with that prefix. This is a case-sensitive comparison. The limit option will limit the maximum number of results returned. Depending on the number of pairs and the storage provider, this may be an expensive operation.

  # Scan everything.
  let results = await store.scan();

  # Scan for up to ten items, with keys that equal or start with 'aaa'.
  results = await store.scan('aaa', { 'limit': 10 })

Clear

Clear all key/value pairs in the bucket. Depending on the number of pairs and the storage provider, this may be an expensive operation.

  await store.clear();

Format

Clear all key/value pairs in all buckets, as well as removing the "stake". Depending on the storage provider, this may be an extremely expensive operation.

Using Buckets

Nearly all operations support the bucket option, which scopes the operation to the specified "bucket". A "bucket" provides namespacing for keyi/value pairs, so that keyA in bucketA is distinct from keyA in bucketB.

  store.set('keyA', 'valueA', { 'bucket': 'bucketA' });

The default bucket may also be set when the Store client object is created:

  let store = new Store(ctx, { 'bucket': 'myBucket' });

Planting Stakes

Each Wireline deployment is given a unique namespace within the store. The first operation for the deployment implicitly "stakes a claim" to the namespace by generating a unique value which will be used to validate all subsequent operations. In addition to the unique Wireline WRN details (domain/stack/deployment), the account ID performing the operation is tied to the "stake". If multiple accounts are used, an explicit "stake" value should be used instead. This can be provided when creating the Store client object. The value should be treated securely, as a kind of credential.

  let store = new Store(ctx, { 'stake': 'myVerySecretStakeValue' });

The format operation not only removes all values from the unique namespace given to the deployment, it releases the stake.

Configuration

The HTTP endpoint will be automatically discovered by adding a reference to a deployed store's WRN under the name wireline.io/store in either the stack.yml or wireline.yml for your service. If for some reason that automatic process needs to be overridden, the full HTTP URL can be set explicitly using the WRL_STORE_URL environment variable.

stack.yml WRN:

name: my-stack
domain: example.com
stage: dev
provider:
  name: aws
  region: us-east-1
stack:
  my-deployment:
    deployment:
      image: 'wrn::my-service'
      version: 0.0.1
  wireline.io/store:
    reference:
      endpointUrl: 'wrn::wireline.io/wireline/store'

wireline.yml WRN:

services:
  'wireline.io/store': 'wrn::wireline.io/wireline/store'

stack.yml by ENV:

name: my-stack
domain: example.com
stage: dev
provider:
  name: aws
  region: us-east-1
stack:
  my-deployment:
    deployment:
      image: 'wrn::my-service'
      version: 0.0.1
      environment:
        WRL_STORE_URL: 'https://example.store.url/store'

Example Usage

Example A - Basic functionality

    let store = new Store(context);

    // All of these operations will happen in the default bucket.
    console.log(await store.set('A-key', 'valA'));
    console.log(await store.get('A-key'));

    console.log(await store.inc('A-counter'));
    console.log(await store.inc('A-counter'));
    console.log(await store.inc('A-counter'));

    console.log(await store.scan('A-'));

    await store.del('A-key');

    console.log(await store.scan('A-'));

    await store.clear();
    console.log(await store.scan());

Example B - Using different buckets to separate types and indices...

    let store = new Store(context);
    
    let userOpts = { 'bucket': 'users' };
    let idxUserByEmailOpts = { 'bucket': 'idx.users.email' };
    let idxUserByUsernameOpts = { 'bucket': 'idx.users.username' };
    
    let deviceOpts = { 'bucket': 'devices' };
    let idxDevByUser = { 'bucket': 'idx.devices.byuser', limit: 50 };
    
    // Insert 'bob' by his UUID.
    await store.put(bob.uuid, bob, userOpts);
    
    // Index bob's username to his UUID.
    await store.put(bob.username, bob.uuid, idxUserByUsernameOpts);
    
    // Also index bob's e-mail address to his uuid.
    await store.put(bob.email, bob.uuid, idxUserByEmailOpts);
    
    // Insert bob's device into the device's bucket.
    await store.put(dev.uuid, dev, deviceOpts);
    
    // And index it to his user.
    await store.put(`${bob.uuid}::${dev.uuid}`, { 'usr:' bob.uuid, 'dev': dev.uuid }, idxDevByUser);
    
    // Scan for all bob's devices...
    let results = await store.scan(`${bob.uuid}::`, idxDevByUser);