github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/table/inmem_table.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 table 16 17 import ( 18 "context" 19 "io" 20 "sort" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 24 "github.com/dolthub/dolt/go/libraries/doltcore/row" 25 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 26 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 27 "github.com/dolthub/dolt/go/store/types" 28 ) 29 30 // InMemTable holds a simple list of rows that can be retrieved, or appended to. It is meant primarily for testing. 31 type InMemTable struct { 32 sch schema.Schema 33 rows []row.Row 34 } 35 36 // NewInMemTable creates an empty Table with the expectation that any rows added will have the given 37 // Schema 38 func NewInMemTable(sch schema.Schema) *InMemTable { 39 return NewInMemTableWithData(sch, []row.Row{}) 40 } 41 42 // NewInMemTableWithData creates a Table with the riven rows 43 func NewInMemTableWithData(sch schema.Schema, rows []row.Row) *InMemTable { 44 return NewInMemTableWithDataAndValidationType(sch, rows) 45 } 46 47 func NewInMemTableWithDataAndValidationType(sch schema.Schema, rows []row.Row) *InMemTable { 48 return &InMemTable{sch, rows} 49 } 50 51 // AppendRow appends a row. Appended rows must be valid for the table's schema. Sorts rows as they are inserted. 52 func (imt *InMemTable) AppendRow(r row.Row) error { 53 if isv, err := row.IsValid(r, imt.sch); err != nil { 54 return err 55 } else if !isv { 56 col, err := row.GetInvalidCol(r, imt.sch) 57 58 if err != nil { 59 return err 60 } 61 62 val, ok := r.GetColVal(col.Tag) 63 64 if !ok { 65 return NewBadRow(r, col.Name+" is missing") 66 } else { 67 encValStr, err := types.EncodedValue(context.Background(), val) 68 69 if err != nil { 70 return err 71 } 72 73 return NewBadRow(r, col.Name+":"+encValStr+" is not valid.") 74 } 75 } 76 77 imt.rows = append(imt.rows, r) 78 79 var err error 80 // If we are going to pipe these into noms, they need to be sorted. 81 sort.Slice(imt.rows, func(i, j int) bool { 82 if err != nil { 83 return false 84 } 85 86 iRow := imt.rows[i] 87 jRow := imt.rows[j] 88 89 isLess := false 90 isLess, err = iRow.NomsMapKey(imt.sch).Less(r.Format(), jRow.NomsMapKey(imt.sch)) 91 92 return isLess 93 }) 94 95 return nil 96 } 97 98 // GetRow gets a row by index 99 func (imt *InMemTable) GetRow(index int) (row.Row, error) { 100 return imt.rows[index], nil 101 } 102 103 // GetSchema gets the table's schema 104 func (imt *InMemTable) GetSchema() schema.Schema { 105 return imt.sch 106 } 107 108 // NumRows returns the number of rows in the table 109 func (imt *InMemTable) NumRows() int { 110 return len(imt.rows) 111 } 112 113 // InMemTableReader is an implementation of a TableReader for an InMemTable 114 type InMemTableReader struct { 115 tt *InMemTable 116 current int 117 } 118 119 var _ SqlTableReader = &InMemTableReader{} 120 121 // NewInMemTableReader creates an instance of a TableReader from an InMemTable 122 func NewInMemTableReader(imt *InMemTable) *InMemTableReader { 123 return &InMemTableReader{imt, 0} 124 } 125 126 // ReadRow reads a row from a table. If there is a bad row the returned error will be non nil, and callin IsBadRow(err) 127 // will be return true. This is a potentially non-fatal error and callers can decide if they want to continue on a bad row, or fail. 128 func (rd *InMemTableReader) ReadRow(ctx context.Context) (row.Row, error) { 129 numRows := rd.tt.NumRows() 130 131 if rd.current < numRows { 132 r := rd.tt.rows[rd.current] 133 rd.current++ 134 135 return r, nil 136 } 137 138 return nil, io.EOF 139 } 140 141 func (rd *InMemTableReader) ReadSqlRow(ctx context.Context) (sql.Row, error) { 142 r, err := rd.ReadRow(ctx) 143 if err != nil { 144 return nil, err 145 } 146 147 return sqlutil.DoltRowToSqlRow(r, rd.GetSchema()) 148 } 149 150 // Close should release resources being held 151 func (rd *InMemTableReader) Close(ctx context.Context) error { 152 rd.current = -1 153 return nil 154 } 155 156 // GetSchema gets the schema of the rows that this reader will return 157 func (rd *InMemTableReader) GetSchema() schema.Schema { 158 return rd.tt.sch 159 } 160 161 // VerifySchema checks that the incoming schema matches the schema from the existing table 162 func (rd *InMemTableReader) VerifySchema(outSch schema.Schema) (bool, error) { 163 return schema.VerifyInSchema(rd.tt.sch, outSch) 164 } 165 166 // InMemTableWriter is an implementation of a TableWriter for an InMemTable 167 type InMemTableWriter struct { 168 tt *InMemTable 169 } 170 171 // NewInMemTableWriter creates an instance of a TableWriter from an InMemTable 172 func NewInMemTableWriter(imt *InMemTable) *InMemTableWriter { 173 return &InMemTableWriter{imt} 174 } 175 176 // WriteRow will write a row to a table 177 func (w *InMemTableWriter) WriteRow(ctx context.Context, r row.Row) error { 178 return w.tt.AppendRow(r) 179 } 180 181 // Close should flush all writes, release resources being held 182 func (w *InMemTableWriter) Close(ctx context.Context) error { 183 return nil 184 } 185 186 // GetSchema gets the schema of the rows that this writer writes 187 func (w *InMemTableWriter) GetSchema() schema.Schema { 188 return w.tt.sch 189 }