버튼에 제어 달기
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
// 인증 서비스
|
||||
// 기존 Java LoginService를 Node.js로 포팅
|
||||
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import prisma from "../config/database";
|
||||
import { JwtUtils } from "../utils/jwtUtils";
|
||||
import { EncryptUtil } from "../utils/encryptUtil";
|
||||
import { PersonBean, LoginResult, LoginLogData } from "../types/auth";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export class AuthService {
|
||||
/**
|
||||
* 기존 Java LoginService.loginPwdCheck() 메서드 포팅
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import prisma from "../config/database";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export interface CodeCategory {
|
||||
category_code: string;
|
||||
category_name: string;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
import prisma from "../config/database";
|
||||
|
||||
interface GetTableDataParams {
|
||||
tableName: string;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PrismaClient, Prisma } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import prisma from "../config/database";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// 타입 정의
|
||||
interface CreateDataflowDiagramData {
|
||||
diagram_name: string;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import prisma from "../config/database";
|
||||
import { logger } from "../utils/logger";
|
||||
import {
|
||||
EntityJoinConfig,
|
||||
@@ -7,8 +8,6 @@ import {
|
||||
} from "../types/tableManagement";
|
||||
import { referenceCacheService } from "./referenceCacheService";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
/**
|
||||
* Entity 조인 기능을 제공하는 서비스
|
||||
* ID값을 의미있는 데이터로 자동 변환하는 스마트 테이블 시스템
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import prisma from "../config/database";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// 외부 호출 설정 타입 정의
|
||||
export interface ExternalCallConfig {
|
||||
id?: number;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "../types/externalDbTypes";
|
||||
import { PasswordEncryption } from "../utils/passwordEncryption";
|
||||
import { DatabaseConnectorFactory } from "../database/DatabaseConnectorFactory";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
export class ExternalDbConnectionService {
|
||||
/**
|
||||
@@ -694,7 +695,8 @@ export class ExternalDbConnectionService {
|
||||
*/
|
||||
static async executeQuery(
|
||||
id: number,
|
||||
query: string
|
||||
query: string,
|
||||
params: any[] = []
|
||||
): Promise<ApiResponse<any[]>> {
|
||||
try {
|
||||
// 연결 정보 조회
|
||||
@@ -751,7 +753,20 @@ export class ExternalDbConnectionService {
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await connector.executeQuery(query);
|
||||
const dbType = connection.db_type?.toLowerCase() || 'postgresql';
|
||||
|
||||
// 파라미터 바인딩을 지원하는 DB 타입들
|
||||
const supportedDbTypes = ['oracle', 'mysql', 'mariadb', 'postgresql', 'sqlite', 'sqlserver', 'mssql'];
|
||||
|
||||
if (supportedDbTypes.includes(dbType) && params.length > 0) {
|
||||
// 파라미터 바인딩 지원 DB: 안전한 파라미터 바인딩 사용
|
||||
logger.info(`${dbType.toUpperCase()} 파라미터 바인딩 실행:`, { query, params });
|
||||
result = await (connector as any).executeQuery(query, params);
|
||||
} else {
|
||||
// 파라미터가 없거나 지원하지 않는 DB: 기본 방식 사용
|
||||
logger.info(`${dbType.toUpperCase()} 기본 쿼리 실행:`, { query });
|
||||
result = await connector.executeQuery(query);
|
||||
}
|
||||
} finally {
|
||||
// 🔧 연결 해제 추가 - 메모리 누수 방지
|
||||
await DatabaseConnectorFactory.closeConnector(id, connection.db_type);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import prisma from "../config/database";
|
||||
import {
|
||||
CreateLayoutRequest,
|
||||
UpdateLayoutRequest,
|
||||
@@ -7,8 +8,6 @@ import {
|
||||
LayoutCategory,
|
||||
} from "../types/layout";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// JSON 데이터를 안전하게 파싱하는 헬퍼 함수
|
||||
function safeJSONParse(data: any): any {
|
||||
if (data === null || data === undefined) {
|
||||
|
||||
@@ -144,21 +144,133 @@ export class MultiConnectionQueryService {
|
||||
}
|
||||
const connection = connectionResult.data;
|
||||
|
||||
// INSERT 쿼리 구성
|
||||
// INSERT 쿼리 구성 (DB 타입별 처리)
|
||||
const columns = Object.keys(data);
|
||||
const values = Object.values(data);
|
||||
const placeholders = values.map((_, index) => `$${index + 1}`).join(", ");
|
||||
let values = Object.values(data);
|
||||
|
||||
// Oracle의 경우 테이블 스키마 확인 및 데이터 타입 변환 처리
|
||||
if (connection.db_type?.toLowerCase() === 'oracle') {
|
||||
try {
|
||||
// Oracle 테이블 스키마 조회
|
||||
const schemaQuery = `
|
||||
SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
|
||||
FROM USER_TAB_COLUMNS
|
||||
WHERE TABLE_NAME = UPPER('${tableName}')
|
||||
ORDER BY COLUMN_ID
|
||||
`;
|
||||
|
||||
logger.info(`🔍 Oracle 테이블 스키마 조회: ${schemaQuery}`);
|
||||
|
||||
const schemaResult = await ExternalDbConnectionService.executeQuery(
|
||||
connectionId,
|
||||
schemaQuery
|
||||
);
|
||||
|
||||
if (schemaResult.success && schemaResult.data) {
|
||||
logger.info(`📋 Oracle 테이블 ${tableName} 스키마:`);
|
||||
schemaResult.data.forEach((col: any) => {
|
||||
logger.info(` - ${col.COLUMN_NAME}: ${col.DATA_TYPE}, NULL: ${col.NULLABLE}, DEFAULT: ${col.DATA_DEFAULT || 'None'}`);
|
||||
});
|
||||
|
||||
// 필수 컬럼 중 누락된 컬럼이 있는지 확인 (기본값이 없는 NOT NULL 컬럼만)
|
||||
const providedColumns = columns.map(col => col.toUpperCase());
|
||||
const missingRequiredColumns = schemaResult.data.filter((schemaCol: any) =>
|
||||
schemaCol.NULLABLE === 'N' &&
|
||||
!schemaCol.DATA_DEFAULT &&
|
||||
!providedColumns.includes(schemaCol.COLUMN_NAME)
|
||||
);
|
||||
|
||||
if (missingRequiredColumns.length > 0) {
|
||||
const missingNames = missingRequiredColumns.map((col: any) => col.COLUMN_NAME);
|
||||
logger.error(`❌ 필수 컬럼 누락: ${missingNames.join(', ')}`);
|
||||
throw new Error(`필수 컬럼이 누락되었습니다: ${missingNames.join(', ')}`);
|
||||
}
|
||||
|
||||
logger.info(`✅ 스키마 검증 통과: 모든 필수 컬럼이 제공되었거나 기본값이 있습니다.`);
|
||||
}
|
||||
} catch (schemaError) {
|
||||
logger.warn(`⚠️ 스키마 조회 실패 (계속 진행): ${schemaError}`);
|
||||
}
|
||||
|
||||
values = values.map(value => {
|
||||
// null이나 undefined는 그대로 유지
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// 숫자로 변환 가능한 문자열은 숫자로 변환
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
const numValue = Number(value);
|
||||
if (!isNaN(numValue)) {
|
||||
logger.info(`🔄 Oracle 데이터 타입 변환: "${value}" (string) → ${numValue} (number)`);
|
||||
return numValue;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
let query: string;
|
||||
let queryParams: any[];
|
||||
const dbType = connection.db_type?.toLowerCase() || 'postgresql';
|
||||
|
||||
const query = `
|
||||
INSERT INTO ${tableName} (${columns.join(", ")})
|
||||
VALUES (${placeholders})
|
||||
RETURNING *
|
||||
`;
|
||||
switch (dbType) {
|
||||
case 'oracle':
|
||||
// Oracle: :1, :2 스타일 바인딩 사용, RETURNING 미지원
|
||||
const oraclePlaceholders = values.map((_, index) => `:${index + 1}`).join(", ");
|
||||
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${oraclePlaceholders})`;
|
||||
queryParams = values;
|
||||
logger.info(`🔍 Oracle INSERT 상세 정보:`);
|
||||
logger.info(` - 테이블: ${tableName}`);
|
||||
logger.info(` - 컬럼: ${JSON.stringify(columns)}`);
|
||||
logger.info(` - 값: ${JSON.stringify(values)}`);
|
||||
logger.info(` - 쿼리: ${query}`);
|
||||
logger.info(` - 파라미터: ${JSON.stringify(queryParams)}`);
|
||||
logger.info(` - 데이터 타입: ${JSON.stringify(values.map(v => typeof v))}`);
|
||||
break;
|
||||
|
||||
case 'mysql':
|
||||
case 'mariadb':
|
||||
// MySQL/MariaDB: ? 스타일 바인딩 사용, RETURNING 미지원
|
||||
const mysqlPlaceholders = values.map(() => '?').join(", ");
|
||||
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${mysqlPlaceholders})`;
|
||||
queryParams = values;
|
||||
logger.info(`MySQL/MariaDB INSERT 쿼리:`, { query, params: queryParams });
|
||||
break;
|
||||
|
||||
case 'sqlserver':
|
||||
case 'mssql':
|
||||
// SQL Server: @param1, @param2 스타일 바인딩 사용
|
||||
const sqlServerPlaceholders = values.map((_, index) => `@param${index + 1}`).join(", ");
|
||||
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${sqlServerPlaceholders})`;
|
||||
queryParams = values;
|
||||
logger.info(`SQL Server INSERT 쿼리:`, { query, params: queryParams });
|
||||
break;
|
||||
|
||||
case 'sqlite':
|
||||
// SQLite: ? 스타일 바인딩 사용, RETURNING 지원 (3.35.0+)
|
||||
const sqlitePlaceholders = values.map(() => '?').join(", ");
|
||||
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${sqlitePlaceholders}) RETURNING *`;
|
||||
queryParams = values;
|
||||
logger.info(`SQLite INSERT 쿼리:`, { query, params: queryParams });
|
||||
break;
|
||||
|
||||
case 'postgresql':
|
||||
default:
|
||||
// PostgreSQL: $1, $2 스타일 바인딩 사용, RETURNING 지원
|
||||
const pgPlaceholders = values.map((_, index) => `$${index + 1}`).join(", ");
|
||||
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${pgPlaceholders}) RETURNING *`;
|
||||
queryParams = values;
|
||||
logger.info(`PostgreSQL INSERT 쿼리:`, { query, params: queryParams });
|
||||
break;
|
||||
}
|
||||
|
||||
// 외부 DB에서 쿼리 실행
|
||||
const result = await ExternalDbConnectionService.executeQuery(
|
||||
connectionId,
|
||||
query
|
||||
query,
|
||||
queryParams
|
||||
);
|
||||
|
||||
if (!result.success || !result.data) {
|
||||
|
||||
Reference in New Issue
Block a user