Merge pull request '추론관리 api 수정, 분석된 도엽 목록 추가' (#22) from feat/demo-20251205 into develop

Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/22
This commit is contained in:
2025-11-28 16:55:53 +09:00
16 changed files with 246 additions and 231 deletions

View File

@@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
@Tag(name = "공통코드 관리", description = "공통코드 관리 API") @Tag(name = "공통코드 관리", description = "공통코드 관리 API")
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/api/code") @RequestMapping({"/demo/code", "/api/code"})
public class CommonCodeApiController { public class CommonCodeApiController {
private final CommonCodeService commonCodeService; private final CommonCodeService commonCodeService;

View File

@@ -1,13 +1,48 @@
package com.kamco.cd.kamcoback.common.api; package com.kamco.cd.kamcoback.common.api;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.inference.dto.LearningModelResultDto;
import com.kamco.cd.kamcoback.inference.service.InferenceResultService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@Tag(name = "공통", description = "공통")
@RestController @RestController
@RequestMapping("/api/common") @RequiredArgsConstructor
@RequestMapping({"/demo/common", "/api/common"})
public class CommonController { public class CommonController {
private final InferenceResultService inferenceResultService;
@Operation(summary = "추론된 도엽 목록", description = "추론된 도엽 목록 5000:1")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema =
@Schema(
implementation = LearningModelResultDto.BatchProcessResponse.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/sheets/{id}") @GetMapping("/sheets/{id}")
public void getSheetList() {} public ApiResponseDto<List<String>> getSheets(
@Parameter(description = "분석결과 id", example = "1") @PathVariable Long id) {
return ApiResponseDto.ok(inferenceResultService.getSheets(id));
}
} }

View File

@@ -1,44 +0,0 @@
package com.kamco.cd.kamcoback.common.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum DetectionClassification {
BUILDING("building", "빌딩"),
CONTAINER("container", "컨테이너(창고·적재함)"),
FIELD("field", "경작지 / 들판"),
FOREST("forest", ""),
GRASS("grass", "초지 / 잔디지역"),
GREENHOUSE("greenhouse", "비닐하우스"),
LAND("land", "나지"),
ORCHARD("orchard", "과수원"),
ROAD("road", "도로"),
STONE("stone", "암석 / 돌 지역"),
TANK("tank", "탱크(저유탱크 등 저장시설)"),
TUMULUS("tumulus", "고분(무덤)"),
WASTE("waste", "폐기물 적치장 / 황폐지"),
WATER("water", "수체(水域) / 물"),
ETC("ETC", "기타"); // For 'etc' (miscellaneous/other)
private final String id;
private final String desc;
/**
* Optional: Helper method to get the enum from a String, case-insensitive, or return ETC if not
* found.
*/
public static DetectionClassification fromString(String text) {
if (text == null || text.trim().isEmpty()) {
return ETC;
}
try {
return DetectionClassification.valueOf(text.toUpperCase());
} catch (IllegalArgumentException e) {
// If the string doesn't match any enum constant name, return ETC
return ETC;
}
}
}

View File

@@ -21,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -28,7 +29,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@Tag(name = "추론관리 분석결과", description = "추론관리 분석결과") @Tag(name = "추론관리 분석결과", description = "추론관리 분석결과")
@RequestMapping("/api/inf/res") @RequestMapping({"/demo/inf/res", "/api/inf/res"})
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
public class InferenceResultApiController { public class InferenceResultApiController {
@@ -53,10 +54,9 @@ public class InferenceResultApiController {
}) })
@GetMapping("/list") @GetMapping("/list")
public ApiResponseDto<Page<InferenceResultDto.AnalResList>> getInferenceResultList( public ApiResponseDto<Page<InferenceResultDto.AnalResList>> getInferenceResultList(
@Parameter(description = "분석상태", example = "0000") @RequestParam(required = false) @Parameter(description = "분석상태", example = "0002") @RequestParam(required = false)
String statCode, String statCode,
@Parameter(description = "제목", example = "2023_2024년도") @RequestParam(required = false) @Parameter(description = "제목", example = "변화탐지") @RequestParam(required = false) String title,
String title,
@Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0")
int page, int page,
@Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20")
@@ -84,9 +84,9 @@ public class InferenceResultApiController {
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@GetMapping("/summary") @GetMapping("/summary/{id}")
public ApiResponseDto<InferenceResultDto.AnalResSummary> getInferenceResultSummary( public ApiResponseDto<InferenceResultDto.AnalResSummary> getInferenceResultSummary(
@Parameter(description = "목록 id", example = "1") @RequestParam Long id) { @Parameter(description = "목록 id", example = "1") @PathVariable Long id) {
return ApiResponseDto.ok(inferenceResultService.getInferenceResultSummary(id)); return ApiResponseDto.ok(inferenceResultService.getInferenceResultSummary(id));
} }
@@ -122,11 +122,12 @@ public class InferenceResultApiController {
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@GetMapping("/geom") @GetMapping("/geom/{id}")
public ApiResponseDto<Page<InferenceResultDto.Geom>> getInferenceResultGeomList( public ApiResponseDto<Page<InferenceResultDto.Geom>> getInferenceResultGeomList(
@Parameter(description = "기준년도 분류", example = "0001") @RequestParam(required = false) @Parameter(description = "분석결과 id", example = "1") @PathVariable Long id,
@Parameter(description = "기준년도 분류", example = "land") @RequestParam(required = false)
String targetClass, String targetClass,
@Parameter(description = "비교년도 분류", example = "0002") @RequestParam(required = false) @Parameter(description = "비교년도 분류", example = "waste") @RequestParam(required = false)
String compareClass, String compareClass,
@Parameter(description = "5000:1 도협번호 37801011,37801012") @RequestParam(required = false) @Parameter(description = "5000:1 도협번호 37801011,37801012") @RequestParam(required = false)
List<Long> mapSheetNum, List<Long> mapSheetNum,
@@ -141,7 +142,7 @@ public class InferenceResultApiController {
new InferenceResultDto.SearchGeoReq( new InferenceResultDto.SearchGeoReq(
targetClass, compareClass, mapSheetNum, page, size, sort); targetClass, compareClass, mapSheetNum, page, size, sort);
Page<InferenceResultDto.Geom> geomList = Page<InferenceResultDto.Geom> geomList =
inferenceResultService.getInferenceResultGeomList(searchGeoReq); inferenceResultService.getInferenceResultGeomList(id, searchGeoReq);
return ApiResponseDto.ok(geomList); return ApiResponseDto.ok(geomList);
} }

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.inference.dto; package com.kamco.cd.kamcoback.inference.dto;
import com.kamco.cd.kamcoback.common.enums.DetectionClassification;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -8,6 +9,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.locationtech.jts.geom.Geometry;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
@@ -50,6 +52,7 @@ public class InferenceResultDto {
@Schema(name = "AnalysisResultList", description = "분석결과 목록") @Schema(name = "AnalysisResultList", description = "분석결과 목록")
@Getter @Getter
public static class AnalResList { public static class AnalResList {
private Long id; private Long id;
private String analTitle; private String analTitle;
private String analMapSheet; private String analMapSheet;
@@ -91,6 +94,7 @@ public class InferenceResultDto {
@Schema(name = "AnalysisResultSummary", description = "분석결과 요약정보") @Schema(name = "AnalysisResultSummary", description = "분석결과 요약정보")
@Getter @Getter
public static class AnalResSummary { public static class AnalResSummary {
private Long id; private Long id;
private String analTitle; private String analTitle;
private String modelInfo; private String modelInfo;
@@ -143,6 +147,7 @@ public class InferenceResultDto {
@Getter @Getter
public static class Dashboard { public static class Dashboard {
Integer compareYyyy; Integer compareYyyy;
Integer targetYyyy; Integer targetYyyy;
Long mapSheetNum; Long mapSheetNum;
@@ -189,19 +194,17 @@ public class InferenceResultDto {
@Getter @Getter
public static class Detail { public static class Detail {
AnalResSummary summary;
List<Dashboard> dashboard;
Long totalCnt;
public Detail(AnalResSummary summary, List<Dashboard> dashboard, Long totalCnt) { AnalResSummary summary;
public Detail(AnalResSummary summary) {
this.summary = summary; this.summary = summary;
this.dashboard = dashboard;
this.totalCnt = totalCnt;
} }
} }
@Getter @Getter
public static class Geom { public static class Geom {
Integer compareYyyy; Integer compareYyyy;
Integer targetYyyy; Integer targetYyyy;
String classBeforeCd; String classBeforeCd;
@@ -211,26 +214,30 @@ public class InferenceResultDto {
String classAfterName; String classAfterName;
Double classAfterProb; Double classAfterProb;
Long mapSheetNum; Long mapSheetNum;
Geometry gemo;
Geometry geomCenter;
public Geom( public Geom(
Integer compareYyyy, Integer compareYyyy,
Integer targetYyyy, Integer targetYyyy,
String classBeforeCd, String classBeforeCd,
String classBeforeName,
Double classBeforeProb, Double classBeforeProb,
String classAfterCd, String classAfterCd,
String classAfterName,
Double classAfterProb, Double classAfterProb,
Long mapSheetNum) { Long mapSheetNum,
Geometry gemo,
Geometry geomCenter) {
this.compareYyyy = compareYyyy; this.compareYyyy = compareYyyy;
this.targetYyyy = targetYyyy; this.targetYyyy = targetYyyy;
this.classBeforeCd = classBeforeCd; this.classBeforeCd = classBeforeCd;
this.classBeforeName = classBeforeName; this.classBeforeName = DetectionClassification.fromString(classBeforeCd).getDesc();
this.classBeforeProb = classBeforeProb; this.classBeforeProb = classBeforeProb;
this.classAfterCd = classAfterCd; this.classAfterCd = classAfterCd;
this.classAfterName = classAfterName; this.classAfterName = DetectionClassification.fromString(classAfterCd).getDesc();
this.classAfterProb = classAfterProb; this.classAfterProb = classAfterProb;
this.mapSheetNum = mapSheetNum; this.mapSheetNum = mapSheetNum;
this.gemo = gemo;
this.geomCenter = geomCenter;
} }
} }

View File

@@ -1,7 +1,6 @@
package com.kamco.cd.kamcoback.inference.service; package com.kamco.cd.kamcoback.inference.service;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Dashboard;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Detail; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Detail;
import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService; import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService;
import java.util.List; import java.util.List;
@@ -38,16 +37,6 @@ public class InferenceResultService {
return inferenceResultCoreService.getInferenceResultSummary(id); return inferenceResultCoreService.getInferenceResultSummary(id);
} }
/**
* 분석결과 대시보드 조회
*
* @param id
* @return
*/
public List<Dashboard> getInferenceResultBasic(Long id) {
return inferenceResultCoreService.getInferenceResultDashboard(id);
}
/** /**
* 분석결과 상세 목록 * 분석결과 상세 목록
* *
@@ -55,8 +44,8 @@ public class InferenceResultService {
* @return * @return
*/ */
public Page<InferenceResultDto.Geom> getInferenceResultGeomList( public Page<InferenceResultDto.Geom> getInferenceResultGeomList(
InferenceResultDto.SearchGeoReq searchGeoReq) { Long id, InferenceResultDto.SearchGeoReq searchGeoReq) {
return inferenceResultCoreService.getInferenceResultGeomList(searchGeoReq); return inferenceResultCoreService.getInferenceResultGeomList(id, searchGeoReq);
} }
/** /**
@@ -68,11 +57,16 @@ public class InferenceResultService {
public Detail getDetail(Long id) { public Detail getDetail(Long id) {
// summary // summary
InferenceResultDto.AnalResSummary summary = this.getInferenceResultSummary(id); InferenceResultDto.AnalResSummary summary = this.getInferenceResultSummary(id);
// 탐지건수 dashBoard return new Detail(summary);
List<InferenceResultDto.Dashboard> dashboardList = this.getInferenceResultBasic(id); }
// 전체 탐지건수
Long totalCnt = dashboardList.stream().mapToLong(Dashboard::getClassAfterCnt).sum();
return new Detail(summary, dashboardList, totalCnt); /**
* 추론된 5000:1 도엽 목록
*
* @param id
* @return
*/
public List<String> getSheets(Long id) {
return inferenceResultCoreService.getSheets(id).stream().map(String::valueOf).toList();
} }
} }

View File

@@ -1,8 +1,6 @@
package com.kamco.cd.kamcoback.postgres.core; package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Dashboard;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalSttcEntity;
import com.kamco.cd.kamcoback.postgres.repository.Inference.InferenceResultRepository; import com.kamco.cd.kamcoback.postgres.repository.Inference.InferenceResultRepository;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
import java.util.List; import java.util.List;
@@ -41,18 +39,6 @@ public class InferenceResultCoreService {
return summary; return summary;
} }
/**
* 분석결과 대시보드 조회
*
* @param id
* @return
*/
public List<Dashboard> getInferenceResultDashboard(Long id) {
return inferenceResultRepository.getInferenceResultDashboard(id).stream()
.map(MapSheetAnalSttcEntity::toDto)
.toList();
}
/** /**
* 분석결과 상세 목록 * 분석결과 상세 목록
* *
@@ -60,7 +46,17 @@ public class InferenceResultCoreService {
* @return * @return
*/ */
public Page<InferenceResultDto.Geom> getInferenceResultGeomList( public Page<InferenceResultDto.Geom> getInferenceResultGeomList(
InferenceResultDto.SearchGeoReq searchGeoReq) { Long id, InferenceResultDto.SearchGeoReq searchGeoReq) {
return inferenceResultRepository.getInferenceGeomList(searchGeoReq); return inferenceResultRepository.getInferenceGeomList(id, searchGeoReq);
}
/**
* 추론된 5000:1 도엽 목록
*
* @param id
* @return
*/
public List<Long> getSheets(Long id) {
return inferenceResultRepository.getSheets(id);
} }
} }

View File

@@ -1,11 +1,17 @@
package com.kamco.cd.kamcoback.postgres.entity; package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.*; import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
@Getter @Getter
@@ -28,13 +34,15 @@ public class MapSheetAnalDataGeomEntity {
@Column(name = "cd_prob") @Column(name = "cd_prob")
private Double cdProb; private Double cdProb;
@Column(name = "class_before_cd") @Size(max = 40)
@Column(name = "class_before_cd", length = 40)
private String classBeforeCd; private String classBeforeCd;
@Column(name = "class_before_prob") @Column(name = "class_before_prob")
private Double classBeforeProb; private Double classBeforeProb;
@Column(name = "class_after_cd") @Size(max = 40)
@Column(name = "class_after_cd", length = 40)
private String classAfterCd; private String classAfterCd;
@Column(name = "class_after_prob") @Column(name = "class_after_prob")
@@ -59,31 +67,34 @@ public class MapSheetAnalDataGeomEntity {
@Column(name = "data_uid") @Column(name = "data_uid")
private Long dataUid; private Long dataUid;
@ColumnDefault("now()")
@Column(name = "created_dttm") @Column(name = "created_dttm")
private ZonedDateTime createdDttm; private OffsetDateTime createdDttm;
@Column(name = "created_uid") @Column(name = "created_uid")
private Long createdUid; private Long createdUid;
@ColumnDefault("now()")
@Column(name = "updated_dttm") @Column(name = "updated_dttm")
private ZonedDateTime updatedDttm; private OffsetDateTime updatedDttm;
@Column(name = "updated_uid") @Column(name = "updated_uid")
private Long updatedUid; private Long updatedUid;
@Column(name = "geom", columnDefinition = "geometry") @ColumnDefault("0")
private Geometry geom;
@Column(name = "geom_cnt") @Column(name = "geom_cnt")
private Long geomCnt; private Long geomCnt;
@ColumnDefault("0")
@Column(name = "pnu") @Column(name = "pnu")
private Long pnu; private Long pnu;
@Size(max = 20) @Size(max = 20)
@ColumnDefault("0")
@Column(name = "fit_state", length = 20) @Column(name = "fit_state", length = 20)
private String fitState; private String fitState;
@ColumnDefault("now()")
@Column(name = "fit_state_dttm") @Column(name = "fit_state_dttm")
private OffsetDateTime fitStateDttm; private OffsetDateTime fitStateDttm;
@@ -91,9 +102,11 @@ public class MapSheetAnalDataGeomEntity {
private Long labelerUid; private Long labelerUid;
@Size(max = 20) @Size(max = 20)
@ColumnDefault("0")
@Column(name = "label_state", length = 20) @Column(name = "label_state", length = 20)
private String labelState; private String labelState;
@ColumnDefault("now()")
@Column(name = "label_state_dttm") @Column(name = "label_state_dttm")
private OffsetDateTime labelStateDttm; private OffsetDateTime labelStateDttm;
@@ -101,17 +114,22 @@ public class MapSheetAnalDataGeomEntity {
private Long testerUid; private Long testerUid;
@Size(max = 20) @Size(max = 20)
@ColumnDefault("0")
@Column(name = "test_state", length = 20) @Column(name = "test_state", length = 20)
private String testState; private String testState;
@ColumnDefault("now()")
@Column(name = "test_state_dttm") @Column(name = "test_state_dttm")
private OffsetDateTime testStateDttm; private OffsetDateTime testStateDttm;
@Column(name = "fit_state_cmmnt", length = Integer.MAX_VALUE) @Column(name = "fit_state_cmmnt", length = Integer.MAX_VALUE)
private String fitStateCmmnt; private String fitStateCmmnt;
@Column(name = "ref_map_sheet_num", length = Integer.MAX_VALUE) @Column(name = "ref_map_sheet_num")
private String refMapSheetNum; private Long refMapSheetNum;
@Column(name = "geom", columnDefinition = "geometry")
private Geometry geom;
@Column(name = "geom_center", columnDefinition = "geometry") @Column(name = "geom_center", columnDefinition = "geometry")
private Geometry geomCenter; private Geometry geomCenter;

View File

@@ -1,11 +1,11 @@
package com.kamco.cd.kamcoback.postgres.entity; package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.EmbeddedId; import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@@ -19,9 +19,11 @@ public class MapSheetAnalSttcEntity {
@EmbeddedId private MapSheetAnalSttcEntityId id; @EmbeddedId private MapSheetAnalSttcEntityId id;
@ColumnDefault("0")
@Column(name = "class_before_cnt") @Column(name = "class_before_cnt")
private Long classBeforeCnt; private Long classBeforeCnt;
@ColumnDefault("0")
@Column(name = "class_after_cnt") @Column(name = "class_after_cnt")
private Long classAfterCnt; private Long classAfterCnt;
@@ -36,7 +38,7 @@ public class MapSheetAnalSttcEntity {
@Column(name = "updated_dttm") @Column(name = "updated_dttm")
private ZonedDateTime updatedDttm; private ZonedDateTime updatedDttm;
@Column(name = "updated_uid", length = Integer.MAX_VALUE) @Column(name = "updated_uid")
private Long updatedUid; private Long updatedUid;
@NotNull @NotNull
@@ -47,26 +49,11 @@ public class MapSheetAnalSttcEntity {
@Column(name = "data_uid", nullable = false) @Column(name = "data_uid", nullable = false)
private Long dataUid; private Long dataUid;
@Column(name = "class_before_cd") @Size(max = 30)
@Column(name = "class_before_cd", length = 30)
private String classBeforeCd; private String classBeforeCd;
@Column(name = "class_after_cd") @Size(max = 30)
@Column(name = "class_after_cd", length = 30)
private String classAfterCd; private String classAfterCd;
public InferenceResultDto.Dashboard toDto() {
return new InferenceResultDto.Dashboard(
id.getCompareYyyy(),
id.getTargetYyyy(),
id.getMapSheetNum(),
id.getClassBeforeName(),
id.getClassAfterName(),
this.classBeforeCnt,
this.classAfterCnt,
this.createdDttm,
this.createdUid,
this.updatedDttm,
this.updatedUid,
this.refMapSheetNum,
this.dataUid);
}
} }

View File

@@ -3,7 +3,6 @@ package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Embeddable; import jakarta.persistence.Embeddable;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects; import java.util.Objects;
import lombok.Getter; import lombok.Getter;
@@ -15,7 +14,7 @@ import org.hibernate.Hibernate;
@Embeddable @Embeddable
public class MapSheetAnalSttcEntityId implements Serializable { public class MapSheetAnalSttcEntityId implements Serializable {
private static final long serialVersionUID = -8630519290255405042L; private static final long serialVersionUID = 2285491656408229553L;
@NotNull @NotNull
@Column(name = "compare_yyyy", nullable = false) @Column(name = "compare_yyyy", nullable = false)
@@ -29,16 +28,6 @@ public class MapSheetAnalSttcEntityId implements Serializable {
@Column(name = "map_sheet_num", nullable = false) @Column(name = "map_sheet_num", nullable = false)
private Long mapSheetNum; private Long mapSheetNum;
@Size(max = 64)
@NotNull
@Column(name = "class_before_name", nullable = false, length = 64)
private String classBeforeName;
@Size(max = 64)
@NotNull
@Column(name = "class_after_name", nullable = false, length = 64)
private String classAfterName;
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@@ -49,14 +38,12 @@ public class MapSheetAnalSttcEntityId implements Serializable {
} }
MapSheetAnalSttcEntityId entity = (MapSheetAnalSttcEntityId) o; MapSheetAnalSttcEntityId entity = (MapSheetAnalSttcEntityId) o;
return Objects.equals(this.targetYyyy, entity.targetYyyy) return Objects.equals(this.targetYyyy, entity.targetYyyy)
&& Objects.equals(this.classBeforeName, entity.classBeforeName)
&& Objects.equals(this.classAfterName, entity.classAfterName)
&& Objects.equals(this.compareYyyy, entity.compareYyyy) && Objects.equals(this.compareYyyy, entity.compareYyyy)
&& Objects.equals(this.mapSheetNum, entity.mapSheetNum); && Objects.equals(this.mapSheetNum, entity.mapSheetNum);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(targetYyyy, classBeforeName, classAfterName, compareYyyy, mapSheetNum); return Objects.hash(targetYyyy, compareYyyy, mapSheetNum);
} }
} }

View File

@@ -1,18 +1,19 @@
package com.kamco.cd.kamcoback.postgres.repository.Inference; package com.kamco.cd.kamcoback.postgres.repository.Inference;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalSttcEntity;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
public interface InferenceResultRepositoryCustom { public interface InferenceResultRepositoryCustom {
Page<InferenceResultDto.AnalResList> getInferenceResultList( Page<InferenceResultDto.AnalResList> getInferenceResultList(
InferenceResultDto.SearchReq searchReq); InferenceResultDto.SearchReq searchReq);
Optional<InferenceResultDto.AnalResSummary> getInferenceResultSummary(Long id); Optional<InferenceResultDto.AnalResSummary> getInferenceResultSummary(Long id);
List<MapSheetAnalSttcEntity> getInferenceResultDashboard(Long id); Page<InferenceResultDto.Geom> getInferenceGeomList(
Long id, InferenceResultDto.SearchGeoReq searchGeoReq);
Page<InferenceResultDto.Geom> getInferenceGeomList(InferenceResultDto.SearchGeoReq searchGeoReq); List<Long> getSheets(Long id);
} }

View File

@@ -2,10 +2,9 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.SearchGeoReq; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.SearchGeoReq;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalSttcEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataGeomEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataGeomEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalSttcEntity;
import com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity; import com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity;
import com.kamco.cd.kamcoback.postgres.entity.QModelVerEntity; import com.kamco.cd.kamcoback.postgres.entity.QModelVerEntity;
import com.querydsl.core.BooleanBuilder; import com.querydsl.core.BooleanBuilder;
@@ -27,12 +26,12 @@ import org.springframework.stereotype.Repository;
public class InferenceResultRepositoryImpl implements InferenceResultRepositoryCustom { public class InferenceResultRepositoryImpl implements InferenceResultRepositoryCustom {
private final JPAQueryFactory queryFactory; private final JPAQueryFactory queryFactory;
private final QMapSheetAnalEntity mapSheetAnal = QMapSheetAnalEntity.mapSheetAnalEntity;
private final QModelMngEntity tmm = QModelMngEntity.modelMngEntity; private final QModelMngEntity tmm = QModelMngEntity.modelMngEntity;
private final QModelVerEntity tmv = QModelVerEntity.modelVerEntity; private final QModelVerEntity tmv = QModelVerEntity.modelVerEntity;
private final QMapSheetAnalSttcEntity mapSheetAnalSttc = private final QMapSheetAnalEntity mapSheetAnalEntity = QMapSheetAnalEntity.mapSheetAnalEntity;
QMapSheetAnalSttcEntity.mapSheetAnalSttcEntity; private final QMapSheetAnalDataEntity mapSheetAnalDataEntity =
private final QMapSheetAnalDataGeomEntity mapSheetAnalDataGeom = QMapSheetAnalDataEntity.mapSheetAnalDataEntity;
private final QMapSheetAnalDataGeomEntity mapSheetAnalDataGeomEntity =
QMapSheetAnalDataGeomEntity.mapSheetAnalDataGeomEntity; QMapSheetAnalDataGeomEntity.mapSheetAnalDataGeomEntity;
/** /**
@@ -48,12 +47,12 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
// "0000" 전체조회 // "0000" 전체조회
BooleanBuilder builder = new BooleanBuilder(); BooleanBuilder builder = new BooleanBuilder();
if (searchReq.getStatCode() != null && !"0000".equals(searchReq.getStatCode())) { if (searchReq.getStatCode() != null && !"0000".equals(searchReq.getStatCode())) {
builder.and(mapSheetAnal.analState.eq(searchReq.getStatCode())); builder.and(mapSheetAnalEntity.analState.eq(searchReq.getStatCode()));
} }
// 제목 // 제목
if (searchReq.getTitle() != null) { if (searchReq.getTitle() != null) {
builder.and(mapSheetAnal.analTitle.like("%" + searchReq.getTitle() + "%")); builder.and(mapSheetAnalEntity.analTitle.like("%" + searchReq.getTitle() + "%"));
} }
List<InferenceResultDto.AnalResList> content = List<InferenceResultDto.AnalResList> content =
@@ -61,27 +60,31 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
.select( .select(
Projections.constructor( Projections.constructor(
InferenceResultDto.AnalResList.class, InferenceResultDto.AnalResList.class,
mapSheetAnal.id, mapSheetAnalEntity.id,
mapSheetAnal.analTitle, mapSheetAnalEntity.analTitle,
mapSheetAnal.analMapSheet, mapSheetAnalEntity.analMapSheet,
mapSheetAnal.detectingCnt, mapSheetAnalEntity.detectingCnt,
mapSheetAnal.analStrtDttm, mapSheetAnalEntity.analStrtDttm,
mapSheetAnal.analEndDttm, mapSheetAnalEntity.analEndDttm,
mapSheetAnal.analSec, mapSheetAnalEntity.analSec,
mapSheetAnal.analPredSec, mapSheetAnalEntity.analPredSec,
mapSheetAnal.analState, mapSheetAnalEntity.analState,
Expressions.stringTemplate( Expressions.stringTemplate(
"fn_code_name({0}, {1})", "0002", mapSheetAnal.analState), "fn_code_name({0}, {1})", "0002", mapSheetAnalEntity.analState),
mapSheetAnal.gukyuinUsed)) mapSheetAnalEntity.gukyuinUsed))
.from(mapSheetAnal) .from(mapSheetAnalEntity)
.where(builder) .where(builder)
.offset(pageable.getOffset()) .offset(pageable.getOffset())
.limit(pageable.getPageSize()) .limit(pageable.getPageSize())
.orderBy(mapSheetAnal.createdDttm.desc()) .orderBy(mapSheetAnalEntity.createdDttm.desc())
.fetch(); .fetch();
long total = long total =
queryFactory.select(mapSheetAnal.id).from(mapSheetAnal).where(builder).fetchCount(); queryFactory
.select(mapSheetAnalEntity.id)
.from(mapSheetAnalEntity)
.where(builder)
.fetchCount();
return new PageImpl<>(content, pageable, total); return new PageImpl<>(content, pageable, total);
} }
@@ -105,47 +108,32 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
.select( .select(
Projections.constructor( Projections.constructor(
InferenceResultDto.AnalResSummary.class, InferenceResultDto.AnalResSummary.class,
mapSheetAnal.id, mapSheetAnalEntity.id,
mapSheetAnal.analTitle, mapSheetAnalEntity.analTitle,
tmm.modelNm.concat(" ").concat(tmv.modelVer).as("modelInfo"), tmm.modelNm.concat(" ").concat(tmv.modelVer).as("modelInfo"),
mapSheetAnal.targetYyyy, mapSheetAnalEntity.targetYyyy,
mapSheetAnal.compareYyyy, mapSheetAnalEntity.compareYyyy,
mapSheetAnal.analMapSheet, mapSheetAnalEntity.analMapSheet,
mapSheetAnal.analStrtDttm, mapSheetAnalEntity.analStrtDttm,
mapSheetAnal.analEndDttm, mapSheetAnalEntity.analEndDttm,
mapSheetAnal.analSec, mapSheetAnalEntity.analSec,
mapSheetAnal.analPredSec, mapSheetAnalEntity.analPredSec,
mapSheetAnal.resultUrl, mapSheetAnalEntity.resultUrl,
mapSheetAnal.detectingCnt, mapSheetAnalEntity.detectingCnt,
mapSheetAnal.accuracy, mapSheetAnalEntity.accuracy,
mapSheetAnal.analState, mapSheetAnalEntity.analState,
Expressions.stringTemplate( Expressions.stringTemplate(
"fn_code_name({0}, {1})", "0002", mapSheetAnal.analState))) "fn_code_name({0}, {1})", "0002", mapSheetAnalEntity.analState)))
.from(mapSheetAnal) .from(mapSheetAnalEntity)
.leftJoin(tmm) .leftJoin(tmm)
.on(mapSheetAnal.modelUid.eq(tmm.id)) .on(mapSheetAnalEntity.modelUid.eq(tmm.id))
.leftJoin(tmv) .leftJoin(tmv)
.on(tmv.modelUid.eq(tmm.id).and(tmv.id.eq(latestVerUidSub))) .on(tmv.modelUid.eq(tmm.id).and(tmv.id.eq(latestVerUidSub)))
.where(mapSheetAnal.id.eq(id)) .where(mapSheetAnalEntity.id.eq(id))
.fetchOne()); .fetchOne());
return content; return content;
} }
/**
* 분석결과 상세 대시보드 조회
*
* @param id
* @return
*/
@Override
public List<MapSheetAnalSttcEntity> getInferenceResultDashboard(Long id) {
return queryFactory
.select(mapSheetAnalSttc)
.from(mapSheetAnalSttc)
.where(mapSheetAnalSttc.dataUid.eq(id))
.fetch();
}
/** /**
* 분석결과 상세 목록 * 분석결과 상세 목록
* *
@@ -153,24 +141,27 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
* @return * @return
*/ */
@Override @Override
public Page<InferenceResultDto.Geom> getInferenceGeomList(SearchGeoReq searchGeoReq) { public Page<InferenceResultDto.Geom> getInferenceGeomList(Long id, SearchGeoReq searchGeoReq) {
Pageable pageable = searchGeoReq.toPageable(); Pageable pageable = searchGeoReq.toPageable();
BooleanBuilder builder = new BooleanBuilder(); BooleanBuilder builder = new BooleanBuilder();
// 추론결과 id
builder.and(mapSheetAnalEntity.id.eq(id));
// 기준년도 분류 // 기준년도 분류
if (searchGeoReq.getTargetClass() != null && !searchGeoReq.getTargetClass().equals("")) { if (searchGeoReq.getTargetClass() != null && !searchGeoReq.getTargetClass().equals("")) {
builder.and(mapSheetAnalDataGeom.classAfterCd.eq(searchGeoReq.getTargetClass())); builder.and(mapSheetAnalDataGeomEntity.classAfterCd.eq(searchGeoReq.getTargetClass()));
} }
// 비교년도 분류 // 비교년도 분류
if (searchGeoReq.getCompareClass() != null && !searchGeoReq.getCompareClass().equals("")) { if (searchGeoReq.getCompareClass() != null && !searchGeoReq.getCompareClass().equals("")) {
builder.and(mapSheetAnalDataGeom.classBeforeCd.eq(searchGeoReq.getCompareClass())); builder.and(mapSheetAnalDataGeomEntity.classBeforeCd.eq(searchGeoReq.getCompareClass()));
} }
// 분석도엽 // 분석도엽
if (searchGeoReq.getMapSheetNum() != null && !searchGeoReq.getMapSheetNum().isEmpty()) { if (searchGeoReq.getMapSheetNum() != null && !searchGeoReq.getMapSheetNum().isEmpty()) {
List<Long> mapSheetNum = searchGeoReq.getMapSheetNum(); List<Long> mapSheetNum = searchGeoReq.getMapSheetNum();
builder.and(mapSheetAnalDataGeom.mapSheetNum.in(mapSheetNum)); builder.and(mapSheetAnalDataGeomEntity.mapSheetNum.in(mapSheetNum));
} }
List<InferenceResultDto.Geom> content = List<InferenceResultDto.Geom> content =
@@ -178,28 +169,54 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
.select( .select(
Projections.constructor( Projections.constructor(
InferenceResultDto.Geom.class, InferenceResultDto.Geom.class,
mapSheetAnalDataGeom.compareYyyy, mapSheetAnalDataGeomEntity.compareYyyy,
mapSheetAnalDataGeom.targetYyyy, mapSheetAnalDataGeomEntity.targetYyyy,
mapSheetAnalDataGeom.classBeforeCd, mapSheetAnalDataGeomEntity.classBeforeCd,
Expressions.stringTemplate( mapSheetAnalDataGeomEntity.classBeforeProb,
"fn_code_name({0}, {1})", "0000", mapSheetAnalDataGeom.classBeforeCd), mapSheetAnalDataGeomEntity.classAfterCd,
mapSheetAnalDataGeom.classBeforeProb, mapSheetAnalDataGeomEntity.classAfterProb,
mapSheetAnalDataGeom.classAfterCd, mapSheetAnalDataGeomEntity.mapSheetNum,
Expressions.stringTemplate( mapSheetAnalDataGeomEntity.geom,
"fn_code_name({0}, {1})", "0000", mapSheetAnalDataGeom.classAfterCd), mapSheetAnalDataGeomEntity.geomCenter))
mapSheetAnalDataGeom.classAfterProb, .from(mapSheetAnalEntity)
mapSheetAnalDataGeom.mapSheetNum)) .join(mapSheetAnalDataEntity)
.from(mapSheetAnalDataGeom) .on(mapSheetAnalDataEntity.analUid.eq(mapSheetAnalEntity.id))
.join(mapSheetAnalDataGeomEntity)
.on(mapSheetAnalDataGeomEntity.dataUid.eq(mapSheetAnalDataEntity.id))
.where(builder) .where(builder)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch(); .fetch();
long total = long total =
queryFactory queryFactory
.select(mapSheetAnalDataGeom.id) .select(mapSheetAnalDataGeomEntity.id)
.from(mapSheetAnalDataGeom) .from(mapSheetAnalEntity)
.join(mapSheetAnalDataEntity)
.on(mapSheetAnalDataEntity.analUid.eq(mapSheetAnalEntity.id))
.join(mapSheetAnalDataGeomEntity)
.on(mapSheetAnalDataGeomEntity.dataUid.eq(mapSheetAnalDataEntity.id))
.where(builder) .where(builder)
.fetchCount(); .fetchCount();
return new PageImpl<>(content, pageable, total); return new PageImpl<>(content, pageable, total);
} }
/**
* 추론된 5000:1 도엽 목록
*
* @param id
* @return
*/
@Override
public List<Long> getSheets(Long id) {
return queryFactory
.select(mapSheetAnalDataEntity.mapSheetNum)
.from(mapSheetAnalEntity)
.join(mapSheetAnalDataEntity)
.on(mapSheetAnalDataEntity.analUid.eq(mapSheetAnalEntity.id))
.where(mapSheetAnalEntity.id.eq(id))
.groupBy(mapSheetAnalDataEntity.mapSheetNum)
.fetch();
}
} }

View File

@@ -75,6 +75,8 @@ public class AuthRepositoryImpl implements AuthRepositoryCustom {
userEntity.createdDttm)) userEntity.createdDttm))
.from(userEntity) .from(userEntity)
.where(builder) .where(builder)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(userEntity.userId.asc()) .orderBy(userEntity.userId.asc())
.fetch(); .fetch();

View File

@@ -49,7 +49,7 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
Projections.constructor( Projections.constructor(
ChangeDetectionDto.CountDto.class, ChangeDetectionDto.CountDto.class,
mapSheetAnalSttcEntity.classAfterCd.toUpperCase(), mapSheetAnalSttcEntity.classAfterCd.toUpperCase(),
mapSheetAnalSttcEntity.id.classAfterName, null, // TOOD classAfterName 삭제해서 수정 필요
mapSheetAnalSttcEntity.classAfterCnt.sum())) mapSheetAnalSttcEntity.classAfterCnt.sum()))
.from(mapSheetAnalEntity) .from(mapSheetAnalEntity)
.innerJoin(mapSheetAnalDataEntity) .innerJoin(mapSheetAnalDataEntity)
@@ -57,7 +57,7 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
.innerJoin(mapSheetAnalSttcEntity) .innerJoin(mapSheetAnalSttcEntity)
.on(mapSheetAnalSttcEntity.dataUid.eq(mapSheetAnalDataEntity.id)) .on(mapSheetAnalSttcEntity.dataUid.eq(mapSheetAnalDataEntity.id))
.where(mapSheetAnalEntity.id.eq(id)) .where(mapSheetAnalEntity.id.eq(id))
.groupBy(mapSheetAnalSttcEntity.classAfterCd, mapSheetAnalSttcEntity.id.classAfterName) .groupBy(mapSheetAnalSttcEntity.classAfterCd)
.fetch(); .fetch();
} }

View File

@@ -22,7 +22,7 @@ spring:
leak-detection-threshold: 60000 leak-detection-threshold: 60000
jpa: jpa:
hibernate: hibernate:
ddl-auto: update # 테이블이 없으면 생성, 있으면 업데이트 ddl-auto: update # 스키마 검증만 수행, 자동 변경하지 않음 (안전)
properties: properties:
hibernate: hibernate:
jdbc: jdbc:

View File

@@ -4,11 +4,25 @@
-- 1. First ensure PostGIS is enabled -- 1. First ensure PostGIS is enabled
CREATE EXTENSION IF NOT EXISTS postgis; CREATE EXTENSION IF NOT EXISTS postgis;
-- 2. Clear existing data since it's in incorrect format (JTS serialized objects) -- 2. Check if column needs to be recreated (only if it's bytea type)
-- This data needs to be reprocessed anyway with the correct PostGIS approach -- Only clear data if the column type is incorrect and needs conversion
DELETE FROM public.tb_map_sheet_learn_data_geom; DO $$
BEGIN
-- Only delete data if geom column exists and is bytea type
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'tb_map_sheet_learn_data_geom'
AND column_name = 'geom'
AND data_type = 'bytea'
) THEN
DELETE FROM public.tb_map_sheet_learn_data_geom WHERE geom IS NOT NULL;
RAISE NOTICE 'Cleared incorrect bytea geometry data for conversion';
ELSE
RAISE NOTICE 'Geometry column is already correct type, skipping data deletion';
END IF;
END $$;
-- 3. Drop and recreate the geom column with correct PostGIS geometry type -- 3. Drop and recreate the geom column with correct PostGIS geometry type (only if needed)
ALTER TABLE public.tb_map_sheet_learn_data_geom DROP COLUMN IF EXISTS geom; ALTER TABLE public.tb_map_sheet_learn_data_geom DROP COLUMN IF EXISTS geom;
ALTER TABLE public.tb_map_sheet_learn_data_geom ADD COLUMN geom geometry(Polygon, 5186); ALTER TABLE public.tb_map_sheet_learn_data_geom ADD COLUMN geom geometry(Polygon, 5186);