github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/cmd/noms/noms_map.go (about)

     1  // Copyright 2018 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package main
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/attic-labs/kingpin"
    11  
    12  	"github.com/attic-labs/noms/cmd/util"
    13  	"github.com/attic-labs/noms/go/d"
    14  	"github.com/attic-labs/noms/go/diff"
    15  	"github.com/attic-labs/noms/go/spec"
    16  	"github.com/attic-labs/noms/go/types"
    17  )
    18  
    19  func nomsMap(noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) {
    20  	maap := noms.Command("map", "Interact with maps.")
    21  
    22  	mapNew := maap.Command("new", "creates a new map")
    23  	newDb := mapNew.Arg("database", "spec to db to create map within").Required().String()
    24  	newEntries := mapNew.Arg("entries", "key/value pairs for entries").Strings()
    25  
    26  	mapSet := maap.Command("set", "sets one or more keys in a map")
    27  	setSpec := mapSet.Arg("spec", "value spec for the map to edit").Required().String()
    28  	setEntries := mapSet.Arg("entries", "key/value pairs for entries").Strings()
    29  
    30  	mapDel := maap.Command("del", "removes one or more entries from a map")
    31  	delSpec := mapDel.Arg("spec", "value spec for the map to edit").Required().String()
    32  	delKeys := mapDel.Arg("keys", "keys for the entries to be removed").Strings()
    33  
    34  	return maap, func(input string) int {
    35  		switch input {
    36  		case mapNew.FullCommand():
    37  			return nomsMapNew(*newDb, *newEntries)
    38  		case mapSet.FullCommand():
    39  			return nomsMapSet(*setSpec, *setEntries)
    40  		case mapDel.FullCommand():
    41  			return nomsMapDel(*delSpec, *delKeys)
    42  		}
    43  		d.Panic("notreached")
    44  		return 1
    45  	}
    46  }
    47  
    48  func nomsMapNew(dbStr string, args []string) int {
    49  	sp, err := spec.ForDatabase(dbStr)
    50  	d.PanicIfError(err)
    51  	applyMapEdits(sp, types.NewMap(sp.GetDatabase()), nil, args)
    52  	return 0
    53  }
    54  
    55  func nomsMapSet(specStr string, args []string) int {
    56  	sp, err := spec.ForPath(specStr)
    57  	d.PanicIfError(err)
    58  	rootVal, basePath := splitPath(sp)
    59  	applyMapEdits(sp, rootVal, basePath, args)
    60  	return 0
    61  }
    62  
    63  func nomsMapDel(specStr string, args []string) int {
    64  	sp, err := spec.ForPath(specStr)
    65  	d.PanicIfError(err)
    66  
    67  	rootVal, basePath := splitPath(sp)
    68  	patch := diff.Patch{}
    69  	for i := 0; i < len(args); i++ {
    70  		kp := parseKeyPart(args, i)
    71  		patch = append(patch, diff.Difference{
    72  			Path:       append(basePath, kp),
    73  			ChangeType: types.DiffChangeRemoved,
    74  		})
    75  	}
    76  
    77  	appplyPatch(sp, rootVal, basePath, patch)
    78  	return 0
    79  }
    80  
    81  func applyMapEdits(sp spec.Spec, rootVal types.Value, basePath types.Path, args []string) {
    82  	if len(args)%2 != 0 {
    83  		d.CheckError(fmt.Errorf("Must be an even number of key/value pairs"))
    84  	}
    85  	if rootVal == nil {
    86  		d.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String()))
    87  		return
    88  	}
    89  	db := sp.GetDatabase()
    90  	patch := diff.Patch{}
    91  	for i := 0; i < len(args); i += 2 {
    92  		kp := parseKeyPart(args, i)
    93  		vv, err := argumentToValue(args[i+1], db)
    94  		if err != nil {
    95  			d.CheckError(fmt.Errorf("Invalid value: %s at position %d: %s", args[i+1], i+1, err))
    96  		}
    97  		patch = append(patch, diff.Difference{
    98  			Path:       append(basePath, kp),
    99  			ChangeType: types.DiffChangeModified,
   100  			NewValue:   vv,
   101  		})
   102  	}
   103  	appplyPatch(sp, rootVal, basePath, patch)
   104  }
   105  
   106  func parseKeyPart(args []string, i int) (res types.PathPart) {
   107  	idx, h, rem, err := types.ParsePathIndex(args[i])
   108  	if rem != "" {
   109  		d.CheckError(fmt.Errorf("Invalid key: %s at position %d", args[i], i))
   110  	}
   111  	if err != nil {
   112  		d.CheckError(fmt.Errorf("Invalid key: %s at position %d: %s", args[i], i, err))
   113  	}
   114  	if idx != nil {
   115  		res = types.NewIndexPath(idx)
   116  	} else {
   117  		res = types.NewHashIndexPath(h)
   118  	}
   119  	return
   120  }