github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/remote/registry/regclient/search.go (about) 1 package regclient 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "strings" 9 10 "github.com/qri-io/dataset" 11 "github.com/qri-io/qri/remote/registry" 12 ) 13 14 // SearchFilter stores various types of filters that may be applied 15 // to a search 16 type SearchFilter struct { 17 // Type denotes the ype of search filter 18 Type string 19 // Relation indicates the relation between the key and value 20 // supported options include ["eq"|"neq"|"gt"|"gte"|"lt"|"lte"] 21 Relation string 22 // Key corresponds to the name of the index mapping that we wish to 23 // apply the filter to 24 Key string 25 // Value is the predicate of the subject-relation-predicate triple 26 // eg. [key=timestamp] [gte] [value=[today]] 27 Value interface{} 28 } 29 30 // SearchParams contains the parameters that are passed to a 31 // Client.Search method 32 type SearchParams struct { 33 QueryString string 34 Filters []SearchFilter 35 Limit int 36 Offset int 37 } 38 39 // Search makes a registry search request 40 func (c Client) Search(p *SearchParams) ([]*dataset.Dataset, error) { 41 params := ®istry.SearchParams{ 42 Q: p.QueryString, 43 //Filters: p.Filters, 44 Limit: p.Limit, 45 Offset: p.Offset, 46 } 47 results, err := c.doJSONSearchReq("GET", params) 48 if err != nil { 49 return nil, err 50 } 51 return results, nil 52 } 53 54 func (c Client) prepPostReq(s *registry.SearchParams) (*http.Request, error) { 55 data, err := json.Marshal(s) 56 if err != nil { 57 return nil, err 58 } 59 req, err := http.NewRequest("POST", fmt.Sprintf("%s/registry/search", c.cfg.Location), bytes.NewReader(data)) 60 if err != nil { 61 return nil, err 62 } 63 req.Header.Set("Content-Type", "application/json") 64 return req, nil 65 } 66 67 func (c Client) prepGetReq(s *registry.SearchParams) (*http.Request, error) { 68 req, err := http.NewRequest("GET", fmt.Sprintf("%s/registry/search", c.cfg.Location), nil) 69 if err != nil { 70 return nil, err 71 } 72 q := req.URL.Query() 73 q.Add("q", s.Q) 74 if s.Limit > 0 { 75 q.Add("limit", fmt.Sprintf("%d", s.Limit)) 76 } 77 if s.Offset > -1 { 78 q.Add("offset", fmt.Sprintf("%d", s.Offset)) 79 } 80 req.URL.RawQuery = q.Encode() 81 return req, nil 82 } 83 84 func (c Client) doJSONSearchReq(method string, s *registry.SearchParams) (results []*dataset.Dataset, err error) { 85 if c.cfg.Location == "" { 86 return nil, ErrNoRegistry 87 } 88 // req := &http.Request{} 89 var req *http.Request 90 switch method { 91 case "POST": 92 req, err = c.prepPostReq(s) 93 case "GET": 94 req, err = c.prepGetReq(s) 95 } 96 if err != nil { 97 return nil, err 98 } 99 100 res, err := c.httpClient.Do(req) 101 if err != nil { 102 if strings.Contains(err.Error(), "no such host") { 103 return nil, ErrNoRegistry 104 } 105 return nil, err 106 } 107 // add response to an envelope 108 env := struct { 109 Data []*dataset.Dataset 110 Meta struct { 111 Error string 112 Status string 113 Code int 114 } 115 }{} 116 117 if err := json.NewDecoder(res.Body).Decode(&env); err != nil { 118 return nil, err 119 } 120 121 if res.StatusCode != http.StatusOK { 122 return nil, fmt.Errorf("error %d: %s", res.StatusCode, env.Meta.Error) 123 } 124 return env.Data, nil 125 }