@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 CHANGED
@@ -1,67 +1,60 @@
1
1
  cat <<EOF > README.md
2
2
  # @nine-lab/nine-connector ๐Ÿš€
3
3
 
4
- ์ž์—ฐ์–ด ๊ธฐ๋ฐ˜ SQL ์ƒ์„ฑ ์—”์ง„(NineQuery)๊ณผ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” **AI ์ „์šฉ DB ์ปค๋„ฅํ„ฐ ์„œ๋น„์Šค**์ž…๋‹ˆ๋‹ค.
4
+ ์ž์—ฐ์–ด ๊ธฐ๋ฐ˜ SQL ์ƒ์„ฑ ์—”์ง„(NineQuery)๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” **AI ์ „์šฉ DB ์ปค๋„ฅํ„ฐ ์„œ๋น„์Šค**์ž…๋‹ˆ๋‹ค.
5
5
 
6
- AI๊ฐ€ ์ƒ์„ฑํ•œ SQL์„ ์•ˆ์ „ํ•˜๊ฒŒ ์‹คํ–‰ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๊ตฌ์กฐ(Schema)๋ฅผ AI์—๊ฒŒ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ API ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
6
+ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ๋ถ„์„ํ•˜์—ฌ ์ตœ์ ์˜ ํ…Œ์ด๋ธ”์„ ํ•„ํ„ฐ๋งํ•˜๊ณ , ์•ˆ์ „ํ•œ SQL์„ ์ƒ์„ฑํ•˜์—ฌ ์ฆ‰์‹œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ†ตํ•ฉ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
7
7
 
8
8
  ---
9
9
 
10
10
  ## ๐ŸŒŸ ์ฃผ์š” ๊ธฐ๋Šฅ
11
11
 
12
- * **Multi-DB ์ง€์›**: MySQL, PostgreSQL, MariaDB์™€ ์ฆ‰์‹œ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
13
- * **์Šคํ‚ค๋งˆ ์ž๋™ ์ถ”์ถœ**: AI๊ฐ€ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ํ•„์š”ํ•œ ํ…Œ์ด๋ธ” ๋ฐ ์ปฌ๋Ÿผ ์ •๋ณด๋ฅผ API๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
14
- * **๋ณด์•ˆ ๊ฐ€๋“œ**: ์˜ค์ง \`SELECT\` ์ฟผ๋ฆฌ๋งŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด ๋ฐ์ดํ„ฐ ๋ณ€์กฐ๋ฅผ ์›์ฒœ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.
15
- * **BigInt ๋Œ€์‘**: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํฐ ์ˆซ์žํ˜•(\`BigInt\`) ๋ฐ์ดํ„ฐ๋ฅผ JSON์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
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. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • (\`.env\`)
29
- ์„œ๋ฒ„ ์‹คํ–‰ ์ „, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘์† ์ •๋ณด๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ํ•  ๊ฒฝ๋กœ์— \`.env\` ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์‹œ์Šคํ…œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.
30
-
31
- \`\`\`env
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
- ### 1. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ์กฐํšŒ
56
- AI ๋ชจ๋ธ์ด ํ˜„์žฌ DB ๊ตฌ์กฐ๋ฅผ ํ•™์Šตํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
57
- * **Endpoint:** \`GET /api/schema\`
48
+ ---
58
49
 
59
- ### 2. SQL ์ฟผ๋ฆฌ ์‹คํ–‰
60
- AI๊ฐ€ ์ƒ์„ฑํ•œ SQL์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ์„ ์œ„ํ•ด **SELECT ๋ฌธ**๋งŒ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.
61
- * **Endpoint:** \`POST /api/query\`
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.9",
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 ์ƒ์„ฑ๊ธฐ์ž…๋‹ˆ๋‹ค. ์ œ๊ณต๋œ ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋‹ตํ•˜๋Š” ์ตœ์ ์˜ 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
- 4. ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋„๋ก ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ์„ค๋ช…(explanation)์„ ์นœ์ ˆํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์„ธ์š”.
18
- 5. ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ปฌ๋Ÿผ์ด๋‚˜ ํ…Œ์ด๋ธ”์€ ์ ˆ๋Œ€ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.
16
+ 3. ์ฟผ๋ฆฌ๋ฌธ ์•ˆ์— ๋งˆํฌ๋‹ค์šด ์ฝ”๋“œ ๋ธ”๋ก(```sql)์„ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”.
17
+
18
+ [๊ณ ๊ฐ์‚ฌ ์ „์šฉ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ฐ ๋ณด์•ˆ ๊ทœ์น™]
19
+ -
20
+ -
21
+ (์—ฌ๊ธฐ์— "ํŠน์ • ํ…Œ์ด๋ธ” ์กฐํšŒ ๊ธˆ์ง€"๋‚˜ "๊ธฐ๋ณธ ์ •๋ ฌ ๊ธฐ์ค€" ๋“ฑ ์ปค์Šคํ…€ ๊ทœ์น™์„ ์ž‘์„ฑํ•˜์„ธ์š”.)
19
22
 
20
23
  [์‘๋‹ต ํฌ๋งท]
21
24
  {{
@@ -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)
@@ -13,14 +13,19 @@ export class AIService {
13
13
 
14
14
  // 2) AI: ํ•„์š”ํ•œ ํ…Œ์ด๋ธ” ํ•„ํ„ฐ๋ง
15
15
  // AI ๊ฒฐ๊ณผ๊ฐ€ ๋ฌธ์ž์—ด์ผ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด ํŒŒ์‹ฑ ๋กœ์ง์ด AIProcessor์— ์—†๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ ๋ณด์™„ ๊ฐ€๋Šฅ
16
- const { tables } = await this.ai.filterTables(question, schemaSummary);
16
+ //const { selected_tables } = await this.ai.filterTables(question, schemaSummary);
17
+ const { selected_tables } = await this.ai.filterTables(question, schemaSummary);
17
18
 
18
- if (!tables || tables.length === 0) {
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 => tables.includes(t.tableName));
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, pg, mariadb)', default: '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
- // Pool ์ƒ์„ฑ์€ ์ „์ ์œผ๋กœ PoolManager์—๊ฒŒ ๋งก๊น๋‹ˆ๋‹ค.
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
- return rows.reduce((acc, row) => {
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
- description: table_comment || "", // ํ…Œ์ด๋ธ” ์„ค๋ช… ์ถ”๊ฐ€
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') AS table_comment,
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
- JOIN pg_class pgc ON t.table_name = pgc.relname
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