@nine-lab/nine-connector 0.1.9 โ 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -35
- package/package.json +2 -1
- package/prompts/query-generator.md +8 -5
- package/src/ai/AIProcessor.js +1 -0
- package/src/ai/AIService.js +8 -3
- package/src/core/init.js +1 -1
- package/src/database/core/DatabaseManager.js +26 -8
- package/src/database/core/Dialects.js +11 -4
- package/src/database/core/PoolManager.js +39 -0
- package/src/index.js +3 -0
package/README.md
CHANGED
|
@@ -1,67 +1,60 @@
|
|
|
1
1
|
cat <<EOF > README.md
|
|
2
2
|
# @nine-lab/nine-connector ๐
|
|
3
3
|
|
|
4
|
-
์์ฐ์ด ๊ธฐ๋ฐ SQL ์์ฑ ์์ง(NineQuery)๊ณผ
|
|
4
|
+
์์ฐ์ด ๊ธฐ๋ฐ SQL ์์ฑ ์์ง(NineQuery)๊ณผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ด๋ฅผ ์ฐ๊ฒฐํ๋ **AI ์ ์ฉ DB ์ปค๋ฅํฐ ์๋น์ค**์
๋๋ค.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
์ฌ์ฉ์์ ์ง๋ฌธ์ ๋ถ์ํ์ฌ ์ต์ ์ ํ
์ด๋ธ์ ํํฐ๋งํ๊ณ , ์์ ํ SQL์ ์์ฑํ์ฌ ์ฆ์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ํตํฉ ํ๊ฒฝ์ ์ ๊ณตํฉ๋๋ค.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
## ๐ ์ฃผ์ ๊ธฐ๋ฅ
|
|
11
11
|
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* **์๋ ์ด๊ธฐํ**: \`nine-connector init\` ๋ช
๋ น์ผ๋ก \`.env\` ์ค์ ๊ณผ AI ํ๋กฌํํธ๋ฅผ ์๋ ๊ตฌ์ถํฉ๋๋ค.
|
|
13
|
+
* **Multi-DB ์ง์**: MySQL, PostgreSQL, MariaDB, Oracle ๋ฑ ๋ค์ํ DB ํ๊ฒฝ์ ๋์ํฉ๋๋ค.
|
|
14
|
+
* **๋น์ฆ๋์ค ๋ก์ง ์ต์ ํ**: ํ๋กฌํํธ ํ์ผ ์์ ์ ํตํด ํน์ ํ
์ด๋ธ ์กฐํ ๊ธ์ง, ํํฐ๋ง ์กฐ๊ฑด ๊ฐ์ ๋ฑ ๊ณ ๊ฐ์ฌ๋ณ ๋ง์ถค ๊ท์น์ ์ ์ฉํ ์ ์์ต๋๋ค.
|
|
15
|
+
* **๋ณด์ ๊ฐ๋**: ๋ด๋ถ์ ์ผ๋ก ์ค์ง \`SELECT\` ์ฟผ๋ฆฌ๋ง ํ์ฉํ์ฌ ๋ฐ์ดํฐ ๋ณ์กฐ๋ฅผ ์ฐจ๋จํฉ๋๋ค.
|
|
16
|
+
* **๋ฐ์ดํฐ ํ์
์ต์ ํ**: \`BigInt\` ๋ฑ JSON ๋ณํ์ด ๊น๋ค๋ก์ด ํ์
์ ํฌํจํ์ฌ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ๋ฐํํฉ๋๋ค.
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
19
|
-
## ๐ ์ค์น ๋ฐ
|
|
20
|
-
|
|
21
|
-
### 1. ์ ์ญ(Global) ์ค์น
|
|
22
|
-
์ด๋ ๊ฒฝ๋ก์์๋ ๋ช
๋ น์ด๋ก ์ฆ์ ๊ธฐ๋ํ ์ ์๋๋ก ์ ์ญ ์ค์น๋ฅผ ๊ถ์ฅํฉ๋๋ค.
|
|
20
|
+
## ๐ ์ค์น ๋ฐ ์ฌ์ฉ ๋ฐฉ๋ฒ
|
|
23
21
|
|
|
22
|
+
### 1. ํจํค์ง ์ค์น
|
|
24
23
|
\`\`\`bash
|
|
25
24
|
npm install -g @nine-lab/nine-connector
|
|
26
25
|
\`\`\`
|
|
27
26
|
|
|
28
|
-
### 2.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# ์๋ฒ ํฌํธ (๊ธฐ๋ณธ๊ฐ: 3000)
|
|
33
|
-
SERVER_PORT=3000
|
|
34
|
-
|
|
35
|
-
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
|
|
36
|
-
DB_TYPE=mysql
|
|
37
|
-
DB_HOST=127.0.0.1
|
|
38
|
-
DB_PORT=3306
|
|
39
|
-
DB_USER=your_user
|
|
40
|
-
DB_PASS=your_password
|
|
41
|
-
DB_NAME=your_database
|
|
27
|
+
### 2. ํ๋ก์ ํธ ์ด๊ธฐํ
|
|
28
|
+
์ ์ ์ ๋ณด ์ค์ ๋ฐ ํ๋กฌํํธ ํ
ํ๋ฆฟ ์์ฑ์ ์ํด ์คํํฉ๋๋ค.
|
|
29
|
+
\`\`\`bash
|
|
30
|
+
nine-connector init
|
|
42
31
|
\`\`\`
|
|
43
32
|
|
|
44
|
-
### 3. ์๋ฒ
|
|
45
|
-
์ค์ ์ด ์๋ฃ๋์๋ค๋ฉด ํฐ๋ฏธ๋์์ ์๋ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํฉ๋๋ค.
|
|
46
|
-
|
|
33
|
+
### 3. ์๋ฒ ์คํ
|
|
47
34
|
\`\`\`bash
|
|
48
35
|
nine-connector
|
|
49
36
|
\`\`\`
|
|
50
37
|
|
|
51
38
|
---
|
|
52
39
|
|
|
53
|
-
## ๐ API ๋ช
์ธ
|
|
40
|
+
## ๐ API ๋ช
์ธ (Public API)
|
|
41
|
+
|
|
42
|
+
### 1. ์์ฐ์ด ์ง์ ์ฒ๋ฆฌ (Main)
|
|
43
|
+
์ฌ์ฉ์์ ์ง๋ฌธ์ ๋ฐ์ **ํ
์ด๋ธ ์ ์ -> SQL ์์ฑ -> ๋ฐ์ดํฐ ์กฐํ**๋ฅผ ํ ๋ฒ์ ์ํํฉ๋๋ค.
|
|
44
|
+
* **Endpoint:** \`POST /api/ask\`
|
|
45
|
+
* **Body:** \`{ "question": "์ฌํด ๋งค์ถ์ด ๊ฐ์ฅ ๋์ ์นดํ
๊ณ ๋ฆฌ ์๋ ค์ค" }\`
|
|
46
|
+
* **Response:** SQL๋ฌธ, AI์ ์ค๋ช
, ๊ทธ๋ฆฌ๊ณ ์กฐํ๋ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ํฌํจํฉ๋๋ค.
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
AI ๋ชจ๋ธ์ด ํ์ฌ DB ๊ตฌ์กฐ๋ฅผ ํ์ตํ ์ ์๋๋ก ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ฐํํฉ๋๋ค.
|
|
57
|
-
* **Endpoint:** \`GET /api/schema\`
|
|
48
|
+
---
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
*
|
|
50
|
+
## ๐ ํ๋ก์ ํธ ๊ตฌ์กฐ ๋ฐ ์ปค์คํฐ๋ง์ด์ง
|
|
51
|
+
* **.env**: DB ์ ์ ๋ฐ AI ๋ชจ๋ธ ์ค์ ๊ฐ
|
|
52
|
+
* **prompts/table-filter.md**: ์ง๋ฌธ์ ํ์ํ ํ
์ด๋ธ์ ๊ณ ๋ฅด๋ AI ๋ก์ง
|
|
53
|
+
* **prompts/query-generator.md**: ์ค์ SQL์ ์์ฑํ๋ AI ํ๋ฅด์๋
|
|
54
|
+
* **Tip**: ํ์ผ ๋ด \`[๊ณ ๊ฐ์ฌ ์ ์ฉ ๋น์ฆ๋์ค ๋ก์ง ๋ฐ ๋ณด์ ๊ท์น]\` ์น์
์ "ํน์ ํ
์ด๋ธ ์กฐํ ๊ธ์ง"๋ "๊ธฐ๋ณธ ์ ๋ ฌ ๊ธฐ์ค" ๋ฑ์ ์์ฑํ์ฌ AI์ ๋์์ ์ ์ดํ ์ ์์ต๋๋ค.
|
|
62
55
|
|
|
63
56
|
---
|
|
64
57
|
|
|
65
58
|
## ๐ ๋ผ์ด์ ์ค
|
|
66
59
|
MIT ยฉ **nine-lab**
|
|
67
|
-
EOF
|
|
60
|
+
EOF
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nine-lab/nine-connector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "NineQuery AI Connector for Database",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"express": "^4.22.1",
|
|
23
23
|
"mariadb": "^3.5.2",
|
|
24
24
|
"mysql2": "^3.9.7",
|
|
25
|
+
"oracledb": "^6.10.0",
|
|
25
26
|
"pg": "^8.11.5"
|
|
26
27
|
},
|
|
27
28
|
"publishConfig": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
### SQL_GENERATE_PROMPT
|
|
2
|
-
๋น์ ์ SQL ์์ฑ๊ธฐ์
๋๋ค. ์ ๊ณต๋
|
|
2
|
+
๋น์ ์ SQL ์์ฑ๊ธฐ์
๋๋ค. ์ ๊ณต๋ ํ
์ด๋ธ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ์ฌ์ฉ์์ ์ง๋ฌธ์ ๋ตํ๋ ์ต์ ์ SQL ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ์ธ์.
|
|
3
3
|
|
|
4
4
|
[์ ํ๋ ํ
์ด๋ธ ์ ๋ณด]
|
|
5
5
|
{detailed_schema}
|
|
@@ -10,12 +10,15 @@
|
|
|
10
10
|
[๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์
]
|
|
11
11
|
{db_type}
|
|
12
12
|
|
|
13
|
-
[์๋ต ๊ท์น]
|
|
13
|
+
[๊ธฐ๋ณธ ์๋ต ๊ท์น]
|
|
14
14
|
1. ๋ฐ๋์ JSON ํ์์ผ๋ก๋ง ์๋ตํ์ธ์.
|
|
15
15
|
2. SQL์ {db_type} ๋ฌธ๋ฒ์ ์๋ฒฝํ๊ฒ ๋ง์์ผ ํ๋ฉฐ, ์ฆ์ ์คํ ๊ฐ๋ฅํด์ผ ํฉ๋๋ค.
|
|
16
|
-
3. ์ฟผ๋ฆฌ๋ฌธ ์์ ๋งํฌ๋ค์ด ์ฝ๋ ๋ธ๋ก(```sql)์ ํฌํจํ์ง ๋ง์ธ์.
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
3. ์ฟผ๋ฆฌ๋ฌธ ์์ ๋งํฌ๋ค์ด ์ฝ๋ ๋ธ๋ก(```sql)์ ํฌํจํ์ง ๋ง์ธ์.
|
|
17
|
+
|
|
18
|
+
[๊ณ ๊ฐ์ฌ ์ ์ฉ ๋น์ฆ๋์ค ๋ก์ง ๋ฐ ๋ณด์ ๊ท์น]
|
|
19
|
+
-
|
|
20
|
+
-
|
|
21
|
+
(์ฌ๊ธฐ์ "ํน์ ํ
์ด๋ธ ์กฐํ ๊ธ์ง"๋ "๊ธฐ๋ณธ ์ ๋ ฌ ๊ธฐ์ค" ๋ฑ ์ปค์คํ
๊ท์น์ ์์ฑํ์ธ์.)
|
|
19
22
|
|
|
20
23
|
[์๋ต ํฌ๋งท]
|
|
21
24
|
{{
|
package/src/ai/AIProcessor.js
CHANGED
|
@@ -24,6 +24,7 @@ export class AIProcessor {
|
|
|
24
24
|
|
|
25
25
|
async filterTables(question, schemaSummary) {
|
|
26
26
|
if (!this.#chains['table-filter']) throw new Error("table-filter ์ฒด์ธ ๋ฏธ๋ฑ๋ก");
|
|
27
|
+
|
|
27
28
|
return await this.#chains['table-filter'].invoke({
|
|
28
29
|
question,
|
|
29
30
|
schema_summary: JSON.stringify(schemaSummary, null, 2)
|
package/src/ai/AIService.js
CHANGED
|
@@ -13,14 +13,19 @@ export class AIService {
|
|
|
13
13
|
|
|
14
14
|
// 2) AI: ํ์ํ ํ
์ด๋ธ ํํฐ๋ง
|
|
15
15
|
// AI ๊ฒฐ๊ณผ๊ฐ ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด ํ์ฑ ๋ก์ง์ด AIProcessor์ ์๋ค๋ฉด ์ฌ๊ธฐ์ ๋ณด์ ๊ฐ๋ฅ
|
|
16
|
-
const {
|
|
16
|
+
//const { selected_tables } = await this.ai.filterTables(question, schemaSummary);
|
|
17
|
+
const { selected_tables } = await this.ai.filterTables(question, schemaSummary);
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
console.log(selected_tables);
|
|
20
|
+
|
|
21
|
+
if (!selected_tables || selected_tables.length === 0) {
|
|
19
22
|
throw new Error("์ง๋ฌธ๊ณผ ๊ด๋ จ๋ ํ
์ด๋ธ์ ์ฐพ์ ์ ์์ต๋๋ค.");
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
console.log(schemaSummary);
|
|
26
|
+
|
|
22
27
|
// 3) ์์ธ ์คํค๋ง ํํฐ๋ง ๋ฐ SQL ์์ฑ
|
|
23
|
-
const detailedSchema = schemaSummary.filter(t =>
|
|
28
|
+
const detailedSchema = schemaSummary.filter(t => selected_tables.includes(t.tableName));
|
|
24
29
|
const { sql, explanation } = await this.ai.generateSql(
|
|
25
30
|
question,
|
|
26
31
|
detailedSchema,
|
package/src/core/init.js
CHANGED
|
@@ -18,7 +18,7 @@ async function createEnvFile(rl) {
|
|
|
18
18
|
{ key: 'SERVER_PORT', label: '1. ์ปค๋ฅํฐ ์๋ฒ ํฌํธ', default: '3000' },
|
|
19
19
|
{ key: 'GEMINI_API_KEY', label: '2. Gemini API Key', default: '' },
|
|
20
20
|
{ key: 'GEMINI_MODEL', label: '3. ์ฌ์ฉํ ๋ชจ๋ธ', default: 'gemini-2.5-flash' },
|
|
21
|
-
{ key: 'DB_TYPE', label: '4. DB ์ข
๋ฅ (mysql,
|
|
21
|
+
{ key: 'DB_TYPE', label: '4. DB ์ข
๋ฅ (mysql, mariadb, postgres, oracle)', default: 'mysql' },
|
|
22
22
|
{ key: 'DB_HOST', label: '5. DB ํธ์คํธ', default: '127.0.0.1' },
|
|
23
23
|
{ key: 'DB_PORT', label: '6. DB ํฌํธ', default: '3306' },
|
|
24
24
|
{ key: 'DB_USER', label: '7. DB ์ฌ์ฉ์ ๊ณ์ ', default: 'root' },
|
|
@@ -16,13 +16,14 @@ class DatabaseManager {
|
|
|
16
16
|
/**
|
|
17
17
|
* DatabaseFactory์ init() ์ญํ ์ ์ํํฉ๋๋ค.
|
|
18
18
|
*/
|
|
19
|
+
// DatabaseManager.js ๋ด๋ถ
|
|
19
20
|
async connect() {
|
|
20
21
|
try {
|
|
21
|
-
//
|
|
22
|
-
this.pool = PoolManager.createPool(this.config);
|
|
22
|
+
// ์ด์ createPool์ด async์ด๋ฏ๋ก await๋ฅผ ๋ถ์
๋๋ค.
|
|
23
|
+
this.pool = await PoolManager.createPool(this.config);
|
|
23
24
|
|
|
24
|
-
//
|
|
25
|
-
await this.query('SELECT 1');
|
|
25
|
+
// ์ฐ๊ฒฐ ํ์ธ
|
|
26
|
+
await this.query(this.dialect.testQuery || 'SELECT 1');
|
|
26
27
|
console.log(`[${this.type}] Database connection successful.`);
|
|
27
28
|
} catch (error) {
|
|
28
29
|
console.error(`[${this.type}] Connection failed:`, error.message);
|
|
@@ -39,6 +40,7 @@ class DatabaseManager {
|
|
|
39
40
|
|
|
40
41
|
const result = await this.pool.query(sql, params);
|
|
41
42
|
|
|
43
|
+
/**
|
|
42
44
|
if (this.type === 'postgres') {
|
|
43
45
|
return result.rows;
|
|
44
46
|
} else {
|
|
@@ -47,7 +49,20 @@ class DatabaseManager {
|
|
|
47
49
|
return (Array.isArray(result) && Array.isArray(result[0]))
|
|
48
50
|
? result[0]
|
|
49
51
|
: result;
|
|
52
|
+
} */
|
|
53
|
+
if (this.type === 'postgres' || this.type === 'postgresql') {
|
|
54
|
+
return result.rows;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// MariaDB/MySQL ๋์:
|
|
58
|
+
// DDL(INSERT/UPDATE) ๊ฒฐ๊ณผ์ DQL(SELECT) ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ๋ถํด์ผ ํจ
|
|
59
|
+
if (Array.isArray(result)) {
|
|
60
|
+
// mysql2 ๋์: rows๊ฐ 0๋ฒ์ ๋ด๊ฒจ์ค๋ ๊ฒฝ์ฐ
|
|
61
|
+
if (Array.isArray(result[0])) return result[0];
|
|
62
|
+
return result;
|
|
50
63
|
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
/**
|
|
@@ -63,18 +78,18 @@ class DatabaseManager {
|
|
|
63
78
|
async getTableSchema() {
|
|
64
79
|
const rows = await this.query(this.dialect.schemaQuery);
|
|
65
80
|
|
|
66
|
-
|
|
81
|
+
// 1. ์ฐ์ ๊ฐ์ฒด ํํ๋ก ๊ทธ๋ฃนํ (์ค๋ณต ๋ฐฉ์ง ๋ฐ ํจ์จ์ ์ ๋ฆฌ๋ฅผ ์ํด)
|
|
82
|
+
const grouped = rows.reduce((acc, row) => {
|
|
67
83
|
const { table_name, table_comment, column_name, data_type } = row;
|
|
68
84
|
|
|
69
|
-
// ํ
์ด๋ธ์ด ์ฒ์ ๋ฑ์ฅํ๋ฉด ์ด๊ธฐํ
|
|
70
85
|
if (!acc[table_name]) {
|
|
71
86
|
acc[table_name] = {
|
|
72
|
-
|
|
87
|
+
tableName: table_name, // ๋ฐฐ์ด๋ก ๋ณํ ์ ์๋ณ์ ์ํด ์ถ๊ฐ
|
|
88
|
+
description: table_comment || "",
|
|
73
89
|
columns: []
|
|
74
90
|
};
|
|
75
91
|
}
|
|
76
92
|
|
|
77
|
-
// ์ปฌ๋ผ ์ ๋ณด push
|
|
78
93
|
acc[table_name].columns.push({
|
|
79
94
|
column: column_name,
|
|
80
95
|
type: data_type
|
|
@@ -82,6 +97,9 @@ class DatabaseManager {
|
|
|
82
97
|
|
|
83
98
|
return acc;
|
|
84
99
|
}, {});
|
|
100
|
+
|
|
101
|
+
// 2. ์ต์ข
์ ์ผ๋ก ๊ฐ์ฒด์ ๊ฐ๋ค๋ง ๋ฝ์์ ๋ฐฐ์ด๋ก ๋ณํ
|
|
102
|
+
return Object.values(grouped);
|
|
85
103
|
}
|
|
86
104
|
}
|
|
87
105
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const Dialects = {
|
|
2
2
|
// MySQL ์ถ๊ฐ (MariaDB์ ๋์ผ)
|
|
3
3
|
mysql: {
|
|
4
|
+
testQuery: 'SELECT 1',
|
|
4
5
|
schemaQuery: `
|
|
5
6
|
SELECT
|
|
6
7
|
c.TABLE_NAME as table_name,
|
|
@@ -15,6 +16,7 @@ const Dialects = {
|
|
|
15
16
|
ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION`
|
|
16
17
|
},
|
|
17
18
|
mariadb: {
|
|
19
|
+
testQuery: 'SELECT 1',
|
|
18
20
|
schemaQuery: `
|
|
19
21
|
SELECT
|
|
20
22
|
c.TABLE_NAME as table_name,
|
|
@@ -29,19 +31,24 @@ const Dialects = {
|
|
|
29
31
|
ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION`
|
|
30
32
|
},
|
|
31
33
|
postgres: {
|
|
34
|
+
testQuery: 'SELECT 1',
|
|
32
35
|
schemaQuery: `
|
|
33
36
|
SELECT
|
|
34
37
|
t.table_name,
|
|
35
|
-
obj_description(pgc.oid, 'pg_class')
|
|
38
|
+
(SELECT obj_description(pgc.oid, 'pg_class')
|
|
39
|
+
FROM pg_class pgc
|
|
40
|
+
WHERE pgc.relname = t.table_name
|
|
41
|
+
AND pgc.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = t.table_schema)
|
|
42
|
+
) AS table_comment,
|
|
36
43
|
c.column_name,
|
|
37
44
|
c.data_type
|
|
38
45
|
FROM information_schema.tables t
|
|
39
|
-
JOIN information_schema.columns c ON t.table_name = c.table_name
|
|
40
|
-
|
|
41
|
-
WHERE t.table_schema = 'public'
|
|
46
|
+
JOIN information_schema.columns c ON t.table_name = c.table_name AND t.table_schema = c.table_schema
|
|
47
|
+
WHERE t.table_schema = CURRENT_SCHEMA() -- ํ์ฌ ์คํค๋ง ์๋ ๋์
|
|
42
48
|
ORDER BY t.table_name, c.ordinal_position`
|
|
43
49
|
},
|
|
44
50
|
oracle: {
|
|
51
|
+
testQuery: 'SELECT 1 FROM DUAL',
|
|
45
52
|
schemaQuery: `
|
|
46
53
|
SELECT
|
|
47
54
|
t.TABLE_NAME as table_name,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as mariadb from 'mariadb';
|
|
2
2
|
import pg from 'pg';
|
|
3
|
+
//import oracledb from 'oracledb';
|
|
3
4
|
|
|
4
5
|
class PoolManager {
|
|
5
6
|
/**
|
|
@@ -15,11 +16,49 @@ class PoolManager {
|
|
|
15
16
|
case 'postgres':
|
|
16
17
|
case 'postgresql':
|
|
17
18
|
return this.#createPostgresPool(config);
|
|
19
|
+
case 'oracle':
|
|
20
|
+
return this.#createOraclePool(config); // ์ถ๊ฐ
|
|
18
21
|
default:
|
|
19
22
|
throw new Error(`[PoolManager] Unsupported DB_TYPE: ${type}`);
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
static async #createOraclePool(config) {
|
|
27
|
+
try {
|
|
28
|
+
const { default: oracledb } = await import('oracledb');
|
|
29
|
+
|
|
30
|
+
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
|
|
31
|
+
oracledb.autoCommit = true;
|
|
32
|
+
|
|
33
|
+
const pool = await oracledb.createPool({
|
|
34
|
+
user: config.user,
|
|
35
|
+
password: config.password,
|
|
36
|
+
connectString: `${config.host}:${config.port}/${config.database}`,
|
|
37
|
+
poolMax: 10,
|
|
38
|
+
poolMin: 2,
|
|
39
|
+
poolIncrement: 1
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// ๋ค๋ฅธ DB๋ค๊ณผ ์ฌ์ฉ๋ฒ์ ๋ง์ถ๊ธฐ ์ํด ๋ํ(Wrapping)
|
|
43
|
+
return {
|
|
44
|
+
query: async (sql, params = []) => {
|
|
45
|
+
let conn;
|
|
46
|
+
try {
|
|
47
|
+
conn = await pool.getConnection();
|
|
48
|
+
const result = await conn.execute(sql, params);
|
|
49
|
+
return result.rows; // ๊ฐ์ฒด ๋ฐฐ์ด ๋ฐํ
|
|
50
|
+
} finally {
|
|
51
|
+
if (conn) await conn.close();
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
close: () => pool.close()
|
|
55
|
+
};
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error("Oracle Pool ์์ฑ ์คํจ:", err.message);
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
23
62
|
static #createMariaDBPool(config) {
|
|
24
63
|
return mariadb.createPool({
|
|
25
64
|
host: config.host,
|
package/src/index.js
CHANGED
|
@@ -69,6 +69,9 @@ async function bootstrap() {
|
|
|
69
69
|
|
|
70
70
|
// [API] ์์ฐ์ด ์ง์ ์๋ํฌ์ธํธ
|
|
71
71
|
app.post('/api/ask', async (req, res) => {
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
72
75
|
const { question } = req.body;
|
|
73
76
|
if (!question) return res.status(400).json({ success: false, error: "์ง๋ฌธ์ ์
๋ ฅํด์ฃผ์ธ์." });
|
|
74
77
|
|