refactor: shorten model and table prefixes
This commit is contained in:
@@ -33,11 +33,11 @@ func TestSearchHandlerRejectsBlankQuery(t *testing.T) {
|
||||
func TestSearchHandlerReturnsCamelCaseIdentityResults(t *testing.T) {
|
||||
database := newSearchHandlerTestDB(t)
|
||||
owner := createSearchUser(t, database, "owner@example.com")
|
||||
project := models.SenlinAgentProject{OwnerID: owner.ID, Name: "回调平台", Identifier: "CALLBACK"}
|
||||
project := models.SaProject{OwnerID: owner.ID, Name: "回调平台", Identifier: "CALLBACK"}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
task := models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "回调任务", Description: "检查签名", Status: "open"}
|
||||
task := models.SaTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "回调任务", Description: "检查签名", Status: "open"}
|
||||
require.NoError(t, database.Create(&task).Error)
|
||||
note := models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "接口说明", Markdown: "回调验签流程"}
|
||||
note := models.SaNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "接口说明", Markdown: "回调验签流程"}
|
||||
require.NoError(t, database.Create(¬e).Error)
|
||||
router := searchHandlerTestRouter(owner.ID)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/search?q=%E5%9B%9E%E8%B0%83", nil)
|
||||
@@ -73,25 +73,25 @@ func TestSearchHandlerOnlyReturnsObjectsVisibleToCurrentUser(t *testing.T) {
|
||||
database := newSearchHandlerTestDB(t)
|
||||
owner := createSearchUser(t, database, "owner@example.com")
|
||||
viewer := createSearchUser(t, database, "viewer@example.com")
|
||||
project := models.SenlinAgentProject{OwnerID: owner.ID, Name: "保密检索词项目", Identifier: "PRIVATE"}
|
||||
project := models.SaProject{OwnerID: owner.ID, Name: "保密检索词项目", Identifier: "PRIVATE"}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
assigned := models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: owner.ID, AssigneeID: &viewer.ID, Title: "检索词已指派任务", Status: "open"}
|
||||
assigned := models.SaTask{ProjectID: project.ID, CreatedBy: owner.ID, AssigneeID: &viewer.ID, Title: "检索词已指派任务", Status: "open"}
|
||||
require.NoError(t, database.Create(&assigned).Error)
|
||||
privateTask := models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "检索词私有任务", Status: "open"}
|
||||
privateTask := models.SaTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "检索词私有任务", Status: "open"}
|
||||
require.NoError(t, database.Create(&privateTask).Error)
|
||||
sharedNote := models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "检索词共享笔记", Markdown: "已显式分享"}
|
||||
sharedNote := models.SaNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "检索词共享笔记", Markdown: "已显式分享"}
|
||||
require.NoError(t, database.Create(&sharedNote).Error)
|
||||
privateNote := models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "检索词私有笔记", Markdown: "不得泄漏"}
|
||||
privateNote := models.SaNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "检索词私有笔记", Markdown: "不得泄漏"}
|
||||
require.NoError(t, database.Create(&privateNote).Error)
|
||||
otherProject := models.SenlinAgentProject{OwnerID: owner.ID, Name: "其他项目", Identifier: "OTHER"}
|
||||
otherProject := models.SaProject{OwnerID: owner.ID, Name: "其他项目", Identifier: "OTHER"}
|
||||
require.NoError(t, database.Create(&otherProject).Error)
|
||||
crossProjectNote := models.SenlinAgentNote{ProjectID: otherProject.ID, CreatedBy: owner.ID, Title: "检索词跨项目笔记", Markdown: "伪造分享也不得泄漏"}
|
||||
crossProjectNote := models.SaNote{ProjectID: otherProject.ID, CreatedBy: owner.ID, Title: "检索词跨项目笔记", Markdown: "伪造分享也不得泄漏"}
|
||||
require.NoError(t, database.Create(&crossProjectNote).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTaskShare{
|
||||
require.NoError(t, database.Create(&models.SaTaskShare{
|
||||
TaskID: assigned.ID, ObjectType: "note", ObjectID: sharedNote.ID,
|
||||
}).Error)
|
||||
// 即使历史数据绕过服务层写入跨项目分享,搜索也必须在读取边界再次校验项目一致性。
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTaskShare{
|
||||
require.NoError(t, database.Create(&models.SaTaskShare{
|
||||
TaskID: assigned.ID, ObjectType: "note", ObjectID: crossProjectNote.ID,
|
||||
}).Error)
|
||||
router := searchHandlerTestRouter(viewer.ID)
|
||||
@@ -145,9 +145,9 @@ func newSearchHandlerTestDB(t *testing.T) *gorm.DB {
|
||||
return database
|
||||
}
|
||||
|
||||
func createSearchUser(t *testing.T, database *gorm.DB, email string) models.SenlinAgentUser {
|
||||
func createSearchUser(t *testing.T, database *gorm.DB, email string) models.SaUser {
|
||||
t.Helper()
|
||||
user := models.SenlinAgentUser{Email: email, DisplayName: email, PasswordHash: "hash"}
|
||||
user := models.SaUser{Email: email, DisplayName: email, PasswordHash: "hash"}
|
||||
require.NoError(t, database.Create(&user).Error)
|
||||
return user
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (s *Service) Search(userID uint, query string) ([]SearchResultDTO, error) {
|
||||
operator = "ILIKE"
|
||||
}
|
||||
|
||||
var projects []models.SenlinAgentProject
|
||||
var projects []models.SaProject
|
||||
projectFilter := fmt.Sprintf("owner_id = ? AND (name %s ? ESCAPE '!' OR description %s ? ESCAPE '!')", operator, operator)
|
||||
if err := s.database().Where(projectFilter, userID, like, like).
|
||||
Order("updated_at DESC").Order("identity ASC").
|
||||
@@ -75,11 +75,11 @@ func (s *Service) Search(userID uint, query string) ([]SearchResultDTO, error) {
|
||||
})
|
||||
}
|
||||
|
||||
var tasks []models.SenlinAgentTask
|
||||
taskFilter := fmt.Sprintf("(senlin_agent_projects.owner_id = ? OR senlin_agent_tasks.assignee_id = ?) AND (senlin_agent_tasks.title %s ? ESCAPE '!' OR senlin_agent_tasks.description %s ? ESCAPE '!')", operator, operator)
|
||||
if err := s.database().Select("senlin_agent_tasks.*").Joins("JOIN senlin_agent_projects ON senlin_agent_projects.id = senlin_agent_tasks.project_id").
|
||||
var tasks []models.SaTask
|
||||
taskFilter := fmt.Sprintf("(sa_projects.owner_id = ? OR sa_tasks.assignee_id = ?) AND (sa_tasks.title %s ? ESCAPE '!' OR sa_tasks.description %s ? ESCAPE '!')", operator, operator)
|
||||
if err := s.database().Select("sa_tasks.*").Joins("JOIN sa_projects ON sa_projects.id = sa_tasks.project_id").
|
||||
Where(taskFilter, userID, userID, like, like).
|
||||
Order("senlin_agent_tasks.updated_at DESC").Order("senlin_agent_tasks.identity ASC").
|
||||
Order("sa_tasks.updated_at DESC").Order("sa_tasks.identity ASC").
|
||||
Limit(maxSearchResults).
|
||||
Find(&tasks).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -92,18 +92,18 @@ func (s *Service) Search(userID uint, query string) ([]SearchResultDTO, error) {
|
||||
})
|
||||
}
|
||||
|
||||
var notes []models.SenlinAgentNote
|
||||
noteFilter := fmt.Sprintf(`(senlin_agent_projects.owner_id = ? OR EXISTS (
|
||||
SELECT 1 FROM senlin_agent_task_shares
|
||||
JOIN senlin_agent_tasks ON senlin_agent_tasks.id = senlin_agent_task_shares.task_id
|
||||
WHERE senlin_agent_task_shares.object_type = 'note'
|
||||
AND senlin_agent_task_shares.object_id = senlin_agent_notes.id
|
||||
AND senlin_agent_tasks.project_id = senlin_agent_notes.project_id
|
||||
AND senlin_agent_tasks.assignee_id = ?
|
||||
)) AND (senlin_agent_notes.title %s ? ESCAPE '!' OR senlin_agent_notes.markdown %s ? ESCAPE '!')`, operator, operator)
|
||||
if err := s.database().Select("senlin_agent_notes.*").Joins("JOIN senlin_agent_projects ON senlin_agent_projects.id = senlin_agent_notes.project_id").
|
||||
var notes []models.SaNote
|
||||
noteFilter := fmt.Sprintf(`(sa_projects.owner_id = ? OR EXISTS (
|
||||
SELECT 1 FROM sa_task_shares
|
||||
JOIN sa_tasks ON sa_tasks.id = sa_task_shares.task_id
|
||||
WHERE sa_task_shares.object_type = 'note'
|
||||
AND sa_task_shares.object_id = sa_notes.id
|
||||
AND sa_tasks.project_id = sa_notes.project_id
|
||||
AND sa_tasks.assignee_id = ?
|
||||
)) AND (sa_notes.title %s ? ESCAPE '!' OR sa_notes.markdown %s ? ESCAPE '!')`, operator, operator)
|
||||
if err := s.database().Select("sa_notes.*").Joins("JOIN sa_projects ON sa_projects.id = sa_notes.project_id").
|
||||
Where(noteFilter, userID, userID, like, like).
|
||||
Order("senlin_agent_notes.updated_at DESC").Order("senlin_agent_notes.identity ASC").
|
||||
Order("sa_notes.updated_at DESC").Order("sa_notes.identity ASC").
|
||||
Limit(maxSearchResults).
|
||||
Find(¬es).Error; err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
func TestPostgresSearchMatchesChinesePartialKeywords(t *testing.T) {
|
||||
database := newPostgresSearchTestDB(t)
|
||||
owner := createSearchUser(t, database, "postgres-search-owner@example.com")
|
||||
project := models.SenlinAgentProject{OwnerID: owner.ID, Name: "中文回调平台", Identifier: "PG-CALLBACK"}
|
||||
project := models.SaProject{OwnerID: owner.ID, Name: "中文回调平台", Identifier: "PG-CALLBACK"}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "回调任务", Status: "open"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "说明", Markdown: "回调验签流程"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "回调任务", Status: "open"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "说明", Markdown: "回调验签流程"}).Error)
|
||||
|
||||
results, err := NewService(database).Search(owner.ID, "回调")
|
||||
|
||||
@@ -33,15 +33,15 @@ func TestPostgresSearchKeepsAssignmentAndExplicitShareBoundaries(t *testing.T) {
|
||||
database := newPostgresSearchTestDB(t)
|
||||
owner := createSearchUser(t, database, "postgres-privacy-owner@example.com")
|
||||
viewer := createSearchUser(t, database, "postgres-privacy-viewer@example.com")
|
||||
project := models.SenlinAgentProject{OwnerID: owner.ID, Name: "保密项目", Identifier: "PG-PRIVATE"}
|
||||
project := models.SaProject{OwnerID: owner.ID, Name: "保密项目", Identifier: "PG-PRIVATE"}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
assigned := models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: owner.ID, AssigneeID: &viewer.ID, Title: "边界词已指派", Status: "open"}
|
||||
assigned := models.SaTask{ProjectID: project.ID, CreatedBy: owner.ID, AssigneeID: &viewer.ID, Title: "边界词已指派", Status: "open"}
|
||||
require.NoError(t, database.Create(&assigned).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "边界词私有任务", Status: "open"}).Error)
|
||||
sharedNote := models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "边界词共享笔记"}
|
||||
require.NoError(t, database.Create(&models.SaTask{ProjectID: project.ID, CreatedBy: owner.ID, Title: "边界词私有任务", Status: "open"}).Error)
|
||||
sharedNote := models.SaNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "边界词共享笔记"}
|
||||
require.NoError(t, database.Create(&sharedNote).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "边界词私有笔记"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTaskShare{TaskID: assigned.ID, ObjectType: "note", ObjectID: sharedNote.ID}).Error)
|
||||
require.NoError(t, database.Create(&models.SaNote{ProjectID: project.ID, CreatedBy: owner.ID, Title: "边界词私有笔记"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaTaskShare{TaskID: assigned.ID, ObjectType: "note", ObjectID: sharedNote.ID}).Error)
|
||||
|
||||
results, err := NewService(database).Search(viewer.ID, "边界词")
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestPostgresSearchUsesStableFairLimitAndRuneBoundedSnippets(t *testing.T) {
|
||||
owner := createSearchUser(t, database, "postgres-search-order@example.com")
|
||||
baseTime := time.Date(2026, time.July, 21, 12, 0, 0, 0, time.UTC)
|
||||
for index := 0; index < 60; index++ {
|
||||
project := models.SenlinAgentProject{
|
||||
project := models.SaProject{
|
||||
Identity: fmt.Sprintf("00000000-0000-7001-8000-%012d", index),
|
||||
OwnerID: owner.ID,
|
||||
Name: fmt.Sprintf("稳定排序项目 %02d", index),
|
||||
@@ -63,7 +63,7 @@ func TestPostgresSearchUsesStableFairLimitAndRuneBoundedSnippets(t *testing.T) {
|
||||
UpdatedAt: baseTime.Add(time.Duration(index) * time.Minute),
|
||||
}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTask{
|
||||
require.NoError(t, database.Create(&models.SaTask{
|
||||
Identity: fmt.Sprintf("00000000-0000-7002-8000-%012d", index),
|
||||
ProjectID: project.ID,
|
||||
CreatedBy: owner.ID,
|
||||
@@ -71,7 +71,7 @@ func TestPostgresSearchUsesStableFairLimitAndRuneBoundedSnippets(t *testing.T) {
|
||||
Status: "open",
|
||||
UpdatedAt: baseTime.Add(time.Duration(index) * time.Minute),
|
||||
}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{
|
||||
require.NoError(t, database.Create(&models.SaNote{
|
||||
Identity: fmt.Sprintf("00000000-0000-7003-8000-%012d", index),
|
||||
ProjectID: project.ID,
|
||||
CreatedBy: owner.ID,
|
||||
|
||||
@@ -17,8 +17,8 @@ func TestSearchFindsNoteBody(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, models.AutoMigrate(database))
|
||||
models.DBService = database
|
||||
require.NoError(t, database.Create(&models.SenlinAgentProject{ID: 1, OwnerID: 7, Name: "支付项目"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{ProjectID: 1, CreatedBy: 7, Title: "接口方案", Markdown: "二维码支付回调设计"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaProject{ID: 1, OwnerID: 7, Name: "支付项目"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaNote{ProjectID: 1, CreatedBy: 7, Title: "接口方案", Markdown: "二维码支付回调设计"}).Error)
|
||||
|
||||
service := NewService()
|
||||
results, err := service.Search(7, "回调")
|
||||
@@ -36,7 +36,7 @@ func TestSearchAppliesStableFairGlobalLimitAcrossResultTypes(t *testing.T) {
|
||||
|
||||
baseTime := time.Date(2026, time.July, 21, 12, 0, 0, 0, time.UTC)
|
||||
for index := 0; index < 60; index++ {
|
||||
project := models.SenlinAgentProject{
|
||||
project := models.SaProject{
|
||||
Identity: fmt.Sprintf("00000000-0000-7001-8000-%012d", index),
|
||||
OwnerID: 7,
|
||||
Name: fmt.Sprintf("稳定排序项目 %02d", index),
|
||||
@@ -44,7 +44,7 @@ func TestSearchAppliesStableFairGlobalLimitAcrossResultTypes(t *testing.T) {
|
||||
UpdatedAt: baseTime.Add(time.Duration(index) * time.Minute),
|
||||
}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTask{
|
||||
require.NoError(t, database.Create(&models.SaTask{
|
||||
Identity: fmt.Sprintf("00000000-0000-7002-8000-%012d", index),
|
||||
ProjectID: project.ID,
|
||||
CreatedBy: 7,
|
||||
@@ -52,7 +52,7 @@ func TestSearchAppliesStableFairGlobalLimitAcrossResultTypes(t *testing.T) {
|
||||
Status: "open",
|
||||
UpdatedAt: baseTime.Add(time.Duration(index) * time.Minute),
|
||||
}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{
|
||||
require.NoError(t, database.Create(&models.SaNote{
|
||||
Identity: fmt.Sprintf("00000000-0000-7003-8000-%012d", index),
|
||||
ProjectID: project.ID,
|
||||
CreatedBy: 7,
|
||||
@@ -89,9 +89,9 @@ func TestSearchBoundsChineseSnippetsByRune(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, models.AutoMigrate(database))
|
||||
models.DBService = database
|
||||
project := models.SenlinAgentProject{OwnerID: 7, Name: "摘要项目", Identifier: "SNIPPET"}
|
||||
project := models.SaProject{OwnerID: 7, Name: "摘要项目", Identifier: "SNIPPET"}
|
||||
require.NoError(t, database.Create(&project).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{
|
||||
require.NoError(t, database.Create(&models.SaNote{
|
||||
ProjectID: project.ID,
|
||||
CreatedBy: 7,
|
||||
Title: "中文摘要",
|
||||
@@ -118,12 +118,12 @@ func TestSearchOnlyReturnsNavigableProjectTaskAndNoteResults(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, models.AutoMigrate(database))
|
||||
models.DBService = database
|
||||
require.NoError(t, database.Create(&models.SenlinAgentProject{ID: 1, OwnerID: 7, Name: "webhook 支付项目"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: 1, CreatedBy: 7, Title: "回调任务", Description: "检查 webhook"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentNote{ProjectID: 1, CreatedBy: 7, Title: "回调笔记", Markdown: "webhook 流程"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentSource{ProjectID: 1, CreatedBy: 7, Kind: "link", Title: "支付文档", URL: "https://example.com/pay", ContentText: "webhook 签名"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentInboxItem{ProjectID: 1, CreatedBy: 7, SourceType: "text", Title: "收集项", Body: "webhook 待整理"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentAISession{ProjectID: 1, CreatedBy: 7, Title: "AI 分析", Context: "webhook 问答"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaProject{ID: 1, OwnerID: 7, Name: "webhook 支付项目"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaTask{ProjectID: 1, CreatedBy: 7, Title: "回调任务", Description: "检查 webhook"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaNote{ProjectID: 1, CreatedBy: 7, Title: "回调笔记", Markdown: "webhook 流程"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaSource{ProjectID: 1, CreatedBy: 7, Kind: "link", Title: "支付文档", URL: "https://example.com/pay", ContentText: "webhook 签名"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaInboxItem{ProjectID: 1, CreatedBy: 7, SourceType: "text", Title: "收集项", Body: "webhook 待整理"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaAISession{ProjectID: 1, CreatedBy: 7, Title: "AI 分析", Context: "webhook 问答"}).Error)
|
||||
|
||||
service := NewService()
|
||||
results, err := service.Search(7, "webhook")
|
||||
@@ -142,8 +142,8 @@ func TestSearchTreatsLikeWildcardsAsLiteralKeywords(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, models.AutoMigrate(database))
|
||||
models.DBService = database
|
||||
require.NoError(t, database.Create(&models.SenlinAgentProject{ID: 1, OwnerID: 7, Name: "100%_完成", Identifier: "SPECIAL"}).Error)
|
||||
require.NoError(t, database.Create(&models.SenlinAgentProject{ID: 2, OwnerID: 7, Name: "普通项目", Identifier: "NORMAL"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaProject{ID: 1, OwnerID: 7, Name: "100%_完成", Identifier: "SPECIAL"}).Error)
|
||||
require.NoError(t, database.Create(&models.SaProject{ID: 2, OwnerID: 7, Name: "普通项目", Identifier: "NORMAL"}).Error)
|
||||
|
||||
percentResults, err := NewService().Search(7, "%")
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user