Repository: genjidb/genji (go)

Issue:
Ignore input with whitespace only
Whenever we press return with no input or whitespace only input in the CLI, it invites the user to add a `;`.
We should simply ignore the input.

Current behavior:

```
genji> <press return, with or without whitespace>
... <press ';', then return>
genji>
```

Expected behavior:

```
genji> <press return, with or without whitespace>
genji>
```

Pull request description:
Ignore Input shell with whitespaces only or no input
This PR fixes #106 by adding `TrimSpace` of input.
The command is ignored if the input is empty.

Patch:
diff --git a/cmd/genji/shell/shell.go b/cmd/genji/shell/shell.go
index d29a3a76..5757d1c4 100644
--- a/cmd/genji/shell/shell.go
+++ b/cmd/genji/shell/shell.go
@@ -185,6 +185,7 @@ func (sh *Shell) execute(in string) {
 }
 
 func (sh *Shell) executeInput(in string) error {
+	in = strings.TrimSpace(in)
 	switch {
 	// if it starts with a "." it's a command
 	// it must not be in the middle of a multi line query though
@@ -198,6 +199,9 @@ func (sh *Shell) executeInput(in string) error {
 		err := sh.runQuery(sh.query)
 		sh.query = ""
 		return err
+	// If the input is empty we ignore it
+	case in == "":
+		return nil
 	// If we reach this case, it means the user is in the middle of a
 	// multi line query. We change the prompt and set the multiLine var to true.
 	default:
diff --git a/database/config.go b/database/config.go
index db290c20..aba1ed95 100644
--- a/database/config.go
+++ b/database/config.go
@@ -12,63 +12,6 @@ import (
 	"github.com/genjidb/genji/index"
 )
 
-// TableConfig holds the configuration of a table
-type TableConfig struct {
-	FieldConstraints []FieldConstraint
-}
-
-// ToDocument returns a document from t.
-func (t *TableConfig) ToDocument() document.Document {
-	buf := document.NewFieldBuffer()
-
-	vbuf := document.NewValueBuffer()
-	for _, fc := range t.FieldConstraints {
-		vbuf = vbuf.Append(document.NewDocumentValue(fc.ToDocument()))
-	}
-
-	buf.Add("field_constraints", document.NewArrayValue(vbuf))
-	return buf
-}
-
-// ScanDocument implements the document.Scanner interface.
-func (t *TableConfig) ScanDocument(d document.Document) error {
-	v, err := d.GetByField("field_constraints")
-	if err != nil {
-		return err
-	}
-	ar, err := v.ConvertToArray()
-	if err != nil {
-		return err
-	}
-
-	l, err := document.ArrayLength(ar)
-	if err != nil {
-		return err
-	}
-
-	t.FieldConstraints = make([]FieldConstraint, l)
-
-	return ar.Iterate(func(i int, value document.Value) error {
-		doc, err := value.ConvertToDocument()
-		if err != nil {
-			return err
-		}
-		return t.FieldConstraints[i].ScanDocument(doc)
-	})
-}
-
-// GetPrimaryKey returns the field constraint of the primary key.
-// Returns nil if there is no primary key.
-func (t TableConfig) GetPrimaryKey() *FieldConstraint {
-	for _, f := range t.FieldConstraints {
-		if f.IsPrimaryKey {
-			return &f
-		}
-	}
-
-	return nil
-}
-
 // FieldConstraint describes constraints on a particular field.
 type FieldConstraint struct {
 	Path         document.ValuePath
@@ -126,25 +69,43 @@ func (f *FieldConstraint) ScanDocument(d document.Document) error {
 	return err
 }
 
-type tableInfo struct {
+type TableInfo struct {
 	// storeID is a generated ID that acts as a key to reference a table.
 	// The first-4 bytes represents the timestamp in second and the last-2 bytes are
 	// randomly generated.
 	storeID [6]byte
 
-	cfg *TableConfig
+	FieldConstraints []FieldConstraint
+}
+
+// GetPrimaryKey returns the field constraint of the primary key.
+// Returns nil if there is no primary key.
+func (ti *TableInfo) GetPrimaryKey() *FieldConstraint {
+	for _, f := range ti.FieldConstraints {
+		if f.IsPrimaryKey {
+			return &f
+		}
+	}
+
+	return nil
 }
 
-func (ti *tableInfo) ToDocument() document.Document {
+func (ti *TableInfo) ToDocument() document.Document {
 	buf := document.NewFieldBuffer()
 
 	buf.Add("storeID", document.NewBlobValue(ti.storeID[:]))
-	buf.Add("config", document.NewDocumentValue(ti.cfg.ToDocument()))
+
+	vbuf := document.NewValueBuffer()
+	for _, fc := range ti.FieldConstraints {
+		vbuf = vbuf.Append(document.NewDocumentValue(fc.ToDocument()))
+	}
+
+	buf.Add("field_constraints", document.NewArrayValue(vbuf))
 
 	return buf
 }
 
-func (ti *tableInfo) ScanDocument(d document.Document) error {
+func (ti *TableInfo) ScanDocument(d document.Document) error {
 	v, err := d.GetByField("storeID")
 	if err != nil {
 		return err
@@ -155,17 +116,29 @@ func (ti *tableInfo) ScanDocument(d document.Document) error {
 	}
 	copy(ti.storeID[:], b)
 
-	v, err = d.GetByField("config")
+	v, err = d.GetByField("field_constraints")
 	if err != nil {
 		return err
 	}
-	doc, err := v.ConvertToDocument()
+	ar, err := v.ConvertToArray()
 	if err != nil {
 		return err
 	}
 
-	ti.cfg = &TableConfig{}
-	return ti.cfg.ScanDocument(doc)
+	l, err := document.ArrayLength(ar)
+	if err != nil {
+		return err
+	}
+
+	ti.FieldConstraints = make([]FieldConstraint, l)
+
+	return ar.Iterate(func(i int, value document.Value) error {
+		doc, err := value.ConvertToDocument()
+		if err != nil {
+			return err
+		}
+		return ti.FieldConstraints[i].ScanDocument(doc)
+	})
 }
 
 type tableInfoStore struct {
@@ -174,7 +147,7 @@ type tableInfoStore struct {
 
 // Insert a new tableInfo for the given table name.
 // It automatically generates a unique storeID for that table.
-func (t *tableInfoStore) Insert(tableName string, cfg TableConfig) (*tableInfo, error) {
+func (t *tableInfoStore) Insert(tableName string, info *TableInfo) ([]byte, error) {
 	key := []byte(tableName)
 	_, err := t.st.Get(key)
 	if err == nil {
@@ -198,12 +171,9 @@ func (t *tableInfoStore) Insert(tableName string, cfg TableConfig) (*tableInfo,
 		}
 		break
 	}
-	ti := tableInfo{
-		storeID: id,
-		cfg:     &cfg,
-	}
+	info.storeID = id
 
-	v, err := encoding.EncodeDocument(ti.ToDocument())
+	v, err := encoding.EncodeDocument(info.ToDocument())
 	if err != nil {
 		return nil, err
 	}
@@ -212,25 +182,10 @@ func (t *tableInfoStore) Insert(tableName string, cfg TableConfig) (*tableInfo,
 	if err != nil {
 		return nil, err
 	}
-	return &ti, err
-}
-
-func (t *tableInfoStore) Replace(tableName string, cfg *TableConfig) error {
-	ti, err := t.Get(tableName)
-	if err != nil {
-		return err
-	}
-
-	ti.cfg = cfg
-	v, err := encoding.EncodeDocument(ti.ToDocument())
-	if err != nil {
-		return err
-	}
-
-	return t.st.Put([]byte(tableName), v)
+	return info.storeID[:], err
 }
 
-func (t *tableInfoStore) Get(tableName string) (*tableInfo, error) {
+func (t *tableInfoStore) Get(tableName string) (*TableInfo, error) {
 	key := []byte(tableName)
 	v, err := t.st.Get(key)
 	if err == engine.ErrKeyNotFound {
@@ -240,7 +195,7 @@ func (t *tableInfoStore) Get(tableName string) (*tableInfo, error) {
 		return nil, err
 	}
 
-	var ti tableInfo
+	var ti TableInfo
 	err = ti.ScanDocument(encoding.EncodedDocument(v))
 	if err != nil {
 		return nil, err
diff --git a/database/table.go b/database/table.go
index b916c3c1..1b6bd6e5 100644
--- a/database/table.go
+++ b/database/table.go
@@ -21,13 +21,14 @@ type Table struct {
 	infoStore *tableInfoStore
 }
 
-// Config of the table.
-func (t *Table) Config() (*TableConfig, error) {
+// Info of the table.
+func (t *Table) Info() (*TableInfo, error) {
 	ti, err := t.infoStore.Get(t.name)
 	if err != nil {
 		return nil, err
 	}
-	return ti.cfg, nil
+
+	return ti, nil
 }
 
 type encodedDocumentWithKey struct {
@@ -101,9 +102,7 @@ func (t *Table) generateKey(d document.Document) ([]byte, error) {
 		return nil, err
 	}
 
-	cfg := ti.cfg
-
-	if pk := cfg.GetPrimaryKey(); pk != nil {
+	if pk := ti.GetPrimaryKey(); pk != nil {
 		v, err := pk.Path.GetValue(d)
 		if err == document.ErrFieldNotFound {
 			return nil, fmt.Errorf("missing primary key at path %q", pk.Path)
@@ -207,14 +206,14 @@ func getParentValue(d document.Document, p document.ValuePath) (document.Value,
 // the document, the fields are converted to these types when possible. if the conversion
 // fails, an error is returned.
 func (t *Table) ValidateConstraints(d document.Document) (document.Document, error) {
-	cfg, err := t.Config()
+	info, err := t.Info()
 	if err != nil {
 		return nil, err
 	}
 
-	pk := cfg.GetPrimaryKey()
+	pk := info.GetPrimaryKey()
 
-	if len(cfg.FieldConstraints) == 0 && pk == nil {
+	if len(info.FieldConstraints) == 0 && pk == nil {
 		return d, nil
 	}
 
@@ -234,7 +233,7 @@ func (t *Table) ValidateConstraints(d document.Document) (document.Document, err
 		}
 	}
 
-	for _, fc := range cfg.FieldConstraints {
+	for _, fc := range info.FieldConstraints {
 		err := validateConstraint(&fb, &fc)
 		if err != nil {
 			return nil, err
diff --git a/database/transaction.go b/database/transaction.go
index c41775ad..578c3813 100644
--- a/database/transaction.go
+++ b/database/transaction.go
@@ -66,16 +66,16 @@ func (tx *Transaction) Promote() error {
 
 // CreateTable creates a table with the given name.
 // If it already exists, returns ErrTableAlreadyExists.
-func (tx Transaction) CreateTable(name string, cfg *TableConfig) error {
-	if cfg == nil {
-		cfg = new(TableConfig)
+func (tx Transaction) CreateTable(name string, info *TableInfo) error {
+	if info == nil {
+		info = new(TableInfo)
 	}
-	ti, err := tx.tableInfoStore.Insert(name, *cfg)
+	sid, err := tx.tableInfoStore.Insert(name, info)
 	if err != nil {
 		return err
 	}
 
-	err = tx.Tx.CreateStore(ti.storeID[:])
+	err = tx.Tx.CreateStore(sid)
 	if err != nil {
 		return fmt.Errorf("failed to create table %q: %w", name, err)
 	}
diff --git a/sql/parser/create.go b/sql/parser/create.go
index 62f43f55..6a341828 100644
--- a/sql/parser/create.go
+++ b/sql/parser/create.go
@@ -46,8 +46,8 @@ func (p *Parser) parseCreateTableStatement() (query.CreateTableStmt, error) {
 		return stmt, err
 	}
 
-	// parse table config
-	err = p.parseTableConfig(&stmt.Config)
+	// parse field constraints
+	err = p.parseFieldConstraints(&stmt.Info)
 	if err != nil {
 		return stmt, err
 	}
@@ -75,7 +75,7 @@ func (p *Parser) parseIfNotExists() (bool, error) {
 	return true, nil
 }
 
-func (p *Parser) parseTableConfig(cfg *database.TableConfig) error {
+func (p *Parser) parseFieldConstraints(info *database.TableInfo) error {
 	// Parse ( token.
 	if tok, _, _ := p.ScanIgnoreWhitespace(); tok != scanner.LPAREN {
 		p.Unscan()
@@ -101,7 +101,7 @@ func (p *Parser) parseTableConfig(cfg *database.TableConfig) error {
 			return err
 		}
 
-		cfg.FieldConstraints = append(cfg.FieldConstraints, fc)
+		info.FieldConstraints = append(info.FieldConstraints, fc)
 
 		if tok, _, _ := p.ScanIgnoreWhitespace(); tok != scanner.COMMA {
 			p.Unscan()
@@ -116,7 +116,7 @@ func (p *Parser) parseTableConfig(cfg *database.TableConfig) error {
 
 	// ensure only one primary key
 	var pkCount int
-	for _, fc := range cfg.FieldConstraints {
+	for _, fc := range info.FieldConstraints {
 		if fc.IsPrimaryKey {
 			pkCount++
 		}
diff --git a/sql/planner/projection.go b/sql/planner/projection.go
index 8a4e9638..c6b1e73f 100644
--- a/sql/planner/projection.go
+++ b/sql/planner/projection.go
@@ -21,8 +21,8 @@ type ProjectionNode struct {
 	Expressions []ResultField
 	tableName   string
 
-	cfg *database.TableConfig
-	tx  *database.Transaction
+	info *database.TableInfo
+	tx   *database.Transaction
 }
 
 var _ outputNode = (*ProjectionNode)(nil)
@@ -52,7 +52,7 @@ func (n *ProjectionNode) Bind(tx *database.Transaction, params []expr.Param) (er
 		return err
 	}
 
-	n.cfg, err = table.Config()
+	n.info, err = table.Info()
 	return
 }
 
@@ -72,7 +72,7 @@ func (n *ProjectionNode) toStream(st document.Stream) (document.Stream, error) {
 
 	return st.Map(func(d document.Document) (document.Document, error) {
 		return documentMask{
-			cfg:          n.cfg,
+			info:         n.info,
 			r:            d,
 			resultFields: n.Expressions,
 		}, nil
@@ -103,7 +103,7 @@ func (n *ProjectionNode) String() string {
 }
 
 type documentMask struct {
-	cfg          *database.TableConfig
+	info         *database.TableInfo
 	r            document.Document
 	resultFields []ResultField
 }
@@ -123,7 +123,7 @@ func (r documentMask) GetByField(field string) (document.Value, error) {
 func (r documentMask) Iterate(fn func(field string, value document.Value) error) error {
 	stack := expr.EvalStack{
 		Document: r.r,
-		Cfg:      r.cfg,
+		Info:     r.info,
 	}
 
 	for _, rf := range r.resultFields {
diff --git a/sql/query/create.go b/sql/query/create.go
index 9cc5d0c1..fbbeccb9 100644
--- a/sql/query/create.go
+++ b/sql/query/create.go
@@ -12,7 +12,7 @@ import (
 type CreateTableStmt struct {
 	TableName   string
 	IfNotExists bool
-	Config      database.TableConfig
+	Info        database.TableInfo
 }
 
 // IsReadOnly always returns false. It implements the Statement interface.
@@ -29,7 +29,7 @@ func (stmt CreateTableStmt) Run(tx *database.Transaction, args []expr.Param) (Re
 		return res, errors.New("missing table name")
 	}
 
-	err := tx.CreateTable(stmt.TableName, &stmt.Config)
+	err := tx.CreateTable(stmt.TableName, &stmt.Info)
 	if stmt.IfNotExists && err == database.ErrTableAlreadyExists {
 		err = nil
 	}
diff --git a/sql/query/expr/expr.go b/sql/query/expr/expr.go
index 5d0707da..3a7d37bf 100644
--- a/sql/query/expr/expr.go
+++ b/sql/query/expr/expr.go
@@ -44,7 +44,7 @@ type EvalStack struct {
 	Tx       *database.Transaction
 	Document document.Document
 	Params   []Param
-	Cfg      *database.TableConfig
+	Info     *database.TableInfo
 }
 
 type simpleOperator struct {
diff --git a/sql/query/expr/function.go b/sql/query/expr/function.go
index 7a2b09b6..b8738e3a 100644
--- a/sql/query/expr/function.go
+++ b/sql/query/expr/function.go
@@ -33,11 +33,11 @@ type PKFunc struct{}
 
 // Eval returns the primary key of the current document.
 func (k PKFunc) Eval(ctx EvalStack) (document.Value, error) {
-	if ctx.Cfg == nil {
+	if ctx.Info == nil {
 		return document.Value{}, errors.New("no table specified")
 	}
 
-	pk := ctx.Cfg.GetPrimaryKey()
+	pk := ctx.Info.GetPrimaryKey()
 	if pk != nil {
 		return pk.Path.GetValue(ctx.Document)
 	}
diff --git a/sql/query/plan.go b/sql/query/plan.go
index 83a1435b..3e8af8c9 100644
--- a/sql/query/plan.go
+++ b/sql/query/plan.go
@@ -39,7 +39,7 @@ func newQueryOptimizer(tx *database.Transaction, tableName string) (qo queryOpti
 		return
 	}
 
-	cfg, err := t.Config()
+	info, err := t.Info()
 	if err != nil {
 		return
 	}
@@ -48,7 +48,7 @@ func newQueryOptimizer(tx *database.Transaction, tableName string) (qo queryOpti
 		tx:        tx,
 		t:         t,
 		tableName: tableName,
-		cfg:       cfg,
+		info:      info,
 		indexes:   indexes,
 	}, nil
 }
@@ -60,7 +60,7 @@ type queryOptimizer struct {
 	tableName        string
 	whereExpr        expr.Expr
 	args             []expr.Param
-	cfg              *database.TableConfig
+	info             *database.TableInfo
 	indexes          map[string]database.Index
 	orderBy          expr.FieldSelector
 	orderByDirection scanner.Token
@@ -79,7 +79,7 @@ func (qo *queryOptimizer) optimizeQuery() (st document.Stream, err error) {
 			pkit := pkIterator{
 				tx:               qo.tx,
 				tb:               qo.t,
-				cfg:              qo.cfg,
+				info:             qo.info,
 				args:             qo.args,
 				e:                qp.field.e,
 				orderByDirection: qo.orderByDirection,
@@ -105,7 +105,7 @@ func (qo *queryOptimizer) optimizeQuery() (st document.Stream, err error) {
 		// for all operators except IN, we require the exact same type
 		// otherwise we operate a scan table.
 		if !expr.IsInOperator(qp.field.op) {
-			v, err = v.ConvertTo(qo.cfg.GetPrimaryKey().Type)
+			v, err = v.ConvertTo(qo.info.GetPrimaryKey().Type)
 			if err != nil {
 				err = nil
 				st = document.NewStream(qo.t)
@@ -116,7 +116,7 @@ func (qo *queryOptimizer) optimizeQuery() (st document.Stream, err error) {
 		pkit := pkIterator{
 			tx:               qo.tx,
 			tb:               qo.t,
-			cfg:              qo.cfg,
+			info:             qo.info,
 			args:             qo.args,
 			e:                qp.field.e,
 			orderByDirection: qo.orderByDirection,
@@ -164,7 +164,7 @@ func (qo *queryOptimizer) buildQueryPlan() queryPlan {
 	if qp.field == nil {
 		if len(qo.orderBy) != 0 {
 			_, ok := qo.indexes[qo.orderBy.Name()]
-			pk := qo.cfg.GetPrimaryKey()
+			pk := qo.info.GetPrimaryKey()
 			if ok || (pk != nil && pk.Path.String() == qo.orderBy.Name()) {
 				qp.field = &queryPlanField{
 					indexedField: qo.orderBy,
@@ -216,7 +216,7 @@ func (qo *queryOptimizer) analyseExpr(e expr.Expr) *queryPlanField {
 			}
 		}
 
-		pk := qo.cfg.GetPrimaryKey()
+		pk := qo.info.GetPrimaryKey()
 		if pk != nil && pk.Path.String() == fs.Name() {
 			return &queryPlanField{
 				indexedField: fs,
@@ -356,7 +356,7 @@ type pkIteratorOperator interface {
 type pkIterator struct {
 	tx               *database.Transaction
 	tb               *database.Table
-	cfg              *database.TableConfig
+	info             *database.TableInfo
 	args             []expr.Param
 	e                expr.Expr
 	pkop             pkIteratorOperator
@@ -388,7 +388,7 @@ func (it pkIterator) Iterate(fn func(d document.Document) error) error {
 		return nil
 	}
 
-	return it.pkop.IteratePK(it.tb, it.evalValue, it.cfg.GetPrimaryKey().Type, fn)
+	return it.pkop.IteratePK(it.tb, it.evalValue, it.info.GetPrimaryKey().Type, fn)
 }
 
 // sortIterator operates a partial sort on the iterator using a heap.


Test patch:
diff --git a/database/config_test.go b/database/config_test.go
index 32ca20fd..3da99b0a 100644
--- a/database/config_test.go
+++ b/database/config_test.go
@@ -23,24 +23,25 @@ func TestTableInfoStore(t *testing.T) {
 
 	tcs := tableInfoStore{st}
 
-	cfg := TableConfig{
+	info := &TableInfo{
 		FieldConstraints: []FieldConstraint{
 			{Path: []string{"k"}, Type: document.Float64Value, IsPrimaryKey: true},
 		},
 	}
 
 	// Inserting one tableInfo should work.
-	ti, err := tcs.Insert("foo1", cfg)
+	sid, err := tcs.Insert("foo1", info)
 	require.NoError(t, err)
+	require.NotNil(t, sid)
 
 	// Inserting an existing tableInfo should not work.
-	_, err = tcs.Insert("foo1", cfg)
+	_, err = tcs.Insert("foo1", info)
 	require.Equal(t, err, ErrTableAlreadyExists)
 
 	// Listing all tables should return their name
 	// lexicographically ordered.
-	_, _ = tcs.Insert("foo3", cfg)
-	_, _ = tcs.Insert("foo2", cfg)
+	_, _ = tcs.Insert("foo3", info)
+	_, _ = tcs.Insert("foo2", info)
 	lt, err := tcs.ListTables()
 	require.NoError(t, err)
 	require.Equal(t, []string{"foo1", "foo2", "foo3"}, lt)
@@ -48,23 +49,12 @@ func TestTableInfoStore(t *testing.T) {
 	// Getting an existing tableInfo should work.
 	received, err := tcs.Get("foo1")
 	require.NoError(t, err)
-	require.Equal(t, ti, received)
+	require.NotNil(t, received.storeID)
 
 	// Getting a non-existing tableInfo should not work.
 	_, err = tcs.Get("unknown")
 	require.Equal(t, ErrTableNotFound, err)
 
-	// Updating the config table.
-	fc := FieldConstraint{Path: []string{"j"}, Type: document.TextValue, IsNotNull: true}
-	cfg.FieldConstraints = append(cfg.FieldConstraints, fc)
-	err = tcs.Replace("foo1", &cfg)
-	require.NoError(t, err)
-
-	received, err = tcs.Get("foo1")
-	require.NoError(t, err)
-	require.Equal(t, ti.storeID, received.storeID)
-	require.Equal(t, cfg, *received.cfg)
-
 	// Deleting an existing tableInfo should work.
 	err = tcs.Delete("foo1")
 	require.NoError(t, err)
diff --git a/database/table_test.go b/database/table_test.go
index 987d9a7f..4997e6ad 100644
--- a/database/table_test.go
+++ b/database/table_test.go
@@ -151,7 +151,7 @@ func TestTableInsert(t *testing.T) {
 			tx, err := db.Begin(true)
 			require.NoError(t, err)
 
-			_ = tx.CreateTable("test", &database.TableConfig{})
+			_ = tx.CreateTable("test", &database.TableInfo{})
 
 			tb, err := tx.GetTable("test")
 			require.NoError(t, err)
@@ -229,7 +229,7 @@ func TestTableInsert(t *testing.T) {
 		tx, cleanup := newTestDB(t)
 		defer cleanup()
 
-		err := tx.CreateTable("test", &database.TableConfig{
+		err := tx.CreateTable("test", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{Path: []string{"foo", "a", "1"}, Type: document.Int32Value, IsPrimaryKey: true},
 			},
@@ -260,7 +260,7 @@ func TestTableInsert(t *testing.T) {
 		tx, cleanup := newTestDB(t)
 		defer cleanup()
 
-		err := tx.CreateTable("test", &database.TableConfig{
+		err := tx.CreateTable("test", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{Path: []string{"foo"}, Type: document.ArrayValue},
 				{Path: []string{"foo", "0"}, Type: document.Int32Value},
@@ -290,7 +290,7 @@ func TestTableInsert(t *testing.T) {
 		tx, cleanup := newTestDB(t)
 		defer cleanup()
 
-		err := tx.CreateTable("test", &database.TableConfig{
+		err := tx.CreateTable("test", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{Path: []string{"foo"}, Type: document.Int32Value, IsPrimaryKey: true},
 			},
@@ -367,7 +367,7 @@ func TestTableInsert(t *testing.T) {
 		tx, cleanup := newTestDB(t)
 		defer cleanup()
 
-		err := tx.CreateTable("test", &database.TableConfig{
+		err := tx.CreateTable("test", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{[]string{"foo"}, document.Int32Value, false, false},
 				{[]string{"bar"}, document.Int8Value, false, false},
@@ -405,7 +405,7 @@ func TestTableInsert(t *testing.T) {
 		defer cleanup()
 
 		// no enforced type, not null
-		err := tx.CreateTable("test1", &database.TableConfig{
+		err := tx.CreateTable("test1", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{[]string{"foo"}, 0, false, true},
 			},
@@ -415,7 +415,7 @@ func TestTableInsert(t *testing.T) {
 		require.NoError(t, err)
 
 		// enforced type, not null
-		err = tx.CreateTable("test2", &database.TableConfig{
+		err = tx.CreateTable("test2", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{[]string{"foo"}, document.Int32Value, false, true},
 			},
@@ -459,7 +459,7 @@ func TestTableInsert(t *testing.T) {
 		tx, cleanup := newTestDB(t)
 		defer cleanup()
 
-		err := tx.CreateTable("test1", &database.TableConfig{
+		err := tx.CreateTable("test1", &database.TableInfo{
 			FieldConstraints: []database.FieldConstraint{
 				{[]string{"foo", "1"}, 0, false, true},
 			},
diff --git a/sql/parser/create_test.go b/sql/parser/create_test.go
index 03a54975..92365056 100644
--- a/sql/parser/create_test.go
+++ b/sql/parser/create_test.go
@@ -21,7 +21,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With primary key", "CREATE TABLE test(foo INT PRIMARY KEY)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, Type: document.Int64Value, IsPrimaryKey: true},
 					},
@@ -32,7 +32,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With type", "CREATE TABLE test(foo INT)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, Type: document.Int64Value},
 					},
@@ -41,7 +41,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With not null", "CREATE TABLE test(foo NOT NULL)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, IsNotNull: true},
 					},
@@ -52,7 +52,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With type and not null", "CREATE TABLE test(foo INT NOT NULL)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, Type: document.Int64Value, IsNotNull: true},
 					},
@@ -61,7 +61,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With not null and primary key", "CREATE TABLE test(foo INT NOT NULL PRIMARY KEY)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, Type: document.Int64Value, IsPrimaryKey: true, IsNotNull: true},
 					},
@@ -70,7 +70,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With primary key and not null", "CREATE TABLE test(foo INT PRIMARY KEY NOT NULL)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, Type: document.Int64Value, IsPrimaryKey: true, IsNotNull: true},
 					},
@@ -79,7 +79,7 @@ func TestParserCreateTable(t *testing.T) {
 		{"With multiple constraints", "CREATE TABLE test(foo INT PRIMARY KEY, bar INT16 NOT NULL, baz.4.1.bat STRING)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"foo"}, Type: document.Int64Value, IsPrimaryKey: true},
 						{Path: []string{"bar"}, Type: document.Int16Value, IsNotNull: true},
@@ -93,7 +93,7 @@ func TestParserCreateTable(t *testing.T) {
 			"CREATE TABLE test(i8 int8, i16 int16, i32 int32, i64 int64, f64 float64, b bool)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"i8"}, Type: document.Int8Value},
 						{Path: []string{"i16"}, Type: document.Int16Value},
@@ -108,7 +108,7 @@ func TestParserCreateTable(t *testing.T) {
 			"CREATE TABLE test(i int, ig integer, n numeric, du duration, b blob, byt bytes, t text, s string, a array, d document)",
 			query.CreateTableStmt{
 				TableName: "test",
-				Config: database.TableConfig{
+				Info: database.TableInfo{
 					FieldConstraints: []database.FieldConstraint{
 						{Path: []string{"i"}, Type: document.Int64Value},
 						{Path: []string{"ig"}, Type: document.Int64Value},
diff --git a/sql/query/create_test.go b/sql/query/create_test.go
index 79153a38..88293f03 100644
--- a/sql/query/create_test.go
+++ b/sql/query/create_test.go
@@ -54,21 +54,19 @@ func TestCreateTable(t *testing.T) {
 			require.NoError(t, err)
 
 			err = db.ViewTable("test", func(_ *genji.Tx, tb *database.Table) error {
-				cfg, err := tb.Config()
+				info, err := tb.Info()
 				if err != nil {
 					return err
 				}
 
-				require.Equal(t, &database.TableConfig{
-					FieldConstraints: []database.FieldConstraint{
-						{Path: []string{"i8"}, Type: document.Int8Value},
-						{Path: []string{"i16"}, Type: document.Int16Value},
-						{Path: []string{"i32"}, Type: document.Int32Value},
-						{Path: []string{"i64"}, Type: document.Int64Value},
-						{Path: []string{"f64"}, Type: document.Float64Value},
-						{Path: []string{"b"}, Type: document.BoolValue},
-					},
-				}, cfg)
+				require.Equal(t, []database.FieldConstraint{
+					{Path: []string{"i8"}, Type: document.Int8Value},
+					{Path: []string{"i16"}, Type: document.Int16Value},
+					{Path: []string{"i32"}, Type: document.Int32Value},
+					{Path: []string{"i64"}, Type: document.Int64Value},
+					{Path: []string{"f64"}, Type: document.Float64Value},
+					{Path: []string{"b"}, Type: document.BoolValue},
+				}, info.FieldConstraints)
 				return nil
 			})
 			require.NoError(t, err)
@@ -85,25 +83,23 @@ func TestCreateTable(t *testing.T) {
 			require.NoError(t, err)
 
 			err = db.ViewTable("test1", func(_ *genji.Tx, tb *database.Table) error {
-				cfg, err := tb.Config()
+				info, err := tb.Info()
 				if err != nil {
 					return err
 				}
 
-				require.Equal(t, &database.TableConfig{
-					FieldConstraints: []database.FieldConstraint{
-						{Path: []string{"foo", "bar", "1", "hello"}, Type: document.BlobValue, IsPrimaryKey: true},
-						{Path: []string{"foo", "a", "1", "2"}, Type: document.TextValue, IsNotNull: true},
-						{Path: []string{"bar", "4", "0", "bat"}, Type: document.Int64Value},
-						{Path: []string{"ig"}, Type: document.Int64Value},
-						{Path: []string{"n"}, Type: document.Float64Value},
-						{Path: []string{"du"}, Type: document.DurationValue},
-						{Path: []string{"b"}, Type: document.BlobValue},
-						{Path: []string{"t"}, Type: document.TextValue},
-						{Path: []string{"a"}, Type: document.ArrayValue},
-						{Path: []string{"d"}, Type: document.DocumentValue},
-					},
-				}, cfg)
+				require.Equal(t, []database.FieldConstraint{
+					{Path: []string{"foo", "bar", "1", "hello"}, Type: document.BlobValue, IsPrimaryKey: true},
+					{Path: []string{"foo", "a", "1", "2"}, Type: document.TextValue, IsNotNull: true},
+					{Path: []string{"bar", "4", "0", "bat"}, Type: document.Int64Value},
+					{Path: []string{"ig"}, Type: document.Int64Value},
+					{Path: []string{"n"}, Type: document.Float64Value},
+					{Path: []string{"du"}, Type: document.DurationValue},
+					{Path: []string{"b"}, Type: document.BlobValue},
+					{Path: []string{"t"}, Type: document.TextValue},
+					{Path: []string{"a"}, Type: document.ArrayValue},
+					{Path: []string{"d"}, Type: document.DocumentValue},
+				}, info.FieldConstraints)
 				return nil
 			})
 			require.NoError(t, err)
diff --git a/sql/query/expr/expr_test.go b/sql/query/expr/expr_test.go
index 2e1ef07b..5ad7a384 100644
--- a/sql/query/expr/expr_test.go
+++ b/sql/query/expr/expr_test.go
@@ -26,15 +26,15 @@ var stackWithDoc = expr.EvalStack{
 	Document: doc,
 }
 
-var fakeTableConfig = &database.TableConfig{
+var fakeTableInfo = &database.TableInfo{
 	FieldConstraints: []database.FieldConstraint{
 		{Path: []string{"c", "0"}, IsPrimaryKey: true},
 		{Path: []string{"c", "1"}},
 	},
 }
-var stackWithDocAndConfig = expr.EvalStack{
+var stackWithDocAndInfo = expr.EvalStack{
 	Document: doc,
-	Cfg:      fakeTableConfig,
+	Info:     fakeTableInfo,
 }
 
 var nullLitteral = document.NewNullValue()
diff --git a/sql/query/expr/function_test.go b/sql/query/expr/function_test.go
index d2e48867..372c9218 100644
--- a/sql/query/expr/function_test.go
+++ b/sql/query/expr/function_test.go
@@ -16,7 +16,7 @@ func TestPkExpr(t *testing.T) {
 	}{
 		{"empty stack", expr.EvalStack{}, nullLitteral, true},
 		{"stack with doc", stackWithDoc, nullLitteral, true},
-		{"stack with doc and config", stackWithDocAndConfig, document.NewIntValue(1), false},
+		{"stack with doc and info", stackWithDocAndInfo, document.NewIntValue(1), false},
 	}
 
 	for _, test := range tests {