Merge remote-tracking branch 'origin/master' into jsqlparser-fix

This commit is contained in:
zhaoyingchao
2025-03-05 10:01:57 +08:00
23 changed files with 165 additions and 123 deletions

View File

@@ -55,8 +55,8 @@ if "%command%"=="restart" (
set "webDir=%baseDir%\webapp" set "webDir=%baseDir%\webapp"
set "logDir=%baseDir%\logs" set "logDir=%baseDir%\logs"
set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%" set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%"
set "java-command=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile% -Xms1024m set "property=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile%"
-Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%" set "java-command=%property% -Xms1024m -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%"
if not exist %logDir% mkdir %logDir% if not exist %logDir% mkdir %logDir%
start /B java %java-command% >nul 2>&1 start /B java %java-command% >nul 2>&1
timeout /t 10 >nul timeout /t 10 >nul

View File

@@ -1,7 +1,7 @@
package com.tencent.supersonic.auth.authentication.interceptor; package com.tencent.supersonic.auth.authentication.interceptor;
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl; import com.tencent.supersonic.auth.api.authentication.service.UserService;
import com.tencent.supersonic.auth.authentication.utils.TokenService; import com.tencent.supersonic.auth.authentication.utils.TokenService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -16,7 +16,7 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
protected AuthenticationConfig authenticationConfig; protected AuthenticationConfig authenticationConfig;
protected UserServiceImpl userServiceImpl; protected UserService userService;
protected TokenService tokenService; protected TokenService tokenService;

View File

@@ -3,7 +3,7 @@ package com.tencent.supersonic.auth.authentication.interceptor;
import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore; import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore;
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword; import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl; import com.tencent.supersonic.auth.api.authentication.service.UserService;
import com.tencent.supersonic.auth.authentication.utils.TokenService; import com.tencent.supersonic.auth.authentication.utils.TokenService;
import com.tencent.supersonic.common.pojo.exception.AccessException; import com.tencent.supersonic.common.pojo.exception.AccessException;
import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.ContextUtils;
@@ -16,12 +16,7 @@ import org.springframework.web.method.HandlerMethod;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Optional; import java.util.Optional;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_IS_ADMIN; import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.*;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_DISPLAY_NAME;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_EMAIL;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD;
@Slf4j @Slf4j
public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor { public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor {
@@ -30,7 +25,7 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws AccessException { Object handler) throws AccessException {
authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class); authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class);
userServiceImpl = ContextUtils.getBean(UserServiceImpl.class); userService = ContextUtils.getBean(UserService.class);
tokenService = ContextUtils.getBean(TokenService.class); tokenService = ContextUtils.getBean(TokenService.class);
if (!authenticationConfig.isEnabled()) { if (!authenticationConfig.isEnabled()) {
return true; return true;

View File

@@ -4,10 +4,13 @@ import com.google.common.base.Objects;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER; import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER;
@Data @Data
public class Order { public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@NotBlank(message = "Invalid order column") @NotBlank(message = "Invalid order column")
private String column; private String column;

View File

@@ -1,25 +1,15 @@
# Use an official OpenJDK runtime as a parent image FROM supersonicbi/supersonic:0.9.10-SNAPSHOT
FROM openjdk:21-jdk-bullseye
# Set the working directory in the container # Set the working directory in the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
# Delete old supersonic installation directory and the symbolic link
RUN rm -rf /usr/src/app/supersonic-standalone-0.9.10-SNAPSHOT
RUN rm -f /usr/src/app/supersonic-standalone-latest
# Argument to pass in the supersonic version at build time # Argument to pass in the supersonic version at build time
ARG SUPERSONIC_VERSION ARG SUPERSONIC_VERSION
# Install necessary packages, including Postgres client
RUN apt-get update && apt-get install -y postgresql-client
# Install the vim editor.
RUN apt-get update && apt-get install -y vim && \
rm -rf /var/lib/apt/lists/*
# Update the package list and install iputils-ping.
RUN apt-get update && apt-get install -y iputils-ping
# 更新包列表并安装 dnsutils 包
RUN apt-get update && apt-get install -y dnsutils
# Copy the supersonic standalone zip file into the container # Copy the supersonic standalone zip file into the container
COPY assembly/build/supersonic-standalone-${SUPERSONIC_VERSION}.zip . COPY assembly/build/supersonic-standalone-${SUPERSONIC_VERSION}.zip .

View File

@@ -12,7 +12,7 @@ services:
ports: ports:
- "15432:5432" - "15432:5432"
# volumes: # volumes:
# - postgres_data:/var/lib/postgresql # - postgres_data:/var/lib/postgresql/data
networks: networks:
- supersonic_network - supersonic_network
dns: dns:
@@ -21,7 +21,7 @@ services:
- 8.8.4.4 - 8.8.4.4
healthcheck: healthcheck:
test: ["CMD-SHELL", "sh -c 'pg_isready -U supersonic_user -d postgres'"] test: ["CMD-SHELL", "sh -c 'pg_isready -U supersonic_user -d postgres'"]
interval: 30s interval: 10s
timeout: 10s timeout: 10s
retries: 5 retries: 5
@@ -62,4 +62,4 @@ services:
# supersonic_data: # supersonic_data:
networks: networks:
supersonic_network: supersonic_network:

View File

@@ -133,6 +133,10 @@
<groupId>io.trino</groupId> <groupId>io.trino</groupId>
<artifactId>trino-jdbc</artifactId> <artifactId>trino-jdbc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
</dependency>
</dependencies> </dependencies>

View File

@@ -1,6 +1,7 @@
package com.tencent.supersonic.headless.core.translator; package com.tencent.supersonic.headless.core.translator;
import com.tencent.supersonic.common.calcite.SqlMergeWithUtils; import com.tencent.supersonic.common.calcite.SqlMergeWithUtils;
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.common.pojo.enums.EngineType;
import com.tencent.supersonic.headless.api.pojo.response.QueryState; import com.tencent.supersonic.headless.api.pojo.response.QueryState;
import com.tencent.supersonic.headless.core.pojo.OntologyQuery; import com.tencent.supersonic.headless.core.pojo.OntologyQuery;
@@ -73,7 +74,7 @@ public class DefaultSemanticTranslator implements SemanticTranslator {
String finalSql = null; String finalSql = null;
if (sqlQuery.isSupportWith()) { if (sqlQuery.isSupportWith()) {
EngineType engineType = queryStatement.getOntology().getDatabaseType(); EngineType engineType = queryStatement.getOntology().getDatabaseType();
if (!SqlMergeWithUtils.hasWith(engineType, ontologyOuterSql)) { if (!SqlSelectHelper.hasWith(ontologyOuterSql)) {
finalSql = "with " + tables.stream() finalSql = "with " + tables.stream()
.map(t -> String.format("%s as (%s)", t.getLeft(), t.getRight())) .map(t -> String.format("%s as (%s)", t.getLeft(), t.getRight()))
.collect(Collectors.joining(",")) + "\n" + ontologyOuterSql; .collect(Collectors.joining(",")) + "\n" + ontologyOuterSql;

View File

@@ -1,5 +1,6 @@
package com.tencent.supersonic.headless.core.translator.parser.calcite; package com.tencent.supersonic.headless.core.translator.parser.calcite;
import com.google.common.collect.Sets;
import com.tencent.supersonic.common.calcite.Configuration; import com.tencent.supersonic.common.calcite.Configuration;
import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.common.pojo.enums.EngineType;
import com.tencent.supersonic.headless.api.pojo.Dimension; import com.tencent.supersonic.headless.api.pojo.Dimension;
@@ -9,17 +10,26 @@ import com.tencent.supersonic.headless.api.pojo.response.DatabaseResp;
import com.tencent.supersonic.headless.api.pojo.response.DimSchemaResp; import com.tencent.supersonic.headless.api.pojo.response.DimSchemaResp;
import com.tencent.supersonic.headless.api.pojo.response.MetricSchemaResp; import com.tencent.supersonic.headless.api.pojo.response.MetricSchemaResp;
import com.tencent.supersonic.headless.api.pojo.response.ModelResp; import com.tencent.supersonic.headless.api.pojo.response.ModelResp;
import com.tencent.supersonic.headless.core.pojo.*; import com.tencent.supersonic.headless.core.pojo.JoinRelation;
import com.tencent.supersonic.headless.core.pojo.Ontology;
import com.tencent.supersonic.headless.core.pojo.OntologyQuery;
import com.tencent.supersonic.headless.core.pojo.QueryStatement;
import com.tencent.supersonic.headless.core.translator.parser.Constants; import com.tencent.supersonic.headless.core.translator.parser.Constants;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.sql.*; import org.apache.calcite.sql.*;
import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.validate.SqlValidatorScope; import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple; import org.apache.commons.lang3.tuple.Triple;
import org.springframework.util.CollectionUtils; import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DefaultUndirectedGraph;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -37,6 +47,8 @@ public class SqlBuilder {
public String buildOntologySql(QueryStatement queryStatement) throws Exception { public String buildOntologySql(QueryStatement queryStatement) throws Exception {
OntologyQuery ontologyQuery = queryStatement.getOntologyQuery(); OntologyQuery ontologyQuery = queryStatement.getOntologyQuery();
Ontology ontology = queryStatement.getOntology();
if (ontologyQuery.getLimit() == null) { if (ontologyQuery.getLimit() == null) {
ontologyQuery.setLimit(0L); ontologyQuery.setLimit(0L);
} }
@@ -46,7 +58,14 @@ public class SqlBuilder {
throw new Exception("data model not found"); throw new Exception("data model not found");
} }
TableView tableView = render(ontologyQuery, new ArrayList<>(dataModels), scope, schema); TableView tableView;
if (!CollectionUtils.isEmpty(ontology.getJoinRelations()) && dataModels.size() > 1) {
Set<ModelResp> models = probeRelatedModels(dataModels, queryStatement.getOntology());
tableView = render(ontologyQuery, models, scope, schema);
} else {
tableView = render(ontologyQuery, dataModels, scope, schema);
}
SqlNode parserNode = tableView.build(); SqlNode parserNode = tableView.build();
DatabaseResp database = queryStatement.getOntology().getDatabase(); DatabaseResp database = queryStatement.getOntology().getDatabase();
EngineType engineType = EngineType.fromString(database.getType()); EngineType engineType = EngineType.fromString(database.getType());
@@ -54,7 +73,61 @@ public class SqlBuilder {
return SemanticNode.getSql(parserNode, engineType); return SemanticNode.getSql(parserNode, engineType);
} }
private SqlNode optimizeParseNode(SqlNode parserNode, EngineType engineType) { private Set<ModelResp> probeRelatedModels(Set<ModelResp> dataModels, Ontology ontology) {
List<JoinRelation> joinRelations = ontology.getJoinRelations();
Graph<String, DefaultEdge> graph = buildGraph(joinRelations);
DijkstraShortestPath<String, DefaultEdge> dijkstraAlg = new DijkstraShortestPath<>(graph);
Set<String> queryModels =
dataModels.stream().map(ModelResp::getName).collect(Collectors.toSet());
GraphPath<String, DefaultEdge> selectedGraphPath = null;
for (String fromModel : queryModels) {
for (String toModel : queryModels) {
if (fromModel != toModel) {
GraphPath<String, DefaultEdge> path = dijkstraAlg.getPath(fromModel, toModel);
if (isGraphPathContainsAll(path, queryModels)) {
selectedGraphPath = path;
break;
}
}
}
}
if (selectedGraphPath == null) {
return dataModels;
}
Set<String> modelNames = Sets.newHashSet();
for (DefaultEdge edge : selectedGraphPath.getEdgeList()) {
modelNames.add(selectedGraphPath.getGraph().getEdgeSource(edge));
modelNames.add(selectedGraphPath.getGraph().getEdgeTarget(edge));
}
return modelNames.stream().map(m -> ontology.getModelMap().get(m))
.collect(Collectors.toSet());
}
private boolean isGraphPathContainsAll(GraphPath<String, DefaultEdge> graphPath,
Set<String> vertex) {
Set<String> allVertex = Sets.newHashSet();
for (DefaultEdge edge : graphPath.getEdgeList()) {
allVertex.add(graphPath.getGraph().getEdgeSource(edge));
allVertex.add(graphPath.getGraph().getEdgeTarget(edge));
}
Collection<String> intersect =
org.apache.commons.collections.CollectionUtils.intersection(vertex, allVertex);
return intersect.size() == vertex.size() ? true : false;
}
private Graph<String, DefaultEdge> buildGraph(List<JoinRelation> joinRelations) {
Graph<String, DefaultEdge> directedGraph = new DefaultUndirectedGraph<>(DefaultEdge.class);
for (JoinRelation joinRelation : joinRelations) {
directedGraph.addVertex(joinRelation.getLeft());
directedGraph.addVertex(joinRelation.getRight());
directedGraph.addEdge(joinRelation.getLeft(), joinRelation.getRight());
}
return directedGraph;
}
private SqlNode optimizeParseNode(SqlNode parserNode, EngineType engineType)
throws SqlParseException {
if (Objects.isNull(schema.getRuntimeOptions()) if (Objects.isNull(schema.getRuntimeOptions())
|| Objects.isNull(schema.getRuntimeOptions().getEnableOptimize()) || Objects.isNull(schema.getRuntimeOptions().getEnableOptimize())
|| !schema.getRuntimeOptions().getEnableOptimize()) { || !schema.getRuntimeOptions().getEnableOptimize()) {
@@ -62,14 +135,10 @@ public class SqlBuilder {
} }
SqlNode optimizeNode = null; SqlNode optimizeNode = null;
try { SqlNode sqlNode = SqlParser.create(SemanticNode.getSql(parserNode, engineType),
SqlNode sqlNode = SqlParser.create(SemanticNode.getSql(parserNode, engineType), Configuration.getParserConfig(engineType)).parseStmt();
Configuration.getParserConfig(engineType)).parseStmt(); if (Objects.nonNull(sqlNode)) {
if (Objects.nonNull(sqlNode)) { optimizeNode = SemanticNode.optimize(scope, schema, sqlNode, engineType);
optimizeNode = SemanticNode.optimize(scope, schema, sqlNode, engineType);
}
} catch (Exception e) {
log.error("optimize error {}", e);
} }
if (Objects.nonNull(optimizeNode)) { if (Objects.nonNull(optimizeNode)) {
@@ -79,7 +148,7 @@ public class SqlBuilder {
return parserNode; return parserNode;
} }
private TableView render(OntologyQuery ontologyQuery, List<ModelResp> dataModels, private TableView render(OntologyQuery ontologyQuery, Set<ModelResp> dataModels,
SqlValidatorScope scope, S2CalciteSchema schema) throws Exception { SqlValidatorScope scope, S2CalciteSchema schema) throws Exception {
SqlNode left = null; SqlNode left = null;
TableView leftTable = null; TableView leftTable = null;
@@ -88,8 +157,7 @@ public class SqlBuilder {
Map<String, String> beforeModels = new HashMap<>(); Map<String, String> beforeModels = new HashMap<>();
EngineType engineType = EngineType.fromString(schema.getOntology().getDatabase().getType()); EngineType engineType = EngineType.fromString(schema.getOntology().getDatabase().getType());
for (int i = 0; i < dataModels.size(); i++) { for (ModelResp dataModel : dataModels) {
final ModelResp dataModel = dataModels.get(i);
final Set<DimSchemaResp> queryDimensions = final Set<DimSchemaResp> queryDimensions =
ontologyQuery.getDimensionsByModel(dataModel.getName()); ontologyQuery.getDimensionsByModel(dataModel.getName());
final Set<MetricSchemaResp> queryMetrics = final Set<MetricSchemaResp> queryMetrics =
@@ -141,7 +209,8 @@ public class SqlBuilder {
SqlLiteral sqlLiteral = SemanticNode.getJoinSqlLiteral(""); SqlLiteral sqlLiteral = SemanticNode.getJoinSqlLiteral("");
JoinRelation matchJoinRelation = getMatchJoinRelation(before, rightTable, schema); JoinRelation matchJoinRelation = getMatchJoinRelation(before, rightTable, schema);
SqlNode joinRelationCondition; SqlNode joinRelationCondition;
if (!CollectionUtils.isEmpty(matchJoinRelation.getJoinCondition())) { if (!org.apache.commons.collections.CollectionUtils
.isEmpty(matchJoinRelation.getJoinCondition())) {
sqlLiteral = SemanticNode.getJoinSqlLiteral(matchJoinRelation.getJoinType()); sqlLiteral = SemanticNode.getJoinSqlLiteral(matchJoinRelation.getJoinType());
joinRelationCondition = getCondition(matchJoinRelation, scope, engineType); joinRelationCondition = getCondition(matchJoinRelation, scope, engineType);
condition = joinRelationCondition; condition = joinRelationCondition;
@@ -170,12 +239,19 @@ public class SqlBuilder {
} else if (joinRelation.getLeft() } else if (joinRelation.getLeft()
.equalsIgnoreCase(tableView.getDataModel().getName()) .equalsIgnoreCase(tableView.getDataModel().getName())
&& before.containsKey(joinRelation.getRight())) { && before.containsKey(joinRelation.getRight())) {
matchJoinRelation.setJoinCondition(joinRelation.getJoinCondition().stream() List<Triple<String, String, String>> candidateJoinCon = joinRelation
.getJoinCondition().stream()
.map(r -> Triple.of( .map(r -> Triple.of(
before.get(joinRelation.getRight()) + "." + r.getRight(), before.get(joinRelation.getRight()) + "." + r.getRight(),
r.getMiddle(), tableView.getAlias() + "." + r.getLeft())) r.getMiddle(), tableView.getAlias() + "." + r.getLeft()))
.collect(Collectors.toList())); .collect(Collectors.toList());
matchJoinRelation.setJoinType(joinRelation.getJoinType()); // added by jerryjzhang on 20250214
// use the one with the most conditions to join left and right tables
if (matchJoinRelation.getJoinCondition() == null || candidateJoinCon
.size() > matchJoinRelation.getJoinCondition().size()) {
matchJoinRelation.setJoinCondition(candidateJoinCon);
matchJoinRelation.setJoinType(joinRelation.getJoinType());
}
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package com.tencent.supersonic.headless.server.rest;
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
import com.tencent.supersonic.common.pojo.User; import com.tencent.supersonic.common.pojo.User;
import com.tencent.supersonic.common.pojo.enums.StatusEnum;
import com.tencent.supersonic.headless.api.pojo.MetaFilter; import com.tencent.supersonic.headless.api.pojo.MetaFilter;
import com.tencent.supersonic.headless.api.pojo.request.DataSetReq; import com.tencent.supersonic.headless.api.pojo.request.DataSetReq;
import com.tencent.supersonic.headless.api.pojo.response.DataSetResp; import com.tencent.supersonic.headless.api.pojo.response.DataSetResp;
@@ -51,6 +52,7 @@ public class DataSetController {
public List<DataSetResp> getDataSetList(@RequestParam("domainId") Long domainId) { public List<DataSetResp> getDataSetList(@RequestParam("domainId") Long domainId) {
MetaFilter metaFilter = new MetaFilter(); MetaFilter metaFilter = new MetaFilter();
metaFilter.setDomainId(domainId); metaFilter.setDomainId(domainId);
metaFilter.setStatus(StatusEnum.ONLINE.getCode());
return dataSetService.getDataSetList(metaFilter); return dataSetService.getDataSetList(metaFilter);
} }

View File

@@ -56,9 +56,9 @@ public class DataSetServiceImpl extends ServiceImpl<DataSetDOMapper, DataSetDO>
public DataSetResp save(DataSetReq dataSetReq, User user) { public DataSetResp save(DataSetReq dataSetReq, User user) {
dataSetReq.createdBy(user.getName()); dataSetReq.createdBy(user.getName());
DataSetDO dataSetDO = convert(dataSetReq); DataSetDO dataSetDO = convert(dataSetReq);
dataSetDO.setStatus(StatusEnum.ONLINE.getCode()); dataSetDO.setStatus(dataSetReq.getStatus() != null ? dataSetReq.getStatus()
: StatusEnum.ONLINE.getCode());
DataSetResp dataSetResp = convert(dataSetDO); DataSetResp dataSetResp = convert(dataSetDO);
// conflictCheck(dataSetResp);
save(dataSetDO); save(dataSetDO);
dataSetResp.setId(dataSetDO.getId()); dataSetResp.setId(dataSetDO.getId());
return dataSetResp; return dataSetResp;

View File

@@ -4,9 +4,9 @@ spring:
url: jdbc:postgresql://${DB_HOST}:${DB_PORT:5432}/${DB_NAME}?stringtype=unspecified url: jdbc:postgresql://${DB_HOST}:${DB_PORT:5432}/${DB_NAME}?stringtype=unspecified
username: ${DB_USERNAME} username: ${DB_USERNAME}
password: ${DB_PASSWORD} password: ${DB_PASSWORD}
sql: sql:
init: init:
continue-on-error: true
mode: always mode: always
username: ${DB_USERNAME} username: ${DB_USERNAME}
password: ${DB_PASSWORD} password: ${DB_PASSWORD}

View File

@@ -5,21 +5,21 @@ CREATE TABLE IF NOT EXISTS `s2_agent` (
`examples` TEXT COLLATE utf8_unicode_ci DEFAULT NULL, `examples` TEXT COLLATE utf8_unicode_ci DEFAULT NULL,
`status` tinyint DEFAULT NULL, `status` tinyint DEFAULT NULL,
`model` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `model` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`tool_config` varchar(6000) COLLATE utf8_unicode_ci DEFAULT NULL, `tool_config` TEXT COLLATE utf8_unicode_ci DEFAULT NULL,
`llm_config` varchar(2000) COLLATE utf8_unicode_ci DEFAULT NULL, `llm_config` TEXT COLLATE utf8_unicode_ci DEFAULT NULL,
`chat_model_config` text COLLATE utf8_unicode_ci DEFAULT NULL, `chat_model_config` text COLLATE utf8_unicode_ci DEFAULT NULL,
`visual_config` varchar(2000) COLLATE utf8_unicode_ci DEFAULT NULL, `visual_config` TEXT COLLATE utf8_unicode_ci DEFAULT NULL,
`enable_search` tinyint DEFAULT 1, `enable_search` tinyint DEFAULT 1,
`enable_feedback` tinyint DEFAULT 1, `enable_feedback` tinyint DEFAULT 1,
`created_by` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `created_by` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` datetime DEFAULT NULL, `created_at` datetime DEFAULT NULL,
`updated_by` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `updated_by` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`updated_at` datetime DEFAULT NULL, `updated_at` datetime DEFAULT NULL,
`admin` varchar(3000) DEFAULT NULL COMMENT '管理员', `admin` varchar(1000) DEFAULT NULL COMMENT '管理员',
`admin_org` varchar(3000) DEFAULT NULL COMMENT '管理员组织', `admin_org` varchar(1000) DEFAULT NULL COMMENT '管理员组织',
`is_open` tinyint DEFAULT NULL COMMENT '是否公开', `is_open` tinyint DEFAULT NULL COMMENT '是否公开',
`viewer` varchar(3000) DEFAULT NULL COMMENT '可用用户', `viewer` varchar(1000) DEFAULT NULL COMMENT '可用用户',
`view_org` varchar(3000) DEFAULT NULL COMMENT '可用组织', `view_org` varchar(1000) DEFAULT NULL COMMENT '可用组织',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

View File

@@ -26,7 +26,7 @@
</parent> </parent>
<properties> <properties>
<revision>0.9.10-SNAPSHOT</revision> <revision>1.0.0-SNAPSHOT</revision>
<java.source.version>21</java.source.version> <java.source.version>21</java.source.version>
<java.target.version>21</java.target.version> <java.target.version>21</java.target.version>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
@@ -82,6 +82,7 @@
<spotless.skip>false</spotless.skip> <spotless.skip>false</spotless.skip>
<stax2.version>4.2.1</stax2.version> <stax2.version>4.2.1</stax2.version>
<aws-java-sdk.version>1.12.780</aws-java-sdk.version> <aws-java-sdk.version>1.12.780</aws-java-sdk.version>
<jgrapht.version>1.5.2</jgrapht.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@@ -236,6 +237,11 @@
<artifactId>aws-java-sdk</artifactId> <artifactId>aws-java-sdk</artifactId>
<version>${aws-java-sdk.version}</version> <version>${aws-java-sdk.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>${jgrapht.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

@@ -155,29 +155,8 @@ export default defineConfig({
//================ pro 插件配置 ================= //================ pro 插件配置 =================
presets: ['umi-presets-pro'], presets: ['umi-presets-pro'],
/**
* @name openAPI 插件的配置
* @description 基于 openapi 的规范生成serve 和mock能减少很多样板代码
* @doc https://pro.ant.design/zh-cn/docs/openapi/
*/
// openAPI: [
// {
// requestLibPath: "import { request } from '@umijs/max'",
// // 或者使用在线的版本
// // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
// schemaPath: join(__dirname, 'oneapi.json'),
// mock: false,
// },
// {
// requestLibPath: "import { request } from '@umijs/max'",
// schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json',
// projectName: 'swagger',
// },
// ],
// 将insights-flow相关包排除出mfsu编译在pnpm link 模式下保持热更新
mfsu: { mfsu: {
strategy: 'normal', strategy: 'normal',
// exclude: ['supersonic-insights-flow-components', 'supersonic-insights-flow-core'],
}, },
requestRecord: {}, requestRecord: {},
exportStatic: {}, exportStatic: {},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -147,8 +147,8 @@ export const layout: RunTimeLayoutConfig = (params) => {
height: location.pathname.includes('chat') ? 'calc(100vh - 56px)' : undefined, height: location.pathname.includes('chat') ? 'calc(100vh - 56px)' : undefined,
}} }}
> >
<AppPage dom={dom} /> {/* <AppPage dom={dom} /> */}
{/* {dom} */} {dom}
{history.location.pathname !== '/chat' && !isMobile && ( {history.location.pathname !== '/chat' && !isMobile && (
<Copilot token={getToken() || ''} isDeveloper /> <Copilot token={getToken() || ''} isDeveloper />
)} )}

View File

@@ -1,9 +1,9 @@
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { Input, message, Popconfirm, Tooltip, Row, Col, Button, Menu } from 'antd'; import { Input, message, Popconfirm, Tooltip, Row, Col, Button, Menu, MenuProps } from 'antd';
import type { DataNode } from 'antd/lib/tree'; import type { DataNode } from 'antd/lib/tree';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { useModel } from '@umijs/max'; import { useModel, history } from '@umijs/max';
import { createDomain, updateDomain, deleteDomain } from '../service'; import { createDomain, updateDomain, deleteDomain } from '../service';
import DomainInfoForm from './DomainInfoForm'; import DomainInfoForm from './DomainInfoForm';
import styles from './style.less'; import styles from './style.less';
@@ -71,6 +71,7 @@ const DomainListTree: FC<DomainListProps> = ({
message.success('编辑分类成功'); message.success('编辑分类成功');
setProjectInfoModalVisible(false); setProjectInfoModalVisible(false);
onTreeDataUpdate?.(); onTreeDataUpdate?.();
window.location.reload();
} else { } else {
message.error(res.msg); message.error(res.msg);
} }
@@ -78,10 +79,13 @@ const DomainListTree: FC<DomainListProps> = ({
const domainSubmit = async (values: any) => { const domainSubmit = async (values: any) => {
if (values.modelType === 'add') { if (values.modelType === 'add') {
const { code, data } = await createDomain(values); const { code, data, msg } = await createDomain(values);
// if (code === 200 && values.type === 'top') { if (code === 200) {
// await createDefaultModelSet(data.id); history.push(`/model/domain/${data.id}`);
// } window.location.reload();
} else {
message.error(msg);
}
} else if (values.modelType === 'edit') { } else if (values.modelType === 'edit') {
await editProject(values); await editProject(values);
} }
@@ -95,6 +99,7 @@ const DomainListTree: FC<DomainListProps> = ({
message.success('删除成功'); message.success('删除成功');
setProjectInfoModalVisible(false); setProjectInfoModalVisible(false);
onTreeDataUpdate?.(); onTreeDataUpdate?.();
window.location.reload();
} else { } else {
message.error(res.msg); message.error(res.msg);
} }
@@ -104,12 +109,7 @@ const DomainListTree: FC<DomainListProps> = ({
const { id, name, path, hasEditPermission, parentId, hasModel } = node as any; const { id, name, path, hasEditPermission, parentId, hasModel } = node as any;
const type = parentId === 0 ? 'top' : 'normal'; const type = parentId === 0 ? 'top' : 'normal';
return ( return (
<div <div className={styles.projectItem}>
className={styles.projectItem}
// onClick={() => {
// handleSelect(id);
// }}
>
<span className={styles.projectItemTitle}>{name}</span> <span className={styles.projectItemTitle}>{name}</span>
{createDomainBtnVisible && hasEditPermission && ( {createDomainBtnVisible && hasEditPermission && (
<span className={`${styles.operation} ${styles.rowHover} `}> <span className={`${styles.operation} ${styles.rowHover} `}>
@@ -175,13 +175,12 @@ const DomainListTree: FC<DomainListProps> = ({
return { return {
key: domain.id, key: domain.id,
label: titleRender(domain), label: titleRender(domain),
// icon: <AppstoreOutlined />,
}; };
}); });
const getLevelKeys = (items1: LevelKeysProps[]) => { const getLevelKeys = (items1: any[]) => {
const key: Record<string, number> = {}; const key: Record<string, number> = {};
const func = (items2: LevelKeysProps[], level = 1) => { const func = (items2: any[], level = 1) => {
items2.forEach((item) => { items2.forEach((item) => {
if (item.key) { if (item.key) {
key[item.key] = level; key[item.key] = level;
@@ -194,7 +193,7 @@ const DomainListTree: FC<DomainListProps> = ({
func(items1); func(items1);
return key; return key;
}; };
const levelKeys = getLevelKeys(items as LevelKeysProps[]); const levelKeys = getLevelKeys(items as any[]);
const [stateOpenKeys, setStateOpenKeys] = useState(['2', '23']); const [stateOpenKeys, setStateOpenKeys] = useState(['2', '23']);
const onOpenChange: MenuProps['onOpenChange'] = (openKeys) => { const onOpenChange: MenuProps['onOpenChange'] = (openKeys) => {

View File

@@ -82,6 +82,7 @@ const ModelTable: React.FC<Props> = ({ modelList, disabledEdit = false, onModelC
}); });
if (code === 200) { if (code === 200) {
onModelChange?.(); onModelChange?.();
window.location.reload();
return; return;
} }
message.error(msg); message.error(msg);
@@ -198,6 +199,7 @@ const ModelTable: React.FC<Props> = ({ modelList, disabledEdit = false, onModelC
const { code, msg } = await deleteModel(record.id); const { code, msg } = await deleteModel(record.id);
if (code === 200) { if (code === 200) {
onModelChange?.(); onModelChange?.();
window.location.reload();
} else { } else {
message.error(msg); message.error(msg);
} }
@@ -292,6 +294,7 @@ const ModelTable: React.FC<Props> = ({ modelList, disabledEdit = false, onModelC
onModelChange?.(); onModelChange?.();
setIsEditing(false); setIsEditing(false);
setCreateDataSourceModalOpen(false); setCreateDataSourceModalOpen(false);
window.location.reload();
}} }}
onCancel={() => { onCancel={() => {
setIsEditing(false); setIsEditing(false);

View File

@@ -1,11 +1,8 @@
import { message } from 'antd'; import { message } from 'antd';
import React, { useEffect, useState } from 'react'; import React, { useEffect } from 'react';
import { history, useParams, useModel, Outlet } from '@umijs/max'; import { useParams, useModel, Outlet } from '@umijs/max';
import DomainListTree from './components/DomainList';
import styles from './components/style.less';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { ISemantic } from './data'; import { ISemantic } from './data';
import { getDomainList, getDataSetList, getModelDetail } from './service'; import { getDomainList, getModelDetail } from './service';
import PageBreadcrumb from './PageBreadcrumb'; import PageBreadcrumb from './PageBreadcrumb';
type Props = {}; type Props = {};
@@ -17,20 +14,10 @@ const SemanticModel: React.FC<Props> = ({}) => {
const domainModel = useModel('SemanticModel.domainData'); const domainModel = useModel('SemanticModel.domainData');
const modelModel = useModel('SemanticModel.modelData'); const modelModel = useModel('SemanticModel.modelData');
const databaseModel = useModel('SemanticModel.databaseData'); const databaseModel = useModel('SemanticModel.databaseData');
const metricModel = useModel('SemanticModel.metricData'); const { setSelectDomain, setDomainList } = domainModel;
const { setSelectDomain, setDomainList, selectDomainId } = domainModel; const { selectModel, setSelectModel } = modelModel;
const { selectModel, setSelectModel, setModelTableHistoryParams, MrefreshModelList } = modelModel;
const { MrefreshDatabaseList } = databaseModel; const { MrefreshDatabaseList } = databaseModel;
const { selectMetric, setSelectMetric } = metricModel;
// useEffect(() => {
// return () => {
// setSelectMetric(undefined);
// }
// }, [])
const initSelectedDomain = (domainList: ISemantic.IDomainItem[]) => { const initSelectedDomain = (domainList: ISemantic.IDomainItem[]) => {
const targetNode = domainList.filter((item: any) => { const targetNode = domainList.filter((item: any) => {
return `${item.id}` === domainId; return `${item.id}` === domainId;
@@ -40,9 +27,7 @@ const SemanticModel: React.FC<Props> = ({}) => {
return item.parentId === 0; return item.parentId === 0;
})[0]; })[0];
if (firstRootNode) { if (firstRootNode) {
const { id } = firstRootNode;
setSelectDomain(firstRootNode); setSelectDomain(firstRootNode);
// pushUrlMenu(id, menuKey);
} }
} else { } else {
setSelectDomain(targetNode); setSelectDomain(targetNode);
@@ -87,7 +72,6 @@ const SemanticModel: React.FC<Props> = ({}) => {
</div> </div>
<div> <div>
<Outlet /> <Outlet />
{/* <OverviewContainer /> */}
</div> </div>
</div> </div>
); );

View File

@@ -3,7 +3,7 @@ import { useState, useEffect } from 'react';
import { useModel } from '@umijs/max'; import { useModel } from '@umijs/max';
export default function Domain() { export default function Domain() {
const [selectDomain, setSelectDomain] = useState<ISemantic.IDomainItem>( const [selectDomain, setSelectDomain] = useState<ISemantic.IDomainItem | undefined>(
{} as ISemantic.IDomainItem, {} as ISemantic.IDomainItem,
); );
const [selectDataSet, setSelectDataSet] = useState<ISemantic.IDatasetItem>(); const [selectDataSet, setSelectDataSet] = useState<ISemantic.IDatasetItem>();