github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/merge/resolve.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 merge 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 22 "github.com/dolthub/dolt/go/libraries/doltcore/row" 23 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 24 "github.com/dolthub/dolt/go/libraries/doltcore/table" 25 "github.com/dolthub/dolt/go/libraries/doltcore/table/editor" 26 "github.com/dolthub/dolt/go/store/types" 27 ) 28 29 type AutoResolver func(key types.Value, conflict doltdb.Conflict) (types.Value, error) 30 31 func Ours(key types.Value, cnf doltdb.Conflict) (types.Value, error) { 32 return cnf.Value, nil 33 } 34 35 func Theirs(key types.Value, cnf doltdb.Conflict) (types.Value, error) { 36 return cnf.MergeValue, nil 37 } 38 39 func ResolveTable(ctx context.Context, vrw types.ValueReadWriter, tblName string, tbl *doltdb.Table, autoResFunc AutoResolver, sess *editor.TableEditSession) error { 40 if has, err := tbl.HasConflicts(); err != nil { 41 return err 42 } else if !has { 43 return doltdb.ErrNoConflicts 44 } 45 46 tblSch, err := tbl.GetSchema(ctx) 47 if err != nil { 48 return err 49 } 50 51 if schema.IsKeyless(tblSch) { 52 tbl, err = resolveKeylessTable(ctx, tbl, autoResFunc) 53 } else { 54 tbl, err = resolvePkTable(ctx, sess, tbl, tblName, autoResFunc) 55 } 56 if err != nil { 57 return err 58 } 59 60 schemas, _, err := tbl.GetConflicts(ctx) 61 if err != nil { 62 return err 63 } 64 65 return sess.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) { 66 m, err := types.NewMap(ctx, vrw) 67 if err != nil { 68 return nil, err 69 } 70 71 tbl, err = tbl.SetConflicts(ctx, schemas, m) 72 if err != nil { 73 return nil, err 74 } 75 76 return root.PutTable(ctx, tblName, tbl) 77 }) 78 } 79 80 func resolvePkTable(ctx context.Context, sess *editor.TableEditSession, tbl *doltdb.Table, tblName string, auto AutoResolver) (*doltdb.Table, error) { 81 tblSch, err := tbl.GetSchema(ctx) 82 if err != nil { 83 return nil, err 84 } 85 86 _, conflicts, err := tbl.GetConflicts(ctx) 87 if err != nil { 88 return nil, err 89 } 90 91 tableEditor, err := sess.GetTableEditor(ctx, tblName, tblSch) 92 if err != nil { 93 return nil, err 94 } 95 96 err = conflicts.Iter(ctx, func(key, value types.Value) (stop bool, err error) { 97 cnf, err := doltdb.ConflictFromTuple(value.(types.Tuple)) 98 if err != nil { 99 return false, err 100 } 101 102 updated, err := auto(key, cnf) 103 if err != nil { 104 return false, err 105 } 106 107 if types.IsNull(updated) { 108 originalRow, err := row.FromNoms(tblSch, key.(types.Tuple), cnf.Base.(types.Tuple)) 109 if err != nil { 110 return false, err 111 } 112 113 err = tableEditor.DeleteRow(ctx, originalRow) 114 if err != nil { 115 return false, err 116 } 117 } else { 118 updatedRow, err := row.FromNoms(tblSch, key.(types.Tuple), updated.(types.Tuple)) 119 if err != nil { 120 return false, err 121 } 122 123 if has, err := row.IsValid(updatedRow, tblSch); err != nil { 124 return false, err 125 } else if !has { 126 return false, table.NewBadRow(updatedRow) 127 } 128 129 if types.IsNull(cnf.Value) { 130 err = tableEditor.InsertRow(ctx, updatedRow, nil) 131 if err != nil { 132 return false, err 133 } 134 } else { 135 originalRow, err := row.FromNoms(tblSch, key.(types.Tuple), cnf.Value.(types.Tuple)) 136 if err != nil { 137 return false, err 138 } 139 err = tableEditor.UpdateRow(ctx, originalRow, updatedRow, nil) 140 if err != nil { 141 return false, err 142 } 143 } 144 } 145 146 return false, nil 147 }) 148 if err != nil { 149 return nil, err 150 } 151 152 root, err := sess.Flush(ctx) 153 if err != nil { 154 return nil, err 155 } 156 157 newTbl, ok, err := root.GetTable(ctx, tblName) 158 if err != nil { 159 return nil, err 160 } 161 if !ok { 162 return nil, fmt.Errorf("resolved table `%s` cannot be found", tblName) 163 } 164 165 return newTbl, nil 166 } 167 168 func resolveKeylessTable(ctx context.Context, tbl *doltdb.Table, auto AutoResolver) (*doltdb.Table, error) { 169 _, conflicts, err := tbl.GetConflicts(ctx) 170 if err != nil { 171 return nil, err 172 } 173 174 rowData, err := tbl.GetRowData(ctx) 175 if err != nil { 176 return nil, err 177 } 178 179 edit := rowData.Edit() 180 181 err = conflicts.Iter(ctx, func(key, value types.Value) (stop bool, err error) { 182 cnf, err := doltdb.ConflictFromTuple(value.(types.Tuple)) 183 if err != nil { 184 return false, err 185 } 186 187 resolved, err := auto(key, cnf) 188 if err != nil { 189 return false, err 190 } 191 192 if types.IsNull(resolved) { 193 edit.Remove(key) 194 } else { 195 edit.Set(key, resolved) 196 } 197 198 return false, nil 199 }) 200 if err != nil { 201 return nil, err 202 } 203 204 rowData, err = edit.Map(ctx) 205 if err != nil { 206 return nil, err 207 } 208 209 return tbl.UpdateRows(ctx, rowData) 210 }