diff --git a/PHASE4_REMAINING_PRISMA_CALLS.md b/PHASE4_REMAINING_PRISMA_CALLS.md index ea621f5d..89742648 100644 --- a/PHASE4_REMAINING_PRISMA_CALLS.md +++ b/PHASE4_REMAINING_PRISMA_CALLS.md @@ -2,14 +2,14 @@ ## ๐Ÿ“Š ํ˜„์žฌ ์ƒํ™ฉ -| ํ•ญ๋ชฉ | ๋‚ด์šฉ | -| --------------- | --------------------------------------- | -| ์ด Prisma ํ˜ธ์ถœ | 29๊ฐœ | -| ๋Œ€์ƒ ํŒŒ์ผ | 7๊ฐœ | -| **ํ˜„์žฌ ์ง„ํ–‰๋ฅ ** | **17/29 (58.6%)** ๐Ÿ”„ **์ง„ํ–‰ ์ค‘** | -| ๋ณต์žก๋„ | ์ค‘๊ฐ„ | -| ์šฐ์„ ์ˆœ์œ„ | ๐Ÿ”ด ๋†’์Œ (Phase 4) | -| **์ƒํƒœ** | โณ **์ง„ํ–‰ ์ค‘** | +| ํ•ญ๋ชฉ | ๋‚ด์šฉ | +| --------------- | -------------------------------- | +| ์ด Prisma ํ˜ธ์ถœ | 29๊ฐœ | +| ๋Œ€์ƒ ํŒŒ์ผ | 7๊ฐœ | +| **ํ˜„์žฌ ์ง„ํ–‰๋ฅ ** | **17/29 (58.6%)** ๐Ÿ”„ **์ง„ํ–‰ ์ค‘** | +| ๋ณต์žก๋„ | ์ค‘๊ฐ„ | +| ์šฐ์„ ์ˆœ์œ„ | ๐Ÿ”ด ๋†’์Œ (Phase 4) | +| **์ƒํƒœ** | โณ **์ง„ํ–‰ ์ค‘** | --- @@ -18,6 +18,7 @@ ### โœ… ์™„๋ฃŒ๋œ ํŒŒ์ผ (2๊ฐœ) 1. **adminController.ts** - โœ… **28๊ฐœ ์™„๋ฃŒ** + - ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ: getUserList, getUserInfo, updateUserStatus, deleteUser - ํ”„๋กœํ•„ ๊ด€๋ฆฌ: getMyProfile, updateMyProfile, resetPassword - ์‚ฌ์šฉ์ž ์ƒ์„ฑ/์ˆ˜์ •: createOrUpdateUser (UPSERT) @@ -41,27 +42,33 @@ #### Prisma ํ˜ธ์ถœ ๋ชฉ๋ก: 1. **๋ผ์ธ 33**: `getWebTypeStandards()` - findMany + ```typescript const webTypes = await prisma.web_type_standards.findMany({ - where, orderBy, select + where, + orderBy, + select, }); ``` 2. **๋ผ์ธ 58**: `getWebTypeStandard()` - findUnique + ```typescript const webTypeData = await prisma.web_type_standards.findUnique({ - where: { id } + where: { id }, }); ``` 3. **๋ผ์ธ 112**: `createWebTypeStandard()` - findUnique (์ค‘๋ณต ์ฒดํฌ) + ```typescript const existingWebType = await prisma.web_type_standards.findUnique({ - where: { web_type: webType } + where: { web_type: webType }, }); ``` 4. **๋ผ์ธ 123**: `createWebTypeStandard()` - create + ```typescript const newWebType = await prisma.web_type_standards.create({ data: { ... } @@ -69,13 +76,15 @@ ``` 5. **๋ผ์ธ 178**: `updateWebTypeStandard()` - findUnique (์กด์žฌ ํ™•์ธ) + ```typescript const existingWebType = await prisma.web_type_standards.findUnique({ - where: { id } + where: { id }, }); ``` 6. **๋ผ์ธ 189**: `updateWebTypeStandard()` - update + ```typescript const updatedWebType = await prisma.web_type_standards.update({ where: { id }, data: { ... } @@ -83,20 +92,23 @@ ``` 7. **๋ผ์ธ 230**: `deleteWebTypeStandard()` - findUnique (์กด์žฌ ํ™•์ธ) + ```typescript const existingWebType = await prisma.web_type_standards.findUnique({ - where: { id } + where: { id }, }); ``` 8. **๋ผ์ธ 241**: `deleteWebTypeStandard()` - delete + ```typescript await prisma.web_type_standards.delete({ - where: { id } + where: { id }, }); ``` 9. **๋ผ์ธ 275**: `updateSortOrder()` - $transaction + ```typescript await prisma.$transaction( updates.map((item) => @@ -110,11 +122,14 @@ 11. **๋ผ์ธ 305**: `getCategories()` - groupBy ```typescript const categories = await prisma.web_type_standards.groupBy({ - by: ['category'], where, _count: true + by: ["category"], + where, + _count: true, }); ``` **์ „ํ™˜ ์ „๋žต**: + - findMany โ†’ `query` with dynamic WHERE - findUnique โ†’ `queryOne` - create โ†’ `queryOne` with INSERT RETURNING @@ -134,11 +149,12 @@ 1. **๋ผ์ธ 726**: `downloadFile()` - findUnique ```typescript const fileRecord = await prisma.attach_file_info.findUnique({ - where: { objid: BigInt(objid) } + where: { objid: BigInt(objid) }, }); ``` **์ „ํ™˜ ์ „๋žต**: + - findUnique โ†’ `queryOne` --- @@ -150,16 +166,19 @@ #### Prisma ํ˜ธ์ถœ ๋ชฉ๋ก: 1. **๋ผ์ธ 1005**: `executeSelect()` - $queryRawUnsafe + ```typescript return await prisma.$queryRawUnsafe(query, ...queryParams); ``` 2. **๋ผ์ธ 1022**: `executeInsert()` - $queryRawUnsafe + ```typescript const insertResult = await prisma.$queryRawUnsafe(...); ``` 3. **๋ผ์ธ 1055**: `executeUpdate()` - $queryRawUnsafe + ```typescript return await prisma.$queryRawUnsafe(updateQuery, ...updateParams); ``` @@ -170,6 +189,7 @@ ``` **์ „ํ™˜ ์ „๋žต**: + - $queryRawUnsafe โ†’ `query` (์ด๋ฏธ Raw SQL ์‚ฌ์šฉ ์ค‘) --- @@ -186,6 +206,7 @@ 4. **๋ผ์ธ 31, 35, 40**: `await prisma.$disconnect()` **์ „ํ™˜ ์ „๋žต**: + - ์ด ํŒŒ์ผ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ • ํŒŒ์ผ์ด๋ฏ€๋กœ ์™„์ „ํžˆ ์ œ๊ฑฐ - ๊ธฐ์กด `db.ts`์˜ connection pool๋กœ ๋Œ€์ฒด - ๋ชจ๋“  import ๊ฒฝ๋กœ๋ฅผ `database` โ†’ `database/db`๋กœ ๋ณ€๊ฒฝ @@ -199,6 +220,7 @@ #### Prisma ํ˜ธ์ถœ: 1. **๋ผ์ธ 183-184**: ๋™์  PrismaClient import + ```typescript const { PrismaClient } = await import("@prisma/client"); const prisma = new PrismaClient(); @@ -211,6 +233,7 @@ ``` **์ „ํ™˜ ์ „๋žต**: + - ๋™์  import ์ œ๊ฑฐ - `query('SELECT 1')` ์‚ฌ์šฉ @@ -223,20 +246,23 @@ #### Prisma ํ˜ธ์ถœ: 1. **๋ผ์ธ 32**: findUnique (์ค‘๋ณต ์ฒดํฌ) + ```typescript const existingCompany = await prisma.company_mng.findUnique({ - where: { company_code } + where: { company_code }, }); ``` 2. **๋ผ์ธ 61**: update (ํšŒ์‚ฌ๋ช… ์—…๋ฐ์ดํŠธ) ```typescript await prisma.company_mng.update({ - where: { company_code }, data: { company_name } + where: { company_code }, + data: { company_name }, }); ``` **์ „ํ™˜ ์ „๋žต**: + - findUnique โ†’ `queryOne` - update โ†’ `query` @@ -253,24 +279,30 @@ ## ๐ŸŽฏ ์ „ํ™˜ ์šฐ์„ ์ˆœ์œ„ ### Phase 4.1: ์ปจํŠธ๋กค๋Ÿฌ (์™„๋ฃŒ) + - [x] screenFileController.ts (2๊ฐœ) - [x] adminController.ts (28๊ฐœ) ### Phase 4.2: ๋‚จ์€ ์ปจํŠธ๋กค๋Ÿฌ (์ง„ํ–‰ ์˜ˆ์ •) + - [ ] webTypeStandardController.ts (11๊ฐœ) - ๐Ÿ”ด ์ตœ์šฐ์„  - [ ] fileController.ts (1๊ฐœ) ### Phase 4.3: Routes (์ง„ํ–‰ ์˜ˆ์ •) + - [ ] ddlRoutes.ts (2๊ฐœ) - [ ] companyManagementRoutes.ts (2๊ฐœ) ### Phase 4.4: Services (์ง„ํ–‰ ์˜ˆ์ •) + - [ ] multiConnectionQueryService.ts (4๊ฐœ) ### Phase 4.5: Config (์ง„ํ–‰ ์˜ˆ์ •) + - [ ] database.ts (4๊ฐœ) - ์ „์ฒด ํŒŒ์ผ ์ œ๊ฑฐ ### Phase 4.6: Tests (Phase 5) + - [ ] authService.test.ts (2๊ฐœ) - ๋ณ„๋„ ์ฒ˜๋ฆฌ --- @@ -278,6 +310,7 @@ ## ๐Ÿ“‹ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ### webTypeStandardController.ts + - [ ] Prisma import ์ œ๊ฑฐ - [ ] query, queryOne import ์ถ”๊ฐ€ - [ ] getWebTypeStandards (findMany โ†’ query) @@ -292,18 +325,21 @@ - [ ] ๋™์ž‘ ํ…Œ์ŠคํŠธ ### fileController.ts + - [ ] Prisma import ์ œ๊ฑฐ - [ ] queryOne import ์ถ”๊ฐ€ - [ ] downloadFile (findUnique โ†’ queryOne) - [ ] TypeScript ์ปดํŒŒ์ผ ํ™•์ธ ### routes/ddlRoutes.ts + - [ ] ๋™์  PrismaClient import ์ œ๊ฑฐ - [ ] query import ์ถ”๊ฐ€ - [ ] ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ ๋กœ์ง ๋ณ€๊ฒฝ - [ ] TypeScript ์ปดํŒŒ์ผ ํ™•์ธ ### routes/companyManagementRoutes.ts + - [ ] Prisma import ์ œ๊ฑฐ - [ ] query, queryOne import ์ถ”๊ฐ€ - [ ] findUnique โ†’ queryOne @@ -311,12 +347,14 @@ - [ ] TypeScript ์ปดํŒŒ์ผ ํ™•์ธ ### services/multiConnectionQueryService.ts + - [ ] Prisma import ์ œ๊ฑฐ - [ ] query import ์ถ”๊ฐ€ - [ ] $queryRawUnsafe โ†’ query (4๊ณณ) - [ ] TypeScript ์ปดํŒŒ์ผ ํ™•์ธ ### config/database.ts + - [ ] ํŒŒ์ผ ์ „์ฒด ๋ถ„์„ - [ ] ์˜์กด์„ฑ ํ™•์ธ - [ ] ๋Œ€์ฒด ๋ฐฉ์•ˆ ๊ตฌํ˜„ @@ -328,15 +366,20 @@ ## ๐Ÿ”ง ์ „ํ™˜ ํŒจํ„ด ์š”์•ฝ ### 1. findMany โ†’ query + ```typescript // Before const items = await prisma.table.findMany({ where, orderBy }); // After -const items = await query(`SELECT * FROM table WHERE ... ORDER BY ...`, params); +const items = await query( + `SELECT * FROM table WHERE ... ORDER BY ...`, + params +); ``` ### 2. findUnique โ†’ queryOne + ```typescript // Before const item = await prisma.table.findUnique({ where: { id } }); @@ -346,6 +389,7 @@ const item = await queryOne(`SELECT * FROM table WHERE id = $1`, [id]); ``` ### 3. create โ†’ queryOne with RETURNING + ```typescript // Before const newItem = await prisma.table.create({ data }); @@ -358,6 +402,7 @@ const [newItem] = await query( ``` ### 4. update โ†’ query with RETURNING + ```typescript // Before const updated = await prisma.table.update({ where, data }); @@ -370,6 +415,7 @@ const [updated] = await query( ``` ### 5. delete โ†’ query + ```typescript // Before await prisma.table.delete({ where: { id } }); @@ -379,6 +425,7 @@ await query(`DELETE FROM table WHERE id = $1`, [id]); ``` ### 6. $transaction โ†’ transaction + ```typescript // Before await prisma.$transaction([ @@ -394,11 +441,12 @@ await transaction(async (client) => { ``` ### 7. groupBy โ†’ query with GROUP BY + ```typescript // Before const result = await prisma.table.groupBy({ - by: ['category'], - _count: true + by: ["category"], + _count: true, }); // After @@ -422,30 +470,34 @@ Phase 4.2: ๋‚จ์€ ํŒŒ์ผ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ ### ์ƒ์„ธ ์ง„ํ–‰ ์ƒํ™ฉ -| ์นดํ…Œ๊ณ ๋ฆฌ | ์™„๋ฃŒ | ๋‚จ์Œ | ์ง„ํ–‰๋ฅ  | -| -------------- | ---- | ---- | ------ | -| Services | 415 | 0 | 100% | -| Controllers | 30 | 11 | 73% | -| Routes | 0 | 4 | 0% | -| Config | 0 | 4 | 0% | -| **์ด๊ณ„** | 445 | 19 | 95.9% | +| ์นดํ…Œ๊ณ ๋ฆฌ | ์™„๋ฃŒ | ๋‚จ์Œ | ์ง„ํ–‰๋ฅ  | +| ----------- | ---- | ---- | ------ | +| Services | 415 | 0 | 100% | +| Controllers | 30 | 11 | 73% | +| Routes | 0 | 4 | 0% | +| Config | 0 | 4 | 0% | +| **์ด๊ณ„** | 445 | 19 | 95.9% | --- ## ๐ŸŽฌ ๋‹ค์Œ ๋‹จ๊ณ„ 1. **webTypeStandardController.ts ์ „ํ™˜** (11๊ฐœ) + - ๊ฐ€์žฅ ๋งŽ์€ Prisma ํ˜ธ์ถœ์„ ๊ฐ€์ง„ ๋‚จ์€ ์ปจํŠธ๋กค๋Ÿฌ - ์›น ํƒ€์ž… ํ‘œ์ค€ ๊ด€๋ฆฌ ํ•ต์‹ฌ ๊ธฐ๋Šฅ 2. **fileController.ts ์ „ํ™˜** (1๊ฐœ) + - ๋‹จ์ˆœ findUnique๋งŒ ์žˆ์–ด ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ 3. **Routes ์ „ํ™˜** (4๊ฐœ) + - ddlRoutes.ts - companyManagementRoutes.ts 4. **Service ์ „ํ™˜** (4๊ฐœ) + - multiConnectionQueryService.ts 5. **Config ์ œ๊ฑฐ** (4๊ฐœ) @@ -457,14 +509,17 @@ Phase 4.2: ๋‚จ์€ ํŒŒ์ผ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ ## โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ 1. **database.ts ์ฒ˜๋ฆฌ** + - ํ˜„์žฌ ๋งŽ์€ ํŒŒ์ผ์ด `import prisma from '../config/database'` ์‚ฌ์šฉ - ๋ชจ๋“  import๋ฅผ `import { query, queryOne } from '../database/db'`๋กœ ๋ณ€๊ฒฝ ํ•„์š” - ๋‹จ๊ณ„์ ์œผ๋กœ ์ง„ํ–‰ํ•˜์—ฌ ๋นŒ๋“œ ์˜ค๋ฅ˜ ๋ฐฉ์ง€ 2. **BigInt ์ฒ˜๋ฆฌ** + - fileController์˜ `objid: BigInt(objid)` โ†’ `objid::bigint` ๋˜๋Š” `CAST(objid AS BIGINT)` 3. **ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ** + - webTypeStandardController์˜ `updateSortOrder`๋Š” ๋ณต์žกํ•œ ํŠธ๋žœ์žญ์…˜ - `transaction` ํ•จ์ˆ˜ ์‚ฌ์šฉ ํ•„์š” @@ -489,4 +544,3 @@ Phase 4.2: ๋‚จ์€ ํŒŒ์ผ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ **์ž‘์„ฑ์ผ**: 2025-10-01 **์ตœ์ข… ์—…๋ฐ์ดํŠธ**: 2025-10-01 **์ƒํƒœ**: ๐Ÿ”„ ์ง„ํ–‰ ์ค‘ (58.6% ์™„๋ฃŒ) - diff --git a/backend-node/src/controllers/fileController.ts b/backend-node/src/controllers/fileController.ts index 87ecf2e0..2856098b 100644 --- a/backend-node/src/controllers/fileController.ts +++ b/backend-node/src/controllers/fileController.ts @@ -723,11 +723,10 @@ export const downloadFile = async ( try { const { objid } = req.params; - const fileRecord = await prisma.attach_file_info.findUnique({ - where: { - objid: parseInt(objid), - }, - }); + const fileRecord = await queryOne( + `SELECT * FROM attach_file_info WHERE objid = $1`, + [parseInt(objid)] + ); if (!fileRecord || fileRecord.status !== "ACTIVE") { res.status(404).json({ diff --git a/backend-node/src/controllers/webTypeStandardController.ts b/backend-node/src/controllers/webTypeStandardController.ts index c35b6dc4..952e688d 100644 --- a/backend-node/src/controllers/webTypeStandardController.ts +++ b/backend-node/src/controllers/webTypeStandardController.ts @@ -1,39 +1,51 @@ import { Request, Response } from "express"; -import { PrismaClient } from "@prisma/client"; +import { query, queryOne, transaction } from "../database/db"; import { AuthenticatedRequest } from "../types/auth"; -const prisma = new PrismaClient(); - export class WebTypeStandardController { // ์›นํƒ€์ž… ๋ชฉ๋ก ์กฐํšŒ static async getWebTypes(req: Request, res: Response) { try { const { active, category, search } = req.query; - const where: any = {}; + // ๋™์  WHERE ์ ˆ ์ƒ์„ฑ + const whereConditions: string[] = []; + const queryParams: any[] = []; + let paramIndex = 1; if (active) { - where.is_active = active as string; + whereConditions.push(`is_active = $${paramIndex}`); + queryParams.push(active); + paramIndex++; } if (category) { - where.category = category as string; + whereConditions.push(`category = $${paramIndex}`); + queryParams.push(category); + paramIndex++; } - if (search) { - where.OR = [ - { type_name: { contains: search as string, mode: "insensitive" } }, - { - type_name_eng: { contains: search as string, mode: "insensitive" }, - }, - { description: { contains: search as string, mode: "insensitive" } }, - ]; + if (search && typeof search === "string") { + whereConditions.push(`( + type_name ILIKE $${paramIndex} OR + type_name_eng ILIKE $${paramIndex} OR + description ILIKE $${paramIndex} + )`); + queryParams.push(`%${search}%`); + paramIndex++; } - const webTypes = await prisma.web_type_standards.findMany({ - where, - orderBy: [{ sort_order: "asc" }, { web_type: "asc" }], - }); + const whereClause = + whereConditions.length > 0 + ? `WHERE ${whereConditions.join(" AND ")}` + : ""; + + const webTypes = await query( + `SELECT * FROM web_type_standards + ${whereClause} + ORDER BY sort_order ASC, web_type ASC`, + queryParams + ); return res.json({ success: true, @@ -55,9 +67,10 @@ export class WebTypeStandardController { try { const { webType } = req.params; - const webTypeData = await prisma.web_type_standards.findUnique({ - where: { web_type: webType }, - }); + const webTypeData = await queryOne( + `SELECT * FROM web_type_standards WHERE web_type = $1`, + [webType] + ); if (!webTypeData) { return res.status(404).json({ @@ -109,9 +122,10 @@ export class WebTypeStandardController { } // ์ค‘๋ณต ์ฒดํฌ - const existingWebType = await prisma.web_type_standards.findUnique({ - where: { web_type }, - }); + const existingWebType = await queryOne( + `SELECT web_type FROM web_type_standards WHERE web_type = $1`, + [web_type] + ); if (existingWebType) { return res.status(409).json({ @@ -120,8 +134,15 @@ export class WebTypeStandardController { }); } - const newWebType = await prisma.web_type_standards.create({ - data: { + const [newWebType] = await query( + `INSERT INTO web_type_standards ( + web_type, type_name, type_name_eng, description, category, + component_name, config_panel, default_config, validation_rules, + default_style, input_properties, sort_order, is_active, + created_by, created_date, updated_by, updated_date + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, NOW(), $15, NOW()) + RETURNING *`, + [ web_type, type_name, type_name_eng, @@ -135,10 +156,10 @@ export class WebTypeStandardController { input_properties, sort_order, is_active, - created_by: req.user?.userId || "system", - updated_by: req.user?.userId || "system", - }, - }); + req.user?.userId || "system", + req.user?.userId || "system", + ] + ); return res.status(201).json({ success: true, @@ -174,37 +195,106 @@ export class WebTypeStandardController { is_active, } = req.body; - // ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ - const existingWebType = await prisma.web_type_standards.findUnique({ - where: { web_type: webType }, - }); + // ๋™์  UPDATE ์ฟผ๋ฆฌ ์ƒ์„ฑ + const updateFields: string[] = []; + const updateValues: any[] = []; + let paramIndex = 1; - if (!existingWebType) { + if (type_name !== undefined) { + updateFields.push(`type_name = $${paramIndex}`); + updateValues.push(type_name); + paramIndex++; + } + if (type_name_eng !== undefined) { + updateFields.push(`type_name_eng = $${paramIndex}`); + updateValues.push(type_name_eng); + paramIndex++; + } + if (description !== undefined) { + updateFields.push(`description = $${paramIndex}`); + updateValues.push(description); + paramIndex++; + } + if (category !== undefined) { + updateFields.push(`category = $${paramIndex}`); + updateValues.push(category); + paramIndex++; + } + if (component_name !== undefined) { + updateFields.push(`component_name = $${paramIndex}`); + updateValues.push(component_name); + paramIndex++; + } + if (config_panel !== undefined) { + updateFields.push(`config_panel = $${paramIndex}`); + updateValues.push(config_panel); + paramIndex++; + } + if (default_config !== undefined) { + updateFields.push(`default_config = $${paramIndex}`); + updateValues.push(default_config); + paramIndex++; + } + if (validation_rules !== undefined) { + updateFields.push(`validation_rules = $${paramIndex}`); + updateValues.push(validation_rules); + paramIndex++; + } + if (default_style !== undefined) { + updateFields.push(`default_style = $${paramIndex}`); + updateValues.push(default_style); + paramIndex++; + } + if (input_properties !== undefined) { + updateFields.push(`input_properties = $${paramIndex}`); + updateValues.push(input_properties); + paramIndex++; + } + if (sort_order !== undefined) { + updateFields.push(`sort_order = $${paramIndex}`); + updateValues.push(sort_order); + paramIndex++; + } + if (is_active !== undefined) { + updateFields.push(`is_active = $${paramIndex}`); + updateValues.push(is_active); + paramIndex++; + } + + // updated_by, updated_date๋Š” ํ•ญ์ƒ ์ถ”๊ฐ€ + updateFields.push(`updated_by = $${paramIndex}`); + updateValues.push(req.user?.userId || "system"); + paramIndex++; + + updateFields.push(`updated_date = NOW()`); + + if (updateFields.length === 2) { + // updated_by, updated_date๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ = ์ˆ˜์ •ํ•  ๋‚ด์šฉ์ด ์—†์Œ + return res.status(400).json({ + success: false, + message: "์ˆ˜์ •ํ•  ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค.", + }); + } + + // WHERE ์กฐ๊ฑด์šฉ ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€ + updateValues.push(webType); + + const result = await query( + `UPDATE web_type_standards + SET ${updateFields.join(", ")} + WHERE web_type = $${paramIndex} + RETURNING *`, + updateValues + ); + + if (result.length === 0) { return res.status(404).json({ success: false, message: "ํ•ด๋‹น ์›นํƒ€์ž…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", }); } - const updatedWebType = await prisma.web_type_standards.update({ - where: { web_type: webType }, - data: { - type_name, - type_name_eng, - description, - category, - component_name, - config_panel, - default_config, - validation_rules, - default_style, - input_properties, - sort_order, - is_active, - updated_by: req.user?.userId || "system", - updated_date: new Date(), - }, - }); + const updatedWebType = result[0]; return res.json({ success: true, @@ -226,22 +316,18 @@ export class WebTypeStandardController { try { const { webType } = req.params; - // ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ - const existingWebType = await prisma.web_type_standards.findUnique({ - where: { web_type: webType }, - }); + const result = await query( + `DELETE FROM web_type_standards WHERE web_type = $1 RETURNING *`, + [webType] + ); - if (!existingWebType) { + if (result.length === 0) { return res.status(404).json({ success: false, message: "ํ•ด๋‹น ์›นํƒ€์ž…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", }); } - await prisma.web_type_standards.delete({ - where: { web_type: webType }, - }); - return res.json({ success: true, message: "์›นํƒ€์ž…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", @@ -272,18 +358,16 @@ export class WebTypeStandardController { } // ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ผ๊ด„ ์—…๋ฐ์ดํŠธ - await prisma.$transaction( - webTypes.map((item) => - prisma.web_type_standards.update({ - where: { web_type: item.web_type }, - data: { - sort_order: item.sort_order, - updated_by: req.user?.userId || "system", - updated_date: new Date(), - }, - }) - ) - ); + await transaction(async (client) => { + for (const item of webTypes) { + await client.query( + `UPDATE web_type_standards + SET sort_order = $1, updated_by = $2, updated_date = NOW() + WHERE web_type = $3`, + [item.sort_order, req.user?.userId || "system", item.web_type] + ); + } + }); return res.json({ success: true, @@ -302,19 +386,17 @@ export class WebTypeStandardController { // ์›นํƒ€์ž… ์นดํ…Œ๊ณ ๋ฆฌ ๋ชฉ๋ก ์กฐํšŒ static async getWebTypeCategories(req: Request, res: Response) { try { - const categories = await prisma.web_type_standards.groupBy({ - by: ["category"], - where: { - is_active: "Y", - }, - _count: { - category: true, - }, - }); + const categories = await query<{ category: string; count: string }>( + `SELECT category, COUNT(*) as count + FROM web_type_standards + WHERE is_active = 'Y' + GROUP BY category`, + [] + ); const categoryList = categories.map((item) => ({ category: item.category, - count: item._count.category, + count: parseInt(item.count, 10), })); return res.json({