[#362] cli/object: Change query language of search filters

Make `--filters` flag to be repeated. Define new filter expression format:
 * `<key> <binary_op> <value>` for binary filters. Supported binary ops: `EQ` (`STRING_EQUAL`), `NE` (`STRING_NOT_EQUAL`).
 * `<key> <unary_op>` for unary filters. Supported unary ops: `NOPRESENT` (`NOT_PRESENT`).
Any other string expressions are considered invalid.

Additionally support shorthand flag `-f`.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-02-11 01:03:46 +03:00 committed by Leonard Lyubich
parent 3b9d4b4df1
commit 6039cd119c

View file

@ -64,6 +64,8 @@ var (
RunE: deleteObject, RunE: deleteObject,
} }
searchFilters []string
objectSearchCmd = &cobra.Command{ objectSearchCmd = &cobra.Command{
Use: "search", Use: "search",
Short: "Search object", Short: "Search object",
@ -138,7 +140,8 @@ func init() {
objectCmd.AddCommand(objectSearchCmd) objectCmd.AddCommand(objectSearchCmd)
objectSearchCmd.Flags().String("cid", "", "Container ID") objectSearchCmd.Flags().String("cid", "", "Container ID")
_ = objectSearchCmd.MarkFlagRequired("cid") _ = objectSearchCmd.MarkFlagRequired("cid")
objectSearchCmd.Flags().String("filters", "", "Filters in the form hdrName=value,...") objectSearchCmd.Flags().StringSliceVarP(&searchFilters, "filters", "f", nil,
"Repeated filter expressions")
objectSearchCmd.Flags().Bool("root", false, "Search for user objects") objectSearchCmd.Flags().Bool("root", false, "Search for user objects")
objectSearchCmd.Flags().Bool("phy", false, "Search physically stored objects") objectSearchCmd.Flags().Bool("phy", false, "Search physically stored objects")
objectSearchCmd.Flags().String(searchOIDFlag, "", "Search object by identifier") objectSearchCmd.Flags().String(searchOIDFlag, "", "Search object by identifier")
@ -520,16 +523,38 @@ func getOwnerID() (*owner.ID, error) {
return ownerID, nil return ownerID, nil
} }
var searchUnaryOpVocabulary = map[string]object.SearchMatchType{
"NOPRESENT": object.MatchNotPresent,
}
var searchBinaryOpVocabulary = map[string]object.SearchMatchType{
"EQ": object.MatchStringEqual,
"NE": object.MatchStringNotEqual,
}
func parseSearchFilters(cmd *cobra.Command) (object.SearchFilters, error) { func parseSearchFilters(cmd *cobra.Command) (object.SearchFilters, error) {
var fs object.SearchFilters var fs object.SearchFilters
if raw := cmd.Flag("filters").Value.String(); len(raw) != 0 {
rawFs := strings.Split(raw, ",") for i := range searchFilters {
for i := range rawFs { words := strings.Fields(searchFilters[i])
kv := strings.SplitN(rawFs[i], "=", 2)
if len(kv) != 2 { switch len(words) {
return nil, fmt.Errorf("invalid filter format: %s", rawFs[i]) default:
return nil, fmt.Errorf("invalid field number: %d", len(words))
case 2:
m, ok := searchUnaryOpVocabulary[words[1]]
if !ok {
return nil, fmt.Errorf("unsupported unary op: %s", words[1])
} }
fs.AddFilter(kv[0], kv[1], object.MatchStringEqual)
fs.AddFilter(words[0], "", m)
case 3:
m, ok := searchBinaryOpVocabulary[words[1]]
if !ok {
return nil, fmt.Errorf("unsupported binary op: %s", words[1])
}
fs.AddFilter(words[0], words[2], m)
} }
} }