summaryrefslogtreecommitdiff
path: root/lib/oracle/db.ts
blob: 57a5cd4956196ad683c1f481fa823d96f8c90331 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import oracledb, { Connection, PoolAttributes, Result } from 'oracledb';

// Oracle 자동 커밋 활성화
oracledb.autoCommit = true;

// 연결 구성 타입
interface DbConfig extends PoolAttributes {
  user: string;
  password: string;
  connectString: string;
}

// 환경 변수에서 DB 설정 가져오기
const dbConfig: DbConfig = {
  user: process.env.ORACLE_USER || '',
  password: process.env.ORACLE_PASSWORD || '',
  connectString: process.env.ORACLE_CONNECTION_STRING || ''
};

// DB 연결 풀
let pool: oracledb.Pool | null = null;

/**
 * DB 연결 풀 초기화
 */
async function initialize(): Promise<void> {
  try {
    pool = await oracledb.createPool(dbConfig);
    console.log('Oracle DB 연결 풀이 초기화되었습니다.');
  } catch (err) {
    console.error('Oracle DB 풀 초기화 오류:', err);
    throw err;
  }
}

/**
 * DB 연결 가져오기
 */
export async function getConnection(): Promise<Connection> {
  if (!pool) {
    await initialize();
  }
  
  if (!pool) {
    throw new Error('DB 풀이 초기화되지 않았습니다.');
  }
  
  return pool.getConnection();
}

/**
 * 쿼리 실행 함수
 */
export async function executeQuery<T = any>(
  query: string, 
  params: any[] = [], 
  options: oracledb.ExecuteOptions = {}
): Promise<Result<T>> {
  let connection: Connection | undefined;
  
  try {
    connection = await getConnection();
    
    const result = await connection.execute<T>(
      query, 
      params, 
      {
        outFormat: oracledb.OUT_FORMAT_OBJECT,
        ...options
      }
    );
    
    return result;
  } catch (err) {
    console.error('쿼리 실행 오류:', err);
    throw err;
  } finally {
    if (connection) {
      try {
        await connection.close();
      } catch (err) {
        console.error('연결 종료 오류:', err);
      }
    }
  }
}

/**
 * 테이블 데이터 가져오기 함수
 */
export async function getTableData<T = any>(tableName: string): Promise<T[]> {
  // SQL 인젝션 방지를 위한 테이블 이름 검증
  // 알파벳, 숫자, 밑줄(_), 달러 기호($), 해시(#) 만 허용
  const tableNameRegex = /^[a-zA-Z0-9_$#]+$/;
  
  if (!tableNameRegex.test(tableName)) {
    throw new Error('유효하지 않은 테이블 이름입니다.');
  }
  
  const query = `SELECT * FROM ${tableName}`;
  const result = await executeQuery<T>(query);
  
  return result.rows as T[] || [];
}

/**
 * 테이블 특정 컬럼 데이터 가져오기 함수
 */
export async function getTableColumns<T = any>(
  tableName: string, 
  columns: string[]
): Promise<T[]> {
  // SQL 인젝션 방지
  const tableNameRegex = /^[a-zA-Z0-9_$#]+$/;
  if (!tableNameRegex.test(tableName)) {
    throw new Error('유효하지 않은 테이블 이름입니다.');
  }
  
  // 컬럼명 검증
  const columnNameRegex = /^[a-zA-Z0-9_$#]+$/;
  const validColumns = columns.filter(col => columnNameRegex.test(col));
  
  if (validColumns.length === 0) {
    throw new Error('유효하지 않은 컬럼 이름입니다.');
  }
  
  const columnsStr = validColumns.join(', ');
  const query = `SELECT ${columnsStr} FROM ${tableName}`;
  
  const result = await executeQuery<T>(query);
  return result.rows as T[] || [];
}

/**
 * 풀 종료 함수
 */
export async function closePool(): Promise<void> {
  if (pool) {
    try {
      await pool.close(0);
      pool = null;
      console.log('Oracle DB 연결 풀이 종료되었습니다.');
    } catch (err) {
      console.error('풀 종료 오류:', err);
      throw err;
    }
  }
}