github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/search/query.go (about)

     1  package search
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  	"strings"
     8  	"unicode"
     9  )
    10  
    11  const (
    12  	KindRepositories = "repositories"
    13  	KindIssues       = "issues"
    14  )
    15  
    16  type Query struct {
    17  	Keywords   []string
    18  	Kind       string
    19  	Limit      int
    20  	Order      string
    21  	Page       int
    22  	Qualifiers Qualifiers
    23  	Sort       string
    24  }
    25  
    26  type Qualifiers struct {
    27  	Archived            *bool
    28  	Assignee            string
    29  	Author              string
    30  	Base                string
    31  	Closed              string
    32  	Commenter           string
    33  	Comments            string
    34  	Created             string
    35  	Draft               *bool
    36  	Followers           string
    37  	Fork                string
    38  	Forks               string
    39  	GoodFirstIssues     string
    40  	Head                string
    41  	HelpWantedIssues    string
    42  	In                  []string
    43  	Interactions        string
    44  	Involves            string
    45  	Is                  []string
    46  	Label               []string
    47  	Language            string
    48  	License             []string
    49  	Mentions            string
    50  	Merged              string
    51  	Milestone           string
    52  	No                  []string
    53  	Project             string
    54  	Pushed              string
    55  	Reactions           string
    56  	Repo                []string
    57  	Review              string
    58  	ReviewRequested     string
    59  	ReviewedBy          string
    60  	Size                string
    61  	Stars               string
    62  	State               string
    63  	Status              string
    64  	Team                string
    65  	TeamReviewRequested string
    66  	Topic               []string
    67  	Topics              string
    68  	Type                string
    69  	Updated             string
    70  	User                string
    71  }
    72  
    73  func (q Query) String() string {
    74  	qualifiers := formatQualifiers(q.Qualifiers)
    75  	keywords := formatKeywords(q.Keywords)
    76  	all := append(keywords, qualifiers...)
    77  	return strings.TrimSpace(strings.Join(all, " "))
    78  }
    79  
    80  func (q Qualifiers) Map() map[string][]string {
    81  	m := map[string][]string{}
    82  	v := reflect.ValueOf(q)
    83  	t := reflect.TypeOf(q)
    84  	for i := 0; i < v.NumField(); i++ {
    85  		fieldName := t.Field(i).Name
    86  		key := camelToKebab(fieldName)
    87  		typ := v.FieldByName(fieldName).Kind()
    88  		value := v.FieldByName(fieldName)
    89  		switch typ {
    90  		case reflect.Ptr:
    91  			if value.IsNil() {
    92  				continue
    93  			}
    94  			v := reflect.Indirect(value)
    95  			m[key] = []string{fmt.Sprintf("%v", v)}
    96  		case reflect.Slice:
    97  			if value.IsNil() {
    98  				continue
    99  			}
   100  			s := []string{}
   101  			for i := 0; i < value.Len(); i++ {
   102  				if value.Index(i).IsZero() {
   103  					continue
   104  				}
   105  				s = append(s, fmt.Sprintf("%v", value.Index(i)))
   106  			}
   107  			m[key] = s
   108  		default:
   109  			if value.IsZero() {
   110  				continue
   111  			}
   112  			m[key] = []string{fmt.Sprintf("%v", value)}
   113  		}
   114  	}
   115  	return m
   116  }
   117  
   118  func quote(s string) string {
   119  	if strings.ContainsAny(s, " \"\t\r\n") {
   120  		return fmt.Sprintf("%q", s)
   121  	}
   122  	return s
   123  }
   124  
   125  func formatQualifiers(qs Qualifiers) []string {
   126  	var all []string
   127  	for k, vs := range qs.Map() {
   128  		for _, v := range vs {
   129  			all = append(all, fmt.Sprintf("%s:%s", k, quote(v)))
   130  		}
   131  	}
   132  	sort.Strings(all)
   133  	return all
   134  }
   135  
   136  func formatKeywords(ks []string) []string {
   137  	for i, k := range ks {
   138  		ks[i] = quote(k)
   139  	}
   140  	return ks
   141  }
   142  
   143  // CamelToKebab returns a copy of the string s that is converted from camel case form to '-' separated form.
   144  func camelToKebab(s string) string {
   145  	var output []rune
   146  	var segment []rune
   147  	for _, r := range s {
   148  		if !unicode.IsLower(r) && string(r) != "-" && !unicode.IsNumber(r) {
   149  			output = addSegment(output, segment)
   150  			segment = nil
   151  		}
   152  		segment = append(segment, unicode.ToLower(r))
   153  	}
   154  	output = addSegment(output, segment)
   155  	return string(output)
   156  }
   157  
   158  func addSegment(inrune, segment []rune) []rune {
   159  	if len(segment) == 0 {
   160  		return inrune
   161  	}
   162  	if len(inrune) != 0 {
   163  		inrune = append(inrune, '-')
   164  	}
   165  	inrune = append(inrune, segment...)
   166  	return inrune
   167  }