<?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: voboda</title>
    <description>The latest articles on DEV Community by voboda (@voboda).</description>
    <link>https://dev.to/voboda</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%2F601854%2F0639f89b-e978-45bd-ae4d-4c99919e5e6f.png</url>
      <title>DEV Community: voboda</title>
      <link>https://dev.to/voboda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/voboda"/>
    <language>en</language>
    <item>
      <title>Upserts with PostgREST or Supabase</title>
      <dc:creator>voboda</dc:creator>
      <pubDate>Sun, 11 Apr 2021 19:06:13 +0000</pubDate>
      <link>https://dev.to/voboda/upserts-with-postgrest-or-supabase-3ep2</link>
      <guid>https://dev.to/voboda/upserts-with-postgrest-or-supabase-3ep2</guid>
      <description>&lt;p&gt;I have a table with a UNIQUE INDEX on multiple columns, and I'd like to upsert new values to that table based on that unique constraint.  Can I do this without major contortions?&lt;/p&gt;

&lt;p&gt;Game on.&lt;/p&gt;

&lt;p&gt;Users can have one pick per event, so the picks table has 4 columns pickid, userid, eventid, pick.  Primary key is unique, and there's also a unique index on userid and eventid.&lt;/p&gt;

&lt;p&gt;Now if a user wants to change their pick, I need an upsert (insert if that userid/eventid pair doesn't exist, otherwise update the pick column of the current record.) &lt;/p&gt;

&lt;p&gt;Upserts in PostgreSQL are handled with &lt;a href="https://wiki.postgresql.org/wiki/UPSERT"&gt;ON CONFLICT&lt;/a&gt;, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO picks (userid, eventid, pick)
VALUES(20, 30,'My pick') 
ON CONFLICT (userid, eventid) 
DO 
   UPDATE SET pick = 'My pick'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://postgrest.org/en/v7.0.0/api.html#upsert"&gt;PostgREST knows about upserts too, and does the ON CONFLICT part automagically for you&lt;/a&gt;.  You can set the &lt;code&gt;Prefer: resolution=merge-duplicates&lt;/code&gt; or &lt;code&gt;Prefer: resolution=ignore-duplicates&lt;/code&gt; headers. &lt;/p&gt;

&lt;p&gt;Things get a bit tricky when you want to upsert based on that UNIQUE INDEX based on multiple columns.  The automagical upsert works only with primary keys.  If you want it to use another column or multiple columns, pass the &lt;code&gt;on_conflict&lt;/code&gt; get variable to the PostgREST api, like &lt;code&gt;on_conflict=userid,eventid&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One more thing though - I'm use the postgrestjs/supabasejs client, so how do I pass on_conflict?  To find out, I heroicly ventured into the postgrest-js source code and found &lt;a href="https://github.com/supabase/postgrest-js/pull/113/files"&gt;this wonderful PR to support on_conflict&lt;/a&gt;.  So I just need to add an &lt;code&gt;onConflict&lt;/code&gt; option like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data, error } = await supabase
  .from('picks')
  .insert([{ userid, eventid, pick}], { upsert: true, onConflict: "userid,eventid"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the camelCase instead of the under_line.  (Mental note: it seems camelCase is kind of the preferred naming convention for Javascript libraries.)&lt;/p&gt;

&lt;p&gt;That's it!  It works nicely, encapsulating somewhat complex logic with clear, understandable and short code.  &lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>postgrest</category>
    </item>
    <item>
      <title>Easy functions and transactions using Postgres + PostgREST or Supabase</title>
      <dc:creator>voboda</dc:creator>
      <pubDate>Thu, 08 Apr 2021 20:49:00 +0000</pubDate>
      <link>https://dev.to/voboda/gotcha-supabase-postgrest-rpc-with-transactions-45a7</link>
      <guid>https://dev.to/voboda/gotcha-supabase-postgrest-rpc-with-transactions-45a7</guid>
      <description>&lt;p&gt;These days, I'm taking advantage of PostgreSQL's ability to handle logic, saving me all the work of an entire middleware layer.  (Instead, using generalized middlewares like Graphile, Supabase, or Postgrest.)&lt;/p&gt;

&lt;p&gt;A little gotcha in the Postgres learning curve has been working out the difference between &lt;em&gt;stored procedures&lt;/em&gt; and &lt;em&gt;functions&lt;/em&gt;, and realizing that the simpler table &lt;code&gt;trigger&lt;/code&gt;s and &lt;code&gt;constraint&lt;/code&gt;s (using &lt;code&gt;with check&lt;/code&gt;) actually does a lot of what I need.&lt;/p&gt;

&lt;p&gt;One place I got stuck is sql transactions, or grouping several sql statements into a group so that if one fails, they all "roll back" as if they didn't happen. PostgreSQL has some specific rules about using transactions in or out of functions and stored procedures -- but I found a simple way out.&lt;/p&gt;

&lt;p&gt;It turns out that PostgREST, the middleware Supabase is based on, surrounds rpc() calls in a transaction already.  So I could just define a function in sql with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION public.topup(user text, amount integer)
    RETURNS integer
    LANGUAGE 'plpgsql'

AS $$
begin
  update users set balance = balance + amount;
  insert into "transactions" (user, amount, note) values (user, amount, 'top up');
  return 1;
end
$$;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Supabase and PostgREST, this automatically exposes &lt;code&gt;topup&lt;/code&gt; in the API. When called over the API, it's automatically wrapped in a transaction.  (I tested this by placing a contraint on user.balance to not let it go above 100, and when the user's balance was higher than the amount in the rpc call, neither user.balance was updated, nor was a new record added to transactions.)&lt;/p&gt;

&lt;p&gt;Now, I can write a lot of logic into the PostgreSQL database itself.  This simplifies my middleware a lot, and often enables me to make apps that call Supabase/PostgREST/Graphile calls directly from my front-end components.  An entire layer of devops and code removed.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>supabase</category>
    </item>
    <item>
      <title>Multiple Github accounts conveniently</title>
      <dc:creator>voboda</dc:creator>
      <pubDate>Fri, 26 Mar 2021 04:09:05 +0000</pubDate>
      <link>https://dev.to/voboda/multiple-github-accounts-conveniently-38mc</link>
      <guid>https://dev.to/voboda/multiple-github-accounts-conveniently-38mc</guid>
      <description>&lt;p&gt;I use several github accounts, and wanted a way to use them without constantly tweaking remote urls and stuff for each repo.&lt;/p&gt;

&lt;p&gt;The good news is at some point, it seems git started to traverse directories upwards, looking for &lt;code&gt;.gitconfig&lt;/code&gt; files. So it makes it easy to setup several directories, each of which uses different credentials automatically.&lt;/p&gt;

&lt;p&gt;So, for my &lt;em&gt;voboda&lt;/em&gt; account on github:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir ~/repos/voboda
cd ~/repos/voboda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there I added a &lt;code&gt;.gitconfig&lt;/code&gt; file containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[core]
    sshCommand = ssh -i ~/.ssh/id_rsa_voboda
[user]
    name = Voboda
    email = voboda@mygithubemail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, anything I need to work on in my voboda account, I just clone that under the ~/repos/voboda directory. For example &lt;code&gt;~/repos/voboda/onelineforyourmind&lt;/code&gt; and &lt;code&gt;~/repos/voboda/underlinery&lt;/code&gt;. Both will use the above user information automatically. That specific ssh command references the ssh key I setup for my &lt;code&gt;voboda&lt;/code&gt; github account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sidenote: separate ssh keys
&lt;/h3&gt;

&lt;p&gt;On Linux, I setup that ssh key using &lt;code&gt;ssh-keygen -f id_rsa_voboda&lt;/code&gt; and then copying the 2 outputted keyfiles to my &lt;code&gt;~.ssh&lt;/code&gt; directory.&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
    </item>
    <item>
      <title>supabase-js with sapper</title>
      <dc:creator>voboda</dc:creator>
      <pubDate>Mon, 22 Mar 2021 18:11:56 +0000</pubDate>
      <link>https://dev.to/voboda/supabase-js-with-sapper-4j3p</link>
      <guid>https://dev.to/voboda/supabase-js-with-sapper-4j3p</guid>
      <description>&lt;p&gt;A few gotchas I found when setting up, so saving my notes here.  Hopefully they save you a bit of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Set the client context to &lt;code&gt;window&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In &lt;em&gt;rollup.config.js&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
    client: {
        context: 'window', // for supabase compatibility
        input: config.client.input(),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2) Install &lt;code&gt;@rollup/plugin-json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Also in &lt;em&gt;rollup.config.js&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json from '@rollup/plugin-json';

...

export default {
    client: {
        context: 'window', // for supabase compatibility
        input: config.client.input(),
        output: config.client.output(),
        plugins: [
            json(),  //For supabase compatibility 

...

    server: {
        input: config.server.input(),
        output: config.server.output(),
        plugins: [
            json(),  //For supabase compatibility 

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

&lt;/div&gt;



</description>
      <category>svelte</category>
      <category>sapper</category>
      <category>supabase</category>
    </item>
  </channel>
</rss>
