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  }