{"id":472,"date":"2020-10-04T11:22:08","date_gmt":"2020-10-04T18:22:08","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=472"},"modified":"2020-10-07T09:53:55","modified_gmt":"2020-10-07T16:53:55","slug":"promises-node-tedious-azure-sql-oh-my","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/promises-node-tedious-azure-sql-oh-my\/","title":{"rendered":"Promises, Node, Tedious, Azure SQL. Oh My!"},"content":{"rendered":"<p><img decoding=\"async\" class=\"wp-image-473 size-full aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2020\/09\/dfqksgvwyecfedpo59vj.jpg\" alt=\"Different Plugs\" width=\"1000\" height=\"420\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2020\/09\/dfqksgvwyecfedpo59vj.jpg 1000w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2020\/09\/dfqksgvwyecfedpo59vj-300x126.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2020\/09\/dfqksgvwyecfedpo59vj-768x323.jpg 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>If you are new to Node.js like I am, using\u00a0<a href=\"https:\/\/github.com\/tediousjs\/tedious\">Tedious<\/a>\u00a0to access Azure SQL can be challenging at the beginning. My understanding is that Tedious, while being fully asynchronous, doesn&#8217;t support nor\u00a0<a href=\"https:\/\/nodejs.dev\/learn\/understanding-javascript-promises\">Promises<\/a>\nnor the more modern\u00a0<a href=\"https:\/\/nodejs.dev\/learn\/modern-asynchronous-javascript-with-async-and-await\">async\/await pattern<\/a>. Tedious, in fact, uses\u00a0<a href=\"http:\/\/tediousjs.github.io\/tedious\/api-request.html\"><em>events<\/em><\/a>\u00a0to execute asynchronous code and so a bit of work is needed to make it compatible with Promises.<\/p>\n<p>At the end of the day is just a few lines of code, but the process of discovering those two lines can be quite long and sometime frustrating. There is no\u00a0<em>clear<\/em>\u00a0statement anywhere that shows how to properly do that. I think that&#8217;s due to the fact that once you get the grasp of Promises it became absolutely obvious&#8230;.but if you haven&#8217;t got to that point, you&#8217;re left in the dark.<\/p>\n<p>Well, let&#8217;s shed some light then, and fix this hole in the shared knowledge book that is the internet!<\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/andrewcourtice\/ocula-a-free-weather-app-written-in-vue-3-2mdl?utm_source=digest_mailer&amp;utm_medium=email&amp;utm_campaign=digest_email#encapsulate-usage-of-tedious\" name=\"encapsulate-usage-of-tedious\"><\/a>Encapsulate usage of Tedious<\/h2>\n<p>To avoid writing the same code again and again, you probably want to encapsulate the business logic that executes a SQL command into a function. Something &#8211; in theory &#8211; like the following<\/p>\n<pre class=\"prettyprint\">executeSQL = function(query, params) {\r\n  var result = null;\r\n\r\n  const conn = new Connection(...);\r\n  conn.on('connect', err =&gt; { ... invoke req ... });\r\n\r\n  const req = new Request(query, err =&gt; { return result });\r\n  req.addParameter(...params...);\r\n  req.on('rows', columns =&gt; { ... build result ... });\r\n  \r\n  conn.connect();  \r\n}<\/pre>\n<p>After the\u00a0<code>connect()<\/code>\u00a0method has been successfully called, the\u00a0<em>connect<\/em>\u00a0event will happen. From there, the created\u00a0<code>Request<\/code>\u00a0can be executed. The request will generate a\u00a0<code>row<\/code>\u00a0event that allows you to get the result coming in from Azure SQL, and process and store it into a variable of your choice.<\/p>\n<p>The challenge now is: how do we return the variable with the resultset to the caller?<\/p>\n<p>Writing something like<\/p>\n<pre class=\"prettyprint\">queryResult = executeSQL(...)<\/pre>\n<p>will work but will not produce any result, as the content of\u00a0<code>executeSQL<\/code>\u00a0function will be executed asynchronously. This means that, even if we would add a\u00a0<code>return result;<\/code>\u00a0to the function body, just before it ends, the only thing that will be stored into our\u00a0<code>queryResult<\/code>\u00a0variable is&#8230;nothing. If fact, the\u00a0<code>return<\/code>\u00a0statement materially switches execution back to the caller, but at that time the\u00a0<code>result<\/code>\u00a0variable will still be empty as it is very unlikely that Azure SQL would have returned results so quickly. Azure SQL can easily return data in milliseconds, but in this case we&#8217;re taking about microseconds or less, and just the network roundtrip is more than that.<\/p>\n<p>So what we need to do is to make sure that we start to use the variable\u00a0<code>result<\/code>\u00a0and its contents only when they are available.<\/p>\n<p>That&#8217;s exactly what a Promise do. Taken from aforementioned and linked documentation:\u00a0<em>&#8220;A promise is commonly defined as a proxy for a value that will eventually become available.&#8221;<\/em><\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/andrewcourtice\/ocula-a-free-weather-app-written-in-vue-3-2mdl?utm_source=digest_mailer&amp;utm_medium=email&amp;utm_campaign=digest_email#create-the-promise-wrapper\" name=\"create-the-promise-wrapper\"><\/a>Create the Promise Wrapper<\/h2>\n<p>With that clear in our mind, it now become obvious that we need to wrap our reusable method in a Promise, instead of a classic function. The code will then look like the following:<\/p>\n<pre class=\"prettyprint\">const executeSQL = (query, params) =&gt; new Promise(\r\n  (resolve, reject) =&gt; { \r\n\r\n  ...function body...\r\n}<\/pre>\n<p>That&#8217;s easy right? There are two callbacks that we now have access to<\/p>\n<ul>\n<li><code>resolve<\/code>: to do something when the everything worked as expected and result is ready to be processed by the caller<\/li>\n<li><code>reject<\/code>: when something didn&#8217;t work and result is not available.<\/li>\n<\/ul>\n<p>Given that we know that the Request object also supports a callback to allow us to execute some code once the resultset has been fully sent by Azure SQL, the original code will now look like this:<\/p>\n<pre class=\"prettyprint\">const req = new Request(query, (err) =&gt; {\r\n        if (err) {\r\n            reject(err);\r\n        } else {\r\n            resolve(result);\r\n        }       \r\n    });<\/pre>\n<p>We know we can safely use the\u00a0<code>result<\/code>\u00a0variable here, which was populated inside the\u00a0<code>row<\/code>\u00a0event handler, as\u00a0<a href=\"http:\/\/tediousjs.github.io\/tedious\/api-request.html\">Tedious doc assure us<\/a>\u00a0that:\u00a0<em>&#8220;The callback is called when the request has completed, either successfully or with an error. If an error occurs during execution of the statement(s), then err will describe the error.&#8221;<\/em><\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/andrewcourtice\/ocula-a-free-weather-app-written-in-vue-3-2mdl?utm_source=digest_mailer&amp;utm_medium=email&amp;utm_campaign=digest_email#use-the-promise-luke\" name=\"use-the-promise-luke\"><\/a>Use the Promise, Luke!<\/h2>\n<p>Now that we have our Promise, let&#8217;s use it.<\/p>\n<p>Somewhere in our code we want to call the\u00a0<code>executeSQL<\/code>\u00a0function and get the result into a variable of our choice. Instead of writing something like,<\/p>\n<pre class=\"prettyprint\">const result = executeSQL(query, params);<\/pre>\n<p>we need to do something like this instead:<\/p>\n<pre class=\"prettyprint\">executeSQL(query, params)\r\n  .then(ok =&gt; {\r\n     ...process result code here...\r\n        })\r\n  .catch(err =&gt; {\r\n     ...handle errors here...\r\n        });<\/pre>\n<p>In the\u00a0<code>then<\/code>\u00a0code block you can use the result, now available in the\u00a0<code>ok<\/code>\u00a0variable.<\/p>\n<p>That&#8217;s, done! All will now work smoothly and nicely.<\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/andrewcourtice\/ocula-a-free-weather-app-written-in-vue-3-2mdl?utm_source=digest_mailer&amp;utm_medium=email&amp;utm_campaign=digest_email#conclusion\" name=\"conclusion\"><\/a>Conclusion<\/h2>\n<p>I really hope this article helps to clearly resolve this challenge once and for all. I would have loved to have such article right away, it would have saved hours and hours in my life. Now I have a quite good understanding on Promises, and &#8211; yeah &#8211; everything is trivial now, but reaching this point has been a painful voyage. Coding should be joy, not pain! Frustration is ok and also helpful sometimes, but I felt that here was way too much. Well, the table is turned now, this article is here to bring joy back to the game.<\/p>\n<p>Until next time, have fun.<\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/andrewcourtice\/ocula-a-free-weather-app-written-in-vue-3-2mdl?utm_source=digest_mailer&amp;utm_medium=email&amp;utm_campaign=digest_email#wait-i-want-the-source-code\" name=\"wait-i-want-the-source-code\"><\/a>Wait! I Want the Source Code!<\/h2>\n<p>Uh yeah, of course, source code! It&#8217;s here:\u00a0<a href=\"https:\/\/github.com\/Azure-Samples\/azure-sql-db-todo-backend-func-node\">Todo Backend Implementation with Azure Functions, Node and Azure SQL<\/a>\u00a0and more specifically the code described in the article is\u00a0<a href=\"https:\/\/github.com\/Azure-Samples\/azure-sql-db-todo-backend-func-node\/blob\/main\/shared\/utils.js\">here<\/a>.<\/p>\n<p>As an exercise I took the chance to implement a fully working back-end API for the\u00a0<a href=\"http:\/\/todomvc.com\/\">Todo MVC app<\/a>, following the\u00a0<a href=\"http:\/\/www.todobackend.com\/\">Todo Backend API<\/a> specifications. Love how everything amazingly works well together like a couple of LEGO bricks.<\/p>\n<p>&#8212;<\/p>\n<p>Photo by <a href=\"https:\/\/www.pexels.com\/@castorlystock?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels\">Castorly Stock<\/a> from <a href=\"https:\/\/www.pexels.com\/photo\/black-wall-plugs-3639031\/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels\">Pexels<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you are new to Node.js like I am, using\u00a0Tedious\u00a0to access Azure SQL can be challenging at the beginning. My understanding is that Tedious, while being fully asynchronous, doesn&#8217;t support nor\u00a0Promises nor the more modern\u00a0async\/await pattern. Tedious, in fact, uses\u00a0events\u00a0to execute asynchronous code and so a bit of work is needed to make it compatible [&hellip;]<\/p>\n","protected":false},"author":24720,"featured_media":480,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,430,429],"tags":[30,449,463,460],"class_list":["post-472","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sql","category-javascript","category-node","tag-developers","tag-development","tag-promises","tag-tedious"],"acf":[],"blog_post_summary":"<p>If you are new to Node.js like I am, using\u00a0Tedious\u00a0to access Azure SQL can be challenging at the beginning. My understanding is that Tedious, while being fully asynchronous, doesn&#8217;t support nor\u00a0Promises nor the more modern\u00a0async\/await pattern. Tedious, in fact, uses\u00a0events\u00a0to execute asynchronous code and so a bit of work is needed to make it compatible [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/472","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/24720"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=472"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/472\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/480"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=472"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=472"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}