<?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: Simone Mosciatti</title>
    <description>The latest articles on DEV Community by Simone Mosciatti (@siscia_).</description>
    <link>https://dev.to/siscia_</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%2F167349%2F49cdaf91-ad78-4fdb-bf8d-56010a16216f.jpg</url>
      <title>DEV Community: Simone Mosciatti</title>
      <link>https://dev.to/siscia_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siscia_"/>
    <language>en</language>
    <item>
      <title>Use SimpleSQL from Github pages</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Wed, 08 Apr 2020 08:50:47 +0000</pubDate>
      <link>https://dev.to/siscia_/use-simplesql-from-github-pages-2jg5</link>
      <guid>https://dev.to/siscia_/use-simplesql-from-github-pages-2jg5</guid>
      <description>&lt;p&gt;&lt;a href="https://simplesql.redbeardlab.com/"&gt;SimpleSQL&lt;/a&gt; is an HTTP API that allow complete control over a SQLite database.&lt;/p&gt;

&lt;p&gt;Underneath &lt;a href="https://simplesql.redbeardlab.com/"&gt;SimpleSQL&lt;/a&gt; is based on &lt;a href="https://redisql.com/"&gt;RediSQL&lt;/a&gt; to manage all the different databases, connections, backups, replication, etc.&lt;/p&gt;

&lt;p&gt;One of the most compelling use case is to &lt;a href="https://simplesql.redbeardlab.com/"&gt;SimpleSQL&lt;/a&gt; to create completely static webpages that can operate against one database. This would allow to create very powerful webapp that don’t need a server backend. All the interaction with the backend can happen directly on the client code.&lt;/p&gt;

&lt;p&gt;A common way to host a simple web app, is to use &lt;a href="https://pages.github.com/"&gt;Github pages&lt;/a&gt;, which offer a free space for open source projects.&lt;/p&gt;

&lt;p&gt;In order to use &lt;a href="https://simplesql.redbeardlab.com/"&gt;SimpleSQL&lt;/a&gt; you need to allow the browser to make CORS requests against &lt;code&gt;simplesql.redbeardlab.com&lt;/code&gt;. Doing so allow the browser to make HTTP requests against the &lt;code&gt;simplesql.redbeardlab.com&lt;/code&gt; domain.&lt;/p&gt;

&lt;p&gt;Fortunately github pages already allow it, so no step is necessary for the CORS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://simplesql.redbeardlab.com/"&gt;SimpleSQL&lt;/a&gt; provide also a &lt;a href="https://github.com/RedBeardLab/SimpleSQLSDK/"&gt;JS SDK&lt;/a&gt;, which makes writing application simpler.&lt;/p&gt;

&lt;p&gt;In order to use &lt;a href="https://github.com/RedBeardLab/SimpleSQLSDK/"&gt;the SDK&lt;/a&gt; is sufficient to import it adding the following line in the head section of your html pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@redbeardlab/simplesql@&amp;gt;=1.0.8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once imported the SDK it will be possible to invoke all the SimpleSQL functions, like: &lt;code&gt;SimpleSQL.newDatabase()&lt;/code&gt; to create a new database, or &lt;code&gt;SimpleSQL.command(db, "select 1;")&lt;/code&gt; to execute a command against one database, all this from client code.&lt;/p&gt;

&lt;p&gt;An example, hosted on Github pages, is &lt;a href="https://redisql.redbeardlab.com/SimpleSQLSDK/"&gt;available here&lt;/a&gt; with the &lt;a href="https://github.com/RedBeardLab/SimpleSQLSDK/blob/master/index.html"&gt;source being here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/RedBeardLab/SimpleSQLSDK/"&gt;The documentation for the SDK is on github.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.swaggerhub.com/apis-docs/redbeardlab/simplesql.redbeardlab.com/"&gt;While the raw HTTP API are documented on swagger.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>simplesql</category>
      <category>api</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Invarian as Interface</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Fri, 21 Feb 2020 21:43:02 +0000</pubDate>
      <link>https://dev.to/siscia_/invarian-as-interface-2n5k</link>
      <guid>https://dev.to/siscia_/invarian-as-interface-2n5k</guid>
      <description>&lt;p&gt;An invariant is a condition that holds true no matter what during the execution of a phase of a computer program.&lt;/p&gt;

&lt;p&gt;For instance, in a classical for loop, for (i = 0; i &amp;lt;= 10; i++) an invariant would be that the value of i is always between 0 and 10 (beside explicit changes of i).&lt;/p&gt;

&lt;p&gt;Trying to keep as many invariant as possible internally our software help the development. But we can use invariant also as interface, and it helps immensely consuming our software.&lt;/p&gt;

&lt;p&gt;I was hit by this problem when I started to actually stress my own software, it took a while to admit that I did a sub-optimal choice in one of the main interface of RediSQL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redisql.com/"&gt;RediSQL&lt;/a&gt; is a Redis module that allow users to send SQL commands to a Redis. The memory space between Redis and RediSQL are separated so you can’t query Redis with SQL, but you can create your own table and use those. RediSQL is based on SQLite.&lt;/p&gt;

&lt;p&gt;One of the main interface of RediSQL is the REDISQL.EXEC command, that execute a raw SQL statement against one SQLite database.&lt;/p&gt;

&lt;p&gt;Upon executing a SQL command, SQLite can return three different values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OK&lt;/li&gt;
&lt;li&gt;DONE, and the number of rows modified&lt;/li&gt;
&lt;li&gt;A result consisting of more than one row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I implemented the REDISQL.EXEC command to return, respectively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The string “OK”&lt;/li&gt;
&lt;li&gt;An array containing the string “DONE” and one integer&lt;/li&gt;
&lt;li&gt;An array of array containing the result of a query&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moreover, a query that returns no rows, will return DONE not an empty result.&lt;/p&gt;

&lt;p&gt;While this seems a reasonable interface when used in the CLI, it is very difficult to use programmatically.&lt;/p&gt;

&lt;p&gt;The user needs to test if the result is a string, and then make sure that the string is actually “OK” to match the first case.&lt;/p&gt;

&lt;p&gt;If it is not a string, it must be an array, so the user will need to check if it is an array of length 2, and if the first elements of the array is the string “DONE” to match the second case.&lt;/p&gt;

&lt;p&gt;Finally to match a query result, the user need to make sure that the result is an array of array, and now it can consume the result.&lt;/p&gt;

&lt;p&gt;This is very cumbersome and tedious to implement, especially in statically typed languages like go(lang) and java. In those languanges the result is consumed as a generic &lt;code&gt;{}interface&lt;/code&gt; or &lt;code&gt;Object&lt;/code&gt; and parsed in something more safe. It is a little better is dynamically typed languages.&lt;/p&gt;

&lt;p&gt;While developing SimpleSQL on top of RediSQL, I understood that this was a real problem and I decide to create a v2 for RediSQL, fixing several other design mistake I did the first time.&lt;/p&gt;

&lt;p&gt;The new interface exploit exactly the concept of Invariant as Interface. Now the REDISQL.EXEC always returns an array of array and in the first array, as first elements there is always a string. Either: “OK”, “DONE” or “RESULT”.&lt;/p&gt;

&lt;p&gt;Consuming this API is much simpler, the user know that it will always receive an array of array, and that in the first position there will be a tag to indicate how the rest of the result should be interpreted and used.&lt;/p&gt;

&lt;p&gt;Then the same concept was exported to SimpleSQL creating an API simple to consume.&lt;/p&gt;

&lt;p&gt;If interested in &lt;a href="https://landing.mailerlite.com/webforms/landing/d5m9d6"&gt;SimpleSQL subscribe to the mail list of the product&lt;/a&gt; or &lt;a href="https://twitter.com/siscia_"&gt;follow me on Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>productivity</category>
    </item>
    <item>
      <title>
Installing software, brief guide for when stuff don’t work.
</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Fri, 31 Jan 2020 18:00:04 +0000</pubDate>
      <link>https://dev.to/siscia_/installing-software-brief-guide-for-when-stuff-don-t-work-pdg</link>
      <guid>https://dev.to/siscia_/installing-software-brief-guide-for-when-stuff-don-t-work-pdg</guid>
      <description>&lt;p&gt;In this short post we are going to understand how to install software when stuff don’t work out of the box. We will understand how a *NIX shell search for software and how to make sure that our binaries are always found.&lt;/p&gt;

&lt;p&gt;When dealing with software, installation is a classical issues. Hopefully the software you wan to install is available as a package from your favorite package manager (deb, rpm, something else) and usually those packages are well done and everything works out of the box.&lt;/p&gt;

&lt;p&gt;However, you may need to install software that is not available as a package, or the package is broken, or something that yesterday use to work, today is not working anymore.&lt;/p&gt;

&lt;p&gt;In those cases there are usually two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start everything from scratch again (delete the virtual machine or stop the docker containers)&lt;/li&gt;
&lt;li&gt;Understand the inner working of the system so that you can fix it, and make sure that similar problems don’t happens again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a brief guide for the second option. I assume a basic knowledge of *NIX systems and some familiarity with the command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it means to install software
&lt;/h2&gt;

&lt;p&gt;The more proficient you become with the topic, the less “install” is simple to define.&lt;/p&gt;

&lt;p&gt;In this post, with “install” we mean to set up the system in such a way that is possible to invoke a binary. A complete installation make sure that all the necessary environmental variables are set up correctly.&lt;/p&gt;

&lt;p&gt;It can be as simple as &lt;code&gt;apt-get install&lt;/code&gt; or it can be more complex.&lt;br&gt;
Binaries&lt;/p&gt;

&lt;p&gt;To install a binary is sufficient to place it in the system &lt;code&gt;PATH&lt;/code&gt;. The system path is an environment variable that stores an ordered list of &lt;code&gt;PATH&lt;/code&gt;s. At the moment, in my system it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The paths are ordered and separated by a colon &lt;code&gt;:&lt;/code&gt; so in this case the paths are:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The different directories are there for convention, for instance the &lt;code&gt;sbin&lt;/code&gt; directories are for system-recovery software.&lt;/p&gt;

&lt;p&gt;When we start a binary, the shell check if it find the binary in the path, the check is done by name.&lt;/p&gt;

&lt;p&gt;To visualize let’s try to log all the system calls when we invoke the &lt;code&gt;tree&lt;/code&gt; binary. (&lt;code&gt;tree&lt;/code&gt; print the directory structure of a given folder, and you can install it from system packages.)&lt;/p&gt;

&lt;p&gt;To visualize the system calls we can use &lt;code&gt;strace&lt;/code&gt; (again available from system packages).&lt;/p&gt;

&lt;p&gt;However, we cannot call just &lt;code&gt;strace tree&lt;/code&gt; since &lt;code&gt;strace&lt;/code&gt; will start to log after we have already found tree, but we can &lt;code&gt;strace bash&lt;/code&gt; that in turn will invoke &lt;code&gt;tree&lt;/code&gt; like so.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ strace bash -c "tree -D 1"
... a lot of stuff ...
stat("/usr/local/sbin/tree", 0x7ffcb15ffea0) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/tree", 0x7ffcb15ffea0) = -1 ENOENT (No such file or directory)
stat("/usr/sbin/tree", 0x7ffcb15ffea0)  = -1 ENOENT (No such file or directory)
stat("/usr/bin/tree", {st_mode=S_IFREG|0755, st_size=77384, ...}) = 0
... yet more stuff ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As expected the system is checking all the directories in the path, in order. It start checking if a file called tree is present in the first directory &lt;code&gt;stat /usr/local/sbin/tree&lt;/code&gt; but it returns an error, &lt;code&gt;-1&lt;/code&gt; the file is not there. Similarly for &lt;code&gt;/usr/local/bin/tree&lt;/code&gt; and &lt;code&gt;/usr/sbin/tree&lt;/code&gt;. Finally it find the file in &lt;code&gt;/usr/bin/tree&lt;/code&gt; and it can finally invoke it.&lt;/p&gt;

&lt;p&gt;So there are two way to install software, the first one is to add the binaries to one of the path in &lt;code&gt;$PATH&lt;/code&gt;, the other is to add the path that contains our binaries to &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tricking the shell into invoking the wrong command
&lt;/h2&gt;

&lt;p&gt;This system is quite fragile, the checks happens only at level of strings, without doing anything more than a plain string comparison.&lt;/p&gt;

&lt;p&gt;What happens if we install a new software, called tree?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir -p /fake/bin
$ cat /fake/bin/tree
#! /bin/bash
echo "fake tree"
$ chmod +x /fake/bin/tree
$ /fake/bin/tree
fake tree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we have created a new binaries directory (&lt;code&gt;/fake/bin&lt;/code&gt;), and we put inside it an executable (&lt;code&gt;chmod +x&lt;/code&gt;) called &lt;code&gt;tree&lt;/code&gt;. The fake tree just print out a string.&lt;/p&gt;

&lt;p&gt;Now if we invoke &lt;code&gt;tree&lt;/code&gt; the regular process will happen, all the directories in &lt;code&gt;$PATH&lt;/code&gt; are checked until a tree executable is found, and if found it is executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree -D 1 
1 [error opening dir]

0 directories, 0 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Indeed the regular tree software is invoked.&lt;/p&gt;

&lt;p&gt;Let’s change the &lt;code&gt;$PATH&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export PATH="/fake/bin:$PATH"
$ echo $PATH
/fake/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now the first directory checked is &lt;code&gt;/fake/bin&lt;/code&gt;, and the system will find an executable called tree in there.&lt;/p&gt;

&lt;p&gt;And if we invoke tree again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree -D 1
fake tree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As expected the fake tree is invoked.&lt;/p&gt;

&lt;p&gt;This is source of great flexibility but also of many frustrations.&lt;/p&gt;

&lt;p&gt;It is flexible because it allow us to install new software without being administrators (&lt;code&gt;sudo&lt;/code&gt; access). Moreover it allow to have in the system system different version of the same software. But of course it is easy to make mistake and invoke by mistake the wrong executable.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;which&lt;/code&gt; to the rescue
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ which tree 
/fake/bin/tree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;which&lt;/code&gt; utility let us discover what path is followed when looking for a binary.&lt;/p&gt;

&lt;p&gt;Let’s fix this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
$  which tree
/usr/bin/tree
$ tree --version
tree v1.7.0 (c) 1996 - 2014 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Subscribe to the mail list, or follow me on &lt;a href="https://twitter.com/siscia_"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>ubuntu</category>
      <category>productivity</category>
      <category>bash</category>
    </item>
    <item>
      <title>Software is a FOCUS intensive industry.</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Sun, 19 Jan 2020 14:03:56 +0000</pubDate>
      <link>https://dev.to/siscia_/software-is-a-focus-intensive-industry-1ia5</link>
      <guid>https://dev.to/siscia_/software-is-a-focus-intensive-industry-1ia5</guid>
      <description>&lt;p&gt;Industries are usually characterized as labor-intensive or as capital-intensive.&lt;/p&gt;

&lt;p&gt;Labor-intensive industries requires a lot of human input in order to produce their output. A classical examples is the industry of services (like restaurants or hotel) or even old manufacturing (where people were building stuff with their hands.)&lt;/p&gt;

&lt;p&gt;Capital-intensive industries requires much less human input but they requires a lot of capital in order to produce their output. An example could be building oil rings, insurance companies, energy producers, airlines.&lt;/p&gt;

&lt;p&gt;Software does not fall in neither this two categories.&lt;/p&gt;

&lt;p&gt;With “software industry” I mean the industry that produce software products, ventures like AWS, Microsoft Azure or Google Cloud Platforms are definitely capital intensive industries. In this post I am talking about software product like Slack, Notion, WordPress, GCC.&lt;/p&gt;

&lt;p&gt;Software is not labor-intensive. Not many people are necessary in order to produce good software. On the contrary, Brooks’s law on software project management states that “adding manpower to a late software project makes it later”.&lt;/p&gt;

&lt;p&gt;Nor software is capital-intensive. Building a great software product does not requires huge money investments. Computing power is almost free nowadays and the same is true for bandwidth and storage.&lt;/p&gt;

&lt;p&gt;What makes or breaks a project, it’s the amount of FOCUS developers can pour into it.&lt;/p&gt;

&lt;p&gt;With focus I mean the internal knowledge of all the nitty-gritty details of the software and its surrounding. The knowledge of how the software is used and of how it solve real problems for the users. The knowledge of why it is implemented the way it is. The capacity to add features and fix bugs without breaking the software for a subset of users.&lt;/p&gt;

&lt;p&gt;What I defined as FOCUS is not just knowledge of computer programming and data structure, it is much more than just knowing the users, it is much more that testing and CI/CD. Of course those things are important but it is not just that. If it was sufficient, companies like Google, Amazon, Facebook, Microsoft would keep pushing out new flawless software product. But that is not the case.&lt;/p&gt;

&lt;p&gt;Obtain and maintaining FOCUS is extremely hard, it requires raw knowledge of the computing fundamentals, a lot of time and experience with the product and having build a strong community that sustains the effort (asking for features, trusting with updates, discuss the general direction of the product.)&lt;/p&gt;

&lt;p&gt;Unfortunately people get bored, especially in creative profession, when the product is mature, the job becomes more boring. Maintenance is still necessary and the most efficient person to maintain a piece of software will be the one less interested in doing it.&lt;/p&gt;

&lt;p&gt;Moreover, it is a risk for people to be stuck too long on the same project using the same set of technologies. The half-life of a particular technologies is very short in the software industry and developers are aware of it. It is a perfectly rational choice trying to mitigate this kind of risk. On the other hand management, pursuing efficiency, will push the developers to use the same old proven technologies.&lt;/p&gt;

&lt;p&gt;Finds the right balance between innovative work and efficient use of time is difficult for people managing projects. Too much innovation and nothing important get done, with developers chasing the new shinny, hyped, project. No innovation at all and developers are quickly alienated by keeping maintaining the same project.&lt;/p&gt;

&lt;p&gt;As last point, especially in the software industry, switching companies very often is the strategy recognized to maximize income. This makes even harder to reach FOCUS. If the team that works in a product completely changes in 5 years it is impossible that the team has FOCUS on the project.&lt;/p&gt;

&lt;p&gt;Unfortunately there are not easy answer, but is clear that being able to create production grade software is almost a necessity for every medium to big organization.&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Hierarchical JSON with SQLite / RediSQL</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Tue, 14 Jan 2020 20:29:02 +0000</pubDate>
      <link>https://dev.to/siscia_/hierarchical-json-with-sqlite-redisql-5e0n</link>
      <guid>https://dev.to/siscia_/hierarchical-json-with-sqlite-redisql-5e0n</guid>
      <description>&lt;h1&gt;
  
  
  Hierarchical JSON with SQLite / RediSQL
&lt;/h1&gt;

&lt;p&gt;RediSQL is compiled including the &lt;a href="https://www.sqlite.org/json1.html"&gt;JSON1&lt;/a&gt; SQLite extensions. Hence, all the functions documented in &lt;a href="https://www.sqlite.org/json1.html"&gt;JSON1&lt;/a&gt; are available out of the box.&lt;/p&gt;

&lt;p&gt;JSON1 is extremely flexible and powerful, as an example consider a report table that track sales in a company  by year, quarter and week.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; REDISQL.CREATE_DB DB
&amp;gt; REDISQL.EXEC DB "CREATE TABLE sales(year STRING, quarter STRING, week STRING, total INT);"
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2019', 'q1', '1', 100);"
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2019', 'q1', '2', 125);"
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2019', 'q2', '1', 200);" 
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2019', 'q2', '2', 300);" 
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2020', 'q1', '1', 400);" 
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2020', 'q1', '2', 450);" 
&amp;gt; REDISQL.EXEC DB "INSERT INTO sales VALUES('2020', 'q2', '1', 500);" 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From this table we would like to generate a JSON report in the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{'2019': 
  {'q1': {'1': 100, '2': 125}, 
   'q2': {'1': 200, '2': 300}}, 
 '2020': 
  {'q1': {'1': 400, '2': 450}, 
   'q2': {'1': 500}}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is not a trivial problem, because SQL generally does not like to return data in this format, just a string. However the JSON1 module is flexible enough and CTE provide us with enough expressing power.&lt;/p&gt;

&lt;p&gt;Let's see the final query first and then we will try to understand it piece by piece.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH quarters AS (
  WITH weeks AS (
      SELECT year, quarter, json_group_object(week, total) AS week_json 
      FROM sales 
      GROUP BY year, quarter
      ) 
  SELECT year, json_group_object(quarter, json(week_json)) AS quarters_json 
  FROM weeks 
  GROUP BY year
) 
SELECT json_group_object(year, json(quarters_json)) 
FROM quarters;"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This returns exactly the single line we are looking for. &lt;/p&gt;

&lt;p&gt;It seems a difficult query, but working on it piece by piece we can understand it quickly.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;WITH&lt;/code&gt; constructor simply create a "virtual table" valid for the execution of the query.&lt;/p&gt;

&lt;p&gt;The simplest way to understand this query is going inside-out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT year, quarter, json_group_object(week, total) AS week_json 
FROM sales 
GROUP BY year, quarter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;json_group_object&lt;/code&gt; is an aggreate query and it returns a JSON string with the &lt;code&gt;week&lt;/code&gt;s as key and the &lt;code&gt;total&lt;/code&gt;s as values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; REDISQL.EXEC DB "SELECT year, quarter, json_group_object(week, total) AS week_json FROM sales GROUP BY year, quarter" 
1) 1) (integer) 2019
   2) "q1"
   3) "{\"1\":100,\"2\":125}"
2) 1) (integer) 2019
   2) "q2"
   3) "{\"1\":200,\"2\":300}"
3) 1) (integer) 2020
   2) "q1"
   3) "{\"1\":400,\"2\":450}"
4) 1) (integer) 2020
   2) "q2"
   3) "{\"1\":500}"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this way we are able to create a JSON document that express the total of sales for each week. We compres the week columns in a flat JSON document.&lt;/p&gt;

&lt;p&gt;The next step is similar, for the year, we compress each quarter in a JSON document, the difficulties lays in maintaining the total of the weeks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;weeks&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;--- same query as above&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_group_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;week&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;week_json&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt; 
    &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quarter&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_group_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;week_json&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;quarters_json&lt;/span&gt; 
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;weeks&lt;/span&gt; 
  &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We introduce the &lt;code&gt;WITH&lt;/code&gt; statement. &lt;br&gt;
Using the &lt;code&gt;WITH&lt;/code&gt; statement we treat the result of the query above as a new table that we can use in the later statement, the new table is called &lt;code&gt;week&lt;/code&gt;.&lt;br&gt;
Note how we conveniently associate a name (&lt;code&gt;week_json&lt;/code&gt;) to the result of the &lt;code&gt;json_group_object&lt;/code&gt; aggregation. This is useful to manipulate that JSON object.&lt;/p&gt;

&lt;p&gt;The rest of the query is very similar, we are compressing all the quarters into a flat JSON object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; REDISQL.EXEC DB "WITH weeks AS ( SELECT year, quarter, json_group_object(week, total) AS week_json FROM sales GROUP BY year, quarter) SELECT year, json_group_object(quarter, json(week_json)) AS quarters_json FROM weeks GROUP BY year"
1) 1) (integer) 2019
   2) "{\"q1\":{\"1\":100,\"2\":125},\"q2\":{\"1\":200,\"2\":300}}"
2) 1) (integer) 2020
   2) "{\"q1\":{\"1\":400,\"2\":450},\"q2\":{\"1\":500}}"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This query provided us, for each year, a JSON hierarchical structure that map quarters and weeks tp total sales.&lt;/p&gt;

&lt;p&gt;Now, we can guess the last step, compress the years into another hierarchical JSON structure.&lt;/p&gt;

&lt;p&gt;This yield to the original query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;quarters&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;--- same query as above&lt;/span&gt;
  &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;weeks&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_group_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;week&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;week_json&lt;/span&gt; 
      &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt; 
      &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quarter&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_group_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;week_json&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;quarters_json&lt;/span&gt; 
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;weeks&lt;/span&gt; 
  &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nb"&gt;year&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;json_group_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quarters_json&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;quarters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nv"&gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And let's see the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; REDISQL.EXEC DB "WITH quarters AS ( WITH weeks AS ( SELECT year, quarter, json_group_object(week, total) AS week_json FROM sales GROUP BY year, quarter ) SELECT year, json_group_object(quarter, json(week_json)) AS quarters_json FROM weeks GROUP BY year) SELECT json_group_object(year, json(quarters_json)) FROM quarters;"

1) 1) "{\"2019\":{\"q1\":{\"1\":100,\"2\":125},\"q2\":{\"1\":200,\"2\":300}},\"2020\":{\"q1\":{\"1\":400,\"2\":450},\"q2\":{\"1\":500}}}"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The last result is a hierarchical JSON structure where the years map to the quartes, the quarters map to the weeks and the weeks map to the sales. &lt;/p&gt;

</description>
      <category>json</category>
      <category>sqlite</category>
      <category>redis</category>
      <category>sql</category>
    </item>
    <item>
      <title>Tracking the Trackers</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Sat, 18 May 2019 17:11:13 +0000</pubDate>
      <link>https://dev.to/siscia_/tracking-the-trackers-gch</link>
      <guid>https://dev.to/siscia_/tracking-the-trackers-gch</guid>
      <description>&lt;p&gt;This project wants to explore how the web is tracked by whom.&lt;/p&gt;

&lt;p&gt;As the most tech savvy readers know, when we visit a web page, several things happen in the background.&lt;/p&gt;

&lt;p&gt;The page from a server is sent to the browser of the user that start to paint on screen the content. However, it may be necessary for the browser to access other resources, the most common are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  images&lt;/li&gt;
&lt;li&gt;  instruction for how to style the several elements (like: color, dimension, position of the text), know as CSS&lt;/li&gt;
&lt;li&gt;  code for animation or smart application, know as JS&lt;/li&gt;
&lt;li&gt;  fonts (how a text appear)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these resources may be provided by the same website, or they may be provide by a different website.&lt;/p&gt;

&lt;p&gt;If those resources are provided by a different website, the browser needs to obtain them making a request to a different actor.&lt;/p&gt;

&lt;p&gt;All these requests may be used to track users on the web, especially if they are associated with cookies (hence the annoying banners on every website) and headers (from those we don’t have banners).&lt;/p&gt;

&lt;p&gt;An example of this are the Social button by Facebook, Twitter, Google, Reddit, etc… in order to show those buttons it is necessary to make a request to the respective company and send information about the user. In this way is possible to show very social buttons like (“Jon, Tyrion and Sansa liked this element”) but those social platforms will know what page you have visited.&lt;/p&gt;

&lt;p&gt;Finally website may also use analytics solutions that help the website to know who visit their website, what page are visited more often, and other information. The most common analytic solution is provide by Google itself for free, of course the website obtain a lot of useful data, but Google obtain the same data as well.&lt;/p&gt;

&lt;p&gt;Armed with this basic knowledge let’s explore how we can know who is tracking the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obtain the data
&lt;/h2&gt;

&lt;p&gt;The simplest way to know what requests are made to what service is to simply render the webpage using a browser like Firefox and track all the requests that are made.&lt;/p&gt;

&lt;p&gt;This procedure is not as simple as it may look like, likely thank to help from friends a reasonable simple solution was possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Chrome headless and selenium may help also&lt;/p&gt;

&lt;p&gt;— Ramiro Algozino (@ralgozino) &lt;a href="https://twitter.com/ralgozino/status/1128403031702294529?ref_src=twsrc%5Etfw"&gt;May 14, 2019&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How difficult can it be to programmatically get a list of all the request a browser does in order to display a web page?&lt;/p&gt;

&lt;p&gt;We programmatically drive Firefox making all the request through a proxy.&lt;/p&gt;

&lt;p&gt;Everything was nicely packed together in the &lt;a href="https://github.com/wkeeling/selenium-wire"&gt;selenium-wire&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;The result is a tiny python script that get in input a domain, start Firefox, make Firefox visit and render the homepage, track all the request through a proxy and finally store all the request into a SQLite file.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys                                                                                                                                                              

from seleniumwire import webdriver  # Import from seleniumwire                                                                                                          
from selenium.webdriver.firefox.options import Options                                                                                                                  

import tldextract                                                                                                                                                       
from urllib.parse import urlparse                                                                                                                                       

import sqlite3                                                                                                                                                          
import json                                                                                                                                                             

options = Options()                                                                                                                                                     
options.headless = True                                                                                                                                                 
# Create a new instance of the Firefox driver                                                                                                                           
driver = webdriver.Firefox(options=options)                                                                                                                             

original_domain = sys.argv[1]                                                                                                                                           
url = 'https://{}'.format(original_domain)                                                                                                                              
# Make a request to the URL
driver.get(url)                                                                                                                                                         

conn = sqlite3.connect("requests.db")                                                                                                                                   
c = conn.cursor()                                                                                                                                                       

c.execute('''                                                                                                                                                           
    CREATE TABLE IF NOT EXISTS requests(                                                                                                                                
        original_domain TEXT NOT NULL,                                                                                                                                  
        original_url TEXT NOT NULL,                                                                                                                                     
        time_request INT DEFAULT (strftime('%s','now')),                                                                                                                
        request TEXT,                                                                                                                                                   
        status_code INT,                                                                                                                                                
        subdomain TEXT,                                                                                                                                                 
        domain TEXT,                                                                                                                                                    
        tld TEXT,                                                                                                                                                       
        scheme TEXT,                                                                                                                                                    
        netloc TEXT,                                                                                                                                                    
        path TEXT,                                                                                                                                                      
        params TEXT,                                                                                                                                                    
        query TEXT,                                                                                                                                                     
        fragment TEXT,                                                                                                                                                  
        request_header TEXT,                                                                                                                                            
        response_header TEXT                                                                                                                                            
    );                                                                                                                                                                  
''')                                                                                                                                                                    
conn.commit()                                                                                                                                                           
insert_stmt = """
INSERT INTO requests(
        original_domain,
        original_url,
        request,
        status_code,
        subdomain,
        domain,
        tld,
        scheme,
        netloc,
        path,
        params,
        query,
        fragment,
        request_header,
        response_header
)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, json(?), json(?));
"""

# Access requests via the `requests` attribute
for request in driver.requests:
    if request.response:
        rpath = request.path
        subdomain, domain, tld = tldextract.extract(rpath)
        parsedRequest = urlparse(rpath)
        scheme, netloc, path, params, query, fragment = parsedRequest
        status_code = request.response.status_code
        data = (
            original_domain,
            url,
            rpath,
            request.response.status_code,
            subdomain,
            domain,
            tld,
            scheme,
            netloc,
            path,
            params,
            query,
            fragment,
            json.dumps(dict(request.headers)),
            json.dumps(dict(request.response.headers)),
        )

        c.execute(insert_stmt, data);

conn.commit()

driver.close()
driver.quit()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At this point we have a script that given a domain in input, get its home page and store all the requests necessary to render that homepage into a small database.&lt;/p&gt;

&lt;p&gt;Then we used the list of the &lt;a href="https://www.domcop.com/top-10-million-domains"&gt;top10million most influent&lt;/a&gt; website (actually domains) to know which website are most visited.&lt;/p&gt;

&lt;p&gt;We manipulate the list of domain to obtain the first few hundreds of domains:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat top10milliondomains.csv | awk -F "," '{ print substr($2, 2, length($2) - 2)}' | head -n 1000 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And finally we use &lt;code&gt;xargs&lt;/code&gt; to run the python script in parallel.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xargs -n1 -P6 python3 tracker.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hence, the whole command command was:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat top10milliondomains.csv | awk -F "," '{ print substr($2, 2, length($2) - 2)}' | head -n 1000 | xargs -n1 -P6 python3 tracker.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After some hours we collect 186582 requests done while rendering the homepage of 1924 domains. Those requests are against 3472 domains.&lt;/p&gt;

&lt;p&gt;The amount of requests is definitely not huge, far from it, but in order to do them Firefox need to render a whole webpage along with the JS and CSS, definitely not a lightweight task.&lt;/p&gt;

&lt;p&gt;A brief data analysis will soon follow, follow me on &lt;a href="https://twitter.com/siscia_"&gt;twitter&lt;/a&gt; or subscribe to the mail-list to receive updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/siscia/TrackingTheTrackers"&gt;Repository here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tracker</category>
      <category>sql</category>
      <category>python</category>
      <category>data</category>
    </item>
    <item>
      <title>Write a Postgres proxy. Day 1. Getting familiar with the API.</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Fri, 17 May 2019 14:32:16 +0000</pubDate>
      <link>https://dev.to/siscia_/write-a-postgres-proxy-day-1-getting-familiar-with-the-api-3006</link>
      <guid>https://dev.to/siscia_/write-a-postgres-proxy-day-1-getting-familiar-with-the-api-3006</guid>
      <description>&lt;h1&gt;
  
  
  Write a Postgres proxy. Day 1.
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://redisql.com"&gt;RediSQL, SQL steroids for Redis.&lt;/a&gt; Is a very fast in-memory SQL engine. Its main features are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Speed, up to 130,000 insert per second&lt;/li&gt;
&lt;li&gt; Familiarity, it support standard SQL, no weird dialects&lt;/li&gt;
&lt;li&gt; Simplicity, it is very easy to operate and to use with binding for any language.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code on github: &lt;a href="https://github.com/RedBeardLab/rediSQL"&gt;RedBeardLab/rediSQL&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In this series of post we are writing a postgres proxy that accept connections made using the postgres (PG) protocol and forward them to &lt;a href="https://redisql.com"&gt;RediSQL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redbeardlab.com/2019/04/20/write-a-postgresql-proxy-motivation/"&gt;Motivation and introduction of the project are here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My hope for this project is to distill the knowledge I am getting from this work and help other that are interested in exploring the PG protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This post is about the first day of this project so it is mostly introduction of the references used during this work and a little bit of code.&lt;/p&gt;

&lt;p&gt;In this day we quickly reach the stage where we are able to receive a query from &lt;code&gt;psql&lt;/code&gt; (the CLI tool for PG).&lt;/p&gt;

&lt;p&gt;We will start the post showing the PG references that are most useful and the Python references of the &lt;code&gt;asyncio&lt;/code&gt; module we used.&lt;/p&gt;

&lt;p&gt;Then we will explore very quickly the few lines of code that I ended up writing.&lt;/p&gt;

&lt;p&gt;The last section will explore the error I made during this day, trivial errors but that where a big time sink anyway.  &lt;/p&gt;

&lt;h2&gt;
  
  
  The references
&lt;/h2&gt;

&lt;p&gt;Before to start this work I questioned if I should implement this proxy for Postgres or for MySQL.&lt;/p&gt;

&lt;p&gt;To choose I explored at the documentation of both projects and both are quite good. However, the documentation for PG looked simpler to follow and more linear and I just decide to go for PG.&lt;/p&gt;

&lt;p&gt;The main documentation for this project is the &lt;a href="https://www.postgresql.org/docs/9.5/protocol.html"&gt;Chapter 50 of the PG documentation.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In particular the following sections are of extreme interest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The &lt;a href="https://www.postgresql.org/docs/9.5/protocol-flow.html"&gt;Message Flow&lt;/a&gt; section explains what is the flow of messages between PG and the client. It helps in understanding what message we should expect from the client and what message we are required to send as a server.&lt;/li&gt;
&lt;li&gt;  The &lt;a href="https://www.postgresql.org/docs/9.5/protocol-message-types.html"&gt;Message Data Types&lt;/a&gt; section simply explains how to read and interpretate the section “Message Formats”.&lt;/li&gt;
&lt;li&gt;  The &lt;a href="https://www.postgresql.org/docs/9.5/protocol-message-formats.html"&gt;Message Formats&lt;/a&gt; section goes into the details and enumerate the format of each kind of message. As an example we discover that usually each message start with a single letter that identify the type of message (like &lt;code&gt;R&lt;/code&gt; is used for authentication related messages or that queries start with &lt;code&gt;Q&lt;/code&gt;), then 4 bytes (an Int32) indicate the length of the whole message and finally the body of the message itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Python “ASYNCIO”
&lt;/h2&gt;

&lt;p&gt;While I would like to merge this project in the main &lt;a href="http://redisql.com"&gt;RediSQL&lt;/a&gt; rust codebase, I am a strong believer that starting the project in Python is a good idea. I will gain the knowledge necessary to successfully re-write the software in Rust while having already faced most of the implementation difficulties in a language that allows very fast iteration. Moreover, it will be just impossible to merge the Python code base into the RediSQL rust codebase, so I will just be forced to re-write it.&lt;/p&gt;

&lt;p&gt;While I am not looking for performance I still opted to work with &lt;code&gt;asyncio&lt;/code&gt;, mostly because it was a long time I didn’t do any big work in Python and I wanted to get a pulse of the available tools. Moreover I hoped that it would be closer to what I would find in Rust with Tokio, but it seems to me that the two models are not very similar.&lt;/p&gt;

&lt;p&gt;On the Python side I keep referring to the &lt;a href="https://docs.python.org/3.5/library/asyncio-protocol.html#transports-and-protocols-callback-based-api"&gt;Callback Based API for&lt;/a&gt; &lt;code&gt;[asyncio](https://docs.python.org/3.5/library/asyncio-protocol.html#transports-and-protocols-callback-based-api)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The API is very simple, you simply sub-classed the &lt;code&gt;asyncio.Protocol&lt;/code&gt; class and implemented three callbacks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;code&gt;connection_made&lt;/code&gt; for when a new connection is created to the server.&lt;/li&gt;
&lt;li&gt; &lt;code&gt;data_received&lt;/code&gt; for when a new packed of data arrives to the server.&lt;/li&gt;
&lt;li&gt; &lt;code&gt;connection_lost&lt;/code&gt; for when we loose connection with the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can imagine all the logic is in the &lt;code&gt;data_received&lt;/code&gt;callback, and it will be more complex than a standard web-server. Indeed HTTP is a stateless protocol, everything is simpler if the protocol is stateless, each request does not depends on the previous one.&lt;/p&gt;

&lt;p&gt;The PG protocol is stateful, it means that we need to store and use information from previous messages. As an example, a client, before to send its queries, needs to send an handshake and to authenticate. This means that our server will have at least two state, an “initial” state where each connection start and a “ready” state where a connection end ups only if it completed the handshake and authenticate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Finally &lt;a href="https://github.com/RedBeardLab/pg-redis-proxy/blob/fe3408b02f7f1cd12061cae75de3a309a5c7d935/main.py"&gt;here the code of this first day of code.&lt;/a&gt; The code is mostly boilerplate copied from the Python documentation but it is already enough to accept a connection from &lt;code&gt;psql&lt;/code&gt; and receive the first query.&lt;/p&gt;

&lt;p&gt;To test our progresses we started the Python server and, at the same time we execute &lt;code&gt;psql&lt;/code&gt; giving as input &lt;a href="https://github.com/RedBeardLab/pg-redis-proxy/blob/70d1c2de917648900289a36e142720237aed29b2/goal.sql"&gt;a file with few SQL statements&lt;/a&gt; to execute.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psql -f goal.sql -h localhost -p 8888&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The workflow of the day
&lt;/h3&gt;

&lt;p&gt;Other than boilerplate code, the interesting part of the code are the definition of the magic number that identifies the messages:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSLRequestCode = b'\x04\xd2\x16\x2f' # == hex(80877103)
StartupMessageCode = b'\x00\x03\x00\x00' # == hex(196608)

NoSSL = b'\x4E' # == 'N'

AuthenticationOk = b'\x52\x00\x00\x00\x08\x00\x00\x00\x00'
AuthenticationCleartextPassword = b'\x52\x00\x00\x00\x08\x00\x00\x00\x03'

ReadyForQuery = b'\x5A\x00\x00\x00\x05\x49' # == Z0005I , the last I stand for Idle 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the logic to reply to the client:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def _reply(self, data):
        if self.state == "initial" and data[4:8] == SSLRequestCode:
            self.transport.write(NoSSL)
        elif self.state == "initial" and data[4:8] == StartupMessageCode:
            # we don't require a password
            self.transport.write(AuthenticationOk)
            # good to go for the first query!
            self.transport.write(ReadyForQuery)
        return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s explore how we get to this few lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  My discovering process
&lt;/h2&gt;

&lt;p&gt;Scanning quickly the documentation it could seems like the first message to expect is the &lt;code&gt;StartupMessage&lt;/code&gt;, however, the first message sent by &lt;code&gt;psql&lt;/code&gt; is the &lt;code&gt;SSLRequest&lt;/code&gt; message, and this took quite a while to figure out.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SSLRequest&lt;/code&gt; message is recognized because it contains the magic number 80877103 which we encode in the python code as &lt;code&gt;b'\x04\xd2\x16\x2f'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since we don’t yet support SSL we simply respond to the &lt;code&gt;SSLRequest&lt;/code&gt; with &lt;code&gt;N&lt;/code&gt;(encoded as &lt;code&gt;b'\x4E'&lt;/code&gt;) to let know to the client that we are not going to use SSL. At this point, the client, can either drop the connection or decide to accept a non-encrypted connection and send the &lt;code&gt;StartupMessage&lt;/code&gt; in plain text.&lt;/p&gt;

&lt;p&gt;Also for the &lt;code&gt;StartupMessage&lt;/code&gt; there is a magic number (196608) which we encoded as &lt;code&gt;b'\x00\x03\x00\x00'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Along with the magic number, the &lt;code&gt;StartupMessage&lt;/code&gt; contains information like the user who is starting the connection, what database the user is trying to connect and other information. At the moment we ignore all those information.&lt;/p&gt;

&lt;p&gt;After the &lt;code&gt;StartupMessage&lt;/code&gt; the server requires authentication, in our case we don’t care about authentication just yet and we just send the &lt;code&gt;AuthenticationOk&lt;/code&gt; message.&lt;/p&gt;

&lt;p&gt;The next step is a little tricky.&lt;/p&gt;

&lt;p&gt;We just send a message to the client, the &lt;code&gt;AuthenticationOk&lt;/code&gt; message and so I would expect the client to send the server something back.&lt;/p&gt;

&lt;p&gt;Wrong!&lt;/p&gt;

&lt;p&gt;Now, the server need to be proactive and tell the client that it is ok to start sending queries. We need to send two messages, one after the other to the client.&lt;/p&gt;

&lt;p&gt;Indeed you can see in the code that we immediately send the &lt;code&gt;ReadyForQuery&lt;/code&gt; message.&lt;/p&gt;

&lt;p&gt;At this point our time is over for this day, however we can clearly see from the log that the next message received by the server is the first query of our file!&lt;/p&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;h2&gt;
  
  
  Errors made during this day
&lt;/h2&gt;

&lt;p&gt;During this coding section I wasted a lot of time because I didn’t read the documentation with enough care.&lt;/p&gt;

&lt;p&gt;Indeed I was expecting the &lt;code&gt;StartupMessage&lt;/code&gt; as first message and not the &lt;code&gt;SSLRequest&lt;/code&gt;. I spend a lot of time trying to fit the &lt;code&gt;StartupMessage&lt;/code&gt; into the &lt;code&gt;SSLRequest&lt;/code&gt;, maybe I was reading the message with the wrong endianess? Maybe there was “garbage” from the protocol layer?&lt;/p&gt;

&lt;p&gt;Nah! I am just reading the wrong message.&lt;/p&gt;

&lt;p&gt;Another time sink was me reading the wrong column in the ASCII table trying to use the decimal, instead of the hexadecimal, encoding. All the messages start with a letter, in our cases we needed the &lt;code&gt;N&lt;/code&gt; for rejecting the SSL, and the &lt;code&gt;R&lt;/code&gt; for the &lt;code&gt;AuthenticationOk&lt;/code&gt; message and finally the &lt;code&gt;Z&lt;/code&gt; for the &lt;code&gt;ReadyForQuery&lt;/code&gt; message. As an example the &lt;code&gt;N&lt;/code&gt; is 78 in decimal and 4E in hexadecimal. I was trying to encode &lt;code&gt;N&lt;/code&gt; as &lt;code&gt;b'\x78'&lt;/code&gt; instead of &lt;code&gt;b'\x4E'&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope your enjoyed the post.&lt;/p&gt;

&lt;p&gt;I will keep publishing about this topic on this blog, so if you are interested feel free to &lt;a href="https://twitter.com/siscia_"&gt;follow me on twitter&lt;/a&gt; or subscribe to the mail list just below.&lt;/p&gt;

&lt;p&gt;All post of this serie: &lt;a href="https://redbeardlab.com/category/pg-redis-proxy/"&gt;Writing a Postgres proxy.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>sql</category>
      <category>postgres</category>
      <category>redisql</category>
    </item>
    <item>
      <title>Write a Postgresql proxy. The Beginning.</title>
      <dc:creator>Simone Mosciatti</dc:creator>
      <pubDate>Tue, 14 May 2019 10:02:02 +0000</pubDate>
      <link>https://dev.to/siscia_/write-a-postgresql-proxy-the-beginning-3c9i</link>
      <guid>https://dev.to/siscia_/write-a-postgresql-proxy-the-beginning-3c9i</guid>
      <description>&lt;p&gt;This series of articles will follow my progress in creating a &lt;a href="http://redisql.com/"&gt;RediSQL&lt;/a&gt; proxy for Postgres, &lt;a href="https://github.com/RedBeardLab/pg-redis-proxy"&gt;pg-redis-proxy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The end goal of this project is to have a proxy that will listen to the PG protocol, forward the queries to RediSQL, and finally return the answer to the original client.&lt;/p&gt;

&lt;p&gt;If the project is successful I hope to integrate the code into RediSQL itself, so to provide another interface for RediSQL, not just the Redis protocol but also — directly — the PG protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;The abstraction I am going to build will definitely be a leaky one.&lt;/p&gt;

&lt;p&gt;Indeed SQLite (on which is based RediSQL) does not support a lot of features of PG. Classical examples are all the DATE datatypes that are not supported in SQLite.&lt;/p&gt;

&lt;p&gt;However I still feel it may be useful and fun to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Ideally I would like to have the code merge into the main RediSQL, this would definitely suggest to code it in Rust.&lt;/p&gt;

&lt;p&gt;But Rust is a “production” language.&lt;/p&gt;

&lt;p&gt;At least in my experience, you need to have a quite good understanding of the problem and of the design before to successfully code something in Rust.&lt;/p&gt;

&lt;p&gt;Moreover, there is this old expression in programming that suggest to plan for at least one prototype that you will eventually throw away and re-write from scratch.&lt;/p&gt;

&lt;p&gt;Indeed I am not so sure of the whole architecture and of the problem I will be facing while writing this proxy.&lt;/p&gt;

&lt;p&gt;The first version of pg-redis-proxy will be written in Python3.&lt;/p&gt;

&lt;h2&gt;
  
  
  The goals of the Python version
&lt;/h2&gt;

&lt;p&gt;The goals of the first python version are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get to know the PG protocol&lt;/li&gt;
&lt;li&gt;Quickly explore several possible architecture&lt;/li&gt;
&lt;li&gt;Provide some open source libraries and guidance for other that wants to explore a similar project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I will stop developing the project when it will be possible to execute a simple SQL file against an instance of pg-redis-proxy and have it return the expected result.&lt;/p&gt;

&lt;p&gt;The SQL file I am aim to is something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;PREPARE&lt;/span&gt; &lt;span class="n"&gt;insertfoo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
    &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="n"&gt;insertfoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="n"&gt;insertfoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&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="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I am not aiming to code anything more than what is extremely strictly necessary, but I will be extremely open to accept pull requests.&lt;/p&gt;

&lt;p&gt;Hence if you are interesting in the project, or in piece of the project, feel free to contribute in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repo
&lt;/h2&gt;

&lt;p&gt;You can follow the progress on &lt;a href="https://github.com/RedBeardLab/pg-redis-proxy"&gt;this github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, if you are interested in following this project you can either follow me on &lt;a href="https://twitter.com/siscia_"&gt;twitter&lt;/a&gt; or subscribe to the mail-list in the &lt;a href="https://redbeardlab.com/2019/04/20/write-a-postgresql-proxy-motivation/"&gt;original blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>sql</category>
      <category>redis</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
