import { NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
import { parse } from 'csv-parse';
import fs from 'fs/promises';
import path from 'path';
// Supabaseクライアントの初期化 (前回のものと同じ)
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || process.env.SUPABASE_ANON_KEY;
const supabaseServiceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY; // 必要に応じてService Role Keyを使用
if (!supabaseUrl || (!supabaseAnonKey && !supabaseServiceRoleKey)) {
throw new Error('Supabase URL or Anon/Service Role Key is missing in environment variables.');
}
// サーバーサイド用のSupabaseクライアントを作成
// 本番環境では anonKey の代わりに serviceRoleKey を使うことを強く推奨します。
// 例: const supabase = createClient(supabaseUrl, supabaseServiceRoleKey || supabaseAnonKey, { ... });
const supabase = createClient(supabaseUrl, supabaseAnonKey as string, { // デバッグ用に anonKey を使用
auth: {
persistSession: false,
},
});
// CSVファイルをパースしてデータを取得するヘルパー関数 (前回のものと同じ)
async function parseCsvFile(filePath: string): Promise<any[]> {
const fileContent = await fs.readFile(filePath, { encoding: 'utf8' });
return new Promise((resolve, reject) => {
parse(
fileContent,
{
columns: true, // ヘッダー行をカラム名として使用
skip_empty_lines: true,
},
(err, records) => {
if (err) {
return reject(err);
}
resolve(records);
}
);
});
}
export async function GET(request: Request) {
const results: {
tableName: string;
status: string;
insertedCount?: number;
error?: string;
details?: any;
hint?: any;
code?: any
}[] = [];
try {
const dataDirPath = path.join(process.cwd(), 'data');
let files: string[];
try {
files = await fs.readdir(dataDirPath);
} catch (readDirError: any) {
if (readDirError.code === 'ENOENT') {
return NextResponse.json(
{ message: 'Data directory not found. Please create a "data" folder at the project root.', status: 'error' },
{ status: 404 }
);
}
console.error('Error reading data directory:', readDirError);
return NextResponse.json(
{ message: `Failed to read data directory: ${readDirError.message}`, status: 'error' },
{ status: 500 }
);
}
const csvFiles = files.filter(file => file.endsWith('.csv'));
if (csvFiles.length === 0) {
return NextResponse.json(
{ message: 'No CSV files found in the "data" directory.', status: 'success', results: [] },
{ status: 200 }
);
}
for (const csvFileName of csvFiles) {
const tableName = path.parse(csvFileName).name.toLowerCase(); // ファイル名からテーブル名を決定 (小文字に変換)
const csvFilePath = path.join(dataDirPath, csvFileName);
console.log(`Processing ${csvFileName} for table ${tableName}...`);
try {
let records = await parseCsvFile(csvFilePath);
if (records.length === 0) {
console.log(`CSV file ${csvFileName} is empty. Skipping insertion.`);
results.push({ tableName, status: 'skipped', error: 'CSV file is empty' });
continue; // 次のファイルへ
}
// ここでレコードを変換する必要がある場合があります。
// 例: USER_IDが自動採番の場合、CSVからUSER_IDを取り除く
if (tableName === 'users' && records[0].USER_ID !== undefined) {
// CSVにUSER_IDがあるが、Supabaseで自動採番されている場合、
// そのカラムを除外して挿入するための変換を行う
records = records.map(({ USER_ID, ...rest }) => rest);
console.log(`Removed USER_ID column for insertion into 'users' table.`);
}
// 他のテーブルで同様の変換が必要ならここに追加
console.log(`Parsed ${records.length} records from ${csvFileName}.`);
const { data: insertedData, error: insertError } = await supabase
.from(tableName)
.insert(records);
if (insertError) {
console.error(`Supabase insertion error for ${tableName}:`, insertError);
// ここを修正: insertError の詳細を results に含める
results.push({
tableName,
status: 'failed',
error: insertError.message || 'Unknown error', // エラーメッセージ
details: (insertError as any).details || null, // Supabaseが返す詳細情報
hint: (insertError as any).hint || null, // Supabaseが返すヒント
code: (insertError as any).code || null, // Supabaseが返すエラーコード (PostgreSQLのコードなど)
});
} else {
console.log(`Successfully inserted ${records.length} records into ${tableName} table.`);
results.push({ tableName, status: 'success', insertedCount: records.length });
}
} catch (fileProcessError: any) {
console.error(`Error processing ${csvFileName}:`, fileProcessError);
results.push({
tableName,
status: 'failed',
error: `Error processing file: ${fileProcessError.message}`,
});
}
}
return NextResponse.json({
message: 'CSV ingestion process completed.',
status: 'completed',
results: results,
});
} catch (error) {
console.error('Unexpected error during batch CSV ingestion:', error);
return NextResponse.json(
{ message: 'An unexpected error occurred during batch CSV ingestion', status: 'error', error: (error as Error).message },
{ status: 500 }
);
}
}