🎲

Supabaseの入れ子selectが期待どおりの順で返ってきたが、それは保証ではなかった

に公開

ダミーデータを3件入れて、入れ子の select で取ってきたら新しい順で返ってきました。画面もそのとおりに並びます。

順序を指定していないのに、です。

順序を指定していない select

feed_sources ( max_entries, last_fetched_at,
  feed_entries ( title, url, published_at, thumbnail_url ) )

feed_entries に order を書いていません。それでも期待どおりに見えたのは、ダミー3件を新しい順に insert したからでした。insert 順のまま物理的に並んでいただけです。

order by が無ければ、PostgreSQL はどの順で返してもよい。これは SQL の基礎なので知っていました。知っていたのに、動いている画面を見て「正しい」と読んでいた。

テストを書いても気づけない

3件しかないので、テストを書いても通ります。返ってくる結果が「正しく見える」ので。

本物のフィードに差し替えると、件数も更新順も変わります。そのとき順番が崩れても、原因が「順序未指定」だと結びつかない。数週間前に書いたコードの、書いていない1行が原因なので。

ここで1つ、自分が最初に間違えた読み方があります。「テストデータを3件から増やせば解決する」と考えかけました。

違います。件数を増やしても、order を書いていない限り正しい順で返る保証は増えません。効いているのは件数ではなくて、何をもって「合格」とするかを決めていなかったこと。「画面に3件並んだ」を合格条件にしていたので、並び順は最初から検査の対象外でした。

対処の選択

案 採否 理由
表示側で並べ替える ✅ 採用 3件しかない。「新しい順に出す」という意図がコードに残る
DB 側(supabase-js の .order(..., { referencedTable })) ❌ 1段目なら書ける。2段ネスト(feed_sources の中の feed_entries)で効く書き方を確かめる項目が増える

DB 側で並べるほうが筋としては正しいと思います。supabase-js には埋め込み先を並べる referencedTable オプションがあるので、書けないわけではない。ただ今回は2段ネストで効くかを確かめる時間を取らず、確かめる項目を増やさない側を取りました。件数が増えたら見直します。

入れ子だと order を書く場所が視界に入らない

order by を書き忘れる、という話ではないと思っています。普通の select なら .order() を書く習慣がありました。

入れ子の select は文字列の中に構造を書くので、feed_entries の順序を指定する場所が、コードを書いている視界に入らない。外側の .order() は付けていて、内側は文字列の中に埋もれていた。

手順書には「表示側は素直に全件出せばよい」と書いてありました。これは件数の話で、順序には触れていません。「全件出せばよい」を「そのまま出せば正しい」と読んだのは自分でした。

動いていることは、保証されていることではない。 当たり前なのですが、動いている画面を前にすると、その当たり前が消えます。

環境: Supabase(PostgREST)/ @supabase/supabase-js 2.112.1 / Next.js 16.3.0。

GitHubで編集を提案

Discussion