github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/merge/stash.go (about) 1 // Copyright 2022 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 20 "github.com/dolthub/dolt/go/libraries/doltcore/conflict" 21 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 22 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 23 "github.com/dolthub/dolt/go/store/types" 24 ) 25 26 type conflictStash struct { 27 Stash map[string]*conflictData 28 } 29 30 type conflictData struct { 31 HasConflicts bool 32 Sch conflict.ConflictSchema 33 ConfIdx durable.ConflictIndex 34 } 35 36 // Empty returns false if any table has a conflict. 37 // True otherwise. 38 func (s *conflictStash) Empty() bool { 39 for _, data := range s.Stash { 40 if data.HasConflicts { 41 return false 42 } 43 } 44 return true 45 } 46 47 type violationStash struct { 48 // todo: durable 49 Stash map[string]types.Map 50 } 51 52 // Empty returns false if any table has constraint violations. 53 // True otherwise. 54 func (s *violationStash) Empty() bool { 55 for _, data := range s.Stash { 56 if data.Len() > 0 { 57 return false 58 } 59 } 60 return true 61 } 62 63 func stashConflicts(ctx context.Context, root doltdb.RootValue) (doltdb.RootValue, *conflictStash, error) { 64 names, err := root.GetTableNames(ctx, doltdb.DefaultSchemaName) 65 if err != nil { 66 return nil, nil, err 67 } 68 69 updatedRoot := root 70 stash := make(map[string]*conflictData, len(names)) 71 for _, name := range names { 72 tbl, _, err := root.GetTable(ctx, doltdb.TableName{Name: name}) 73 if err != nil { 74 return nil, nil, err 75 } 76 d, err := getConflictData(ctx, tbl) 77 if err != nil { 78 return nil, nil, err 79 } 80 stash[name] = d 81 tbl, err = tbl.ClearConflicts(ctx) 82 if err != nil { 83 return nil, nil, err 84 } 85 updatedRoot, err = updatedRoot.PutTable(ctx, doltdb.TableName{Name: name}, tbl) 86 if err != nil { 87 return nil, nil, err 88 } 89 } 90 91 return updatedRoot, &conflictStash{stash}, nil 92 } 93 94 func stashViolations(ctx context.Context, root doltdb.RootValue) (doltdb.RootValue, *violationStash, error) { 95 names, err := root.GetTableNames(ctx, doltdb.DefaultSchemaName) 96 if err != nil { 97 return nil, nil, err 98 } 99 100 updatedRoot := root 101 stash := make(map[string]types.Map, len(names)) 102 for _, name := range names { 103 tbl, _, err := root.GetTable(ctx, doltdb.TableName{Name: name}) 104 if err != nil { 105 return nil, nil, err 106 } 107 v, err := tbl.GetConstraintViolations(ctx) 108 stash[name] = v 109 tbl, err = tbl.SetConstraintViolations(ctx, types.EmptyMap) 110 if err != nil { 111 return nil, nil, err 112 } 113 updatedRoot, err = updatedRoot.PutTable(ctx, doltdb.TableName{Name: name}, tbl) 114 if err != nil { 115 return nil, nil, err 116 } 117 } 118 119 return updatedRoot, &violationStash{stash}, nil 120 } 121 122 // applyConflictStash applies the data in |stash| to the root value. Missing 123 // tables will be skipped. This function will override any previous conflict 124 // data. 125 func applyConflictStash(ctx context.Context, stash map[string]*conflictData, root doltdb.RootValue) (doltdb.RootValue, error) { 126 updatedRoot := root 127 for name, data := range stash { 128 tbl, ok, err := root.GetTable(ctx, doltdb.TableName{Name: name}) 129 if err != nil { 130 return nil, err 131 } 132 if !ok { 133 continue 134 } 135 tbl, err = setConflictData(ctx, tbl, data) 136 if err != nil { 137 return nil, err 138 } 139 updatedRoot, err = updatedRoot.PutTable(ctx, doltdb.TableName{Name: name}, tbl) 140 if err != nil { 141 return nil, err 142 } 143 } 144 145 return updatedRoot, nil 146 } 147 148 func getConflictData(ctx context.Context, tbl *doltdb.Table) (*conflictData, error) { 149 var sch conflict.ConflictSchema 150 var confIdx durable.ConflictIndex 151 152 hasCnf, err := tbl.HasConflicts(ctx) 153 if err != nil { 154 return nil, err 155 } 156 if hasCnf { 157 sch, confIdx, err = tbl.GetConflicts(ctx) 158 if err != nil { 159 return nil, err 160 } 161 } 162 163 return &conflictData{ 164 HasConflicts: hasCnf, 165 Sch: sch, 166 ConfIdx: confIdx, 167 }, nil 168 } 169 170 func setConflictData(ctx context.Context, tbl *doltdb.Table, data *conflictData) (*doltdb.Table, error) { 171 var err error 172 if !data.HasConflicts { 173 tbl, err = tbl.ClearConflicts(ctx) 174 } else { 175 tbl, err = tbl.SetConflicts(ctx, data.Sch, data.ConfIdx) 176 } 177 if err != nil { 178 return nil, err 179 } 180 181 return tbl, nil 182 }