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  }