외부 db연동 구현

This commit is contained in:
dohyeons
2025-10-01 14:36:46 +09:00
parent 12087cbdd7
commit 2ee4dd0b58
8 changed files with 212 additions and 18 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
@@ -8,12 +8,13 @@ import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Plus, Trash2, Play, AlertCircle, Database } from "lucide-react";
import { Plus, Trash2, Play, AlertCircle, Database, Link2 } from "lucide-react";
import { useReportDesigner, ReportQuery } from "@/contexts/ReportDesignerContext";
import { Badge } from "@/components/ui/badge";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { reportApi } from "@/lib/api/reportApi";
import { useToast } from "@/hooks/use-toast";
import type { ExternalConnection } from "@/types/report";
export function QueryManager() {
const { queries, setQueries, reportId, setQueryResult, getQueryResult } = useReportDesigner();
@@ -21,11 +22,32 @@ export function QueryManager() {
const [isTestRunning, setIsTestRunning] = useState(false);
const [parameterValues, setParameterValues] = useState<Record<string, string>>({});
const [parameterTypes, setParameterTypes] = useState<Record<string, string>>({});
const [externalConnections, setExternalConnections] = useState<ExternalConnection[]>([]);
const [isLoadingConnections, setIsLoadingConnections] = useState(false);
const { toast } = useToast();
const selectedQuery = queries.find((q) => q.id === selectedQueryId);
const testResult = selectedQuery ? getQueryResult(selectedQuery.id) : null;
// 외부 DB 연결 목록 조회
useEffect(() => {
const fetchConnections = async () => {
setIsLoadingConnections(true);
try {
const response = await reportApi.getExternalConnections();
if (response.success && response.data) {
setExternalConnections(response.data);
}
} catch (error) {
console.error("외부 DB 연결 목록 조회 실패:", error);
} finally {
setIsLoadingConnections(false);
}
};
fetchConnections();
}, []);
// 파라미터 감지 ($1, $2 등, 단 작은따옴표 안은 제외)
const detectParameters = (sql: string): string[] => {
// 작은따옴표 안의 내용을 제거
@@ -55,6 +77,7 @@ export function QueryManager() {
type: "MASTER",
sqlQuery: "",
parameters: [],
externalConnectionId: null, // 기본값: 내부 DB
};
setQueries([...queries, newQuery]);
setSelectedQueryId(newQuery.id);
@@ -121,9 +144,16 @@ export function QueryManager() {
// new 리포트는 임시 ID 사용하고 SQL 쿼리 직접 전달
const testReportId = reportId === "new" ? "TEMP_TEST" : reportId;
const sqlQuery = reportId === "new" ? selectedQuery.sqlQuery : undefined;
const externalConnectionId = (selectedQuery as any).externalConnectionId || null;
// 실제 API 호출
const response = await reportApi.executeQuery(testReportId, selectedQuery.id, parameterValues, sqlQuery);
const response = await reportApi.executeQuery(
testReportId,
selectedQuery.id,
parameterValues,
sqlQuery,
externalConnectionId,
);
if (response.success && response.data) {
// Context에 실행 결과 저장
@@ -246,6 +276,51 @@ export function QueryManager() {
</Select>
</div>
{/* DB 연결 선택 */}
<div className="space-y-2">
<Label className="flex items-center gap-2 text-xs">
<Link2 className="h-3 w-3" />
DB
</Label>
<Select
value={(selectedQuery as any).externalConnectionId?.toString() || "internal"}
onValueChange={(value) =>
handleUpdateQuery(selectedQuery.id, {
externalConnectionId: value === "internal" ? null : parseInt(value),
} as any)
}
disabled={isLoadingConnections}
>
<SelectTrigger className="h-8">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="internal">
<div className="flex items-center gap-2">
<Database className="h-4 w-4" />
DB (PostgreSQL)
</div>
</SelectItem>
{externalConnections.length > 0 && (
<>
<div className="px-2 py-1.5 text-xs font-semibold text-gray-500"> DB</div>
{externalConnections.map((conn) => (
<SelectItem key={conn.id} value={conn.id.toString()}>
<div className="flex items-center gap-2">
<Database className="h-4 w-4" />
{conn.connection_name}
<Badge variant="outline" className="text-xs">
{conn.db_type.toUpperCase()}
</Badge>
</div>
</SelectItem>
))}
</>
)}
</SelectContent>
</Select>
</div>
{/* SQL 쿼리 */}
<div className="space-y-2">
<Textarea