[agent-pipeline] pipe-20260327053504-cc40 round-2
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
package com.erp.service;
|
||||
|
||||
import com.erp.mapper.CodeMergeMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CodeMergeService {
|
||||
|
||||
private final CodeMergeMapper codeMergeMapper;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
// ── Tables With Column ────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /tables-with-column/:columnName
|
||||
* 해당 컬럼과 company_code 컬럼을 함께 가진 public 테이블 목록 반환
|
||||
*/
|
||||
public Map<String, Object> getTablesWithColumn(String columnName) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("columnName", columnName);
|
||||
List<Map<String, Object>> rows = codeMergeMapper.getTablesWithColumn(params);
|
||||
|
||||
// map-underscore-to-camel-case: true 적용 → key = "tableName"
|
||||
List<String> tables = rows.stream()
|
||||
.map(r -> {
|
||||
Object val = r.get("tableName");
|
||||
if (val == null) val = r.get("table_name");
|
||||
return val != null ? val.toString() : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("columnName", columnName);
|
||||
result.put("tables", tables);
|
||||
result.put("count", tables.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Preview (column-based) ────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /preview
|
||||
* columnName + oldValue 기준으로 영향받을 테이블/행 수 미리보기 (DB 변경 없음)
|
||||
*/
|
||||
public Map<String, Object> previewCodeMerge(Map<String, Object> body) {
|
||||
String columnName = str(body.get("columnName"));
|
||||
String oldValue = str(body.get("oldValue"));
|
||||
String companyCode = str(body.get("companyCode"));
|
||||
|
||||
if (isBlank(columnName) || isBlank(oldValue)) {
|
||||
throw new IllegalArgumentException("필수 필드가 누락되었습니다. (columnName, oldValue)");
|
||||
}
|
||||
|
||||
log.info("코드 병합 미리보기: column={}, oldValue={}, company={}", columnName, oldValue, companyCode);
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("columnName", columnName);
|
||||
List<Map<String, Object>> tableRows = codeMergeMapper.getTablesWithColumn(params);
|
||||
|
||||
List<Map<String, Object>> preview = new ArrayList<>();
|
||||
int totalRows = 0;
|
||||
|
||||
for (Map<String, Object> tableRow : tableRows) {
|
||||
Object nameVal = tableRow.get("tableName");
|
||||
if (nameVal == null) nameVal = tableRow.get("table_name");
|
||||
if (nameVal == null) continue;
|
||||
String tableName = nameVal.toString();
|
||||
|
||||
// 테이블명·컬럼명은 information_schema에서 검증된 값 — SQL 인젝션 위험 없음
|
||||
String countSql = String.format(
|
||||
"SELECT COUNT(*) FROM \"%s\" WHERE \"%s\" = ? AND company_code = ?",
|
||||
tableName, columnName);
|
||||
try {
|
||||
Integer count = jdbcTemplate.queryForObject(countSql, Integer.class, oldValue, companyCode);
|
||||
if (count != null && count > 0) {
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("tableName", tableName);
|
||||
item.put("affectedRows", count);
|
||||
preview.add(item);
|
||||
totalRows += count;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("테이블 {} 조회 실패 (건너뜀): {}", tableName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("columnName", columnName);
|
||||
result.put("oldValue", oldValue);
|
||||
result.put("preview", preview);
|
||||
result.put("totalAffectedRows", totalRows);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Merge All Tables (column-based) ───────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /merge-all-tables
|
||||
* PostgreSQL 함수 merge_code_all_tables(columnName, oldValue, newValue, companyCode) 호출
|
||||
*/
|
||||
@Transactional
|
||||
public Map<String, Object> mergeAllTables(Map<String, Object> body) {
|
||||
String columnName = str(body.get("columnName"));
|
||||
String oldValue = str(body.get("oldValue"));
|
||||
String newValue = str(body.get("newValue"));
|
||||
String companyCode = str(body.get("companyCode"));
|
||||
|
||||
if (isBlank(columnName) || isBlank(oldValue) || isBlank(newValue)) {
|
||||
throw new IllegalArgumentException("필수 필드가 누락되었습니다. (columnName, oldValue, newValue)");
|
||||
}
|
||||
if (oldValue.equals(newValue)) {
|
||||
throw new IllegalArgumentException("기존 값과 새 값이 동일합니다.");
|
||||
}
|
||||
|
||||
log.info("코드 병합 시작: column={}, {} → {}, company={}", columnName, oldValue, newValue, companyCode);
|
||||
|
||||
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
|
||||
"SELECT * FROM merge_code_all_tables(?, ?, ?, ?)",
|
||||
columnName, oldValue, newValue, companyCode);
|
||||
|
||||
int totalRows = rows.stream()
|
||||
.mapToInt(r -> r.get("rows_updated") != null ? ((Number) r.get("rows_updated")).intValue() : 0)
|
||||
.sum();
|
||||
|
||||
List<Map<String, Object>> affectedTables = rows.stream().map(r -> {
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("tableName", r.get("table_name"));
|
||||
item.put("rowsUpdated", r.get("rows_updated") != null ? ((Number) r.get("rows_updated")).intValue() : 0);
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
log.info("코드 병합 완료: 영향 테이블 {}개, 총 {}행", affectedTables.size(), totalRows);
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("columnName", columnName);
|
||||
result.put("oldValue", oldValue);
|
||||
result.put("newValue", newValue);
|
||||
result.put("affectedTables", affectedTables);
|
||||
result.put("totalRowsUpdated", totalRows);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Merge By Value ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /merge-by-value
|
||||
* PostgreSQL 함수 merge_code_by_value(oldValue, newValue, companyCode) 호출
|
||||
* 컬럼명에 관계없이 해당 값을 가진 모든 위치를 변경
|
||||
*/
|
||||
@Transactional
|
||||
public Map<String, Object> mergeByValue(Map<String, Object> body) {
|
||||
String oldValue = str(body.get("oldValue"));
|
||||
String newValue = str(body.get("newValue"));
|
||||
String companyCode = str(body.get("companyCode"));
|
||||
|
||||
if (isBlank(oldValue) || isBlank(newValue)) {
|
||||
throw new IllegalArgumentException("필수 필드가 누락되었습니다. (oldValue, newValue)");
|
||||
}
|
||||
if (oldValue.equals(newValue)) {
|
||||
throw new IllegalArgumentException("기존 값과 새 값이 동일합니다.");
|
||||
}
|
||||
|
||||
log.info("값 기반 코드 병합 시작: {} → {}, company={}", oldValue, newValue, companyCode);
|
||||
|
||||
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
|
||||
"SELECT * FROM merge_code_by_value(?, ?, ?)",
|
||||
oldValue, newValue, companyCode);
|
||||
|
||||
int totalRows = rows.stream()
|
||||
.mapToInt(r -> r.get("out_rows_updated") != null ? ((Number) r.get("out_rows_updated")).intValue() : 0)
|
||||
.sum();
|
||||
|
||||
List<Map<String, Object>> affectedData = rows.stream().map(r -> {
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("tableName", r.get("out_table_name"));
|
||||
item.put("columnName", r.get("out_column_name"));
|
||||
item.put("rowsUpdated", r.get("out_rows_updated") != null ? ((Number) r.get("out_rows_updated")).intValue() : 0);
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
log.info("값 기반 코드 병합 완료: {} → {}, 총 {}행", oldValue, newValue, totalRows);
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("oldValue", oldValue);
|
||||
result.put("newValue", newValue);
|
||||
result.put("affectedData", affectedData);
|
||||
result.put("totalRowsUpdated", totalRows);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Preview By Value ──────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /preview-by-value
|
||||
* PostgreSQL 함수 preview_merge_code_by_value(oldValue, companyCode) 호출
|
||||
*/
|
||||
public Map<String, Object> previewByValue(Map<String, Object> body) {
|
||||
String oldValue = str(body.get("oldValue"));
|
||||
String companyCode = str(body.get("companyCode"));
|
||||
|
||||
if (isBlank(oldValue)) {
|
||||
throw new IllegalArgumentException("필수 필드가 누락되었습니다. (oldValue)");
|
||||
}
|
||||
|
||||
log.info("값 기반 코드 병합 미리보기: oldValue={}, company={}", oldValue, companyCode);
|
||||
|
||||
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
|
||||
"SELECT * FROM preview_merge_code_by_value(?, ?)",
|
||||
oldValue, companyCode);
|
||||
|
||||
int totalRows = rows.stream()
|
||||
.mapToInt(r -> r.get("out_affected_rows") != null ? ((Number) r.get("out_affected_rows")).intValue() : 0)
|
||||
.sum();
|
||||
|
||||
List<Map<String, Object>> preview = rows.stream().map(r -> {
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("tableName", r.get("out_table_name"));
|
||||
item.put("columnName", r.get("out_column_name"));
|
||||
item.put("affectedRows", r.get("out_affected_rows") != null ? ((Number) r.get("out_affected_rows")).intValue() : 0);
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("oldValue", oldValue);
|
||||
result.put("preview", preview);
|
||||
result.put("totalAffectedRows", totalRows);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private String str(Object val) {
|
||||
return val != null ? val.toString() : null;
|
||||
}
|
||||
|
||||
private boolean isBlank(String s) {
|
||||
return s == null || s.isBlank();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user