github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/cmd/noms/noms_map.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // This file incorporates work covered by the following copyright and 16 // permission notice: 17 // 18 // Copyright 2018 Attic Labs, Inc. All rights reserved. 19 // Licensed under the Apache License, version 2.0: 20 // http://www.apache.org/licenses/LICENSE-2.0 21 22 package main 23 24 import ( 25 "context" 26 "fmt" 27 28 "github.com/attic-labs/kingpin" 29 30 "github.com/dolthub/dolt/go/store/cmd/noms/util" 31 "github.com/dolthub/dolt/go/store/d" 32 "github.com/dolthub/dolt/go/store/datas" 33 "github.com/dolthub/dolt/go/store/diff" 34 "github.com/dolthub/dolt/go/store/spec" 35 "github.com/dolthub/dolt/go/store/types" 36 ) 37 38 func nomsMap(ctx context.Context, noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) { 39 maap := noms.Command("map", "interact with maps") 40 41 mapNew := maap.Command("new", "creates a new map") 42 newDb := mapNew.Arg("database", "spec to db to create map within").Required().String() 43 newEntries := mapNew.Arg("entries", "key/value pairs for entries").Strings() 44 45 mapSet := maap.Command("set", "sets one or more keys in a map") 46 setSpec := mapSet.Arg("spec", "value spec for the map to edit").Required().String() 47 setEntries := mapSet.Arg("entries", "key/value pairs for entries").Strings() 48 49 mapDel := maap.Command("del", "removes one or more entries from a map") 50 delSpec := mapDel.Arg("spec", "value spec for the map to edit").Required().String() 51 delKeys := mapDel.Arg("keys", "keys for the entries to be removed").Strings() 52 53 return maap, func(input string) int { 54 switch input { 55 case mapNew.FullCommand(): 56 return nomsMapNew(ctx, *newDb, *newEntries) 57 case mapSet.FullCommand(): 58 return nomsMapSet(ctx, *setSpec, *setEntries) 59 case mapDel.FullCommand(): 60 return nomsMapDel(ctx, *delSpec, *delKeys) 61 } 62 d.Panic("notreached") 63 return 1 64 } 65 } 66 67 func nomsMapNew(ctx context.Context, dbStr string, args []string) int { 68 sp, err := spec.ForDatabase(dbStr) 69 d.PanicIfError(err) 70 db := sp.GetDatabase(ctx) 71 m, err := types.NewMap(ctx, db) 72 d.PanicIfError(err) 73 applyMapEdits(ctx, db, sp, m, nil, args) 74 return 0 75 } 76 77 func nomsMapSet(ctx context.Context, specStr string, args []string) int { 78 sp, err := spec.ForPath(specStr) 79 d.PanicIfError(err) 80 db := sp.GetDatabase(ctx) 81 rootVal, basePath := splitPath(ctx, db, sp) 82 applyMapEdits(ctx, db, sp, rootVal, basePath, args) 83 return 0 84 } 85 86 func nomsMapDel(ctx context.Context, specStr string, args []string) int { 87 sp, err := spec.ForPath(specStr) 88 d.PanicIfError(err) 89 90 db := sp.GetDatabase(ctx) 91 rootVal, basePath := splitPath(ctx, db, sp) 92 patch := diff.Patch{} 93 for i := 0; i < len(args); i++ { 94 kp := parseKeyPart(args, i) 95 patch = append(patch, diff.Difference{ 96 Path: append(basePath, kp), 97 ChangeType: types.DiffChangeRemoved, 98 }) 99 } 100 101 appplyPatch(ctx, db, sp, rootVal, basePath, patch) 102 return 0 103 } 104 105 func applyMapEdits(ctx context.Context, db datas.Database, sp spec.Spec, rootVal types.Value, basePath types.Path, args []string) { 106 if len(args)%2 != 0 { 107 util.CheckError(fmt.Errorf("Must be an even number of key/value pairs")) 108 } 109 if rootVal == nil { 110 util.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String())) 111 return 112 } 113 patch := diff.Patch{} 114 for i := 0; i < len(args); i += 2 { 115 kp := parseKeyPart(args, i) 116 vv, err := argumentToValue(ctx, args[i+1], db) 117 if err != nil { 118 util.CheckError(fmt.Errorf("Invalid value: %s at position %d: %s", args[i+1], i+1, err)) 119 } 120 patch = append(patch, diff.Difference{ 121 Path: append(basePath, kp), 122 ChangeType: types.DiffChangeModified, 123 NewValue: vv, 124 }) 125 } 126 appplyPatch(ctx, db, sp, rootVal, basePath, patch) 127 } 128 129 func parseKeyPart(args []string, i int) (res types.PathPart) { 130 idx, h, rem, err := types.ParsePathIndex(args[i]) 131 if rem != "" { 132 util.CheckError(fmt.Errorf("Invalid key: %s at position %d", args[i], i)) 133 } 134 if err != nil { 135 util.CheckError(fmt.Errorf("Invalid key: %s at position %d: %s", args[i], i, err)) 136 } 137 if idx != nil { 138 res = types.NewIndexPath(idx) 139 } else { 140 res = types.NewHashIndexPath(h) 141 } 142 return 143 }