mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Explain SearchOptions and fix ToSearchOptions (#26542)
Follow #26012 #26490. A detailed description has been added to the comment.
This commit is contained in:
		@@ -14,6 +14,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_model.IssuesOptions, error) {
 | 
					func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_model.IssuesOptions, error) {
 | 
				
			||||||
 | 
						// See the comment of issues_model.SearchOptions for the reason why we need to convert
 | 
				
			||||||
	convertID := func(id *int64) int64 {
 | 
						convertID := func(id *int64) int64 {
 | 
				
			||||||
		if id == nil {
 | 
							if id == nil {
 | 
				
			||||||
			return 0
 | 
								return 0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,6 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
 | 
				
			|||||||
		IsClosed:  opts.IsClosed,
 | 
							IsClosed:  opts.IsClosed,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.ProjectID != 0 {
 | 
					 | 
				
			||||||
		searchOpt.ProjectID = &opts.ProjectID
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 {
 | 
						if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 {
 | 
				
			||||||
		searchOpt.NoLabelOnly = true
 | 
							searchOpt.NoLabelOnly = true
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -41,25 +37,27 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
 | 
				
			|||||||
		searchOpt.MilestoneIDs = opts.MilestoneIDs
 | 
							searchOpt.MilestoneIDs = opts.MilestoneIDs
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.AssigneeID > 0 {
 | 
						// See the comment of issues_model.SearchOptions for the reason why we need to convert
 | 
				
			||||||
		searchOpt.AssigneeID = &opts.AssigneeID
 | 
						convertID := func(id int64) *int64 {
 | 
				
			||||||
 | 
							if id > 0 {
 | 
				
			||||||
 | 
								return &id
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	if opts.PosterID > 0 {
 | 
							if id == db.NoConditionID {
 | 
				
			||||||
		searchOpt.PosterID = &opts.PosterID
 | 
								var zero int64
 | 
				
			||||||
 | 
								return &zero
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	if opts.MentionedID > 0 {
 | 
							return nil
 | 
				
			||||||
		searchOpt.MentionID = &opts.MentionedID
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if opts.ReviewedID > 0 {
 | 
					 | 
				
			||||||
		searchOpt.ReviewedID = &opts.ReviewedID
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if opts.ReviewRequestedID > 0 {
 | 
					 | 
				
			||||||
		searchOpt.ReviewRequestedID = &opts.ReviewRequestedID
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if opts.SubscriberID > 0 {
 | 
					 | 
				
			||||||
		searchOpt.SubscriberID = &opts.SubscriberID
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						searchOpt.ProjectID = convertID(opts.ProjectID)
 | 
				
			||||||
 | 
						searchOpt.ProjectBoardID = convertID(opts.ProjectBoardID)
 | 
				
			||||||
 | 
						searchOpt.PosterID = convertID(opts.PosterID)
 | 
				
			||||||
 | 
						searchOpt.AssigneeID = convertID(opts.AssigneeID)
 | 
				
			||||||
 | 
						searchOpt.MentionID = convertID(opts.MentionedID)
 | 
				
			||||||
 | 
						searchOpt.ReviewedID = convertID(opts.ReviewedID)
 | 
				
			||||||
 | 
						searchOpt.ReviewRequestedID = convertID(opts.ReviewRequestedID)
 | 
				
			||||||
 | 
						searchOpt.SubscriberID = convertID(opts.SubscriberID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.UpdatedAfterUnix > 0 {
 | 
						if opts.UpdatedAfterUnix > 0 {
 | 
				
			||||||
		searchOpt.UpdatedAfterUnix = &opts.UpdatedAfterUnix
 | 
							searchOpt.UpdatedAfterUnix = &opts.UpdatedAfterUnix
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,21 @@ type SearchResult struct {
 | 
				
			|||||||
	Hits  []Match
 | 
						Hits  []Match
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SearchOptions represents search options
 | 
					// SearchOptions represents search options.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It has a slightly different design from database query options.
 | 
				
			||||||
 | 
					// In database query options, a field is never a pointer, so it could be confusing when it's zero value:
 | 
				
			||||||
 | 
					// Do you want to find data with a field value of 0, or do you not specify the field in the options?
 | 
				
			||||||
 | 
					// To avoid this confusion, db introduced db.NoConditionID(-1).
 | 
				
			||||||
 | 
					// 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 ...)"
 | 
				
			||||||
 | 
					// It's still not ideal, it trapped developers many times.
 | 
				
			||||||
 | 
					// And sometimes -1 could be a valid value, like issue ID, negative numbers indicate exclusion.
 | 
				
			||||||
 | 
					// Since db.NoConditionID is for "db" (the package name is db), it makes sense not to use it in the indexer:
 | 
				
			||||||
 | 
					// Why do bleve/elasticsearch/meilisearch indexers need to know about db.NoConditionID?
 | 
				
			||||||
 | 
					// So in SearchOptions, we use pointer for fields which could be not specified,
 | 
				
			||||||
 | 
					// and always use the value to filter if it's not nil, even if it's zero or negative.
 | 
				
			||||||
 | 
					// It can handle almost all cases, if there is an exception, we can add a new field, like NoLabelOnly.
 | 
				
			||||||
 | 
					// Unfortunately, we still use db for the indexer and have to convert between db.NoConditionID and nil for legacy reasons.
 | 
				
			||||||
type SearchOptions struct {
 | 
					type SearchOptions struct {
 | 
				
			||||||
	Keyword string // keyword to search
 | 
						Keyword string // keyword to search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user