diff --git a/package.json b/package.json index e15d3f4..83a7283 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tmtek/convo", - "version": "0.1.5", + "version": "0.1.7", "description": "A uility for building conversational responses in DialogFlow fufillments", "main": "index.js", "scripts": { diff --git a/readme.md b/readme.md index 052241d..1733c13 100644 --- a/readme.md +++ b/readme.md @@ -158,6 +158,26 @@ new MyApplication() ``` We use`then()` of the resulting promises returned from `intent()` to simulate the multiple conversation steps. Notice how for each intent call we create a new instance of Convo derived from the previous: `new Convo(convo)`. This allows us to create a new response for each intent, but still carry over the context and storage data to simulate how things work in DialogFlow with a standard `conv` object. +### Using Storage + +Convo allows you to simulate DialogFlow's storage capabilities. Storage lets you store arbitrary data for the user that is accessible across sessions of usage. Convo offers methods to simply interaction with storage, but to also simulate it in the dev/test environment. + +```javascript +let convo = new Convo() + .onStorageUpdated(storage => {console.log(storage)}) //fires after setToStorage call. + .setStorage({}) //populates storage with data (doesn't trigger onStorageUpdated). + .setToStorage("list", ["one","two","three"]); //Add value to storage. + +convo.isInStorage("list", list => list.length > 0); //returns true +convo.getFromStorage("list"); //returns ["one","two","three"] + +``` + +`setToStorage()`, `getFromStorage()`, and `isInStorage()` will be the methods that are most commonly used in application development. + +`onStorageUpdated()` and `setStorage()` are useful when testing your application outside of DialogFlow, because you can use those methods to simulate persisted data, or actually persist it yourself. + + ## API Reference @@ -182,6 +202,10 @@ We use`then()` of the resulting promises returned from `intent()` to simulate th * setConext(contextName, lifespan, value) * getContext(contextName) * getStorage() +* setStorage(data) +* setToStorage(name, data) +* getFromStorage(name) +* isInStorage(name, predicate) #### Convo Rich Responses * Convo.SimpleResponse() diff --git a/src/convo.js b/src/convo.js index 32291a7..48ece9b 100644 --- a/src/convo.js +++ b/src/convo.js @@ -142,10 +142,18 @@ class Convo { } constructor(obj) { - this.conv = !obj ? Convo.mockConv() : obj.conv || obj; + this.conv = !obj ? Convo.mockConv() : copyConvo(obj); this.clear(); } + copyConvo(obj) { + if (obj.conv) { + this_onStorageUpdated = obj._onStorageUpdated; + return obj.conv; + } + return obj; + } + clear() { this._write = []; this._speak = []; @@ -213,6 +221,42 @@ class Convo { getStorage() { return this.conv && this.conv.user && this.conv.user.storage || {}; } + + setStorage(data) { + if (this.conv && this.conv.user) { + this.conv.user.storage = data; + } + return this; + } + + setToStorage(name, value) { + if (this.conv && this.conv.user && this.conv.user.storage) { + this.conv.user.storage[name] = value; + if(this._onStorageUpdated) {this._onStorageUpdated(this.conv.user.storage)}; + } + return this; + } + + onStorageUpdated(callback) { + this._onStorageUpdated = callback; + return this; + } + + getFromStorage(name) { + if (this.conv && this.conv.user && this.conv.user.storage) { + return this.conv.user.storage[name]; + } + return null; + } + + isInStorage(name, predicate = null) { + return this.conv && + this.conv.user && + this.conv.user.storage && + this.conv.user.storage[name] && + (!predicate || predicate(this.conv.user.storage[name])); + } + } function isPromise(obj) {