github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/diff/docs_diffs.go (about) 1 // Copyright 2020 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 diff 16 17 import ( 18 "context" 19 "strconv" 20 21 "github.com/dolthub/dolt/go/libraries/doltcore/doltdocs" 22 23 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 24 ) 25 26 type docComparison struct { 27 DocName string 28 CurrentText []byte 29 OldText []byte 30 } 31 32 // DocsDiff returns the added, modified and removed docs when comparing a root value with an other (newer) value. If the other value, 33 // is not provided, then we compare the docs on the root value to the docs provided. 34 func DocsDiff(ctx context.Context, root *doltdb.RootValue, other *doltdb.RootValue, docs doltdocs.Docs) (added, modified, removed []string, err error) { 35 docComparisons, err := DocsDiffToComparisons(ctx, root, other, docs) 36 37 if err != nil { 38 return nil, nil, nil, err 39 } 40 41 a, m, r := computeDiffsFromDocComparisons(docComparisons) 42 return a, m, r, nil 43 } 44 45 // DocsDiffToComparisons returns the docComparisons between an old root, a new root, and a set of docs. It is exported 46 // due to the cli usage of doc diffs. 47 func DocsDiffToComparisons(ctx context.Context, root *doltdb.RootValue, other *doltdb.RootValue, docs doltdocs.Docs) ([]docComparison, error) { 48 if other == nil { 49 return compareRootWithDocs(ctx, root, docs) 50 } else { 51 return compareDocsBtwnRoots(ctx, root, other) 52 } 53 } 54 55 // compareRootWithDocs compares a root and set of new docs. 56 func compareRootWithDocs(ctx context.Context, root *doltdb.RootValue, docs doltdocs.Docs) ([]docComparison, error) { 57 oldDocs, found, err := doltdocs.GetAllDocs(ctx, root) 58 if err != nil { 59 return nil, err 60 } 61 if !found { 62 oldDocs = make(doltdocs.Docs, 0) 63 } 64 65 return getDocComparisons(oldDocs, docs), nil 66 } 67 68 // compareDocsBtwnRoots takes an oldRoot and a newRoot and compares the docs tables between the two. 69 func compareDocsBtwnRoots(ctx context.Context, oldRoot *doltdb.RootValue, newRoot *doltdb.RootValue) ([]docComparison, error) { 70 oldDocs, found, err := doltdocs.GetAllDocs(ctx, oldRoot) 71 if err != nil { 72 return nil, err 73 } 74 if !found { 75 oldDocs = make(doltdocs.Docs, 0) 76 } 77 78 newDocs, found, err := doltdocs.GetAllDocs(ctx, newRoot) 79 if err != nil { 80 return nil, err 81 } 82 if !found { 83 newDocs = make(doltdocs.Docs, 0) 84 } 85 86 return getDocComparisons(oldDocs, newDocs), nil 87 } 88 89 // getDocComparisons compares two sets of docs looking for modifications, removals, and additions as docComparisons 90 func getDocComparisons(oldDocs doltdocs.Docs, newDocs doltdocs.Docs) []docComparison { 91 docComparisons := make([]docComparison, 0) 92 93 // First case is looking at the old docs and seeing what was modified or removed 94 for _, oldDoc := range oldDocs { 95 dc := docComparison{DocName: oldDoc.DocPk, OldText: oldDoc.Text, CurrentText: getMatchingText(oldDoc, newDocs)} 96 docComparisons = append(docComparisons, dc) 97 } 98 99 // Second case is looking back at the old docs and seeing what was added 100 for _, newDoc := range newDocs { 101 oldText := getMatchingText(newDoc, oldDocs) 102 if oldText == nil { 103 dc := docComparison{DocName: newDoc.DocPk, OldText: nil, CurrentText: newDoc.Text} 104 docComparisons = append(docComparisons, dc) 105 } 106 } 107 108 return docComparisons 109 } 110 111 // getMatchingText matches a doc in a set of other docs and returns the relevant text. 112 func getMatchingText(doc doltdocs.Doc, docs doltdocs.Docs) []byte { 113 for _, toCompare := range docs { 114 if doc.DocPk == toCompare.DocPk { 115 return toCompare.Text 116 } 117 } 118 119 return nil 120 } 121 122 // computeDiffsFromDocComparisons takes the docComparisons and returns the final add, modified, removed count. 123 func computeDiffsFromDocComparisons(docComparisons []docComparison) (added, modified, removed []string) { 124 added = []string{} 125 modified = []string{} 126 removed = []string{} 127 for _, doc := range docComparisons { 128 added, modified, removed = appendDocDiffs(added, modified, removed, doc.OldText, doc.CurrentText, doc.DocName) 129 } 130 return added, modified, removed 131 } 132 133 func appendDocDiffs(added, modified, removed []string, olderVal []byte, newerVal []byte, docPk string) (add, mod, rem []string) { 134 if olderVal == nil && newerVal != nil { 135 added = append(added, docPk) 136 } else if olderVal != nil { 137 if newerVal == nil { 138 removed = append(removed, docPk) 139 } else if strconv.Quote(string(olderVal)) != strconv.Quote(string(newerVal)) { 140 modified = append(modified, docPk) 141 } 142 } 143 return added, modified, removed 144 }