102 lines
3.3 KiB
Java
102 lines
3.3 KiB
Java
package com.cloudhandson.vpdbackoffice.service;
|
|
|
|
import com.cloudhandson.vpdbackoffice.domain.structured.StructuredDataPreview;
|
|
import com.cloudhandson.vpdbackoffice.domain.structured.StructuredDataTable;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import org.springframework.dao.DataAccessException;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
@Service
|
|
public class StructuredDataService {
|
|
|
|
private static final int ROW_LIMIT = 50;
|
|
|
|
private final JdbcTemplate jdbcTemplate;
|
|
private final DataCatalog catalog;
|
|
|
|
public StructuredDataService(
|
|
JdbcTemplate jdbcTemplate,
|
|
DataCatalog catalog
|
|
) {
|
|
this.jdbcTemplate = jdbcTemplate;
|
|
this.catalog = catalog;
|
|
}
|
|
|
|
public DataCatalog catalog() {
|
|
return catalog;
|
|
}
|
|
|
|
public String owner() {
|
|
return catalog.owner();
|
|
}
|
|
|
|
public List<StructuredDataTable> tables() {
|
|
return catalog.objects();
|
|
}
|
|
|
|
public String defaultKey() {
|
|
return catalog.objects().getFirst().key();
|
|
}
|
|
|
|
public StructuredDataTable requireTable(String key) {
|
|
return catalog.require(key);
|
|
}
|
|
|
|
public StructuredDataPreview preview(String key) {
|
|
StructuredDataTable table = requireTable(key);
|
|
try {
|
|
List<String> columns = jdbcTemplate.query(
|
|
"""
|
|
SELECT column_name
|
|
FROM all_tab_columns
|
|
WHERE owner = ?
|
|
AND table_name = ?
|
|
ORDER BY column_id
|
|
""",
|
|
(resultSet, rowNum) -> resultSet.getString(1), catalog.owner(), table.tableName());
|
|
if (columns.isEmpty()) {
|
|
throw new AppException("정형 데이터 테이블의 컬럼 정보를 찾을 수 없습니다.");
|
|
}
|
|
List<String> previewColumns =
|
|
table.previewColumns().isEmpty() ? columns : table.previewColumns();
|
|
if (!columns.containsAll(previewColumns)) {
|
|
throw new AppException("환경 카탈로그의 미리보기 컬럼이 실제 객체와 일치하지 않습니다.");
|
|
}
|
|
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
|
|
previewSql(table, previewColumns), ROW_LIMIT);
|
|
return new StructuredDataPreview(table, previewColumns, rows, ROW_LIMIT);
|
|
} catch (DataAccessException exception) {
|
|
throw new AppException("정형 데이터를 조회할 수 없습니다. " + catalog.owner()
|
|
+ " 조회 권한과 대상 객체 상태를 확인하세요.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The table is selected from a closed application whitelist, so the query
|
|
* text remains fixed and no request value can become a SQL identifier.
|
|
*/
|
|
String previewSql(StructuredDataTable table) {
|
|
return previewSql(table, table.previewColumns());
|
|
}
|
|
|
|
private String previewSql(
|
|
StructuredDataTable table,
|
|
List<String> previewColumns
|
|
) {
|
|
StructuredDataTable approved = requireTable(table.key());
|
|
if (!approved.tableName().equals(table.tableName())) {
|
|
throw new AppException("선택할 수 없는 카탈로그 객체입니다.");
|
|
}
|
|
String projection = previewColumns == null || previewColumns.isEmpty()
|
|
? "*"
|
|
: previewColumns.stream()
|
|
.map(column -> "\"" + column + "\"")
|
|
.reduce((left, right) -> left + ", " + right)
|
|
.orElseThrow();
|
|
return "SELECT " + projection + " FROM \"" + catalog.owner() + "\".\"" + approved.tableName()
|
|
+ "\" WHERE ROWNUM <= ?";
|
|
}
|
|
}
|