{"id":2722,"date":"2018-11-07T16:36:44","date_gmt":"2018-11-07T14:36:44","guid":{"rendered":"http:\/\/hasselba.ch\/blog\/?p=2722"},"modified":"2018-11-07T23:21:17","modified_gmt":"2018-11-07T21:21:17","slug":"node-js-domino-db-docker-7-the-valueholder","status":"publish","type":"post","link":"https:\/\/hasselba.ch\/blog\/?p=2722","title":{"rendered":"node.js, domino-db &#038; Docker (7): The ValueHolder"},"content":{"rendered":"<p>I am using this for years in Java, so I thought it would be great to use this approach also in the JavaScript world: The <em>ValueHolder<\/em>. The class allows to easily define &#8222;cachable&#8220; code and it&#8217;s result, without having to handle the memcached part and &#8211; maybe in the future &#8211; background processing stuff.<\/p>\n<p>To give you an idea what it is for here is a small example:<\/p>\n<pre><code>const allDummyDocs = new ValueHolder('allDummyDocs', 60, async () =&gt; {\r\n  \/\/ get all documents with the Form 'dummy'\r\n  return useServer(serverConfig).then(\r\n    async server =&gt; {\r\n      const db = await server.useDatabase(databaseConfig);\r\n      const response = await db.bulkReadDocuments({\r\n        query: \"Form = 'dummy'\"\r\n      });\r\n      return JSON.stringify(response);\r\n    }).catch(err =&gt; {\r\n      console.log(err);\r\n      return err;\r\n    });\r\n});<\/code><\/pre>\n<p>The first parameter is the key used to store\/retreive the value from memcached. The second one is the time how long the value should be cached. And the third parameter is the code to execute:<\/p>\n<ul>\n<li>Get all documents from the database with <em>Form = &#8218;dummy&#8216;<\/em><\/li>\n<li>Convert the resulting collection object to JSON.<\/li>\n<\/ul>\n<p>The JSON String is then stored in the cache for 60 seconds, and everytime the <em>get<\/em> method is called again the Domino server is not queried.<\/p>\n<p>To use the definition in the application, you now have to use the <em>get<\/em> method of the value holder:<\/p>\n<pre><code>router.get('\/showAllDummyDocs', (req, res) =&gt; {\r\n  allDummyDocs.get(\r\n      (error, result) =&gt; {\r\n        if (error) {\r\n          res.render('error', { title: 'Error', error });\r\n        } else {\r\n          res.render('index', { title: 'Express', result: `Result: ${result}` });\r\n        }\r\n      }\r\n    );\r\n  }\r\n);<\/code><\/pre>\n<p>The <em>ValueHolder<\/em> checks now automatically, if the result is stored in the cache. If not, the code is executed and stored in the cache.<\/p>\n<p>Here is the <em>ValueHolder.js<\/em> file (which has to be created in the <em>\/app\/classes<\/em> folder):<\/p>\n<pre><code>const mf = require('..\/classes\/MemcachedFactory');\r\n\r\nconst nullHelper = '###NULL###';\r\n\/**\r\n * Helper class for cached values\r\n * \r\n * @author Sven Hasselbach\r\n * @version 0.1\r\n *\/\r\nclass ValueHolder {\r\n\r\n    \/**\r\n     * \r\n     * @param {string} key \r\n     *  unique identifier\r\n     * @param {number} ttl\r\n     *  time-to-live in seconds \r\n     * @param {function} code \r\n     *  code to execute to calculate the value\r\n     *\/\r\n    constructor(key, ttl, code) {\r\n        this.key = key;\r\n        this.code = code;\r\n        this.ttl = ttl;\r\n    }\r\n\r\n    \/**\r\n     * loads the value from cache or \r\n     * computes it and stores it in the cache\r\n     * \r\n     * @param {function} callback \r\n     * @returns Promise\r\n     *\/\r\n    async get(callback) {\r\n        const { code, ttl, key } = this;\r\n    \r\n        \/\/ check if value is in cache...\r\n        mf.getInstance().get(key, (error, value) =&gt; {\r\n            if (error) {\r\n                callback(error);\r\n                return;\r\n            }\r\n            if (value != null) {\r\n                console.debug(`Found '${key}' in cache.`);\r\n                if (value === nullHelper) {\r\n                    \/\/ result is \"special\", so let's return null\r\n                    callback(error, null);\r\n                } else {\r\n                    console.log(value);\r\n                    callback(error, JSON.parse(value));\r\n                }\r\n            } else {\r\n                console.debug(`Computing '${key}' and adding to cache with ttl ${ttl}.`);\r\n\r\n                \/\/ execute the computation\r\n                code().then((result) =&gt; {\r\n                    \/\/ check if result must be stored \"special\" or not\r\n                    if (result === null) {\r\n                        mf.getInstance().set(key, nullHelper, ttl);\r\n                    } else {\r\n                        mf.getInstance().set(key, JSON.stringify(result), ttl);\r\n                    }   \r\n                    callback(error, result);\r\n                });\r\n            }\r\n        });\r\n     }\r\n\r\n}\r\n\r\nmodule.exports = ValueHolder;<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I am using this for years in Java, so I thought it would be great to use this approach also in the JavaScript world: The ValueHolder. The class allows to easily define &#8222;cachable&#8220; code and it&#8217;s result, without having to &hellip; <a href=\"https:\/\/hasselba.ch\/blog\/?p=2722\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[139,9,131],"tags":[138,140,143,132],"class_list":["post-2722","post","type-post","status-publish","format-standard","hentry","category-es6","category-javascript","category-node-js","tag-domino-db","tag-es6","tag-memcached","tag-node-js"],"_links":{"self":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2722"}],"version-history":[{"count":5,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2722\/revisions"}],"predecessor-version":[{"id":2727,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2722\/revisions\/2727"}],"wp:attachment":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}