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  }