From 885b33ad672fce7803b9dfa7197162321eff944a Mon Sep 17 00:00:00 2001 From: zhouyongkang Date: Sat, 4 Jul 2026 18:53:27 +0800 Subject: [PATCH 1/9] feat: add sync service in semantic --- .../agent/tools/GetDomainsTool.java | 2 +- .../controller/DomainController.java | 2 +- .../TableSemanticSyncController.java | 53 ++++ .../convertor/SemanticConverter.java | 16 +- .../PhysicalTableCandidatePageQuery.java | 28 ++ .../PhysicalTableCandidateResponse.java | 21 ++ .../dto/semantic/SyncTableResult.java | 31 +++ .../semantic/SyncTableSemanticsRequest.java | 26 ++ .../semantic/SyncTableSemanticsResponse.java | 31 +++ .../github/malonetalk/entity/ColumnInfo.java | 4 + .../github/malonetalk/entity/TableInfo.java | 2 + .../mapper/ColumnSemanticInfoMapper.java | 4 +- .../malonetalk/mapper/TableInfoMapper.java | 4 +- .../service/{ => semantic}/DomainService.java | 2 +- .../{ => semantic}/DomainServiceImpl.java | 2 +- .../column/ColumnSemanticServiceImpl.java | 3 +- .../sync/SemanticSyncDiffService.java | 262 ++++++++++++++++++ .../sync/SemanticSyncResultService.java | 68 +++++ .../semantic/sync/SemanticSyncService.java | 32 +++ .../sync/SemanticSyncServiceImpl.java | 236 ++++++++++++++++ .../table/TableSemanticServiceImpl.java | 3 +- .../mapper/ColumnSemanticInfoMapper.xml | 27 +- .../main/resources/mapper/TableInfoMapper.xml | 22 +- data-agent-frontend/src/api/semantic.ts | 71 +++-- .../src/views/semantic/SemanticManage.vue | 2 +- .../components/ColumnSemanticManage.vue | 12 + .../components/RelationEditDialog.vue | 11 +- .../RelationManage.vue | 43 +-- .../components/RelationWorkspace.vue | 2 +- .../components/SyncPhysicalTableDialog.vue | 233 ++++++++++++++++ .../components/TableSemanticManage.vue | 50 +++- .../views/semantic/{relation => }/types.ts | 22 +- sql/data_source.sql | 6 + 33 files changed, 1248 insertions(+), 85 deletions(-) create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/controller/TableSemanticSyncController.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidatePageQuery.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidateResponse.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableResult.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsRequest.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsResponse.java rename data-agent-backend/src/main/java/io/github/malonetalk/service/{ => semantic}/DomainService.java (96%) rename data-agent-backend/src/main/java/io/github/malonetalk/service/{ => semantic}/DomainServiceImpl.java (99%) create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncDiffService.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncResultService.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncService.java create mode 100644 data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncServiceImpl.java rename data-agent-frontend/src/views/semantic/{relation => }/components/RelationEditDialog.vue (95%) rename data-agent-frontend/src/views/semantic/{relation => components}/RelationManage.vue (94%) rename data-agent-frontend/src/views/semantic/{relation => }/components/RelationWorkspace.vue (99%) create mode 100644 data-agent-frontend/src/views/semantic/components/SyncPhysicalTableDialog.vue rename data-agent-frontend/src/views/semantic/{relation => }/types.ts (82%) diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/agent/tools/GetDomainsTool.java b/data-agent-backend/src/main/java/io/github/malonetalk/agent/tools/GetDomainsTool.java index c53fcf0..792c359 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/agent/tools/GetDomainsTool.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/agent/tools/GetDomainsTool.java @@ -18,7 +18,7 @@ package io.github.malonetalk.agent.tools; import io.agentscope.core.tool.Tool; -import io.github.malonetalk.service.DomainService; +import io.github.malonetalk.service.semantic.DomainService; import java.util.List; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/controller/DomainController.java b/data-agent-backend/src/main/java/io/github/malonetalk/controller/DomainController.java index 3f905c1..f228756 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/controller/DomainController.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/controller/DomainController.java @@ -23,7 +23,7 @@ import io.github.malonetalk.dto.DomainUpdateRequest; import io.github.malonetalk.dto.pagination.PageResponse; import io.github.malonetalk.entity.DomainInfo; -import io.github.malonetalk.service.DomainService; +import io.github.malonetalk.service.semantic.DomainService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/controller/TableSemanticSyncController.java b/data-agent-backend/src/main/java/io/github/malonetalk/controller/TableSemanticSyncController.java new file mode 100644 index 0000000..2092c52 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/controller/TableSemanticSyncController.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.controller; + +import io.github.malonetalk.common.Result; +import io.github.malonetalk.dto.pagination.PageResponse; +import io.github.malonetalk.dto.semantic.PhysicalTableCandidatePageQuery; +import io.github.malonetalk.dto.semantic.PhysicalTableCandidateResponse; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsRequest; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsResponse; +import io.github.malonetalk.service.semantic.sync.SemanticSyncService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/semantic/tables/sync") +@RequiredArgsConstructor +public class TableSemanticSyncController { + + private final SemanticSyncService semanticSyncService; + + @GetMapping("/candidates") + public Result> getPhysicalTableCandidates( + @Valid PhysicalTableCandidatePageQuery query) { + return Result.success(semanticSyncService.getPhysicalTableCandidates(query)); + } + + @PostMapping + public Result syncTables( + @Valid @RequestBody SyncTableSemanticsRequest request) { + return Result.success(semanticSyncService.syncTables(request)); + } +} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/convertor/SemanticConverter.java b/data-agent-backend/src/main/java/io/github/malonetalk/convertor/SemanticConverter.java index d2192d6..7824d01 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/convertor/SemanticConverter.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/convertor/SemanticConverter.java @@ -39,25 +39,35 @@ public class SemanticConverter { public TableSemanticResponse toResponse(TableInfo tableInfo) { Boolean isVisible = tableInfo.getIsVisible(); + boolean hasPhysicalTable = !Boolean.FALSE.equals(tableInfo.getPhysicalStatus()); return TableSemanticResponse.builder() .id(tableInfo.getId()) .tableName(tableInfo.getTableName()) .domain(SemanticUtils.normalizeDomain(tableInfo.getDomain())) + .physicalTableDescription( + SemanticUtils.trimToNull(tableInfo.getPhysicalTableDescription())) .tableDescription(SemanticUtils.trimToNull(tableInfo.getTableDescription())) .isVisible(isVisible) - .hasPhysicalTable(true) + .hasPhysicalTable(hasPhysicalTable) + .invalidReason(hasPhysicalTable ? null : "物理表不存在") .updateTime(tableInfo.getUpdateTime()) .build(); } public ColumnSemanticResponse toResponse(ColumnInfo columnInfo) { + boolean hasPhysicalColumn = !Boolean.FALSE.equals(columnInfo.getPhysicalStatus()); return ColumnSemanticResponse.builder() .id(columnInfo.getId()) .columnName(columnInfo.getColumnName()) + .physicalColumnDescription( + SemanticUtils.trimToNull(columnInfo.getPhysicalColumnDescription())) .columnDescription(columnInfo.getColumnDescription()) + .typeName(SemanticUtils.trimToNull(columnInfo.getTypeName())) + .primaryKey(columnInfo.getPrimaryKey()) .isVisible(columnInfo.getIsVisible()) - .hasPhysicalColumn(true) - .effective(Boolean.TRUE.equals(columnInfo.getIsVisible())) + .hasPhysicalColumn(hasPhysicalColumn) + .effective(Boolean.TRUE.equals(columnInfo.getIsVisible()) && hasPhysicalColumn) + .invalidReason(hasPhysicalColumn ? null : "物理列不存在") .updateTime(columnInfo.getUpdateTime()) .build(); } diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidatePageQuery.java b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidatePageQuery.java new file mode 100644 index 0000000..a6ca465 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidatePageQuery.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.dto.semantic; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +public record PhysicalTableCandidatePageQuery( + @NotNull(message = "datasourceId 不能为空") Integer datasourceId, + @Min(value = 1, message = "page 不能小于 1") Integer page, + @Min(value = 1, message = "pageSize 不能小于 1") Integer pageSize, + String keyword, + String sortOrder) {} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidateResponse.java b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidateResponse.java new file mode 100644 index 0000000..9c1acb0 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/PhysicalTableCandidateResponse.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.dto.semantic; + +public record PhysicalTableCandidateResponse( + String tableName, String physicalTableDescription, Boolean synced) {} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableResult.java b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableResult.java new file mode 100644 index 0000000..a1d1860 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableResult.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.dto.semantic; + +public record SyncTableResult( + String tableName, + boolean physicalTableFound, + boolean tableAdded, + boolean tableReactivated, + boolean tableUpdated, + boolean tableMarkedMissing, + int addedColumns, + int reactivatedColumns, + int updatedColumns, + int missingColumnsMarked, + String message) {} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsRequest.java b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsRequest.java new file mode 100644 index 0000000..5098f01 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsRequest.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.dto.semantic; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +public record SyncTableSemanticsRequest( + @NotNull(message = "datasourceId 不能为空") Integer datasourceId, + @NotEmpty(message = "tableNames 不能为空") List tableNames) {} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsResponse.java b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsResponse.java new file mode 100644 index 0000000..deff25e --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/dto/semantic/SyncTableSemanticsResponse.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.dto.semantic; + +import java.util.List; + +public record SyncTableSemanticsResponse( + int addedTables, + int reactivatedTables, + int updatedTables, + int missingTablesMarked, + int addedColumns, + int reactivatedColumns, + int updatedColumns, + int missingColumnsMarked, + List results) {} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/entity/ColumnInfo.java b/data-agent-backend/src/main/java/io/github/malonetalk/entity/ColumnInfo.java index 45bb532..e3df009 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/entity/ColumnInfo.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/entity/ColumnInfo.java @@ -27,8 +27,12 @@ public class ColumnInfo { private Integer datasourceId; private String tableName; private String columnName; + private String physicalColumnDescription; + private String typeName; + private Boolean primaryKey; private String columnDescription; private Boolean isVisible; + private Boolean physicalStatus; private LocalDateTime createTime; private LocalDateTime updateTime; } diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/entity/TableInfo.java b/data-agent-backend/src/main/java/io/github/malonetalk/entity/TableInfo.java index cb2c16f..653e429 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/entity/TableInfo.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/entity/TableInfo.java @@ -25,10 +25,12 @@ public class TableInfo { private Integer id; private String tableName; + private String physicalTableDescription; private String tableDescription; private String domain; private Integer datasourceId; private Boolean isVisible; + private Boolean physicalStatus; private LocalDateTime createTime; private LocalDateTime updateTime; } diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/mapper/ColumnSemanticInfoMapper.java b/data-agent-backend/src/main/java/io/github/malonetalk/mapper/ColumnSemanticInfoMapper.java index 470e761..59b1966 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/mapper/ColumnSemanticInfoMapper.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/mapper/ColumnSemanticInfoMapper.java @@ -42,7 +42,9 @@ ColumnInfo selectByDatasourceIdAndTableNameAndColumnName( int insert(ColumnInfo columnInfo); - int update(ColumnInfo columnInfo); + int updateSemanticFields(ColumnInfo columnInfo); + + int updatePhysicalCacheFields(ColumnInfo columnInfo); int deleteByDatasourceId(@Param("datasourceId") Integer datasourceId); diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/mapper/TableInfoMapper.java b/data-agent-backend/src/main/java/io/github/malonetalk/mapper/TableInfoMapper.java index 92bfee3..9381c62 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/mapper/TableInfoMapper.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/mapper/TableInfoMapper.java @@ -28,7 +28,9 @@ public interface TableInfoMapper { int insert(TableInfo tableInfo); - int update(TableInfo tableInfo); + int updateSemanticFields(TableInfo tableInfo); + + int updatePhysicalCacheFields(TableInfo tableInfo); int deleteByDatasourceIdAndIds( @Param("datasourceId") Integer datasourceId, @Param("ids") List ids); diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/DomainService.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/DomainService.java similarity index 96% rename from data-agent-backend/src/main/java/io/github/malonetalk/service/DomainService.java rename to data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/DomainService.java index cfb6117..fdfd11f 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/service/DomainService.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/DomainService.java @@ -15,7 +15,7 @@ * along with this program. If not, see . * limitations under the License. */ -package io.github.malonetalk.service; +package io.github.malonetalk.service.semantic; import io.github.malonetalk.dto.DomainCreateRequest; import io.github.malonetalk.dto.DomainPageQuery; diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/DomainServiceImpl.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/DomainServiceImpl.java similarity index 99% rename from data-agent-backend/src/main/java/io/github/malonetalk/service/DomainServiceImpl.java rename to data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/DomainServiceImpl.java index 59579e2..e2c62be 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/service/DomainServiceImpl.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/DomainServiceImpl.java @@ -15,7 +15,7 @@ * along with this program. If not, see . * limitations under the License. */ -package io.github.malonetalk.service; +package io.github.malonetalk.service.semantic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/column/ColumnSemanticServiceImpl.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/column/ColumnSemanticServiceImpl.java index 87e723e..e9f5d7c 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/column/ColumnSemanticServiceImpl.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/column/ColumnSemanticServiceImpl.java @@ -94,6 +94,7 @@ public void updateColumnSemantic(String tableName, ColumnSemanticUpdateRequest r columnInfo.setColumnName(normalizedColumnName); columnInfo.setColumnDescription(SemanticUtils.trimToNull(request.columnDescription())); columnInfo.setIsVisible(request.isVisible()); + columnInfo.setPhysicalStatus(Boolean.FALSE); columnInfo.setCreateTime(LocalDateTime.now()); columnInfo.setUpdateTime(LocalDateTime.now()); columnSemanticInfoMapper.insert(columnInfo); @@ -104,7 +105,7 @@ public void updateColumnSemantic(String tableName, ColumnSemanticUpdateRequest r existing.setColumnDescription(SemanticUtils.trimToNull(request.columnDescription())); existing.setIsVisible(request.isVisible()); existing.setUpdateTime(LocalDateTime.now()); - columnSemanticInfoMapper.update(existing); + columnSemanticInfoMapper.updateSemanticFields(existing); } @Override diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncDiffService.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncDiffService.java new file mode 100644 index 0000000..4ae1961 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncDiffService.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.service.semantic.sync; + +import io.github.malonetalk.common.SemanticConstants; +import io.github.malonetalk.dto.semantic.SyncTableResult; +import io.github.malonetalk.entity.ColumnInfo; +import io.github.malonetalk.entity.TableInfo; +import io.github.malonetalk.mapper.ColumnSemanticInfoMapper; +import io.github.malonetalk.mapper.TableInfoMapper; +import io.github.malonetalk.utils.SemanticUtils; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class SemanticSyncDiffService { + + private final TableInfoMapper tableInfoMapper; + private final ColumnSemanticInfoMapper columnSemanticInfoMapper; + + public TableSyncDiff ensureTablePresent( + Integer datasourceId, + String normalizedTableName, + String physicalTableDescription, + LocalDateTime now) { + TableInfo existingTable = + tableInfoMapper.selectByDatasourceIdAndTableName(datasourceId, normalizedTableName); + if (existingTable == null) { + try { + tableInfoMapper.insert( + buildNewTableInfo( + datasourceId, + normalizedTableName, + physicalTableDescription, + now)); + return new TableSyncDiff(true, false, false); + } catch (DuplicateKeyException ignored) { + existingTable = + tableInfoMapper.selectByDatasourceIdAndTableName( + datasourceId, normalizedTableName); + } + } + if (existingTable == null) { + return new TableSyncDiff(false, false, false); + } + + boolean reactivated = Boolean.FALSE.equals(existingTable.getPhysicalStatus()); + boolean descriptionChanged = + !Objects.equals(existingTable.getPhysicalTableDescription(), physicalTableDescription); + boolean updated = descriptionChanged; + if (reactivated || descriptionChanged) { + existingTable.setPhysicalTableDescription(physicalTableDescription); + existingTable.setPhysicalStatus(Boolean.TRUE); + existingTable.setUpdateTime(now); + tableInfoMapper.updatePhysicalCacheFields(existingTable); + } + if (reactivated) { + return new TableSyncDiff(false, true, updated); + } + if (updated) { + return new TableSyncDiff(false, false, true); + } + return new TableSyncDiff(false, false, false); + } + + public ColumnSyncDiff ensureColumnPresent( + Integer datasourceId, + String normalizedTableName, + String normalizedColumnName, + String physicalColumnDescription, + String typeName, + boolean primaryKey, + LocalDateTime now, + Map semanticColumnMap) { + ColumnInfo existingColumn = semanticColumnMap.get(normalizedColumnName); + if (existingColumn == null) { + try { + columnSemanticInfoMapper.insert( + buildNewColumnInfo( + datasourceId, + normalizedTableName, + normalizedColumnName, + physicalColumnDescription, + typeName, + primaryKey, + now)); + return new ColumnSyncDiff(true, false, false); + } catch (DuplicateKeyException ignored) { + existingColumn = + columnSemanticInfoMapper.selectByDatasourceIdAndTableNameAndColumnName( + datasourceId, normalizedTableName, normalizedColumnName); + if (existingColumn != null) { + semanticColumnMap.put(normalizedColumnName, existingColumn); + } + } + } + if (existingColumn == null) { + return new ColumnSyncDiff(false, false, false); + } + + boolean reactivated = Boolean.FALSE.equals(existingColumn.getPhysicalStatus()); + boolean descriptionChanged = + !Objects.equals(existingColumn.getPhysicalColumnDescription(), physicalColumnDescription); + boolean typeChanged = !Objects.equals(existingColumn.getTypeName(), typeName); + boolean primaryKeyChanged = + !Objects.equals(existingColumn.getPrimaryKey(), Boolean.valueOf(primaryKey)); + boolean updated = descriptionChanged || typeChanged || primaryKeyChanged; + if (reactivated || updated) { + existingColumn.setPhysicalColumnDescription(physicalColumnDescription); + existingColumn.setTypeName(typeName); + existingColumn.setPrimaryKey(primaryKey); + existingColumn.setPhysicalStatus(Boolean.TRUE); + existingColumn.setUpdateTime(now); + columnSemanticInfoMapper.updatePhysicalCacheFields(existingColumn); + } + if (reactivated) { + return new ColumnSyncDiff(false, true, updated); + } + if (updated) { + return new ColumnSyncDiff(false, false, true); + } + return new ColumnSyncDiff(false, false, false); + } + + public SyncTableResult markMissingTable( + Integer datasourceId, String normalizedTableName, LocalDateTime now) { + TableInfo existingTable = + tableInfoMapper.selectByDatasourceIdAndTableName(datasourceId, normalizedTableName); + if (existingTable == null) { + return new SyncTableResult( + normalizedTableName, false, false, false, false, false, 0, 0, 0, 0, "物理表不存在"); + } + + boolean tableMarkedMissing = !Boolean.FALSE.equals(existingTable.getPhysicalStatus()); + if (tableMarkedMissing) { + existingTable.setPhysicalStatus(Boolean.FALSE); + existingTable.setUpdateTime(now); + tableInfoMapper.updatePhysicalCacheFields(existingTable); + } + int missingColumnsMarked = + markAllColumnsMissing( + columnSemanticInfoMapper.selectByDatasourceIdAndTableName( + datasourceId, normalizedTableName), + now); + return new SyncTableResult( + existingTable.getTableName(), + false, + false, + false, + false, + tableMarkedMissing, + 0, + 0, + 0, + missingColumnsMarked, + "物理表不存在"); + } + + public int markMissingColumns( + List semanticColumns, Set physicalColumnNames, LocalDateTime now) { + int missingColumnsMarked = 0; + for (ColumnInfo semanticColumn : semanticColumns) { + if (physicalColumnNames.contains(normalizeName(semanticColumn.getColumnName()))) { + continue; + } + if (Boolean.FALSE.equals(semanticColumn.getPhysicalStatus())) { + continue; + } + semanticColumn.setPhysicalStatus(Boolean.FALSE); + semanticColumn.setUpdateTime(now); + columnSemanticInfoMapper.updatePhysicalCacheFields(semanticColumn); + missingColumnsMarked++; + } + return missingColumnsMarked; + } + + private int markAllColumnsMissing(List semanticColumns, LocalDateTime now) { + int missingColumnsMarked = 0; + for (ColumnInfo semanticColumn : semanticColumns) { + if (Boolean.FALSE.equals(semanticColumn.getPhysicalStatus())) { + continue; + } + semanticColumn.setPhysicalStatus(Boolean.FALSE); + semanticColumn.setUpdateTime(now); + columnSemanticInfoMapper.updatePhysicalCacheFields(semanticColumn); + missingColumnsMarked++; + } + return missingColumnsMarked; + } + + private TableInfo buildNewTableInfo( + Integer datasourceId, + String normalizedTableName, + String physicalTableDescription, + LocalDateTime now) { + TableInfo tableInfo = new TableInfo(); + tableInfo.setDatasourceId(datasourceId); + tableInfo.setTableName(normalizedTableName); + tableInfo.setPhysicalTableDescription(physicalTableDescription); + tableInfo.setTableDescription(null); + tableInfo.setDomain(SemanticConstants.DEFAULT_DOMAIN); + tableInfo.setIsVisible(Boolean.TRUE); + tableInfo.setPhysicalStatus(Boolean.TRUE); + tableInfo.setCreateTime(now); + tableInfo.setUpdateTime(now); + return tableInfo; + } + + private ColumnInfo buildNewColumnInfo( + Integer datasourceId, + String normalizedTableName, + String normalizedColumnName, + String physicalColumnDescription, + String typeName, + boolean primaryKey, + LocalDateTime now) { + ColumnInfo columnInfo = new ColumnInfo(); + columnInfo.setDatasourceId(datasourceId); + columnInfo.setTableName(normalizedTableName); + columnInfo.setColumnName(normalizedColumnName); + columnInfo.setPhysicalColumnDescription(physicalColumnDescription); + columnInfo.setTypeName(typeName); + columnInfo.setPrimaryKey(primaryKey); + columnInfo.setColumnDescription(null); + columnInfo.setIsVisible(Boolean.TRUE); + columnInfo.setPhysicalStatus(Boolean.TRUE); + columnInfo.setCreateTime(now); + columnInfo.setUpdateTime(now); + return columnInfo; + } + + private String normalizeName(String value) { + return SemanticUtils.trimToNotBlank(value, "objectName").toLowerCase(Locale.ROOT); + } + + public record TableSyncDiff(boolean added, boolean reactivated, boolean updated) {} + + public record ColumnSyncDiff(boolean added, boolean reactivated, boolean updated) {} +} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncResultService.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncResultService.java new file mode 100644 index 0000000..0de1e57 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncResultService.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.service.semantic.sync; + +import io.github.malonetalk.dto.semantic.SyncTableResult; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsResponse; +import java.util.List; +import org.springframework.stereotype.Service; + +@Service +public class SemanticSyncResultService { + + public SyncTableSemanticsResponse summarize(List results) { + int addedTables = 0; + int reactivatedTables = 0; + int updatedTables = 0; + int missingTablesMarked = 0; + int addedColumns = 0; + int reactivatedColumns = 0; + int updatedColumns = 0; + int missingColumnsMarked = 0; + + for (SyncTableResult result : results) { + if (result.tableAdded()) { + addedTables++; + } + if (result.tableReactivated()) { + reactivatedTables++; + } + if (result.tableUpdated()) { + updatedTables++; + } + if (result.tableMarkedMissing()) { + missingTablesMarked++; + } + addedColumns += result.addedColumns(); + reactivatedColumns += result.reactivatedColumns(); + updatedColumns += result.updatedColumns(); + missingColumnsMarked += result.missingColumnsMarked(); + } + + return new SyncTableSemanticsResponse( + addedTables, + reactivatedTables, + updatedTables, + missingTablesMarked, + addedColumns, + reactivatedColumns, + updatedColumns, + missingColumnsMarked, + results); + } +} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncService.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncService.java new file mode 100644 index 0000000..92c2c7f --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncService.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.service.semantic.sync; + +import io.github.malonetalk.dto.pagination.PageResponse; +import io.github.malonetalk.dto.semantic.PhysicalTableCandidatePageQuery; +import io.github.malonetalk.dto.semantic.PhysicalTableCandidateResponse; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsRequest; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsResponse; + +public interface SemanticSyncService { + + PageResponse getPhysicalTableCandidates( + PhysicalTableCandidatePageQuery query); + + SyncTableSemanticsResponse syncTables(SyncTableSemanticsRequest request); +} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncServiceImpl.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncServiceImpl.java new file mode 100644 index 0000000..94e0541 --- /dev/null +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/sync/SemanticSyncServiceImpl.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2026 github.com/MaloneTalk + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * limitations under the License. + */ +package io.github.malonetalk.service.semantic.sync; + +import io.github.malonetalk.agent.datasource.SchemaReader; +import io.github.malonetalk.dto.datasource.PhysicalColumnInfo; +import io.github.malonetalk.dto.datasource.PhysicalTableInfo; +import io.github.malonetalk.dto.pagination.PageResponse; +import io.github.malonetalk.dto.semantic.PhysicalTableCandidatePageQuery; +import io.github.malonetalk.dto.semantic.PhysicalTableCandidateResponse; +import io.github.malonetalk.dto.semantic.SyncTableResult; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsRequest; +import io.github.malonetalk.dto.semantic.SyncTableSemanticsResponse; +import io.github.malonetalk.entity.ColumnInfo; +import io.github.malonetalk.entity.Datasource; +import io.github.malonetalk.entity.TableInfo; +import io.github.malonetalk.mapper.ColumnSemanticInfoMapper; +import io.github.malonetalk.mapper.TableInfoMapper; +import io.github.malonetalk.service.DatasourceService; +import io.github.malonetalk.utils.SemanticUtils; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class SemanticSyncServiceImpl implements SemanticSyncService { + + private final DatasourceService datasourceService; + private final TableInfoMapper tableInfoMapper; + private final ColumnSemanticInfoMapper columnSemanticInfoMapper; + private final SchemaReader schemaReader; + private final SemanticSyncDiffService semanticSyncDiffService; + private final SemanticSyncResultService semanticSyncResultService; + + @Override + public PageResponse getPhysicalTableCandidates( + PhysicalTableCandidatePageQuery query) { + Datasource datasource = requireDatasource(query.datasourceId()); + int pageNumber = PageResponse.resolvePage(query.page()); + int pageSize = PageResponse.resolvePageSize(query.pageSize()); + List physicalTables = schemaReader.getTables(datasource); + Map semanticTables = + tableInfoMapper.selectByDatasourceId(query.datasourceId()).stream() + .collect( + Collectors.toMap( + table -> normalizeName(table.getTableName()), + table -> table, + (left, _right) -> left, + LinkedHashMap::new)); + String keyword = SemanticUtils.trimToNull(query.keyword()); + boolean sortDescending = SemanticUtils.isDescendingSort(query.sortOrder()); + + List filtered = + physicalTables.stream() + .filter(table -> matchesKeyword(table, keyword)) + .sorted(buildTableComparator(sortDescending)) + .map( + table -> + new PhysicalTableCandidateResponse( + table.tableName(), + SemanticUtils.trimToNull(table.remarks()), + semanticTables.containsKey( + normalizeName(table.tableName())))) + .toList(); + + int fromIndex = Math.min((pageNumber - 1) * pageSize, filtered.size()); + int toIndex = Math.min(fromIndex + pageSize, filtered.size()); + return PageResponse.of( + filtered.subList(fromIndex, toIndex), filtered.size(), pageNumber, pageSize); + } + + @Override + @Transactional + public SyncTableSemanticsResponse syncTables(SyncTableSemanticsRequest request) { + Datasource datasource = requireDatasource(request.datasourceId()); + Map physicalTables = + schemaReader.getTables(datasource).stream() + .collect( + Collectors.toMap( + table -> normalizeName(table.tableName()), + table -> table, + (left, _right) -> left, + LinkedHashMap::new)); + Set selectedTableNames = + request.tableNames().stream() + .map(name -> SemanticUtils.trimToNotBlank(name, "tableName")) + .map(this::normalizeName) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + List results = new ArrayList<>(); + for (String normalizedTableName : selectedTableNames) { + PhysicalTableInfo physicalTable = physicalTables.get(normalizedTableName); + SyncTableResult result = + physicalTable == null + ? semanticSyncDiffService.markMissingTable( + request.datasourceId(), normalizedTableName, LocalDateTime.now()) + : syncSingleTable( + datasource, + request.datasourceId(), + physicalTable, + normalizedTableName); + results.add(result); + } + + return semanticSyncResultService.summarize(results); + } + + private SyncTableResult syncSingleTable( + Datasource datasource, + Integer datasourceId, + PhysicalTableInfo physicalTable, + String normalizedTableName) { + LocalDateTime now = LocalDateTime.now(); + SemanticSyncDiffService.TableSyncDiff tableSyncDiff = + semanticSyncDiffService.ensureTablePresent( + datasourceId, + normalizedTableName, + SemanticUtils.trimToNull(physicalTable.remarks()), + now); + + List semanticColumns = + columnSemanticInfoMapper.selectByDatasourceIdAndTableName( + datasourceId, normalizedTableName); + Map semanticColumnMap = + semanticColumns.stream() + .collect( + Collectors.toMap( + column -> normalizeName(column.getColumnName()), + column -> column, + (left, _right) -> left, + LinkedHashMap::new)); + List physicalColumns = + schemaReader.getTableSchema(datasource, physicalTable.tableName()); + Set physicalColumnNames = new LinkedHashSet<>(); + int addedColumns = 0; + int reactivatedColumns = 0; + int updatedColumns = 0; + + for (PhysicalColumnInfo physicalColumn : physicalColumns) { + String normalizedColumnName = normalizeName(physicalColumn.columnName()); + physicalColumnNames.add(normalizedColumnName); + SemanticSyncDiffService.ColumnSyncDiff columnSyncDiff = + semanticSyncDiffService.ensureColumnPresent( + datasourceId, + normalizedTableName, + normalizedColumnName, + SemanticUtils.trimToNull(physicalColumn.remarks()), + SemanticUtils.trimToNull(physicalColumn.typeName()), + physicalColumn.primaryKey(), + now, + semanticColumnMap); + if (columnSyncDiff.added()) { + addedColumns++; + } + if (columnSyncDiff.reactivated()) { + reactivatedColumns++; + } + if (columnSyncDiff.updated()) { + updatedColumns++; + } + } + + int missingColumnsMarked = + semanticSyncDiffService.markMissingColumns(semanticColumns, physicalColumnNames, now); + + return new SyncTableResult( + physicalTable.tableName(), + true, + tableSyncDiff.added(), + tableSyncDiff.reactivated(), + tableSyncDiff.updated(), + false, + addedColumns, + reactivatedColumns, + updatedColumns, + missingColumnsMarked, + "同步完成"); + } + + private Datasource requireDatasource(Integer datasourceId) { + SemanticUtils.requireDatasourceId(datasourceId); + Datasource datasource = datasourceService.findById(datasourceId); + if (datasource == null) { + throw new IllegalArgumentException("Datasource does not exist: " + datasourceId); + } + return datasource; + } + + private boolean matchesKeyword(PhysicalTableInfo table, String keyword) { + if (keyword == null) { + return true; + } + String normalizedKeyword = keyword.toLowerCase(Locale.ROOT); + return table.tableName().toLowerCase(Locale.ROOT).contains(normalizedKeyword) + || (table.remarks() != null + && table.remarks().toLowerCase(Locale.ROOT).contains(normalizedKeyword)); + } + + private Comparator buildTableComparator(boolean sortDescending) { + Comparator comparator = + Comparator.comparing( + table -> table.tableName().toLowerCase(Locale.ROOT), + Comparator.naturalOrder()); + return sortDescending ? comparator.reversed() : comparator; + } + + private String normalizeName(String value) { + return SemanticUtils.trimToNotBlank(value, "objectName").toLowerCase(Locale.ROOT); + } +} diff --git a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/table/TableSemanticServiceImpl.java b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/table/TableSemanticServiceImpl.java index 13c9875..9728e17 100644 --- a/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/table/TableSemanticServiceImpl.java +++ b/data-agent-backend/src/main/java/io/github/malonetalk/service/semantic/table/TableSemanticServiceImpl.java @@ -153,6 +153,7 @@ public void updateTableSemantic(TableSemanticUpdateRequest request) { tableInfo.setTableDescription(SemanticUtils.trimToNull(request.tableDescription())); tableInfo.setDomain(SemanticUtils.normalizeDomain(request.domain())); tableInfo.setIsVisible(request.isVisible()); + tableInfo.setPhysicalStatus(Boolean.FALSE); tableInfo.setCreateTime(LocalDateTime.now()); tableInfo.setUpdateTime(LocalDateTime.now()); tableInfoMapper.insert(tableInfo); @@ -163,7 +164,7 @@ public void updateTableSemantic(TableSemanticUpdateRequest request) { existing.setDomain(SemanticUtils.normalizeDomain(request.domain())); existing.setIsVisible(request.isVisible()); existing.setUpdateTime(LocalDateTime.now()); - tableInfoMapper.update(existing); + tableInfoMapper.updateSemanticFields(existing); } @Override diff --git a/data-agent-backend/src/main/resources/mapper/ColumnSemanticInfoMapper.xml b/data-agent-backend/src/main/resources/mapper/ColumnSemanticInfoMapper.xml index eb3cf09..e088f58 100644 --- a/data-agent-backend/src/main/resources/mapper/ColumnSemanticInfoMapper.xml +++ b/data-agent-backend/src/main/resources/mapper/ColumnSemanticInfoMapper.xml @@ -7,8 +7,12 @@ + + + + @@ -54,15 +58,16 @@ INSERT INTO column_info ( - datasource_id, table_name, column_name, column_description, - is_visible, create_time, update_time + datasource_id, table_name, column_name, physical_column_description, type_name, + primary_key, column_description, is_visible, physical_status, create_time, update_time ) VALUES ( - #{datasourceId}, #{tableName}, #{columnName}, #{columnDescription}, - #{isVisible}, #{createTime}, #{updateTime} + #{datasourceId}, #{tableName}, #{columnName}, #{physicalColumnDescription}, + #{typeName}, #{primaryKey}, #{columnDescription}, + #{isVisible}, #{physicalStatus}, #{createTime}, #{updateTime} ) - + UPDATE column_info table_name = #{tableName}, @@ -74,6 +79,18 @@ WHERE id = #{id} + + UPDATE column_info + + physical_column_description = #{physicalColumnDescription}, + type_name = #{typeName}, + primary_key = #{primaryKey}, + physical_status = #{physicalStatus}, + update_time = #{updateTime}, + + WHERE id = #{id} + + DELETE FROM column_info WHERE datasource_id = #{datasourceId} diff --git a/data-agent-backend/src/main/resources/mapper/TableInfoMapper.xml b/data-agent-backend/src/main/resources/mapper/TableInfoMapper.xml index 56d5e26..3464fb4 100644 --- a/data-agent-backend/src/main/resources/mapper/TableInfoMapper.xml +++ b/data-agent-backend/src/main/resources/mapper/TableInfoMapper.xml @@ -5,10 +5,12 @@ + + @@ -45,27 +47,39 @@ INSERT INTO table_info ( - table_name, table_description, domain, datasource_id, is_visible, + table_name, physical_table_description, table_description, domain, datasource_id, + is_visible, physical_status, create_time, update_time ) VALUES ( - #{tableName}, #{tableDescription}, #{domain}, #{datasourceId}, #{isVisible}, + #{tableName}, #{physicalTableDescription}, #{tableDescription}, #{domain}, + #{datasourceId}, #{isVisible}, + #{physicalStatus}, #{createTime}, #{updateTime} ) - + UPDATE table_info table_name = #{tableName}, table_description = #{tableDescription}, domain = #{domain}, - datasource_id = #{datasourceId}, is_visible = #{isVisible}, update_time = #{updateTime}, WHERE id = #{id} + + UPDATE table_info + + physical_table_description = #{physicalTableDescription}, + physical_status = #{physicalStatus}, + update_time = #{updateTime}, + + WHERE id = #{id} + + + + + +