feature: support search group & project in global system (#178)

* feat: add global search api

* featï: add global search menu
This commit is contained in:
vran 2022-05-16 08:55:41 +08:00 committed by GitHub
parent 59570a9ee6
commit ff3f2e111f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 227 additions and 49 deletions

View File

@ -182,4 +182,8 @@ public interface Routes {
String GET_SQL_MOCK_DATA = BASE + "/groups/{groupId}/projects/{projectId}/mock_data/sql";
}
interface Search {
String SEARCH = BASE + "/search";
}
}

View File

@ -0,0 +1,27 @@
package com.databasir.api;
import com.databasir.common.JsonData;
import com.databasir.core.domain.search.SearchService;
import com.databasir.core.domain.search.data.SearchResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@Validated
@Tag(name = "SearchController", description = "全局搜索 API")
public class SearchController {
private final SearchService searchService;
@GetMapping(Routes.Search.SEARCH)
@Operation(summary = "搜索")
public JsonData<SearchResponse> search(@RequestParam(name = "query") String keyword) {
return JsonData.ok(searchService.search(keyword));
}
}

View File

@ -1 +0,0 @@
.left-menu:not(.el-menu--collapse){height:100vh}.databasir-nav{left:0;bottom:0}.databasir-main-header,.databasir-nav{position:fixed;transform:scale(1);top:0}.databasir-main-header{display:flex;justify-content:space-between;align-items:center;right:0;left:50px;padding:30px;margin-left:33px;background:#fff;z-index:100;border-color:#eee;border-width:0 0 1px 0;border-style:solid}.databasir{display:block}.databasir-main{position:relative;margin-left:60px;margin-top:80px;--el-main-padding:0px 20px 20px 20px}.databasir-main-expand{margin-left:50px}.databasir-main-content{max-width:95%;--el-main-padding:0px 20px 20px 20px}.h2{font-size:24px;color:#606266;margin-top:13px;margin-bottom:13px}.h2,.h3{font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,,Arial,sans-serif}.h3{font-size:20px;color:#909399;margin-top:18px;margin-bottom:18px}

View File

@ -0,0 +1 @@
.left-menu:not(.el-menu--collapse){height:100vh}.search-item{padding:10px;width:99%;margin-bottom:12px;margin-right:12px;display:flex;justify-content:space-between;border-radius:8px}.search-item:hover{background-color:#f0f2f5}.search-item .jump{margin-right:8px}.search-container{max-height:420px;overflow-y:auto;overflow-x:hidden}.databasir-nav{left:0;bottom:0}.databasir-main-header,.databasir-nav{position:fixed;transform:scale(1);top:0}.databasir-main-header{display:flex;justify-content:space-between;align-items:center;right:0;left:50px;padding:30px;margin-left:33px;background:#fff;z-index:100;border-color:#eee;border-width:0 0 1px 0;border-style:solid}.databasir{display:block}.databasir-main{position:relative;margin-left:60px;margin-top:80px;--el-main-padding:0px 20px 20px 20px}.databasir-main-expand{margin-left:50px}.databasir-main-content{max-width:95%;--el-main-padding:0px 20px 20px 20px}.h2{font-size:24px;color:#606266;margin-top:13px;margin-bottom:13px}.h2,.h3{font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,,Arial,sans-serif}.h3{font-size:20px;color:#909399;margin-top:18px;margin-bottom:18px}

View File

@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir</title><script defer="defer" type="module" src="/js/chunk-vendors.9effab81.js"></script><script defer="defer" type="module" src="/js/app.1aa391ea.js"></script><link href="/css/chunk-vendors.81898547.css" rel="stylesheet"><link href="/css/app.15b40a89.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.fb0c8458.js" nomodule></script><script defer="defer" src="/js/app-legacy.18135b1d.js" nomodule></script></head><body><noscript><strong>We're sorry but databasir doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir</title><script defer="defer" type="module" src="/js/chunk-vendors.4f3fe369.js"></script><script defer="defer" type="module" src="/js/app.7ac511a9.js"></script><link href="/css/chunk-vendors.81898547.css" rel="stylesheet"><link href="/css/app.ee11d130.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.572a3b83.js" nomodule></script><script defer="defer" src="/js/app-legacy.94b013ac.js" nomodule></script></head><body><noscript><strong>We're sorry but databasir doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
package com.databasir.core.domain.search;
import com.databasir.core.domain.search.converter.SearchResponseConverter;
import com.databasir.core.domain.search.data.SearchResponse;
import com.databasir.dao.impl.GroupDao;
import com.databasir.dao.impl.ProjectDao;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class SearchService {
private final ProjectDao projectDao;
private final GroupDao groupDao;
private final SearchResponseConverter searchResponseConverter;
public SearchResponse search(String query) {
var groupPojoList = groupDao.selectByName(query);
var groupResults = searchResponseConverter.toGroupResults(groupPojoList);
var projectList = projectDao.selectByProjectNameOrDatabaseOrSchemaOrGroup(query);
var projectResults = searchResponseConverter.toProjectResults(projectList);
// build response
SearchResponse response = new SearchResponse();
response.setGroups(groupResults);
response.setProjects(projectResults);
// TODO support Table search
return response;
}
}

View File

@ -0,0 +1,16 @@
package com.databasir.core.domain.search.converter;
import com.databasir.core.domain.search.data.SearchResponse;
import com.databasir.dao.tables.pojos.GroupPojo;
import com.databasir.dao.value.ProjectQueryPojo;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring")
public interface SearchResponseConverter {
List<SearchResponse.GroupSearchResult> toGroupResults(List<GroupPojo> groups);
List<SearchResponse.ProjectSearchResult> toProjectResults(List<ProjectQueryPojo> projects);
}

View File

@ -0,0 +1,51 @@
package com.databasir.core.domain.search.data;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Collections;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SearchResponse {
@Builder.Default
private List<GroupSearchResult> groups = Collections.emptyList();
@Builder.Default
private List<ProjectSearchResult> projects = Collections.emptyList();
@Data
public static class GroupSearchResult {
private Integer id;
private String name;
private String description;
}
@Data
public static class ProjectSearchResult {
private Integer projectId;
private Integer groupId;
private String groupName;
private String projectName;
private String projectDescription;
private String databaseName;
private String schemaName;
}
}

View File

@ -69,4 +69,12 @@ public class GroupDao extends BaseDao<GroupPojo> {
.where(GROUP.ID.in(ids))
.fetchInto(GroupPojo.class);
}
public List<GroupPojo> selectByName(String nameContains) {
return getDslContext()
.select(GROUP.fields()).from(GROUP)
.where(GROUP.NAME.contains(nameContains))
.and(GROUP.DELETED.eq(false))
.fetchInto(GroupPojo.class);
}
}

View File

@ -2,6 +2,7 @@ package com.databasir.dao.impl;
import com.databasir.dao.tables.pojos.ProjectPojo;
import com.databasir.dao.value.GroupProjectCountPojo;
import com.databasir.dao.value.ProjectQueryPojo;
import lombok.Getter;
import org.jooq.Condition;
import org.jooq.DSLContext;
@ -19,8 +20,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.databasir.dao.Tables.DATA_SOURCE;
import static com.databasir.dao.Tables.PROJECT;
import static com.databasir.dao.Tables.*;
@Repository
public class ProjectDao extends BaseDao<ProjectPojo> {
@ -126,4 +126,28 @@ public class ProjectDao extends BaseDao<ProjectPojo> {
.where(PROJECT.ID.in(projectIds))
.fetchMap(PROJECT.ID, PROJECT.GROUP_ID);
}
public List<ProjectQueryPojo> selectByProjectNameOrDatabaseOrSchemaOrGroup(String query) {
return getDslContext()
.select(
PROJECT.ID.as("project_id"),
PROJECT.NAME.as("project_name"),
PROJECT.DESCRIPTION.as("project_description"),
DATA_SOURCE.DATABASE_NAME,
DATA_SOURCE.SCHEMA_NAME,
GROUP.NAME.as("group_name"),
GROUP.ID.as("group_id")
)
.from(PROJECT)
.leftJoin(DATA_SOURCE).on(DATA_SOURCE.PROJECT_ID.eq(PROJECT.ID))
.leftJoin(GROUP).on(GROUP.ID.eq(PROJECT.GROUP_ID))
.where(PROJECT.DELETED.eq(false)
.and(GROUP.DELETED.eq(false))
.and(PROJECT.NAME.contains(query)
.or(DATA_SOURCE.DATABASE_NAME.contains(query))
.or(DATA_SOURCE.SCHEMA_NAME.contains(query))
.or(GROUP.NAME.contains(query)))
)
.fetchInto(ProjectQueryPojo.class);
}
}

View File

@ -0,0 +1,21 @@
package com.databasir.dao.value;
import lombok.Data;
@Data
public class ProjectQueryPojo {
private Integer projectId;
private Integer groupId;
private String groupName;
private String projectName;
private String projectDescription;
private String databaseName;
private String schemaName;
}

@ -1 +1 @@
Subproject commit b027e133261b2df4e56bc6cab26fcb99113e0f0e
Subproject commit f616e30e5bac5d500ce6722cd550329a731b8fac