248 lines
11 KiB
Java
248 lines
11 KiB
Java
package com.erp.service;
|
|
|
|
import com.erp.common.BaseService;
|
|
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 extends BaseService {
|
|
|
|
private final JdbcTemplate jdbcTemplate;
|
|
|
|
private static final String NS = "codeMerge.";
|
|
|
|
// ── 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("column_name", columnName);
|
|
List<Map<String, Object>> rows = sqlSession.selectList(NS + "getTablesWithColumn", params);
|
|
|
|
List<String> tables = rows.stream()
|
|
.map(r -> {
|
|
Object 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("column_name", 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("column_name"));
|
|
String oldValue = str(body.get("old_value"));
|
|
String companyCode = str(body.get("company_code"));
|
|
|
|
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("column_name", columnName);
|
|
List<Map<String, Object>> tableRows = sqlSession.selectList(NS + "getTablesWithColumn", params);
|
|
|
|
List<Map<String, Object>> preview = new ArrayList<>();
|
|
int totalRows = 0;
|
|
|
|
for (Map<String, Object> tableRow : tableRows) {
|
|
Object 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("table_name", tableName);
|
|
item.put("affected_rows", count);
|
|
preview.add(item);
|
|
totalRows += count;
|
|
}
|
|
} catch (Exception e) {
|
|
log.warn("테이블 {} 조회 실패 (건너뜀): {}", tableName, e.getMessage());
|
|
}
|
|
}
|
|
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
|
result.put("column_name", columnName);
|
|
result.put("old_value", oldValue);
|
|
result.put("preview", preview);
|
|
result.put("total_affected_rows", 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("column_name"));
|
|
String oldValue = str(body.get("old_value"));
|
|
String newValue = str(body.get("new_value"));
|
|
String companyCode = str(body.get("company_code"));
|
|
|
|
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("table_name", r.get("table_name"));
|
|
item.put("rows_updated", 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("column_name", columnName);
|
|
result.put("old_value", oldValue);
|
|
result.put("new_value", newValue);
|
|
result.put("affected_tables", affectedTables);
|
|
result.put("total_rows_updated", 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("old_value"));
|
|
String newValue = str(body.get("new_value"));
|
|
String companyCode = str(body.get("company_code"));
|
|
|
|
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("table_name", r.get("out_table_name"));
|
|
item.put("column_name", r.get("out_column_name"));
|
|
item.put("rows_updated", 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("old_value", oldValue);
|
|
result.put("new_value", newValue);
|
|
result.put("affected_data", affectedData);
|
|
result.put("total_rows_updated", 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("old_value"));
|
|
String companyCode = str(body.get("company_code"));
|
|
|
|
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("table_name", r.get("out_table_name"));
|
|
item.put("column_name", r.get("out_column_name"));
|
|
item.put("affected_rows", 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("old_value", oldValue);
|
|
result.put("preview", preview);
|
|
result.put("total_affected_rows", 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();
|
|
}
|
|
}
|