<?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: Adrian</title>
    <description>The latest articles on DEV Community by Adrian (@avuserow).</description>
    <link>https://dev.to/avuserow</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%2F1078113%2Fa5d35ae2-2998-4f52-88c9-326064861d91.png</url>
      <title>DEV Community: Adrian</title>
      <link>https://dev.to/avuserow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/avuserow"/>
    <language>en</language>
    <item>
      <title>Avoiding the "End Weight Problem" when Building SQL Queries</title>
      <dc:creator>Adrian</dc:creator>
      <pubDate>Sun, 28 May 2023 00:24:07 +0000</pubDate>
      <link>https://dev.to/avuserow/avoiding-the-end-weight-problem-when-building-sql-queries-1i1</link>
      <guid>https://dev.to/avuserow/avoiding-the-end-weight-problem-when-building-sql-queries-1i1</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/avuserow/sqlbuilder-making-the-complex-sql-query-manageable-in-raku-4mgn"&gt;previous post, I introduced SQL::Builder&lt;/a&gt;. I briefly alluded to an extension to allow running the queries, looking something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my @data = $sql.from('table').select('a', 'b').all;
# roughly equivalent to:
# my $b = $sql.from('table').select('a', 'b').build;
# my @data = $db.execute($b.sql, $b.bind.flat);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is much nicer, but I ran into a familiar roadblock: what happens when I inevitably forget the call to &lt;code&gt;.all&lt;/code&gt;? I was especially prone to forgetting the final call to &lt;code&gt;.execute&lt;/code&gt; for update statements. A strongly typed language would help with the former case, but the latter would be permitted in basically every language.&lt;/p&gt;

&lt;p&gt;My first attempt to solve this was to use Raku's concept of context. By implementing a &lt;code&gt;sink&lt;/code&gt; method, I could turn this into a runtime error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# in my class {
    method sink() {die "Forgot to call .all on a StatementBuilder!"}
# }


# later:
$sql.update('table').set(foo =&amp;gt; "bar"); # oops, forgot to execute, dies
$sql.update('table').set(foo =&amp;gt; "bar").execute; # fine, .execute called
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps, but it doesn't address the real problem: there's an &lt;a href="https://akrzemi1.wordpress.com/2023/04/23/the-obvious-final-step/"&gt;Obvious Final Step&lt;/a&gt; but it's not obvious when the final step happens. This is an end-weight problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End Weight Problem
&lt;/h2&gt;

&lt;p&gt;In a nearly 20-year old article about Raku (then known as Perl 6), &lt;a href="https://www.perl.com/pub/2003/06/25/perl6essentials.html/"&gt;this is called the "principle of end weight"&lt;/a&gt;. Raku solves this in a number of places relative to Perl 5:&lt;/p&gt;

&lt;p&gt;A classic example of this change in Raku is that regex flags are moved to the front of &lt;code&gt;m//&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$string =~ m/foobar/ig; # Perl 5
$string ~~ m:ig/foobar/; # Raku
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The article also mentions re-arranging the arguments to &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt; to address this. It ended up happening, though not quite like the article suggested:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my @foo = grep {$_ % 2} @bar; # Perl 5
my @foo = grep {$_ % 2}, @bar; # Raku
my @foo = @bar.grep({$_ % 2}); # Raku, using the method form
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, most functions gained method variants in Raku, allowing you flexibility that can help avoid this issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my @parts = split /\/, $string; # Raku, in the style of Perl 5
my @parts = $string.split(/some really long sequence here/); # Raku, using a method call to make this more obvious
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Applying the Lesson
&lt;/h2&gt;

&lt;p&gt;With this in mind, a simple solution comes to mind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my @data = $sql.all($sql.from('table').select('a', 'b'));
$sql.execute($sql.update('table').set(foo =&amp;gt; 'bar'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids the end-weight problem: the tiny portion &lt;code&gt;all&lt;/code&gt; is moved earlier, making it easier to see what's going on. By using a method call instead of method chaining, the parentheses do the work of telling us when the query is built and should be called.&lt;/p&gt;

&lt;p&gt;As a bonus, this moves &lt;code&gt;all&lt;/code&gt; next to the variable assignment, making it more apparent that &lt;code&gt;@data&lt;/code&gt; will contain all matching rows.&lt;/p&gt;

&lt;p&gt;This solution is simple enough to implement as a subclass of &lt;code&gt;SQL::Builder&lt;/code&gt;, and it's now available as &lt;a href="https://modules.raku.org/dist/SQL::Builder::ExecuteWithDBIish:zef:zef:avuserow"&gt;SQL::Builder::ExecuteWithDBIish&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This module adds helper functions for fetching all rows, fetching a single row, and fetching a single row with a single column (&lt;code&gt;all&lt;/code&gt;, &lt;code&gt;one&lt;/code&gt;, and &lt;code&gt;scalar&lt;/code&gt;, respectively). More helpers can be added in the future, so file an issue if you have an idea.&lt;/p&gt;

&lt;p&gt;As the name implies, this provides the given API for &lt;code&gt;DBIish&lt;/code&gt; connections. Eventually I plan to make a variant for the &lt;code&gt;DB::Pg&lt;/code&gt; family of modules, so making these separate modules keeps the dependency tree under control.&lt;/p&gt;

&lt;p&gt;I think APIs can be made safer and easier to use when taking this into account. Let me know if you come across the end-weight problem in your API design.&lt;/p&gt;

</description>
      <category>rakulang</category>
      <category>raku</category>
    </item>
    <item>
      <title>SQL::Builder - making the complex SQL query manageable in Raku</title>
      <dc:creator>Adrian</dc:creator>
      <pubDate>Sun, 07 May 2023 05:00:19 +0000</pubDate>
      <link>https://dev.to/avuserow/sqlbuilder-making-the-complex-sql-query-manageable-in-raku-4mgn</link>
      <guid>https://dev.to/avuserow/sqlbuilder-making-the-complex-sql-query-manageable-in-raku-4mgn</guid>
      <description>&lt;p&gt;I just released the first version of &lt;a href="https://raku.land/zef:avuserow/SQL::Builder"&gt;SQL::Builder&lt;/a&gt;, a module to make SQL queries from data structures in Raku.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $sql = SQL::Builder.new;
my $built = $sql.from('table').select('table.foo', 'other.bar').join('other', :using&amp;lt;id&amp;gt;).build;
say $built.sql;
# SELECT table.foo, other.bar FROM table JOIN other USING(id)

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

&lt;/div&gt;



&lt;p&gt;SQL::Builder: You're still basically writing SQL.&lt;/p&gt;

&lt;p&gt;There's already other modules out there (&lt;a href="https://raku.land/zef:FCO/Red"&gt;Red&lt;/a&gt;,  &lt;a href="https://raku.land/zef:avuserow/SQL::Builder"&gt;SQL::Abstract&lt;/a&gt;, among others), so what does this bring to the ecosystem?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Support for complex queries. This module can do nested joins and subselects, while enabling reusable logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SQL that's close to the metal. An ORM was not a good fit for this project, but generating queries from code is very helpful.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better &lt;code&gt;WHERE&lt;/code&gt; clause support. It can currently represent any condition in the form of &lt;code&gt;left op right&lt;/code&gt;, and while optimized for the typical &lt;code&gt;foo = ?&lt;/code&gt; query, it can safely handle functions and expressions. &lt;br&gt;This syntax is used for &lt;code&gt;HAVING&lt;/code&gt; and &lt;code&gt;JOIN ... ON&lt;/code&gt; as well, providing a lot of flexibility. This was easily the part requiring the most thought, and I plan to write more about the design choices here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's faster, mostly due to returning rows instead of objects and having a simpler interface.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short, this module is great for queries that are complex, but have some level of variability, like a query that has optional JOINs depending on user input.&lt;/p&gt;

&lt;p&gt;What's coming next?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;support for &lt;code&gt;UPDATE/INSERT/DELETE&lt;/code&gt; statements&lt;/li&gt;
&lt;li&gt;better support for Arrays as values in WHERE clauses&lt;/li&gt;
&lt;li&gt;optional support for actually running the queries, either via &lt;code&gt;DBIish&lt;/code&gt; or &lt;code&gt;DB::Pg&lt;/code&gt; (and related modules)&lt;/li&gt;
&lt;li&gt;I'm sure there will be something else as I continue work on my other project that uses this :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This module won't be for everyone, but I've found it very useful in another project. Any feedback is appreciated, please either leave a comment here, &lt;a href="https://github.com/avuserow/raku-sql-builder"&gt;open an issue on GitHub&lt;/a&gt;, or find me in &lt;code&gt;#raku&lt;/code&gt; on &lt;code&gt;irc.libera.chat&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>rakulang</category>
      <category>raku</category>
    </item>
  </channel>
</rss>
