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 }