github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/cmd/search.go (about)

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  
     9  	"github.com/qri-io/dataset"
    10  	"github.com/qri-io/ioes"
    11  	"github.com/qri-io/qri/base/params"
    12  	"github.com/qri-io/qri/errors"
    13  	"github.com/qri-io/qri/lib"
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  // NewSearchCommand creates a new `qri search` command that searches for datasets
    18  func NewSearchCommand(f Factory, ioStreams ioes.IOStreams) *cobra.Command {
    19  	o := &SearchOptions{IOStreams: ioStreams}
    20  	cmd := &cobra.Command{
    21  		Use:   "search QUERY",
    22  		Short: "search the registry for datasets",
    23  		Long: `Search datasets & peers that match your query. Search pings the qri registry. 
    24  
    25  Any dataset that has been pushed to the registry is available for search.`,
    26  		Example: `  # Search for datasets featuring "annual population":
    27    $ qri search "annual population"`,
    28  		Annotations: map[string]string{
    29  			"group": "network",
    30  		},
    31  		Args: cobra.MaximumNArgs(1),
    32  		RunE: func(cmd *cobra.Command, args []string) error {
    33  			if err := o.Complete(f, args); err != nil {
    34  				return err
    35  			}
    36  			if err := o.Validate(); err != nil {
    37  				return err
    38  			}
    39  			return o.Run()
    40  		},
    41  	}
    42  
    43  	cmd.Flags().StringVarP(&o.Format, "format", "f", "", "set output format [json|simple]")
    44  	cmd.Flags().IntVar(&o.Offset, "offset", 0, "number of records to skip from results, default 0")
    45  	cmd.Flags().IntVar(&o.Limit, "limit", 25, "size of results, default 25")
    46  
    47  	return cmd
    48  }
    49  
    50  // SearchOptions encapsulates state for the search command
    51  type SearchOptions struct {
    52  	ioes.IOStreams
    53  
    54  	Query  string
    55  	Format string
    56  	Offset int
    57  	Limit  int
    58  	// Reindex bool
    59  
    60  	Instance *lib.Instance
    61  }
    62  
    63  // Complete adds any missing configuration that can only be added just before calling Run
    64  func (o *SearchOptions) Complete(f Factory, args []string) (err error) {
    65  	if o.Instance, err = f.Instance(); err != nil {
    66  		return err
    67  	}
    68  	if len(args) != 0 {
    69  		o.Query = args[0]
    70  	}
    71  	return
    72  }
    73  
    74  // Validate checks that any user inputs are valid
    75  func (o *SearchOptions) Validate() error {
    76  	if o.Query == "" {
    77  		return errors.New(lib.ErrBadArgs, "please provide search parameters, for example:\n    $ qri search census\n    $ qri search 'census 2018'\nsee `qri search --help` for more information")
    78  	}
    79  	return nil
    80  }
    81  
    82  // Run executes the search command
    83  func (o *SearchOptions) Run() (err error) {
    84  	ctx := context.TODO()
    85  	inst := o.Instance
    86  
    87  	o.StartSpinner()
    88  	defer o.StopSpinner()
    89  
    90  	// TODO: add reindex option back in
    91  
    92  	p := &lib.SearchParams{
    93  		Query: o.Query,
    94  		List: params.List{
    95  			Offset: o.Offset,
    96  			Limit:  o.Limit,
    97  		},
    98  	}
    99  
   100  	results, err := inst.Search().Search(ctx, p)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	switch o.Format {
   106  	case "":
   107  		fmt.Fprintf(o.Out, "showing %d results for '%s'\n", len(results), o.Query)
   108  		items := make([]fmt.Stringer, len(results))
   109  		for i, result := range results {
   110  			items[i] = searchResultStringer(result)
   111  		}
   112  		o.StopSpinner()
   113  		printItems(o.Out, items, o.Offset)
   114  		return nil
   115  	case "simple":
   116  		items := make([]string, len(results))
   117  		for i, r := range results {
   118  			items[i] = fmt.Sprintf("%s/%s", r.Value.Peername, r.Value.Name)
   119  		}
   120  		printlnStringItems(o.Out, items)
   121  		return nil
   122  	case dataset.JSONDataFormat.String():
   123  		data, err := json.MarshalIndent(results, "", "  ")
   124  		if err != nil {
   125  			return err
   126  		}
   127  		buf := bytes.NewBuffer(data)
   128  		o.StopSpinner()
   129  		printToPager(o.Out, buf)
   130  	default:
   131  		return fmt.Errorf("unrecognized format: %s", o.Format)
   132  	}
   133  	return nil
   134  }