// src/app/api/export-csv/route.ts
import { NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
import { stringify } from 'csv-stringify';
import fs from 'fs/promises'; // Node.jsのファイルシステムモジュール
import path from 'path'; // Node.jsのパス操作モジュール
// Supabaseクライアントの初期化
// データのエクスポートには、通常、読み取り権限のある anon key で十分ですが、
// Row Level Security (RLS) のポリシーに注意してください。
// RLSが有効な場合、ポリシーによってはデータが取得できません。
// 全データをエクスポートしたい場合は、SUPABASE_SERVICE_ROLE_KEY を使うのが確実です。
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.SUPABASE_URL;
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; // Service Role Keyを優先
if (!supabaseUrl || !supabaseKey) {
throw new Error('Supabase URL or API Key is missing in environment variables.');
}
const supabase = createClient(supabaseUrl, supabaseKey as string, {
auth: {
persistSession: false,
},
});
// エクスポート先のフォルダ
const exportDirPath = path.join(process.cwd(), 'export');
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const tableNamesParam = searchParams.get('tables'); // URLパラメータからテーブル名を取得 (例: ?tables=users,products)
// エクスポートしたいテーブル名の配列
// URLパラメータで指定されたテーブル名、またはデフォルトのリスト
let tablesToExport: string[];
if (tableNamesParam) {
tablesToExport = tableNamesParam.split(',').map(name => name.trim().toLowerCase());
} else {
// デフォルトでエクスポートしたいテーブルのリスト
// ここにあなたのテーブル名を追加してください。
// 例: ['users', 'serif', 'tests']
tablesToExport = ['users', 'serif', 'tests'];
}
const results: {
tableName: string;
status: string;
insertedCount?: number;
error?: string;
details?: any;
hint?: any;
code?: any;
rowCount?: Number;
filePath?: string;
}[] = [];
try {
// export フォルダが存在しない場合は作成
await fs.mkdir(exportDirPath, { recursive: true });
for (const tableName of tablesToExport) {
console.log(`Exporting data from table: ${tableName}...`);
const csvFilePath = path.join(exportDirPath, `${tableName}.csv`);
try {
// Supabaseからデータを取得
// RLSが有効な場合、適切なSELECTポリシーがないと空のデータが返るか、権限エラーになります。
const { data, error } = await supabase
.from(tableName)
.select('*'); // すべてのカラムを選択
if (error) {
console.error(`Supabase fetch error for ${tableName}:`, error);
results.push({
tableName,
status: 'failed',
error: error.message,
details: (error as any).details || null,
hint: (error as any).hint || null,
code: (error as any).code || null,
});
continue; // 次のテーブルへ
}
if (!data || data.length === 0) {
console.log(`No data found in table: ${tableName}. Skipping CSV creation.`);
results.push({ tableName, status: 'skipped', error: 'No data found' });
continue;
}
// CSV文字列に変換
// `stringify` は、データ配列とオプションを受け取る
// ヘッダー行を自動で含めるために `header: true` を指定
const csvString = await new Promise<string>((resolve, reject) => {
stringify(data, { header: true }, (err, output) => {
if (err) {
return reject(err);
}
resolve(output as string);
});
});
// CSVファイルを保存
await fs.writeFile(csvFilePath, csvString, { encoding: 'utf8' });
console.log(`Successfully exported ${data.length} rows to ${csvFilePath}`);
results.push({
tableName,
status: 'success',
rowCount: data.length,
filePath: csvFilePath,
});
} catch (tableExportError: any) {
console.error(`Error exporting table ${tableName}:`, tableExportError);
results.push({
tableName,
status: 'failed',
error: `Error processing table ${tableName}: ${tableExportError.message}`,
});
}
}
return NextResponse.json({
message: 'CSV export process completed.',
status: 'completed',
results: results,
});
} catch (error) {
console.error('Unexpected error during batch CSV export:', error);
return NextResponse.json(
{ message: 'An unexpected error occurred during batch CSV export', status: 'error', error: (error as Error).message },
{ status: 500 }
);
}
}