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 }