【Supabase初心者メモ】基本的な使い方

# Supabaseクライアントの作成
Supabaseとのやりとりは、以下のように@supabase/auth-helpers-nextjsからcreateClient関数を呼び出し、Supabaseクライアント（SupabaseのAPIとやり取りするためのオブジェクト）を作成して行います。

クライアントサイド：
```
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
const supabase = createClientComponentClient()
```

サーバーサイド：
```
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
const supabase = createServerComponentClient()
```

ライブラリをインストールしていない場合は以下のコマンドでインストールします。

npm install @supabase/auth-helpers-nextjs


# 基本構文
Supabaseクライアント作成後、作成したオブジェクトを元に以下のように操作します。

```
const { data, error } = await supabase
  .from('<テーブル名>')
  .<操作名>(<データまたは条件>)
  .<条件メソッド>()
```

# 四つの操作
SupabaseはPostgreSQLをベースにしたサービスなため、基本的な操作を以下四つで行います。

SELECT：データの取得
INSERT：新規レコードの追加
UPDATE：既存レコードの更新
DELETE：レコードの削除

### SELECT
基本：
```
supabase.from('<テーブル名>').select('カラム名')
```
例：
```
const { data, error } = await supabase
  .from('users')
  .select('id, name, email')  // 取得したいカラム名をカンマ区切りで指定

if (error) console.error(error)
else console.log(data)
```

### INSERT
基本：
```
supabase.from('<テーブル名>').insert([ { ...データ } ])
```
例：
```
const { data, error } = await supabase
  .from('users')
  .insert([
    { name: 'Alice', email: 'alice@example.com' }
  ])

if (error) console.error(error)
else console.log(data)
```

### UPDATE
基本：
```
supabase.from('<テーブル名>').update({ ...更新内容 }).eq('<条件カラム>', 値)
```
例：
```
const { data, error } = await supabase
  .from('users')
  .update({ email: 'newalice@example.com' })
  .eq('id', 1)

if (error) console.error(error)
else console.log(data)
```
### DELETE
基本：
```
supabase.from('<テーブル名>').delete().eq('<条件カラム>', 値)
```
例：
```
const { data, error } = await supabase
  .from('users')
  .delete()
  .eq('id', 1)

if (error) console.error(error)
else console.log(data)
```

## 条件メソッド
条件メソッドは、データベースの条件やオプションを指定するためのものです。以下がよく使われるものです。
```
const { data, error } = await supabase
  .from('<テーブル名>')
   .<操作名>(<データまたは条件>)
  // ↓以下がよく使う条件やオプションメソッド
  .eq('カラム', 値)             // = 条件（等しい）
  .neq('カラム', 値)            // != 条件（等しくない）
  .gt('カラム', 値)             // > 条件（より大きい）
  .gte('カラム', 値)            // >= 条件（以上）
  .lt('カラム', 値)             // < 条件（より小さい）
  .lte('カラム', 値)            // <= 条件（以下）
  .like('カラム', 'パターン')    // 部分一致（SQLのLIKE）
  .ilike('カラム', 'パターン')   // 大文字小文字区別しないLIKE
  .in('カラム', [値1, 値2])      // 配列のいずれかに一致
  .is('カラム', null)            // nullかどうかチェック
  .order('カラム', { ascending: true })  // ソート順指定
  .limit(数)                    // 取得件数の上限
  .range(from, to)              // 範囲指定（offsetとlimitの組み合わせ）
  .single()                    // 1件だけ取得したい場合に使う
  .maybeSingle()               // 1件またはnullを許容する
```

# データ構造
これまでの例のように、supabaseから取得したデータはdataとerrorに分割代入するのが一般的です。取得したデータ構造は以下のようになっています。

### data
取得したデータ本体で、成功すればオブジェクト、失敗すればnullで返ります。複数レコードの場合、複数オブジェクトが配列に格納されて返されます。

例：
```
[
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob', email: 'bob@example.com' }
]
```

### error
エラー情報で、何か問題があればオブジェクト、成功時はnullで返ります。
基本的に以下のデータを持ちます。

message： エラーメッセージの説明
details: 追加の詳細情報
hint： 解決のヒント
code: エラーコード（PostgreSQL準拠）

例：
```
// 存在しないテーブルにアクセスした場合のエラー
{
  "message": "relation \"non_existent_table\" does not exist",
  "details": null,
  "hint": null,
  "code": "42P01"
}
```

## 補足
### 別名（エイリアス）指定
「:」はテーブルのカラム名を、利用しやすい別名にリネームしたい時に使います。

例：
```
const { data, error } = await supabase
  .from('users')
  .select('userFirstName:first_name');
```

取得結果：
```
[
  { "userFirstName": "Alice" },
  { "userFirstName": "Bob" }
]
```

### .order()メソッド
.order()は、クエリ結果の並び順を指定するためのメソッドです。SQLのORDER BYに相当します。

基本：
```
.order('カラム名', { ascending: true | false })
// { ascending: true }：昇順（小さい→大きい）
// { ascending: false }：降順（大きい→小さい）
```

例：
```
const { data, error } = await supabase
  .from('posts')
  .select('*')
  .order('category', { ascending: true })
  .order('created_at', { ascending: false })
```