code.gitea.io/gitea@v1.22.3/modules/indexer/issues/internal/model.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package internal 5 6 import ( 7 "code.gitea.io/gitea/models/db" 8 "code.gitea.io/gitea/modules/optional" 9 "code.gitea.io/gitea/modules/timeutil" 10 ) 11 12 // IndexerData data stored in the issue indexer 13 type IndexerData struct { 14 ID int64 `json:"id"` 15 RepoID int64 `json:"repo_id"` 16 IsPublic bool `json:"is_public"` // If the repo is public 17 18 // Fields used for keyword searching 19 Title string `json:"title"` 20 Content string `json:"content"` 21 Comments []string `json:"comments"` 22 23 // Fields used for filtering 24 IsPull bool `json:"is_pull"` 25 IsClosed bool `json:"is_closed"` 26 LabelIDs []int64 `json:"label_ids"` 27 NoLabel bool `json:"no_label"` // True if LabelIDs is empty 28 MilestoneID int64 `json:"milestone_id"` 29 ProjectID int64 `json:"project_id"` 30 ProjectBoardID int64 `json:"project_board_id"` 31 PosterID int64 `json:"poster_id"` 32 AssigneeID int64 `json:"assignee_id"` 33 MentionIDs []int64 `json:"mention_ids"` 34 ReviewedIDs []int64 `json:"reviewed_ids"` 35 ReviewRequestedIDs []int64 `json:"review_requested_ids"` 36 SubscriberIDs []int64 `json:"subscriber_ids"` 37 UpdatedUnix timeutil.TimeStamp `json:"updated_unix"` 38 39 // Fields used for sorting 40 // UpdatedUnix is both used for filtering and sorting. 41 // ID is used for sorting too, to make the sorting stable. 42 CreatedUnix timeutil.TimeStamp `json:"created_unix"` 43 DeadlineUnix timeutil.TimeStamp `json:"deadline_unix"` 44 CommentCount int64 `json:"comment_count"` 45 } 46 47 // Match represents on search result 48 type Match struct { 49 ID int64 `json:"id"` 50 Score float64 `json:"score"` 51 } 52 53 // SearchResult represents search results 54 type SearchResult struct { 55 Total int64 56 Hits []Match 57 } 58 59 // SearchOptions represents search options. 60 // 61 // It has a slightly different design from database query options. 62 // In database query options, a field is never a pointer, so it could be confusing when it's zero value: 63 // Do you want to find data with a field value of 0, or do you not specify the field in the options? 64 // To avoid this confusion, db introduced db.NoConditionID(-1). 65 // So zero value means the field is not specified in the search options, and db.NoConditionID means "== 0" or "id NOT IN (SELECT id FROM ...)" 66 // It's still not ideal, it trapped developers many times. 67 // And sometimes -1 could be a valid value, like issue ID, negative numbers indicate exclusion. 68 // Since db.NoConditionID is for "db" (the package name is db), it makes sense not to use it in the indexer: 69 // Why do bleve/elasticsearch/meilisearch indexers need to know about db.NoConditionID? 70 // So in SearchOptions, we use pointer for fields which could be not specified, 71 // and always use the value to filter if it's not nil, even if it's zero or negative. 72 // It can handle almost all cases, if there is an exception, we can add a new field, like NoLabelOnly. 73 // Unfortunately, we still use db for the indexer and have to convert between db.NoConditionID and nil for legacy reasons. 74 type SearchOptions struct { 75 Keyword string // keyword to search 76 77 IsFuzzyKeyword bool // if false the levenshtein distance is 0 78 79 RepoIDs []int64 // repository IDs which the issues belong to 80 AllPublic bool // if include all public repositories 81 82 IsPull optional.Option[bool] // if the issues is a pull request 83 IsClosed optional.Option[bool] // if the issues is closed 84 85 IncludedLabelIDs []int64 // labels the issues have 86 ExcludedLabelIDs []int64 // labels the issues don't have 87 IncludedAnyLabelIDs []int64 // labels the issues have at least one. It will be ignored if IncludedLabelIDs is not empty. It's an uncommon filter, but it has been supported accidentally by issues.IssuesOptions.IncludedLabelNames. 88 NoLabelOnly bool // if the issues have no label, if true, IncludedLabelIDs and ExcludedLabelIDs, IncludedAnyLabelIDs will be ignored 89 90 MilestoneIDs []int64 // milestones the issues have 91 92 ProjectID optional.Option[int64] // project the issues belong to 93 ProjectBoardID optional.Option[int64] // project board the issues belong to 94 95 PosterID optional.Option[int64] // poster of the issues 96 97 AssigneeID optional.Option[int64] // assignee of the issues, zero means no assignee 98 99 MentionID optional.Option[int64] // mentioned user of the issues 100 101 ReviewedID optional.Option[int64] // reviewer of the issues 102 ReviewRequestedID optional.Option[int64] // requested reviewer of the issues 103 104 SubscriberID optional.Option[int64] // subscriber of the issues 105 106 UpdatedAfterUnix optional.Option[int64] 107 UpdatedBeforeUnix optional.Option[int64] 108 109 Paginator *db.ListOptions 110 111 SortBy SortBy // sort by field 112 } 113 114 // Copy returns a copy of the options. 115 // Be careful, it's not a deep copy, so `SearchOptions.RepoIDs = {...}` is OK while `SearchOptions.RepoIDs[0] = ...` is not. 116 func (o *SearchOptions) Copy(edit ...func(options *SearchOptions)) *SearchOptions { 117 if o == nil { 118 return nil 119 } 120 v := *o 121 for _, e := range edit { 122 e(&v) 123 } 124 return &v 125 } 126 127 type SortBy string 128 129 const ( 130 SortByCreatedDesc SortBy = "-created_unix" 131 SortByUpdatedDesc SortBy = "-updated_unix" 132 SortByCommentsDesc SortBy = "-comment_count" 133 SortByDeadlineDesc SortBy = "-deadline_unix" 134 SortByCreatedAsc SortBy = "created_unix" 135 SortByUpdatedAsc SortBy = "updated_unix" 136 SortByCommentsAsc SortBy = "comment_count" 137 SortByDeadlineAsc SortBy = "deadline_unix" 138 // Unsupported sort types which are supported by issues.IssuesOptions.SortType: 139 // 140 // - "priorityrepo": 141 // It's impossible to support it in the indexer. 142 // It is based on the specified repository in the request, so we cannot add static field to the indexer. 143 // If we do something like that query the issues in the specified repository first then append other issues, 144 // it will break the pagination. 145 // 146 // - "project-column-sorting": 147 // Although it's possible to support it by adding project.ProjectIssue.Sorting to the indexer, 148 // but what if the issue belongs to multiple projects? 149 // Since it's unsupported to search issues with keyword in project page, we don't need to support it. 150 )