<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andy Wermke</title>
    <description>The latest articles on DEV Community by Andy Wermke (@andywer).</description>
    <link>https://dev.to/andywer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F40703%2Fc7550012-abbd-47ce-8a22-7a9e2009b30a.jpg</url>
      <title>DEV Community: Andy Wermke</title>
      <link>https://dev.to/andywer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andywer"/>
    <language>en</language>
    <item>
      <title>Seamless web workers &amp; worker threads - threads.js</title>
      <dc:creator>Andy Wermke</dc:creator>
      <pubDate>Sat, 28 Dec 2019 16:19:42 +0000</pubDate>
      <link>https://dev.to/andywer/seamless-web-workers-worker-threads-threads-js-2g36</link>
      <guid>https://dev.to/andywer/seamless-web-workers-worker-threads-threads-js-2g36</guid>
      <description>&lt;p&gt;A quick leap into running cross-platform Javascript / TypeScript code in workers. Using a transparent API – minus the hassle.&lt;/p&gt;

&lt;p&gt;After half a year in beta, &lt;a href="https://threads.js.org"&gt;threads.js&lt;/a&gt; v1.0 has finally been released. It allows you to use web workers and worker threads in an intuitive way, provides features like thread pools, works in web clients as well as node.js and is less than 10kB in size!&lt;/p&gt;

&lt;p&gt;The benefits of using workers have already been covered in plenty of other articles, so here is the gist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leverage all the available CPU power to run heavy CPU-bound tasks&lt;/li&gt;
&lt;li&gt;Move all non-rendering code off the main thread to ensure smooth animations and a responsive user interface (web workers)&lt;/li&gt;
&lt;li&gt;Isolate software modules, restrict them to communicate via message passing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now even though the web worker and worker threads APIs are similar, unfortunately they are not fully compatible. Furthermore, they are rather low-level building blocks: Create a worker, subscribe to message, post a message, etc.&lt;/p&gt;

&lt;p&gt;What happens if you post some messages to a worker and one causes the worker to throw? Chances are the calling code will never know there was an error - it will just not receive a response message. And then there is all the glue code…&lt;/p&gt;

&lt;h2&gt;
  
  
  Powers of a transparent API
&lt;/h2&gt;

&lt;p&gt;Enter the stage… threads.js! Let's write a simple worker that hashes passwords for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// workers/auth.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sha256&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js-sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expose&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;threads/worker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's write the main thread's code – spawn a new worker and hash a password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// master.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;threads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./workers/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Super secret password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1234&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hashed password:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's simple. Expose a function in the worker, call it from the other thread – done!&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;auth.hashPassword()&lt;/code&gt; will always return a promise, whether &lt;code&gt;hashPassword&lt;/code&gt; originally returns a promise or not – the return value will be promisified, due to the async nature of worker communication.&lt;/p&gt;

&lt;p&gt;So what about error handling? It's simple as we are now working with a promise-based API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// master.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;threads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashed&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./workers/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Cannot spawn the worker or crashed immediately before doing anything&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Super secret password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1234&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Hashing this password failed&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hashed password:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By the way, did you notice &lt;code&gt;Thread.terminate()&lt;/code&gt;? We use it to terminate a worker once we are done using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run in node.js
&lt;/h2&gt;

&lt;p&gt;Let's take our previous sample code and change the ES module &lt;code&gt;import&lt;/code&gt; statements into &lt;code&gt;require()&lt;/code&gt; calls for now. You can clone the code from &lt;a href="https://gist.github.com/andywer/925395687f42f6da04d111adf7d428ac"&gt;this GitHub Gist&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone git@gist.github.com:925395687f42f6da04d111adf7d428ac.git ./threads-gist
$ cd threads-gist
$ npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running it is trivial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ node ./master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code will run in any node.js version that comes with worker threads support, so node 12+ or node 10+ with a feature flag set.&lt;/p&gt;

&lt;p&gt;You can even run it on node 8.12+. Install the &lt;code&gt;tiny-worker&lt;/code&gt; npm package – threads.js will automatically pick it up as a polyfill if worker threads are not available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build using webpack
&lt;/h2&gt;

&lt;p&gt;A vast number of people use webpack to bundle their code for front-end deployment. So how do we now make that code build with webpack?&lt;/p&gt;

&lt;p&gt;We use our code as is, take our webpack config and add the &lt;a href="https://www.npmjs.com/package/threads-plugin"&gt;&lt;code&gt;threads-plugin&lt;/code&gt;&lt;/a&gt; – that's it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;  // webpack.config.js
  const path = require("path")
&lt;span class="gi"&gt;+ const ThreadsPlugin = require("threads-plugin")
&lt;/span&gt;
  module.exports = {
    entry: {
      app: "./src/index.js"
    },
    mode: "development",
    module: {
      rules: [
        {
          test: /\.css$/,
          use: ["style-loader", "css-loader"]
        },
        {
          test: /\.jsx?$/,
          use: ["babel-loader"]
        }
      ]
    },
    output: {
      path: path.join(__dirname, "dist")
    },
    plugins: [
      new HtmlPlugin(),
&lt;span class="gi"&gt;+     new ThreadsPlugin()
&lt;/span&gt;    ]
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The plugin is based on Google's &lt;a href="https://github.com/GoogleChromeLabs/worker-plugin"&gt;&lt;code&gt;worker-plugin&lt;/code&gt;&lt;/a&gt; – it will recognize &lt;code&gt;new Worker()&lt;/code&gt; expressions, make sure the referenced worker file is bundled independently from the main entrypoint and rewrite the path in the &lt;code&gt;new Worker()&lt;/code&gt; expression to the worker bundle path.&lt;/p&gt;

&lt;h2&gt;
  
  
  First class TypeScript support
&lt;/h2&gt;

&lt;p&gt;Threads.js is written in TypeScript and thus fully statically typed, so your IDE's IntelliSense will show you all available exports, functions and parameters with documentation as you write. That's not all – even running TypeScript workers becomes easier.&lt;/p&gt;

&lt;p&gt;When running your TypeScript code in node.js you will frequently find yourself using &lt;code&gt;ts-node&lt;/code&gt; in development and running the transpiled JavaScript code in production.&lt;/p&gt;

&lt;p&gt;When resolving a worker, threads.js will try to load the transpiled JavaScript worker. If that fails and &lt;code&gt;ts-node&lt;/code&gt; is installed it will automatically fail-over to run the untranspiled TypeScript worker file using &lt;code&gt;ts-node&lt;/code&gt;. You don't have to lift a finger 🙌&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread pools, observables &amp;amp; more
&lt;/h2&gt;

&lt;p&gt;There is more to explore!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thread pools to spawn multiple workers and dispatch jobs to them&lt;/li&gt;
&lt;li&gt;Returning observables to expose events to subscribe to&lt;/li&gt;
&lt;li&gt;Support for transferable objects to efficiently pass binary data&lt;/li&gt;
&lt;li&gt;and more… 🚀&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the detailed documentation on &lt;a href="https://threads.js.org"&gt;threads.js.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are also more features to come. Check out the &lt;a href="https://github.com/andywer/threads.js"&gt;GitHub repository&lt;/a&gt; and its issues to see what's in discussion right now or watch the repository's releases to stay up to date.&lt;/p&gt;




&lt;p&gt;That's it for today – I hope you enjoyed the blog post. If you like the project, give the repository a 🌟 on GitHub, contribute to the development or &lt;a href="https://github.com/sponsors/andywer"&gt;become a sponsor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel invited to comment and leave feedback of any kind below.&lt;/p&gt;

&lt;p&gt;Happy holidays and happy hacking!&lt;/p&gt;

&lt;p&gt;Andy&lt;/p&gt;

&lt;p&gt;&lt;a href="https://unsplash.com/photos/EUsVwEOsblE"&gt;&lt;em&gt;Teaser image by Adi Goldstein on Unsplash&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to use: npm tags</title>
      <dc:creator>Andy Wermke</dc:creator>
      <pubDate>Fri, 25 Jan 2019 16:01:57 +0000</pubDate>
      <link>https://dev.to/andywer/how-to-use-npm-tags-4lla</link>
      <guid>https://dev.to/andywer/how-to-use-npm-tags-4lla</guid>
      <description>&lt;p&gt;There is a feature in npm that affects every &lt;code&gt;npm install&lt;/code&gt;, every &lt;code&gt;npm publish&lt;/code&gt;, yet most npm users seem to be unaware of.&lt;/p&gt;

&lt;p&gt;Time to talk about &lt;a href="https://docs.npmjs.com/cli/dist-tag"&gt;npm tags&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  What they are
&lt;/h2&gt;

&lt;p&gt;Let's jump right into it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;On every &lt;code&gt;npm install &amp;lt;package&amp;gt;&lt;/code&gt; without an explicit version, a tag is used to resolve the right version number: The &lt;code&gt;latest&lt;/code&gt; tag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On every &lt;code&gt;npm publish&lt;/code&gt; a tag is either updated or created. Yes, it defaults to the &lt;code&gt;latest&lt;/code&gt; tag, too.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let's assume a busy work day has just begun and you add a new package to your dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install cowsay
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now as you did not specify any version to install, how does npm decide which version to use? It uses the &lt;code&gt;latest&lt;/code&gt; tag!&lt;/p&gt;

&lt;p&gt;Check this out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm show cowsay

cowsay@1.4.0 | MIT | deps: 4 | versions: 19
cowsay is a configurable talking cow
https://github.com/piuccio/cowsay

keywords: cow, cowsay, cowthink, figlet, talking, ASCII

bin: cowsay, cowthink

(...)

dist-tags:
latest: 1.4.0

published a month ago by piuccio &amp;lt;piuccio@gmail.com&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Have a look at &lt;code&gt;dist-tags&lt;/code&gt;. It shows only one tag, the &lt;code&gt;latest&lt;/code&gt; tag. Judging by &lt;code&gt;npm show&lt;/code&gt;'s output we can already imagine what a tag's function is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tags are a mapping from some human-friendly identifier to a specific version number.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aha! So when you do your casual &lt;code&gt;npm install cowsay&lt;/code&gt;, npm will fetch the package metadata (try &lt;code&gt;npm show cowsay --json&lt;/code&gt;), including a list of all published tags of the package. The &lt;code&gt;latest&lt;/code&gt; tag will tell npm what version to install.&lt;/p&gt;

&lt;p&gt;So why doesn't npm just install the version with the most recent publishing timestamp? We will get to this in no time, but let's add a spoiler here:&lt;/p&gt;

&lt;p&gt;Because the most recent &lt;code&gt;npm publish&lt;/code&gt; might not have published a &lt;em&gt;stable&lt;/em&gt; version, but maybe some early beta version that the user is not supposed to run in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using tags
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Consuming
&lt;/h3&gt;

&lt;p&gt;To install a package, but &lt;em&gt;not&lt;/em&gt; the &lt;code&gt;latest&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install &amp;lt;package&amp;gt;@&amp;lt;tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A popular example would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install the latest alpha version of React
$ npm install react@next
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Publishing
&lt;/h3&gt;

&lt;p&gt;To publish a version of your precious package that should not be installed by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm publish --tag &amp;lt;tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This way you can easily share some unstable code with others, so they can test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm publish --tag beta
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm publish --tag testing-feature-new-dashboard
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As already mentioned before, running &lt;code&gt;npm publish&lt;/code&gt; without a &lt;code&gt;--tag&lt;/code&gt; parameter will also update a tag: The &lt;code&gt;latest&lt;/code&gt; tag which is the default tag for publishing and installing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Changing tags
&lt;/h3&gt;

&lt;p&gt;You can always change tags to point to another version if you need to. Use the &lt;code&gt;npm dist-tag&lt;/code&gt; sub-command for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm dist-tag --help
npm dist-tag add &amp;lt;pkg&amp;gt;@&amp;lt;version&amp;gt; [&amp;lt;tag&amp;gt;]
npm dist-tag rm &amp;lt;pkg&amp;gt; &amp;lt;tag&amp;gt;
npm dist-tag ls [&amp;lt;pkg&amp;gt;]

alias: dist-tags
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Use it to fix the tag if you accidentally published a version using the wrong tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difference to git tags
&lt;/h2&gt;

&lt;p&gt;It's important to note that npm tags are semantically different to how git tags are commonly used, even though technically they are very similar.&lt;/p&gt;

&lt;p&gt;A git tag points to a commit, which is the code at a particular point in time, and usually never changes. The git tag is essentially the equivalent of an npm version.&lt;/p&gt;

&lt;p&gt;An npm tag on the other hand is a mutable pointer to a version, which in turn is an immutable pointer to the code at one particular point in time. So an npm tag is basically a meta pointer.&lt;/p&gt;

&lt;p&gt;When thinking in git terms, both npm tags and npm versions could be implemented using git tags, just that the former type of tag would be considered mutable, while the version git tags would be considered immutable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Profit $$
&lt;/h2&gt;

&lt;p&gt;So how can we use that feature to our benefit in day-to-day work?&lt;/p&gt;

&lt;p&gt;We can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Share an unstable version with beta testers&lt;/strong&gt;: &lt;code&gt;npm publish --tag beta&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish a use-once-and-forget version&lt;/strong&gt;: &lt;code&gt;npm publish --tag testing-new-feature&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installing that version on the other end will be just as simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install my-fancy-package@testing-new-feature
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Release early, release often. Don't screw with your production users, though. Use npm tags.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Teaser photo by &lt;a href="https://unsplash.com/photos/Ut9yic62qLE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Paul Murphy&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/graffiti?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;. Shows spray tags, not npm tags.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Built an unconventional database thing</title>
      <dc:creator>Andy Wermke</dc:creator>
      <pubDate>Wed, 09 Jan 2019 20:02:32 +0000</pubDate>
      <link>https://dev.to/andywer/built-an-unconventional-database-thing---feedback-5e52</link>
      <guid>https://dev.to/andywer/built-an-unconventional-database-thing---feedback-5e52</guid>
      <description>&lt;p&gt;Hey folks!&lt;/p&gt;

&lt;p&gt;I just built a tool to statically evaluate SQL queries in JavaScript and TypeScript code: &lt;a href="https://github.com/andywer/postguard"&gt;Postguard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's born out of the desire to write explicit database queries without a query builder, yet statically analyzable, and built on top of Babel and the TypeScript compiler API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it do?
&lt;/h2&gt;

&lt;p&gt;You query the database like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;squid/pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;queryUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
    SELECT * FROM users WHERE if = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  `&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Define a schema for your tables. The record type can be derived from the schema when using TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// schema.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TableRow&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;squid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TableRow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;usersTable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defineTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's run &lt;code&gt;postguard&lt;/code&gt; to validate what we just wrote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx postguard ./sample/*.ts

✖ Query validation failed in sample/test.ts:7:32:

  No table in the query's scope has a column "if".
  Tables in scope: "users"

   5 | export async function queryUserByID(id: number) {
   6 |   const { rows } = await database.query&amp;lt;UserRecord&amp;gt;(sql`
&amp;gt;  7 |     SELECT * FROM users WHERE if = ${id}
     |                               ^
   8 |   `)
   9 |   return rows[0] || null
  10 | }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ahhh, we have a typo in our query! Let's fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
  SELECT * FROM users WHERE id = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's run it again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx postguard ./sample/*.ts

✔ Validated 1 queries against 1 table schemas. All fine!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  More advanced stuff
&lt;/h2&gt;

&lt;p&gt;Let's take our previous sample code and change the SELECT query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;squid/pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;queryUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
    SELECT id, name FROM users WHERE id = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  `&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx postguard ./sample/*.ts

✖ Query validation failed in sample/test.ts:6:40:

  Query's result does not match the expected result type.
    Missing columns in result rows: "created_at"
    Actual columns in result rows: "id", "name"

  4 |
  5 | export async function queryUserByID(id: number) {
&amp;gt; 6 |   const { rows } = await database.query&amp;lt;UserRecord&amp;gt;(sql`
    |                                        ^^^^^^^^^^^^
  7 |     SELECT id, name FROM users WHERE id = ${id}
  8 |   `)
  9 |   return rows[0] || null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What happened? We defined that we expect the query to return &lt;code&gt;rows&lt;/code&gt; of type &lt;code&gt;UserRecord&lt;/code&gt;:&lt;br&gt;
&lt;code&gt;await database.query&amp;lt;UserRecord&amp;gt;(/*...*/)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Postguard evaluated the query and noticed that the result rows of that SELECT query do not match the TypeScript type &lt;code&gt;UserRecord&lt;/code&gt;, since that type has a &lt;code&gt;created_at&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;The fix is trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;squid/pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;queryUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
    SELECT * FROM users WHERE id = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  `&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx postguard ./sample/*.ts

✔ Validated 1 queries against 1 table schemas. All fine!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;So why did I even spent my time on that? Having worked with ORMs for years, I slowly grew more and more tired of them. A query builder seemed like a better solution.&lt;/p&gt;

&lt;p&gt;Now the issue with query builders is that you effectively write SQL queries, but not as SQL queries; you formulate them using the query builder's proprietary API. Now I need to read up on two complex interfaces: My Postgres' fancy SQL features AND the query builder's comprehensive API...&lt;/p&gt;

&lt;p&gt;Writing good old SQL feels like the natural way, so back to that. But now I've lost all confidence in my code and need to keep a really high test coverage, since I cannot statically reason about my queries. I actually need to run them to see if they work at all.&lt;/p&gt;

&lt;p&gt;Enter the stage: Postguard. Back to confidence and short feedback cycles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;So this tool is still pretty damn young and should not be used for production code yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I would love to hear some feedback regarding the overall approach, though!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The concept might seem a bit esoteric, but the code feels quite natural.&lt;/p&gt;

&lt;p&gt;Share anything that's on your mind :)&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

</description>
      <category>githunt</category>
      <category>postgres</category>
      <category>node</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
