외부 db연동 구현
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user