github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/row/noms_row.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  package row
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  
    21  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    22  	"github.com/dolthub/dolt/go/store/types"
    23  )
    24  
    25  type nomsRow struct {
    26  	key   TaggedValues
    27  	value TaggedValues
    28  	nbf   *types.NomsBinFormat
    29  }
    30  
    31  var _ Row = nomsRow{}
    32  
    33  func pkRowFromNoms(sch schema.Schema, nomsKey, nomsVal types.Tuple) (Row, error) {
    34  	keySl, err := nomsKey.AsSlice()
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	valSl, err := nomsVal.AsSlice()
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	allCols := sch.GetAllCols()
    45  
    46  	err = IterPkTuple(keySl, func(tag uint64, val types.Value) (stop bool, err error) {
    47  		col, ok := allCols.GetByTag(tag)
    48  
    49  		if !ok {
    50  			return false, errors.New("Trying to set a value on an unknown tag is a bug for the key.  Validation should happen upstream. col:" + col.Name)
    51  		} else if !col.IsPartOfPK {
    52  			return false, errors.New("writing columns that are not part of the primary key to pk values. col:" + col.Name)
    53  		} else if !types.IsNull(val) && col.Kind != val.Kind() {
    54  			return false, errors.New("bug.  Setting a value to an incorrect kind. col: " + col.Name)
    55  		}
    56  
    57  		return false, nil
    58  	})
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	filteredVals := make(TaggedValues, len(valSl))
    64  	err = IterPkTuple(valSl, func(tag uint64, val types.Value) (stop bool, err error) {
    65  		col, ok := allCols.GetByTag(tag)
    66  		if !ok {
    67  			return false, nil
    68  		}
    69  
    70  		if col.IsPartOfPK {
    71  			return false, errors.New("writing columns that are part of the primary key to non-pk values. col:" + col.Name)
    72  		} else if !types.IsNull(val) {
    73  			if col.Kind != val.Kind() {
    74  				return false, errors.New("bug.  Setting a value to an incorrect kind. col:" + col.Name)
    75  			} else {
    76  				filteredVals[tag] = val
    77  			}
    78  		}
    79  
    80  		return false, nil
    81  	})
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	taggedKeyVals, err := TaggedValuesFromTupleValueSlice(keySl)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	return nomsRow{taggedKeyVals, filteredVals, nomsKey.Format()}, nil
    92  }
    93  
    94  func (nr nomsRow) IterSchema(sch schema.Schema, cb func(tag uint64, val types.Value) (stop bool, err error)) (bool, error) {
    95  	err := sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (bool, error) {
    96  		value, _ := nr.GetColVal(tag)
    97  		return cb(tag, value)
    98  	})
    99  
   100  	return false, err
   101  }
   102  
   103  func (nr nomsRow) IterCols(cb func(tag uint64, val types.Value) (bool, error)) (bool, error) {
   104  	stopped, err := nr.key.Iter(cb)
   105  
   106  	if err != nil {
   107  		return false, err
   108  	}
   109  
   110  	if !stopped {
   111  		stopped, err = nr.value.Iter(cb)
   112  	}
   113  
   114  	if err != nil {
   115  		return false, err
   116  	}
   117  
   118  	return stopped, nil
   119  }
   120  
   121  func (nr nomsRow) GetColVal(tag uint64) (types.Value, bool) {
   122  	val, ok := nr.key.Get(tag)
   123  
   124  	if !ok {
   125  		val, ok = nr.value.Get(tag)
   126  	}
   127  
   128  	return val, ok
   129  }
   130  
   131  func (nr nomsRow) SetColVal(tag uint64, val types.Value, sch schema.Schema) (Row, error) {
   132  	rowKey := nr.key
   133  	rowVal := nr.value
   134  
   135  	cols := sch.GetAllCols()
   136  	col, ok := cols.GetByTag(tag)
   137  
   138  	if ok {
   139  		if col.IsPartOfPK {
   140  			rowKey = nr.key.Set(tag, val)
   141  		} else {
   142  			rowVal = nr.value.Set(tag, val)
   143  		}
   144  
   145  		return nomsRow{rowKey, rowVal, nr.nbf}, nil
   146  	}
   147  
   148  	panic("can't set a column whose tag isn't in the schema.  verify before calling this function.")
   149  }
   150  
   151  func (nr nomsRow) Format() *types.NomsBinFormat {
   152  	return nr.nbf
   153  }
   154  
   155  // TaggedValues implements the Row interface.
   156  func (nr nomsRow) TaggedValues() (TaggedValues, error) {
   157  	tv := make(TaggedValues)
   158  	for k, v := range nr.key {
   159  		tv[k] = v
   160  	}
   161  	for k, v := range nr.value {
   162  		tv[k] = v
   163  	}
   164  	return tv, nil
   165  }
   166  
   167  func pkRowFromTaggedValues(nbf *types.NomsBinFormat, sch schema.Schema, colVals TaggedValues) (Row, error) {
   168  	allCols := sch.GetAllCols()
   169  
   170  	keyVals := make(TaggedValues)
   171  	nonKeyVals := make(TaggedValues)
   172  
   173  	_, err := colVals.Iter(func(tag uint64, val types.Value) (stop bool, err error) {
   174  		col, ok := allCols.GetByTag(tag)
   175  
   176  		if !ok {
   177  			return false, errors.New("Trying to set a value on an unknown tag is a bug.  Validation should happen upstream.")
   178  		} else if col.IsPartOfPK {
   179  			keyVals[tag] = val
   180  		} else {
   181  			nonKeyVals[tag] = val
   182  		}
   183  		return false, nil
   184  	})
   185  
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	return fromTaggedVals(nbf, sch, keyVals, nonKeyVals)
   191  }
   192  
   193  // fromTaggedVals will take a schema, a map of tag to value for the key, and a map of tag to value for non key values,
   194  // and generates a row.  When a schema adds or removes columns from the non-key portion of the row, the schema will be
   195  // updated, but the rows will not be touched.  So the non-key portion of the row may contain values that are not in the
   196  // schema (The keys must match the schema though).
   197  func fromTaggedVals(nbf *types.NomsBinFormat, sch schema.Schema, keyVals, nonKeyVals TaggedValues) (Row, error) {
   198  	allCols := sch.GetAllCols()
   199  
   200  	_, err := keyVals.Iter(func(tag uint64, val types.Value) (stop bool, err error) {
   201  		col, ok := allCols.GetByTag(tag)
   202  
   203  		if !ok {
   204  			return false, errors.New("Trying to set a value on an unknown tag is a bug for the key.  Validation should happen upstream. col:" + col.Name)
   205  		} else if !col.IsPartOfPK {
   206  			return false, errors.New("writing columns that are not part of the primary key to pk values. col:" + col.Name)
   207  		} else if !types.IsNull(val) && col.Kind != val.Kind() {
   208  			return false, errors.New("bug.  Setting a value to an incorrect kind. col: " + col.Name)
   209  		}
   210  
   211  		return false, nil
   212  	})
   213  
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	filteredVals := make(TaggedValues, len(nonKeyVals))
   219  	_, err = nonKeyVals.Iter(func(tag uint64, val types.Value) (stop bool, err error) {
   220  		col, ok := allCols.GetByTag(tag)
   221  		if !ok {
   222  			return false, nil
   223  		}
   224  
   225  		if col.IsPartOfPK {
   226  			return false, errors.New("writing columns that are part of the primary key to non-pk values. col:" + col.Name)
   227  		} else if !types.IsNull(val) && col.Kind != val.Kind() {
   228  			return false, errors.New("bug.  Setting a value to an incorrect kind. col:" + col.Name)
   229  		} else {
   230  			filteredVals[tag] = val
   231  		}
   232  
   233  		return false, nil
   234  	})
   235  
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	return nomsRow{keyVals, filteredVals, nbf}, nil
   241  }
   242  
   243  func (nr nomsRow) NomsMapKey(sch schema.Schema) types.LesserValuable {
   244  	return nr.key.NomsTupleForPKCols(nr.nbf, sch.GetPKCols())
   245  }
   246  
   247  func (nr nomsRow) NomsMapValue(sch schema.Schema) types.Valuable {
   248  	return nr.value.NomsTupleForNonPKCols(nr.nbf, sch.GetNonPKCols())
   249  }
   250  
   251  func IterPkTuple(tvs types.TupleValueSlice, cb func(tag uint64, val types.Value) (stop bool, err error)) error {
   252  	if len(tvs)%2 != 0 {
   253  		return fmt.Errorf("expected len(TupleValueSlice) to be even, got %d", len(tvs))
   254  	}
   255  
   256  	l := len(tvs)
   257  	for i := 0; i < l; i += 2 {
   258  		stop, err := cb(uint64(tvs[i].(types.Uint)), tvs[i+1])
   259  
   260  		if err != nil {
   261  			return err
   262  		}
   263  
   264  		if stop {
   265  			break
   266  		}
   267  	}
   268  
   269  	return nil
   270  }