github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/cmd/noms/noms_list.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 nomsList(ctx context.Context, noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) { 39 list := noms.Command("list", "interact with lists") 40 41 listNew := list.Command("new", "creates a new list") 42 newDb := listNew.Arg("database", "spec to db to create list within").Required().String() 43 newEntries := listNew.Arg("items", "items to insert").Strings() 44 45 listAppend := list.Command("append", "appends one or more items to a list") 46 appendSpec := listAppend.Arg("spec", "value spec for the list to edit").Required().String() 47 appendEntries := listAppend.Arg("items", "items to insert").Strings() 48 49 listInsert := list.Command("insert", "inserts one or more items into a list") 50 insertAt := listInsert.Arg("pos", "position to insert new items at").Required().Uint64() 51 insertSpec := listInsert.Arg("spec", "value spec for the list to edit").Required().String() 52 insertEntries := listInsert.Arg("items", "items to insert").Strings() 53 54 listDel := list.Command("del", "removes one or more items from the list") 55 delSpec := listDel.Arg("spec", "value spec for the list to edit").Required().String() 56 delPos := listDel.Arg("pos", "index to remove items at").Required().Uint64() 57 delLen := listDel.Arg("len", "number of items to remove").Required().Uint64() 58 59 return list, func(input string) int { 60 switch input { 61 case listNew.FullCommand(): 62 return nomsListNew(ctx, *newDb, *newEntries) 63 case listAppend.FullCommand(): 64 return nomsListAppend(ctx, *appendSpec, *appendEntries) 65 case listInsert.FullCommand(): 66 return nomsListInsert(ctx, *insertSpec, *insertAt, *insertEntries) 67 case listDel.FullCommand(): 68 return nomsListDel(ctx, *delSpec, *delPos, *delLen) 69 } 70 d.Panic("notreached") 71 return 1 72 } 73 } 74 75 func nomsListNew(ctx context.Context, dbStr string, args []string) int { 76 sp, err := spec.ForDatabase(dbStr) 77 d.PanicIfError(err) 78 db := sp.GetDatabase(ctx) 79 l, err := types.NewList(ctx, db) 80 d.PanicIfError(err) 81 applyListInserts(ctx, db, sp, l, nil, 0, args) 82 return 0 83 } 84 85 func nomsListAppend(ctx context.Context, specStr string, args []string) int { 86 sp, err := spec.ForPath(specStr) 87 d.PanicIfError(err) 88 db := sp.GetDatabase(ctx) 89 rootVal, basePath := splitPath(ctx, db, sp) 90 if list, ok := rootVal.(types.List); ok { 91 applyListInserts(ctx, db, sp, rootVal, basePath, list.Len(), args) 92 } else { 93 util.CheckErrorNoUsage(fmt.Errorf("%s is not a list", specStr)) 94 } 95 return 0 96 } 97 98 func nomsListInsert(ctx context.Context, specStr string, pos uint64, args []string) int { 99 sp, err := spec.ForPath(specStr) 100 d.PanicIfError(err) 101 db := sp.GetDatabase(ctx) 102 rootVal, basePath := splitPath(ctx, db, sp) 103 applyListInserts(ctx, db, sp, rootVal, basePath, pos, args) 104 return 0 105 } 106 107 func nomsListDel(ctx context.Context, specStr string, pos uint64, len uint64) int { 108 sp, err := spec.ForPath(specStr) 109 d.PanicIfError(err) 110 111 db := sp.GetDatabase(ctx) 112 rootVal, basePath := splitPath(ctx, db, sp) 113 patch := diff.Patch{} 114 // TODO: if len-pos is large this will start to become problematic 115 for i := pos; i < pos+len; i++ { 116 patch = append(patch, diff.Difference{ 117 Path: append(basePath, types.NewIndexPath(types.Float(i))), 118 ChangeType: types.DiffChangeRemoved, 119 }) 120 } 121 122 appplyPatch(ctx, sp.GetDatabase(ctx), sp, rootVal, basePath, patch) 123 return 0 124 } 125 126 func applyListInserts(ctx context.Context, db datas.Database, sp spec.Spec, rootVal types.Value, basePath types.Path, pos uint64, args []string) { 127 if rootVal == nil { 128 util.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String())) 129 return 130 } 131 patch := diff.Patch{} 132 for i := 0; i < len(args); i++ { 133 vv, err := argumentToValue(ctx, args[i], db) 134 if err != nil { 135 util.CheckError(fmt.Errorf("Invalid value: %s at position %d: %s", args[i], i, err)) 136 } 137 patch = append(patch, diff.Difference{ 138 Path: append(basePath, types.NewIndexPath(types.Float(pos+uint64(i)))), 139 ChangeType: types.DiffChangeAdded, 140 NewValue: vv, 141 }) 142 } 143 appplyPatch(ctx, db, sp, rootVal, basePath, patch) 144 }