Supabaseを使用したデータベース操作、認証、ストレージ管理
このスキルは、Supabaseとの連携に特化しています。
環境変数:
NEXT_PUBLIC_SUPABASE_URL: SupabaseプロジェクトURLNEXT_PUBLIC_SUPABASE_ANON_KEY: 匿名キーSUPABASE_SERVICE_ROLE_KEY: サービスロールキー(サーバーサイドのみ)import { createClient } from '@supabase/supabase-js';
import type { Database } from '@/types/database';
// クライアントサイド用
const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// サーバーサイド用(Admin権限)
const supabaseAdmin = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
// 全件取得
const { data, error } = await supabase
.from('table_name')
.select('*');
// 条件付き取得
const { data, error } = await supabase
.from('table_name')
.select('*')
.eq('status', 'active')
.order('created_at', { ascending: false });
// 単一レコード取得
const { data, error } = await supabase
.from('table_name')
.select('*')
.eq('id', id)
.single();
// リレーション込みで取得
const { data, error } = await supabase
.from('table_name')
.select(`
*,
related_table (
id,
name
)
`);
const { data, error } = await supabase
.from('table_name')
.insert({
name: 'テスト',
email: '[email protected]',
})
.select()
.single();
const { data, error } = await supabase
.from('table_name')
.update({
status: 'completed',
updated_at: new Date().toISOString(),
})
.eq('id', id)
.select()
.single();
const { error } = await supabase
.from('table_name')
.delete()
.eq('id', id);
// ファイルアップロード
const { data, error } = await supabase.storage
.from('bucket_name')
.upload(`${folder}/${filename}`, file);
// 公開URL取得
const { data } = supabase.storage
.from('bucket_name')
.getPublicUrl(`${folder}/${filename}`);
// ファイル削除
const { error } = await supabase.storage
.from('bucket_name')
.remove([`${folder}/${filename}`]);
-- RLSを有効化
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;
-- ポリシー作成
CREATE POLICY policy_name ON table_name
FOR ALL TO authenticated
USING (
-- 条件
auth.uid() = user_id
);
// infrastructure/repositories/supabase/example-repository.ts
import { supabase } from '@/lib/supabase';
import type { Example } from '@/types/database';
export const exampleRepository = {
async findById(id: string): Promise<Example | null> {
const { data, error } = await supabase
.from('examples')
.select('*')
.eq('id', id)
.single();
if (error) throw error;
return data;
},
async findAll(): Promise<Example[]> {
const { data, error } = await supabase
.from('examples')
.select('*')
.order('created_at', { ascending: false });
if (error) throw error;
return data || [];
},
async create(input: Omit<Example, 'id' | 'created_at' | 'updated_at'>): Promise<Example> {
const { data, error } = await supabase
.from('examples')
.insert(input)
.select()
.single();
if (error) throw error;
return data;
},
async update(id: string, input: Partial<Example>): Promise<Example> {
const { data, error } = await supabase
.from('examples')
.update({ ...input, updated_at: new Date().toISOString() })
.eq('id', id)
.select()
.single();
if (error) throw error;
return data;
},
async delete(id: string): Promise<void> {
const { error } = await supabase
.from('examples')
.delete()
.eq('id', id);
if (error) throw error;
},
};
const { data, error } = await supabase
.from('table_name')
.select('*');
if (error) {
console.error('Supabase error:', error.message);
throw new Error(`Database error: ${error.message}`);
}
types/database.tsの型定義とSupabaseスキーマを常に同期させること。
// types/database.ts
export interface Example {
id: string;
name: string;
status: 'active' | 'inactive';
created_at: string;
updated_at: string;
}