code.gitea.io/gitea@v1.22.3/modules/indexer/issues/db/db.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package db
     5  
     6  import (
     7  	"context"
     8  
     9  	"code.gitea.io/gitea/models/db"
    10  	issue_model "code.gitea.io/gitea/models/issues"
    11  	indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
    12  	inner_db "code.gitea.io/gitea/modules/indexer/internal/db"
    13  	"code.gitea.io/gitea/modules/indexer/issues/internal"
    14  
    15  	"xorm.io/builder"
    16  )
    17  
    18  var _ internal.Indexer = &Indexer{}
    19  
    20  // Indexer implements Indexer interface to use database's like search
    21  type Indexer struct {
    22  	indexer_internal.Indexer
    23  }
    24  
    25  func NewIndexer() *Indexer {
    26  	return &Indexer{
    27  		Indexer: &inner_db.Indexer{},
    28  	}
    29  }
    30  
    31  // Index dummy function
    32  func (i *Indexer) Index(_ context.Context, _ ...*internal.IndexerData) error {
    33  	return nil
    34  }
    35  
    36  // Delete dummy function
    37  func (i *Indexer) Delete(_ context.Context, _ ...int64) error {
    38  	return nil
    39  }
    40  
    41  // Search searches for issues
    42  func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (*internal.SearchResult, error) {
    43  	// FIXME: I tried to avoid importing models here, but it seems to be impossible.
    44  	//        We can provide a function to register the search function, so models/issues can register it.
    45  	//        So models/issues will import modules/indexer/issues, it's OK because it's by design.
    46  	//        But modules/indexer/issues has already imported models/issues to do UpdateRepoIndexer and UpdateIssueIndexer.
    47  	//        And to avoid circular import, we have to move the functions to another package.
    48  	//        I believe it should be services/indexer, sounds great!
    49  	//        But the two functions are used in modules/notification/indexer, that means we will import services/indexer in modules/notification/indexer.
    50  	//        So that's the root problem:
    51  	//        The notification is defined in modules, but it's using lots of things should be in services.
    52  
    53  	cond := builder.NewCond()
    54  
    55  	if options.Keyword != "" {
    56  		repoCond := builder.In("repo_id", options.RepoIDs)
    57  		if len(options.RepoIDs) == 1 {
    58  			repoCond = builder.Eq{"repo_id": options.RepoIDs[0]}
    59  		}
    60  		subQuery := builder.Select("id").From("issue").Where(repoCond)
    61  
    62  		cond = builder.Or(
    63  			db.BuildCaseInsensitiveLike("issue.name", options.Keyword),
    64  			db.BuildCaseInsensitiveLike("issue.content", options.Keyword),
    65  			builder.In("issue.id", builder.Select("issue_id").
    66  				From("comment").
    67  				Where(builder.And(
    68  					builder.Eq{"type": issue_model.CommentTypeComment},
    69  					builder.In("issue_id", subQuery),
    70  					db.BuildCaseInsensitiveLike("content", options.Keyword),
    71  				)),
    72  			),
    73  		)
    74  	}
    75  
    76  	opt, err := ToDBOptions(ctx, options)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	// If pagesize == 0, return total count only. It's a special case for search count.
    82  	if options.Paginator != nil && options.Paginator.PageSize == 0 {
    83  		total, err := issue_model.CountIssues(ctx, opt, cond)
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  		return &internal.SearchResult{
    88  			Total: total,
    89  		}, nil
    90  	}
    91  
    92  	ids, total, err := issue_model.IssueIDs(ctx, opt, cond)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	hits := make([]internal.Match, 0, len(ids))
    98  	for _, id := range ids {
    99  		hits = append(hits, internal.Match{
   100  			ID: id,
   101  		})
   102  	}
   103  	return &internal.SearchResult{
   104  		Total: total,
   105  		Hits:  hits,
   106  	}, nil
   107  }