github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/dtables/status_table.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 dtables 16 17 import ( 18 "fmt" 19 "io" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 23 "github.com/dolthub/dolt/go/libraries/doltcore/diff" 24 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 25 "github.com/dolthub/dolt/go/libraries/doltcore/env" 26 "github.com/dolthub/dolt/go/libraries/doltcore/merge" 27 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 28 "github.com/dolthub/dolt/go/store/types" 29 ) 30 31 // StatusTable is a sql.Table implementation that implements a system table which shows the dolt branches 32 type StatusTable struct { 33 ddb *doltdb.DoltDB 34 rsr env.RepoStateReader 35 drw env.DocsReadWriter 36 } 37 38 func (s StatusTable) Name() string { 39 return doltdb.StatusTableName 40 } 41 42 func (s StatusTable) String() string { 43 return doltdb.StatusTableName 44 } 45 46 func (s StatusTable) Schema() sql.Schema { 47 return []*sql.Column{ 48 {Name: "table_name", Type: sql.Text, Source: doltdb.StatusTableName, PrimaryKey: true, Nullable: false}, 49 {Name: "staged", Type: sql.Boolean, Source: doltdb.StatusTableName, PrimaryKey: false, Nullable: false}, 50 {Name: "status", Type: sql.Text, Source: doltdb.StatusTableName, PrimaryKey: false, Nullable: false}, 51 } 52 } 53 54 func (s StatusTable) Partitions(*sql.Context) (sql.PartitionIter, error) { 55 return sqlutil.NewSinglePartitionIter(types.Map{}), nil 56 } 57 58 func (s StatusTable) PartitionRows(context *sql.Context, _ sql.Partition) (sql.RowIter, error) { 59 return newStatusItr(context, &s) 60 } 61 62 // NewStatusTable creates a StatusTable 63 func NewStatusTable(_ *sql.Context, ddb *doltdb.DoltDB, rsr env.RepoStateReader, drw env.DocsReadWriter) sql.Table { 64 return &StatusTable{ddb: ddb, rsr: rsr, drw: drw} 65 } 66 67 // StatusIter is a sql.RowItr implementation which iterates over each commit as if it's a row in the table. 68 type StatusItr struct { 69 tables []string 70 isStaged []bool 71 statuses []string 72 idx int 73 } 74 75 func newStatusItr(ctx *sql.Context, st *StatusTable) (*StatusItr, error) { 76 ddb := st.ddb 77 rsr := st.rsr 78 drw := st.drw 79 80 stagedTables, unstagedTables, err := diff.GetStagedUnstagedTableDeltas(ctx, ddb, rsr) 81 82 if err != nil { 83 return &StatusItr{}, err 84 } 85 86 stagedDocDiffs, unStagedDocDiffs, err := diff.GetDocDiffs(ctx, ddb, rsr, drw) 87 88 if err != nil { 89 return &StatusItr{}, err 90 } 91 92 workingTblsInConflict, _, _, err := merge.GetTablesInConflict(ctx, ddb, rsr) 93 94 if err != nil { 95 return &StatusItr{}, err 96 } 97 98 workingDocsInConflict, err := merge.GetDocsInConflict(ctx, ddb, rsr, drw) 99 100 if err != nil { 101 return &StatusItr{}, err 102 } 103 104 tLength := len(stagedTables) + len(unstagedTables) + len(stagedDocDiffs.Docs) + len(unStagedDocDiffs.Docs) + len(workingTblsInConflict) + len(workingDocsInConflict.Docs) 105 106 tables := make([]string, tLength) 107 isStaged := make([]bool, tLength) 108 statuses := make([]string, tLength) 109 110 itr := &StatusItr{tables: tables, isStaged: isStaged, statuses: statuses, idx: 0} 111 112 idx := handleStagedUnstagedTables(stagedTables, unstagedTables, itr, 0) 113 idx = handleStagedUnstagedDocDiffs(stagedDocDiffs, unStagedDocDiffs, itr, idx) 114 idx = handleWorkingTablesInConflict(workingTblsInConflict, itr, idx) 115 idx = handleWorkingDocConflicts(workingDocsInConflict, itr, idx) 116 117 return itr, nil 118 } 119 120 var tblDiffTypeToLabel = map[diff.TableDiffType]string{ 121 diff.ModifiedTable: "modified", 122 diff.RenamedTable: "renamed", 123 diff.RemovedTable: "deleted", 124 diff.AddedTable: "new table", 125 } 126 127 func handleStagedUnstagedTables(staged, unstaged []diff.TableDelta, itr *StatusItr, idx int) int { 128 combined := append(staged, unstaged...) 129 for i, td := range combined { 130 itr.isStaged[idx] = i < len(staged) 131 if td.IsAdd() { 132 itr.tables[idx] = td.CurName() 133 itr.statuses[idx] = tblDiffTypeToLabel[diff.AddedTable] 134 } else if td.IsDrop() { 135 itr.tables[idx] = td.CurName() 136 itr.statuses[idx] = tblDiffTypeToLabel[diff.RemovedTable] 137 } else if td.IsRename() { 138 itr.tables[idx] = fmt.Sprintf("%s -> %s", td.FromName, td.ToName) 139 itr.statuses[idx] = tblDiffTypeToLabel[diff.RemovedTable] 140 } else { 141 itr.tables[idx] = td.CurName() 142 itr.statuses[idx] = tblDiffTypeToLabel[diff.ModifiedTable] 143 } 144 145 idx += 1 146 } 147 148 return idx 149 } 150 151 var docDiffTypeToLabel = map[diff.DocDiffType]string{ 152 diff.ModifiedDoc: "modified", 153 diff.RemovedDoc: "deleted", 154 diff.AddedDoc: "new doc", 155 } 156 157 func handleStagedUnstagedDocDiffs(staged *diff.DocDiffs, unstaged *diff.DocDiffs, itr *StatusItr, idx int) int { 158 combined := append(staged.Docs, unstaged.Docs...) 159 for i, docName := range combined { 160 dType := staged.DocToType[docName] 161 162 itr.tables[idx] = docName 163 itr.isStaged[idx] = i < len(staged.Docs) 164 itr.statuses[idx] = docDiffTypeToLabel[dType] 165 166 idx += 1 167 } 168 169 return idx 170 } 171 172 const mergeConflictStatus = "conflict" 173 174 func handleWorkingTablesInConflict(workingTables []string, itr *StatusItr, idx int) int { 175 for _, tableName := range workingTables { 176 itr.tables[idx] = tableName 177 itr.isStaged[idx] = false 178 itr.statuses[idx] = mergeConflictStatus 179 180 idx += 1 181 } 182 183 return idx 184 } 185 186 func handleWorkingDocConflicts(workingDocs *diff.DocDiffs, itr *StatusItr, idx int) int { 187 for _, docName := range workingDocs.Docs { 188 itr.tables[idx] = docName 189 itr.isStaged[idx] = false 190 itr.statuses[idx] = mergeConflictStatus 191 192 idx += 1 193 } 194 195 return idx 196 } 197 198 // Next retrieves the next row. It will return io.EOF if it's the last row. 199 // After retrieving the last row, Close will be automatically closed. 200 func (itr *StatusItr) Next() (sql.Row, error) { 201 if itr.idx >= len(itr.tables) { 202 return nil, io.EOF 203 } 204 205 defer func() { 206 itr.idx++ 207 }() 208 209 return sql.NewRow(itr.tables[itr.idx], itr.isStaged[itr.idx], itr.statuses[itr.idx]), nil 210 } 211 212 // Close closes the iterator. 213 func (itr *StatusItr) Close(*sql.Context) error { 214 return nil 215 }