Move statements into their own package

This commit is contained in:
Asdine El Hrychy
2021-05-29 21:22:48 +04:00
parent fc043bf179
commit 7a98a2025f
55 changed files with 233 additions and 219 deletions

11
db.go
View File

@@ -9,6 +9,7 @@ import (
errs "github.com/genjidb/genji/errors" errs "github.com/genjidb/genji/errors"
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query"
"github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/stream" "github.com/genjidb/genji/internal/stream"
"github.com/genjidb/genji/internal/stringutil" "github.com/genjidb/genji/internal/stringutil"
@@ -197,7 +198,7 @@ type Statement struct {
// Query the database and return the result. // Query the database and return the result.
// The returned result must always be closed after usage. // The returned result must always be closed after usage.
func (s *Statement) Query(args ...interface{}) (*Result, error) { func (s *Statement) Query(args ...interface{}) (*Result, error) {
var r *query.Result var r *statement.Result
var err error var err error
if s.tx != nil { if s.tx != nil {
@@ -269,7 +270,7 @@ func (s *Statement) Exec(args ...interface{}) (err error) {
// Result of a query. // Result of a query.
type Result struct { type Result struct {
result *query.Result result *statement.Result
} }
func (r *Result) Iterate(fn func(d document.Document) error) error { func (r *Result) Iterate(fn func(d document.Document) error) error {
@@ -281,7 +282,7 @@ func (r *Result) Fields() []string {
return nil return nil
} }
stmt, ok := r.result.Iterator.(*query.StreamStmtIterator) stmt, ok := r.result.Iterator.(*statement.StreamStmtIterator)
if !ok || stmt.Stream.Op == nil { if !ok || stmt.Stream.Op == nil {
return nil return nil
} }
@@ -369,7 +370,7 @@ func loadCatalogTables(tx *database.Transaction) ([]database.TableInfo, error) {
return err return err
} }
ti := stmt.(query.CreateTableStmt).Info ti := stmt.(statement.CreateTableStmt).Info
v, err := d.GetByField("store_name") v, err := d.GetByField("store_name")
if err != nil { if err != nil {
@@ -402,7 +403,7 @@ func loadCatalogIndexes(tx *database.Transaction) ([]database.IndexInfo, error)
return err return err
} }
indexes = append(indexes, stmt.(query.CreateIndexStmt).Info) indexes = append(indexes, stmt.(statement.CreateIndexStmt).Info)
return nil return nil
}) })

View File

@@ -65,7 +65,7 @@ SELECT * FROM foo;
To populate tests that would be in an `query_test` package, create a go file named `gentests.go` in the `query` package with the following code: To populate tests that would be in an `query_test` package, create a go file named `gentests.go` in the `query` package with the following code:
```go ```go
package query package statement
//go:generate go run ../dev/gensqltest -package=query_test ./*_test.sql //go:generate go run ../dev/gensqltest -package=query_test ./*_test.sql
``` ```

View File

@@ -1,3 +0,0 @@
package query
//go:generate go run ../../dev/gensqltest -package=query_test ./*_test.sql

View File

@@ -2,25 +2,25 @@ package query
import ( import (
"context" "context"
"errors"
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query/statement"
) )
// A Query can execute statements against the database. It can read or write data // A Query can execute statements against the database. It can read or write data
// from any table, or even alter the structure of the database. // from any table, or even alter the structure of the database.
// Results are returned as streams. // Results are returned as streams.
type Query struct { type Query struct {
Statements []Statement Statements []statement.Statement
tx *database.Transaction tx *database.Transaction
autoCommit bool autoCommit bool
} }
// Run executes all the statements in their own transaction and returns the last result. // Run executes all the statements in their own transaction and returns the last result.
func (q Query) Run(ctx context.Context, db *database.Database, args []expr.Param) (*Result, error) { func (q Query) Run(ctx context.Context, db *database.Database, args []expr.Param) (*statement.Result, error) {
var res Result var res statement.Result
var err error var err error
q.tx = db.GetAttachedTx() q.tx = db.GetAttachedTx()
@@ -40,7 +40,7 @@ func (q Query) Run(ctx context.Context, db *database.Database, args []expr.Param
} }
// reinitialize the result // reinitialize the result
res = Result{} res = statement.Result{}
if qa, ok := stmt.(queryAlterer); ok { if qa, ok := stmt.(queryAlterer); ok {
err = qa.alterQuery(ctx, db, &q) err = qa.alterQuery(ctx, db, &q)
@@ -114,8 +114,8 @@ func (q Query) Run(ctx context.Context, db *database.Database, args []expr.Param
} }
// Exec the query within the given transaction. // Exec the query within the given transaction.
func (q Query) Exec(tx *database.Transaction, args []expr.Param) (*Result, error) { func (q Query) Exec(tx *database.Transaction, args []expr.Param) (*statement.Result, error) {
var res Result var res statement.Result
var err error var err error
for i, stmt := range q.Statements { for i, stmt := range q.Statements {
@@ -139,54 +139,6 @@ func (q Query) Exec(tx *database.Transaction, args []expr.Param) (*Result, error
} }
// New creates a new query with the given statements. // New creates a new query with the given statements.
func New(statements ...Statement) Query { func New(statements ...statement.Statement) Query {
return Query{Statements: statements} return Query{Statements: statements}
} }
// A Statement represents a unique action that can be executed against the database.
type Statement interface {
Run(*database.Transaction, []expr.Param) (Result, error)
IsReadOnly() bool
}
// Result of a query.
type Result struct {
Iterator document.Iterator
Tx *database.Transaction
closed bool
err error
}
func (r *Result) Iterate(fn func(d document.Document) error) error {
if r.Iterator == nil {
return nil
}
r.err = r.Iterator.Iterate(fn)
return r.err
}
// Close the result stream.
// After closing the result, Stream is not supposed to be used.
// If the result stream was already closed, it returns an error.
func (r *Result) Close() (err error) {
if r == nil {
return nil
}
if r.closed {
return errors.New("result already closed")
}
r.closed = true
if r.Tx != nil {
if r.Tx.Writable && r.err == nil {
err = r.Tx.Commit()
} else {
err = r.Tx.Rollback()
}
}
return err
}

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"testing" "testing"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"bytes" "bytes"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"testing" "testing"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"testing" "testing"

View File

@@ -2,7 +2,7 @@
* CODE GENERATED AUTOMATICALLY WITH github.com/genjidb/genji/dev/gensqltest * CODE GENERATED AUTOMATICALLY WITH github.com/genjidb/genji/dev/gensqltest
* THIS FILE SHOULD NOT BE EDITED BY HAND * THIS FILE SHOULD NOT BE EDITED BY HAND
*/ */
package query_test package statement_test
import ( import (
"regexp" "regexp"

View File

@@ -2,7 +2,7 @@
* CODE GENERATED AUTOMATICALLY WITH github.com/genjidb/genji/dev/gensqltest * CODE GENERATED AUTOMATICALLY WITH github.com/genjidb/genji/dev/gensqltest
* THIS FILE SHOULD NOT BE EDITED BY HAND * THIS FILE SHOULD NOT BE EDITED BY HAND
*/ */
package query_test package statement_test
import ( import (
"testing" "testing"

View File

@@ -2,7 +2,7 @@
* CODE GENERATED AUTOMATICALLY WITH github.com/genjidb/genji/dev/gensqltest * CODE GENERATED AUTOMATICALLY WITH github.com/genjidb/genji/dev/gensqltest
* THIS FILE SHOULD NOT BE EDITED BY HAND * THIS FILE SHOULD NOT BE EDITED BY HAND
*/ */
package query_test package statement_test
import ( import (
"testing" "testing"

View File

@@ -0,0 +1,3 @@
package statement
//go:generate go run ../../../dev/gensqltest -package=statement_test ./*_test.sql

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"bytes" "bytes"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"testing" "testing"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"errors" "errors"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"bytes" "bytes"

View File

@@ -0,0 +1,57 @@
package statement
import (
"errors"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr"
)
// A Statement represents a unique action that can be executed against the database.
type Statement interface {
Run(*database.Transaction, []expr.Param) (Result, error)
IsReadOnly() bool
}
// Result of a query.
type Result struct {
Iterator document.Iterator
Tx *database.Transaction
closed bool
err error
}
func (r *Result) Iterate(fn func(d document.Document) error) error {
if r.Iterator == nil {
return nil
}
r.err = r.Iterator.Iterate(fn)
return r.err
}
// Close the result stream.
// After closing the result, Stream is not supposed to be used.
// If the result stream was already closed, it returns an error.
func (r *Result) Close() (err error) {
if r == nil {
return nil
}
if r.closed {
return errors.New("result already closed")
}
r.closed = true
if r.Tx != nil {
if r.Tx.Writable && r.err == nil {
err = r.Tx.Commit()
} else {
err = r.Tx.Rollback()
}
}
return err
}

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"

View File

@@ -1,4 +1,4 @@
package query package statement
import ( import (
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"

View File

@@ -1,4 +1,4 @@
package query_test package statement_test
import ( import (
"bytes" "bytes"

View File

@@ -6,6 +6,7 @@ import (
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query/statement"
) )
// BeginStmt is a statement that creates a new transaction. // BeginStmt is a statement that creates a new transaction.
@@ -31,8 +32,8 @@ func (stmt BeginStmt) IsReadOnly() bool {
return !stmt.Writable return !stmt.Writable
} }
func (stmt BeginStmt) Run(tx *database.Transaction, args []expr.Param) (Result, error) { func (stmt BeginStmt) Run(tx *database.Transaction, args []expr.Param) (statement.Result, error) {
return Result{}, errors.New("cannot begin a transaction within a transaction") return statement.Result{}, errors.New("cannot begin a transaction within a transaction")
} }
// RollbackStmt is a statement that rollbacks the current active transaction. // RollbackStmt is a statement that rollbacks the current active transaction.
@@ -56,8 +57,8 @@ func (stmt RollbackStmt) IsReadOnly() bool {
return false return false
} }
func (stmt RollbackStmt) Run(tx *database.Transaction, args []expr.Param) (Result, error) { func (stmt RollbackStmt) Run(tx *database.Transaction, args []expr.Param) (statement.Result, error) {
return Result{}, errors.New("cannot rollback with no active transaction") return statement.Result{}, errors.New("cannot rollback with no active transaction")
} }
// CommitStmt is a statement that commits the current active transaction. // CommitStmt is a statement that commits the current active transaction.
@@ -81,6 +82,6 @@ func (stmt CommitStmt) IsReadOnly() bool {
return false return false
} }
func (stmt CommitStmt) Run(tx *database.Transaction, args []expr.Param) (Result, error) { func (stmt CommitStmt) Run(tx *database.Transaction, args []expr.Param) (statement.Result, error) {
return Result{}, errors.New("cannot commit with no active transaction") return statement.Result{}, errors.New("cannot commit with no active transaction")
} }

View File

@@ -1,12 +1,12 @@
package parser package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
func (p *Parser) parseAlterTableRenameStatement(tableName string) (_ query.AlterStmt, err error) { func (p *Parser) parseAlterTableRenameStatement(tableName string) (_ statement.AlterStmt, err error) {
var stmt query.AlterStmt var stmt statement.AlterStmt
stmt.TableName = tableName stmt.TableName = tableName
// Parse "TO". // Parse "TO".
@@ -23,8 +23,8 @@ func (p *Parser) parseAlterTableRenameStatement(tableName string) (_ query.Alter
return stmt, nil return stmt, nil
} }
func (p *Parser) parseAlterTableAddFieldStatement(tableName string) (_ query.AlterTableAddField, err error) { func (p *Parser) parseAlterTableAddFieldStatement(tableName string) (_ statement.AlterTableAddField, err error) {
var stmt query.AlterTableAddField var stmt statement.AlterTableAddField
stmt.TableName = tableName stmt.TableName = tableName
// Parse "FIELD". // Parse "FIELD".
@@ -47,7 +47,7 @@ func (p *Parser) parseAlterTableAddFieldStatement(tableName string) (_ query.Alt
// parseAlterStatement parses a Alter query string and returns a Statement AST object. // parseAlterStatement parses a Alter query string and returns a Statement AST object.
// This function assumes the ALTER token has already been consumed. // This function assumes the ALTER token has already been consumed.
func (p *Parser) parseAlterStatement() (query.Statement, error) { func (p *Parser) parseAlterStatement() (statement.Statement, error) {
var err error var err error
// Parse "TABLE". // Parse "TABLE".

View File

@@ -5,7 +5,7 @@ import (
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/testutil" "github.com/genjidb/genji/internal/testutil"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -15,13 +15,13 @@ func TestParserAlterTable(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"Basic", "ALTER TABLE foo RENAME TO bar", query.AlterStmt{TableName: "foo", NewTableName: "bar"}, false}, {"Basic", "ALTER TABLE foo RENAME TO bar", statement.AlterStmt{TableName: "foo", NewTableName: "bar"}, false},
{"With error / missing TABLE keyword", "ALTER foo RENAME TO bar", query.AlterStmt{}, true}, {"With error / missing TABLE keyword", "ALTER foo RENAME TO bar", statement.AlterStmt{}, true},
{"With error / two identifiers for table name", "ALTER TABLE foo baz RENAME TO bar", query.AlterStmt{}, true}, {"With error / two identifiers for table name", "ALTER TABLE foo baz RENAME TO bar", statement.AlterStmt{}, true},
{"With error / two identifiers for new table name", "ALTER TABLE foo RENAME TO bar baz", query.AlterStmt{}, true}, {"With error / two identifiers for new table name", "ALTER TABLE foo RENAME TO bar baz", statement.AlterStmt{}, true},
} }
for _, test := range tests { for _, test := range tests {
@@ -42,26 +42,26 @@ func TestParserAlterTableAddField(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"Basic", "ALTER TABLE foo ADD FIELD bar", query.AlterTableAddField{TableName: "foo", {"Basic", "ALTER TABLE foo ADD FIELD bar", statement.AlterTableAddField{TableName: "foo",
Constraint: database.FieldConstraint{}, Constraint: database.FieldConstraint{},
}, true}, }, true},
{"With type", "ALTER TABLE foo ADD FIELD bar integer", query.AlterTableAddField{TableName: "foo", {"With type", "ALTER TABLE foo ADD FIELD bar integer", statement.AlterTableAddField{TableName: "foo",
Constraint: database.FieldConstraint{ Constraint: database.FieldConstraint{
Path: document.Path(testutil.ParsePath(t, "bar")), Path: document.Path(testutil.ParsePath(t, "bar")),
Type: document.IntegerValue, Type: document.IntegerValue,
}, },
}, false}, }, false},
{"With not null", "ALTER TABLE foo ADD FIELD bar NOT NULL", query.AlterTableAddField{TableName: "foo", {"With not null", "ALTER TABLE foo ADD FIELD bar NOT NULL", statement.AlterTableAddField{TableName: "foo",
Constraint: database.FieldConstraint{ Constraint: database.FieldConstraint{
Path: document.Path(testutil.ParsePath(t, "bar")), Path: document.Path(testutil.ParsePath(t, "bar")),
IsNotNull: true, IsNotNull: true,
}, },
}, false}, }, false},
{"With primary key", "ALTER TABLE foo ADD FIELD bar PRIMARY KEY", query.AlterTableAddField{}, true}, {"With primary key", "ALTER TABLE foo ADD FIELD bar PRIMARY KEY", statement.AlterTableAddField{}, true},
{"With multiple constraints", "ALTER TABLE foo ADD FIELD bar integer NOT NULL DEFAULT 0", query.AlterTableAddField{TableName: "foo", {"With multiple constraints", "ALTER TABLE foo ADD FIELD bar integer NOT NULL DEFAULT 0", statement.AlterTableAddField{TableName: "foo",
Constraint: database.FieldConstraint{ Constraint: database.FieldConstraint{
Path: document.Path(testutil.ParsePath(t, "bar")), Path: document.Path(testutil.ParsePath(t, "bar")),
Type: document.IntegerValue, Type: document.IntegerValue,

View File

@@ -3,14 +3,14 @@ package parser
import ( import (
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
"github.com/genjidb/genji/internal/stringutil" "github.com/genjidb/genji/internal/stringutil"
) )
// parseCreateStatement parses a create string and returns a Statement AST object. // parseCreateStatement parses a create string and returns a Statement AST object.
// This function assumes the CREATE token has already been consumed. // This function assumes the CREATE token has already been consumed.
func (p *Parser) parseCreateStatement() (query.Statement, error) { func (p *Parser) parseCreateStatement() (statement.Statement, error) {
tok, pos, lit := p.ScanIgnoreWhitespace() tok, pos, lit := p.ScanIgnoreWhitespace()
switch tok { switch tok {
case scanner.TABLE: case scanner.TABLE:
@@ -30,8 +30,8 @@ func (p *Parser) parseCreateStatement() (query.Statement, error) {
// parseCreateTableStatement parses a create table string and returns a Statement AST object. // parseCreateTableStatement parses a create table string and returns a Statement AST object.
// This function assumes the CREATE TABLE tokens have already been consumed. // This function assumes the CREATE TABLE tokens have already been consumed.
func (p *Parser) parseCreateTableStatement() (query.CreateTableStmt, error) { func (p *Parser) parseCreateTableStatement() (statement.CreateTableStmt, error) {
var stmt query.CreateTableStmt var stmt statement.CreateTableStmt
var err error var err error
// Parse IF NOT EXISTS // Parse IF NOT EXISTS
@@ -75,7 +75,7 @@ func (p *Parser) parseFieldDefinition(fc *database.FieldConstraint) (err error)
return nil return nil
} }
func (p *Parser) parseConstraints(stmt *query.CreateTableStmt) error { func (p *Parser) parseConstraints(stmt *statement.CreateTableStmt) error {
// Parse ( token. // Parse ( token.
if ok, err := p.parseOptional(scanner.LPAREN); !ok || err != nil { if ok, err := p.parseOptional(scanner.LPAREN); !ok || err != nil {
return err return err
@@ -203,7 +203,7 @@ func (p *Parser) parseFieldConstraint(fc *database.FieldConstraint) error {
} }
} }
func (p *Parser) parseTableConstraint(stmt *query.CreateTableStmt) (bool, error) { func (p *Parser) parseTableConstraint(stmt *statement.CreateTableStmt) (bool, error) {
var err error var err error
tok, _, _ := p.ScanIgnoreWhitespace() tok, _, _ := p.ScanIgnoreWhitespace()
@@ -283,9 +283,9 @@ func (p *Parser) parseTableConstraint(stmt *query.CreateTableStmt) (bool, error)
// parseCreateIndexStatement parses a create index string and returns a Statement AST object. // parseCreateIndexStatement parses a create index string and returns a Statement AST object.
// This function assumes the CREATE INDEX or CREATE UNIQUE INDEX tokens have already been consumed. // This function assumes the CREATE INDEX or CREATE UNIQUE INDEX tokens have already been consumed.
func (p *Parser) parseCreateIndexStatement(unique bool) (query.CreateIndexStmt, error) { func (p *Parser) parseCreateIndexStatement(unique bool) (statement.CreateIndexStmt, error) {
var err error var err error
var stmt query.CreateIndexStmt var stmt statement.CreateIndexStmt
stmt.Info.Unique = unique stmt.Info.Unique = unique
// Parse IF NOT EXISTS // Parse IF NOT EXISTS

View File

@@ -5,7 +5,7 @@ import (
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/testutil" "github.com/genjidb/genji/internal/testutil"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -15,14 +15,14 @@ func TestParserCreateTable(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"Basic", "CREATE TABLE test", query.CreateTableStmt{Info: database.TableInfo{TableName: "test"}}, false}, {"Basic", "CREATE TABLE test", statement.CreateTableStmt{Info: database.TableInfo{TableName: "test"}}, false},
{"If not exists", "CREATE TABLE IF NOT EXISTS test", query.CreateTableStmt{Info: database.TableInfo{TableName: "test"}, IfNotExists: true}, false}, {"If not exists", "CREATE TABLE IF NOT EXISTS test", statement.CreateTableStmt{Info: database.TableInfo{TableName: "test"}, IfNotExists: true}, false},
{"Path only", "CREATE TABLE test(a)", query.CreateTableStmt{}, true}, {"Path only", "CREATE TABLE test(a)", statement.CreateTableStmt{}, true},
{"With primary key", "CREATE TABLE test(foo INTEGER PRIMARY KEY)", {"With primary key", "CREATE TABLE test(foo INTEGER PRIMARY KEY)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -31,9 +31,9 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With primary key twice", "CREATE TABLE test(foo PRIMARY KEY PRIMARY KEY)", {"With primary key twice", "CREATE TABLE test(foo PRIMARY KEY PRIMARY KEY)",
query.CreateTableStmt{}, true}, statement.CreateTableStmt{}, true},
{"With type", "CREATE TABLE test(foo INTEGER)", {"With type", "CREATE TABLE test(foo INTEGER)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -42,7 +42,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With not null", "CREATE TABLE test(foo NOT NULL)", {"With not null", "CREATE TABLE test(foo NOT NULL)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -51,7 +51,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With default", "CREATE TABLE test(foo DEFAULT \"10\")", {"With default", "CREATE TABLE test(foo DEFAULT \"10\")",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -60,7 +60,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With unique", "CREATE TABLE test(foo UNIQUE)", {"With unique", "CREATE TABLE test(foo UNIQUE)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -69,13 +69,13 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With default twice", "CREATE TABLE test(foo DEFAULT 10 DEFAULT 10)", {"With default twice", "CREATE TABLE test(foo DEFAULT 10 DEFAULT 10)",
query.CreateTableStmt{}, true}, statement.CreateTableStmt{}, true},
{"With not null twice", "CREATE TABLE test(foo NOT NULL NOT NULL)", {"With not null twice", "CREATE TABLE test(foo NOT NULL NOT NULL)",
query.CreateTableStmt{}, true}, statement.CreateTableStmt{}, true},
{"With unique twice", "CREATE TABLE test(foo UNIQUE UNIQUE)", {"With unique twice", "CREATE TABLE test(foo UNIQUE UNIQUE)",
query.CreateTableStmt{}, true}, statement.CreateTableStmt{}, true},
{"With type and not null", "CREATE TABLE test(foo INTEGER NOT NULL)", {"With type and not null", "CREATE TABLE test(foo INTEGER NOT NULL)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -84,7 +84,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With not null and primary key", "CREATE TABLE test(foo INTEGER NOT NULL PRIMARY KEY)", {"With not null and primary key", "CREATE TABLE test(foo INTEGER NOT NULL PRIMARY KEY)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -93,7 +93,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With primary key and not null", "CREATE TABLE test(foo INTEGER PRIMARY KEY NOT NULL)", {"With primary key and not null", "CREATE TABLE test(foo INTEGER PRIMARY KEY NOT NULL)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -102,7 +102,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With multiple constraints", "CREATE TABLE test(foo INTEGER PRIMARY KEY, bar INTEGER NOT NULL, baz[4][1].bat TEXT)", {"With multiple constraints", "CREATE TABLE test(foo INTEGER PRIMARY KEY, bar INTEGER NOT NULL, baz[4][1].bat TEXT)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -113,7 +113,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With table constraints / PK on defined field", "CREATE TABLE test(foo INTEGER, bar NOT NULL, PRIMARY KEY (foo))", {"With table constraints / PK on defined field", "CREATE TABLE test(foo INTEGER, bar NOT NULL, PRIMARY KEY (foo))",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -123,7 +123,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With table constraints / PK on undefined field", "CREATE TABLE test(foo INTEGER, PRIMARY KEY (bar))", {"With table constraints / PK on undefined field", "CREATE TABLE test(foo INTEGER, PRIMARY KEY (bar))",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -136,7 +136,7 @@ func TestParserCreateTable(t *testing.T) {
{"With table constraints / duplicate pk", "CREATE TABLE test(foo INTEGER PRIMARY KEY, PRIMARY KEY (bar))", nil, true}, {"With table constraints / duplicate pk", "CREATE TABLE test(foo INTEGER PRIMARY KEY, PRIMARY KEY (bar))", nil, true},
{"With table constraints / duplicate pk on same path", "CREATE TABLE test(foo INTEGER PRIMARY KEY, PRIMARY KEY (foo))", nil, true}, {"With table constraints / duplicate pk on same path", "CREATE TABLE test(foo INTEGER PRIMARY KEY, PRIMARY KEY (foo))", nil, true},
{"With table constraints / UNIQUE on defined field", "CREATE TABLE test(foo INTEGER, bar NOT NULL, UNIQUE (foo))", {"With table constraints / UNIQUE on defined field", "CREATE TABLE test(foo INTEGER, bar NOT NULL, UNIQUE (foo))",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -146,7 +146,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With table constraints / UNIQUE on undefined field", "CREATE TABLE test(foo INTEGER, UNIQUE (bar))", {"With table constraints / UNIQUE on undefined field", "CREATE TABLE test(foo INTEGER, UNIQUE (bar))",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -156,7 +156,7 @@ func TestParserCreateTable(t *testing.T) {
}, },
}, false}, }, false},
{"With table constraints / UNIQUE twice", "CREATE TABLE test(foo INTEGER UNIQUE, UNIQUE (foo))", {"With table constraints / UNIQUE twice", "CREATE TABLE test(foo INTEGER UNIQUE, UNIQUE (foo))",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -166,10 +166,10 @@ func TestParserCreateTable(t *testing.T) {
}, false}, }, false},
{"With table constraints / duplicate pk on same path", "CREATE TABLE test(foo INTEGER PRIMARY KEY, PRIMARY KEY (foo))", nil, true}, {"With table constraints / duplicate pk on same path", "CREATE TABLE test(foo INTEGER PRIMARY KEY, PRIMARY KEY (foo))", nil, true},
{"With multiple primary keys", "CREATE TABLE test(foo PRIMARY KEY, bar PRIMARY KEY)", {"With multiple primary keys", "CREATE TABLE test(foo PRIMARY KEY, bar PRIMARY KEY)",
query.CreateTableStmt{}, true}, statement.CreateTableStmt{}, true},
{"With all supported fixed size data types", {"With all supported fixed size data types",
"CREATE TABLE test(d double, b bool)", "CREATE TABLE test(d double, b bool)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -180,7 +180,7 @@ func TestParserCreateTable(t *testing.T) {
}, false}, }, false},
{"With all supported variable size data types", {"With all supported variable size data types",
"CREATE TABLE test(i integer, b blob, byt bytes, t text, a array, d document)", "CREATE TABLE test(i integer, b blob, byt bytes, t text, a array, d document)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -195,7 +195,7 @@ func TestParserCreateTable(t *testing.T) {
}, false}, }, false},
{"With integer aliases types", {"With integer aliases types",
"CREATE TABLE test(i int, ii int2, ei int8, m mediumint, s smallint, b bigint, t tinyint)", "CREATE TABLE test(i int, ii int2, ei int8, m mediumint, s smallint, b bigint, t tinyint)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -211,7 +211,7 @@ func TestParserCreateTable(t *testing.T) {
}, false}, }, false},
{"With double aliases types", {"With double aliases types",
"CREATE TABLE test(dp DOUBLE PRECISION, r real, d double)", "CREATE TABLE test(dp DOUBLE PRECISION, r real, d double)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -223,7 +223,7 @@ func TestParserCreateTable(t *testing.T) {
}, false}, }, false},
{"With text aliases types", {"With text aliases types",
"CREATE TABLE test(v VARCHAR(255), c CHARACTER(64), t TEXT)", "CREATE TABLE test(v VARCHAR(255), c CHARACTER(64), t TEXT)",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -235,7 +235,7 @@ func TestParserCreateTable(t *testing.T) {
}, false}, }, false},
{"With errored text aliases types", {"With errored text aliases types",
"CREATE TABLE test(v VARCHAR(1 IN [1, 2, 3] AND foo > 4) )", "CREATE TABLE test(v VARCHAR(1 IN [1, 2, 3] AND foo > 4) )",
query.CreateTableStmt{ statement.CreateTableStmt{
Info: database.TableInfo{ Info: database.TableInfo{
TableName: "test", TableName: "test",
FieldConstraints: []*database.FieldConstraint{ FieldConstraints: []*database.FieldConstraint{
@@ -263,26 +263,26 @@ func TestParserCreateIndex(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"Basic", "CREATE INDEX idx ON test (foo)", query.CreateIndexStmt{ {"Basic", "CREATE INDEX idx ON test (foo)", statement.CreateIndexStmt{
Info: database.IndexInfo{ Info: database.IndexInfo{
IndexName: "idx", TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo"))}, IndexName: "idx", TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo"))},
}}, false}, }}, false},
{"If not exists", "CREATE INDEX IF NOT EXISTS idx ON test (foo.bar[1])", query.CreateIndexStmt{ {"If not exists", "CREATE INDEX IF NOT EXISTS idx ON test (foo.bar[1])", statement.CreateIndexStmt{
Info: database.IndexInfo{ Info: database.IndexInfo{
IndexName: "idx", TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo.bar[1]"))}, IndexName: "idx", TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo.bar[1]"))},
}, IfNotExists: true}, false}, }, IfNotExists: true}, false},
{"Unique", "CREATE UNIQUE INDEX IF NOT EXISTS idx ON test (foo[3].baz)", query.CreateIndexStmt{ {"Unique", "CREATE UNIQUE INDEX IF NOT EXISTS idx ON test (foo[3].baz)", statement.CreateIndexStmt{
Info: database.IndexInfo{ Info: database.IndexInfo{
IndexName: "idx", TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo[3].baz"))}, Unique: true, IndexName: "idx", TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo[3].baz"))}, Unique: true,
}, IfNotExists: true}, false}, }, IfNotExists: true}, false},
{"No name", "CREATE UNIQUE INDEX ON test (foo[3].baz)", query.CreateIndexStmt{ {"No name", "CREATE UNIQUE INDEX ON test (foo[3].baz)", statement.CreateIndexStmt{
Info: database.IndexInfo{TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo[3].baz"))}, Unique: true}}, false}, Info: database.IndexInfo{TableName: "test", Paths: []document.Path{document.Path(testutil.ParsePath(t, "foo[3].baz"))}, Unique: true}}, false},
{"No name with IF NOT EXISTS", "CREATE UNIQUE INDEX IF NOT EXISTS ON test (foo[3].baz)", nil, true}, {"No name with IF NOT EXISTS", "CREATE UNIQUE INDEX IF NOT EXISTS ON test (foo[3].baz)", nil, true},
{"More than 1 path", "CREATE INDEX idx ON test (foo, bar)", {"More than 1 path", "CREATE INDEX idx ON test (foo, bar)",
query.CreateIndexStmt(query.CreateIndexStmt{ statement.CreateIndexStmt(statement.CreateIndexStmt{
Info: database.IndexInfo{ Info: database.IndexInfo{
IndexName: "idx", IndexName: "idx",
TableName: "test", TableName: "test",

View File

@@ -1,14 +1,14 @@
package parser package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseDeleteStatement parses a delete string and returns a Statement AST object. // parseDeleteStatement parses a delete string and returns a Statement AST object.
// This function assumes the DELETE token has already been consumed. // This function assumes the DELETE token has already been consumed.
func (p *Parser) parseDeleteStatement() (*query.DeleteStmt, error) { func (p *Parser) parseDeleteStatement() (*statement.DeleteStmt, error) {
var stmt query.DeleteStmt var stmt statement.DeleteStmt
var err error var err error
// Parse "FROM". // Parse "FROM".

View File

@@ -3,7 +3,7 @@ package parser_test
import ( import (
"testing" "testing"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/stream" "github.com/genjidb/genji/internal/stream"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -54,9 +54,9 @@ func TestParserDelete(t *testing.T) {
q, err := parser.ParseQuery(test.s) q, err := parser.ParseQuery(test.s)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, q.Statements, 1) require.Len(t, q.Statements, 1)
stmt, err := q.Statements[0].(*query.DeleteStmt).ToStream() stmt, err := q.Statements[0].(*statement.DeleteStmt).ToStream()
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, &query.StreamStmt{Stream: test.expected}, stmt) require.EqualValues(t, &statement.StreamStmt{Stream: test.expected}, stmt)
}) })
} }
} }

View File

@@ -1,13 +1,13 @@
package parser package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseDropStatement parses a drop string and returns a Statement AST object. // parseDropStatement parses a drop string and returns a Statement AST object.
// This function assumes the DROP token has already been consumed. // This function assumes the DROP token has already been consumed.
func (p *Parser) parseDropStatement() (query.Statement, error) { func (p *Parser) parseDropStatement() (statement.Statement, error) {
tok, pos, lit := p.ScanIgnoreWhitespace() tok, pos, lit := p.ScanIgnoreWhitespace()
switch tok { switch tok {
case scanner.TABLE: case scanner.TABLE:
@@ -21,8 +21,8 @@ func (p *Parser) parseDropStatement() (query.Statement, error) {
// parseDropTableStatement parses a drop table string and returns a Statement AST object. // parseDropTableStatement parses a drop table string and returns a Statement AST object.
// This function assumes the DROP TABLE tokens have already been consumed. // This function assumes the DROP TABLE tokens have already been consumed.
func (p *Parser) parseDropTableStatement() (query.DropTableStmt, error) { func (p *Parser) parseDropTableStatement() (statement.DropTableStmt, error) {
var stmt query.DropTableStmt var stmt statement.DropTableStmt
var err error var err error
stmt.IfExists, err = p.parseOptional(scanner.IF, scanner.EXISTS) stmt.IfExists, err = p.parseOptional(scanner.IF, scanner.EXISTS)
@@ -43,8 +43,8 @@ func (p *Parser) parseDropTableStatement() (query.DropTableStmt, error) {
// parseDropIndexStatement parses a drop index string and returns a Statement AST object. // parseDropIndexStatement parses a drop index string and returns a Statement AST object.
// This function assumes the DROP INDEX tokens have already been consumed. // This function assumes the DROP INDEX tokens have already been consumed.
func (p *Parser) parseDropIndexStatement() (query.DropIndexStmt, error) { func (p *Parser) parseDropIndexStatement() (statement.DropIndexStmt, error) {
var stmt query.DropIndexStmt var stmt statement.DropIndexStmt
var err error var err error
stmt.IfExists, err = p.parseOptional(scanner.IF, scanner.EXISTS) stmt.IfExists, err = p.parseOptional(scanner.IF, scanner.EXISTS)

View File

@@ -3,7 +3,7 @@ package parser_test
import ( import (
"testing" "testing"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -12,13 +12,13 @@ func TestParserDrop(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"Drop table", "DROP TABLE test", query.DropTableStmt{TableName: "test"}, false}, {"Drop table", "DROP TABLE test", statement.DropTableStmt{TableName: "test"}, false},
{"Drop table If not exists", "DROP TABLE IF EXISTS test", query.DropTableStmt{TableName: "test", IfExists: true}, false}, {"Drop table If not exists", "DROP TABLE IF EXISTS test", statement.DropTableStmt{TableName: "test", IfExists: true}, false},
{"Drop index", "DROP INDEX test", query.DropIndexStmt{IndexName: "test"}, false}, {"Drop index", "DROP INDEX test", statement.DropIndexStmt{IndexName: "test"}, false},
{"Drop index if exists", "DROP INDEX IF EXISTS test", query.DropIndexStmt{IndexName: "test", IfExists: true}, false}, {"Drop index if exists", "DROP INDEX IF EXISTS test", statement.DropIndexStmt{IndexName: "test", IfExists: true}, false},
} }
for _, test := range tests { for _, test := range tests {

View File

@@ -1,13 +1,13 @@
package parser package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseExplainStatement parses any statement and returns an ExplainStmt object. // parseExplainStatement parses any statement and returns an ExplainStmt object.
// This function assumes the EXPLAIN token has already been consumed. // This function assumes the EXPLAIN token has already been consumed.
func (p *Parser) parseExplainStatement() (query.Statement, error) { func (p *Parser) parseExplainStatement() (statement.Statement, error) {
// ensure we don't have multiple EXPLAIN keywords // ensure we don't have multiple EXPLAIN keywords
tok, pos, lit := p.ScanIgnoreWhitespace() tok, pos, lit := p.ScanIgnoreWhitespace()
if tok != scanner.SELECT && tok != scanner.UPDATE && tok != scanner.DELETE && tok != scanner.INSERT { if tok != scanner.SELECT && tok != scanner.UPDATE && tok != scanner.DELETE && tok != scanner.INSERT {
@@ -20,5 +20,5 @@ func (p *Parser) parseExplainStatement() (query.Statement, error) {
return nil, err return nil, err
} }
return &query.ExplainStmt{Statement: innerStmt}, nil return &statement.ExplainStmt{Statement: innerStmt}, nil
} }

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -13,10 +13,10 @@ func TestParserExplain(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"Explain create table", "EXPLAIN SELECT * FROM test", &query.ExplainStmt{Statement: &query.SelectStmt{ {"Explain create table", "EXPLAIN SELECT * FROM test", &statement.ExplainStmt{Statement: &statement.SelectStmt{
TableName: "test", TableName: "test",
ProjectionExprs: []expr.Expr{expr.Wildcard{}}, ProjectionExprs: []expr.Expr{expr.Wildcard{}},
}}, false}, }}, false},

View File

@@ -3,15 +3,15 @@ package parser
import ( import (
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
"github.com/genjidb/genji/internal/stringutil" "github.com/genjidb/genji/internal/stringutil"
) )
// parseInsertStatement parses an insert string and returns a Statement AST object. // parseInsertStatement parses an insert string and returns a Statement AST object.
// This function assumes the INSERT token has already been consumed. // This function assumes the INSERT token has already been consumed.
func (p *Parser) parseInsertStatement() (*query.InsertStmt, error) { func (p *Parser) parseInsertStatement() (*statement.InsertStmt, error) {
var stmt query.InsertStmt var stmt statement.InsertStmt
var err error var err error
// Parse "INTO". // Parse "INTO".

View File

@@ -5,7 +5,7 @@ import (
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/stream" "github.com/genjidb/genji/internal/stream"
"github.com/genjidb/genji/internal/testutil" "github.com/genjidb/genji/internal/testutil"
@@ -181,7 +181,7 @@ func TestParserInsert(t *testing.T) {
} }
require.NoError(t, err) require.NoError(t, err)
require.Len(t, q.Statements, 1) require.Len(t, q.Statements, 1)
stmt := q.Statements[0].(*query.InsertStmt) stmt := q.Statements[0].(*statement.InsertStmt)
require.False(t, stmt.IsReadOnly()) require.False(t, stmt.IsReadOnly())
ss, err := stmt.ToStream() ss, err := stmt.ToStream()
require.NoError(t, err) require.NoError(t, err)

View File

@@ -7,6 +7,7 @@ import (
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query"
"github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
"github.com/genjidb/genji/internal/stringutil" "github.com/genjidb/genji/internal/stringutil"
) )
@@ -61,7 +62,7 @@ func MustParseExpr(s string) expr.Expr {
// ParseQuery parses a Genji SQL string and returns a Query. // ParseQuery parses a Genji SQL string and returns a Query.
func (p *Parser) ParseQuery() (query.Query, error) { func (p *Parser) ParseQuery() (query.Query, error) {
var statements []query.Statement var statements []statement.Statement
semi := true semi := true
for { for {
@@ -85,7 +86,7 @@ func (p *Parser) ParseQuery() (query.Query, error) {
} }
// ParseStatement parses a Genji SQL string and returns a Statement AST object. // ParseStatement parses a Genji SQL string and returns a Statement AST object.
func (p *Parser) ParseStatement() (query.Statement, error) { func (p *Parser) ParseStatement() (statement.Statement, error) {
tok, pos, lit := p.ScanIgnoreWhitespace() tok, pos, lit := p.ScanIgnoreWhitespace()
switch tok { switch tok {
case scanner.ALTER: case scanner.ALTER:

View File

@@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
) )
@@ -14,15 +14,15 @@ func TestParserMultiStatement(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected []query.Statement expected []statement.Statement
}{ }{
{"OnlyCommas", ";;;", nil}, {"OnlyCommas", ";;;", nil},
{"TrailingComma", "SELECT * FROM foo;;;DELETE FROM foo;", []query.Statement{ {"TrailingComma", "SELECT * FROM foo;;;DELETE FROM foo;", []statement.Statement{
&query.SelectStmt{ &statement.SelectStmt{
TableName: "foo", TableName: "foo",
ProjectionExprs: []expr.Expr{expr.Wildcard{}}, ProjectionExprs: []expr.Expr{expr.Wildcard{}},
}, },
&query.DeleteStmt{ &statement.DeleteStmt{
TableName: "foo", TableName: "foo",
}, },
}}, }},

View File

@@ -1,14 +1,14 @@
package parser package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseReindexStatement parses a reindex statement. // parseReindexStatement parses a reindex statement.
// This function assumes the REINDEX token has already been consumed. // This function assumes the REINDEX token has already been consumed.
func (p *Parser) parseReIndexStatement() (query.Statement, error) { func (p *Parser) parseReIndexStatement() (statement.Statement, error) {
var stmt query.ReIndexStmt var stmt statement.ReIndexStmt
var err error var err error
tok, _, lit := p.ScanIgnoreWhitespace() tok, _, lit := p.ScanIgnoreWhitespace()

View File

@@ -3,7 +3,7 @@ package parser_test
import ( import (
"testing" "testing"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -12,11 +12,11 @@ func TestParserReIndex(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"All", "REINDEX", query.ReIndexStmt{}, false}, {"All", "REINDEX", statement.ReIndexStmt{}, false},
{"With ident", "REINDEX tableOrIndex", query.ReIndexStmt{TableOrIndexName: "tableOrIndex"}, false}, {"With ident", "REINDEX tableOrIndex", statement.ReIndexStmt{TableOrIndexName: "tableOrIndex"}, false},
{"With extra", "REINDEX tableOrIndex tableOrIndex", nil, true}, {"With extra", "REINDEX tableOrIndex tableOrIndex", nil, true},
} }

View File

@@ -2,14 +2,14 @@ package parser
import ( import (
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseSelectStatement parses a select string and returns a Statement AST object. // parseSelectStatement parses a select string and returns a Statement AST object.
// This function assumes the SELECT token has already been consumed. // This function assumes the SELECT token has already been consumed.
func (p *Parser) parseSelectStatement() (*query.SelectStmt, error) { func (p *Parser) parseSelectStatement() (*statement.SelectStmt, error) {
var stmt query.SelectStmt var stmt statement.SelectStmt
var err error var err error
stmt.Distinct, err = p.parseDistinct() stmt.Distinct, err = p.parseDistinct()

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/stream" "github.com/genjidb/genji/internal/stream"
"github.com/genjidb/genji/internal/testutil" "github.com/genjidb/genji/internal/testutil"
@@ -132,9 +132,9 @@ func TestParserSelect(t *testing.T) {
if !test.mustFail { if !test.mustFail {
require.NoError(t, err) require.NoError(t, err)
require.Len(t, q.Statements, 1) require.Len(t, q.Statements, 1)
st, err := q.Statements[0].(*query.SelectStmt).ToStream() st, err := q.Statements[0].(*statement.SelectStmt).ToStream()
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, &query.StreamStmt{Stream: test.expected, ReadOnly: true}, st) require.EqualValues(t, &statement.StreamStmt{Stream: test.expected, ReadOnly: true}, st)
} else { } else {
require.Error(t, err) require.Error(t, err)
} }

View File

@@ -2,12 +2,13 @@ package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query"
"github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseBeginStatement parses a BEGIN statement. // parseBeginStatement parses a BEGIN statement.
// This function assumes the BEGIN token has already been consumed. // This function assumes the BEGIN token has already been consumed.
func (p *Parser) parseBeginStatement() (query.Statement, error) { func (p *Parser) parseBeginStatement() (statement.Statement, error) {
// parse optional TRANSACTION token // parse optional TRANSACTION token
_, _ = p.parseOptional(scanner.TRANSACTION) _, _ = p.parseOptional(scanner.TRANSACTION)
@@ -34,7 +35,7 @@ func (p *Parser) parseBeginStatement() (query.Statement, error) {
// parseRollbackStatement parses a ROLLBACK statement. // parseRollbackStatement parses a ROLLBACK statement.
// This function assumes the ROLLBACK token has already been consumed. // This function assumes the ROLLBACK token has already been consumed.
func (p *Parser) parseRollbackStatement() (query.Statement, error) { func (p *Parser) parseRollbackStatement() (statement.Statement, error) {
// parse optional TRANSACTION token // parse optional TRANSACTION token
_, _ = p.parseOptional(scanner.TRANSACTION) _, _ = p.parseOptional(scanner.TRANSACTION)
@@ -43,7 +44,7 @@ func (p *Parser) parseRollbackStatement() (query.Statement, error) {
// parseCommitStatement parses a COMMIT statement. // parseCommitStatement parses a COMMIT statement.
// This function assumes the COMMIT token has already been consumed. // This function assumes the COMMIT token has already been consumed.
func (p *Parser) parseCommitStatement() (query.Statement, error) { func (p *Parser) parseCommitStatement() (statement.Statement, error) {
// parse optional TRANSACTION token // parse optional TRANSACTION token
_, _ = p.parseOptional(scanner.TRANSACTION) _, _ = p.parseOptional(scanner.TRANSACTION)

View File

@@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query"
"github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -11,7 +12,7 @@ import (
func TestParserTransactions(t *testing.T) { func TestParserTransactions(t *testing.T) {
tests := []struct { tests := []struct {
s string s string
expected query.Statement expected statement.Statement
errored bool errored bool
}{ }{
{"BEGIN", query.BeginStmt{Writable: true}, false}, {"BEGIN", query.BeginStmt{Writable: true}, false},

View File

@@ -1,14 +1,14 @@
package parser package parser
import ( import (
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/scanner" "github.com/genjidb/genji/internal/sql/scanner"
) )
// parseUpdateStatement parses a update string and returns a Statement AST object. // parseUpdateStatement parses a update string and returns a Statement AST object.
// This function assumes the UPDATE token has already been consumed. // This function assumes the UPDATE token has already been consumed.
func (p *Parser) parseUpdateStatement() (*query.UpdateStmt, error) { func (p *Parser) parseUpdateStatement() (*statement.UpdateStmt, error) {
var stmt query.UpdateStmt var stmt statement.UpdateStmt
var err error var err error
// Parse table name // Parse table name
@@ -43,8 +43,8 @@ func (p *Parser) parseUpdateStatement() (*query.UpdateStmt, error) {
} }
// parseSetClause parses the "SET" clause of the query. // parseSetClause parses the "SET" clause of the query.
func (p *Parser) parseSetClause() ([]query.UpdateSetPair, error) { func (p *Parser) parseSetClause() ([]statement.UpdateSetPair, error) {
var pairs []query.UpdateSetPair var pairs []statement.UpdateSetPair
firstPair := true firstPair := true
for { for {
@@ -75,7 +75,7 @@ func (p *Parser) parseSetClause() ([]query.UpdateSetPair, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
pairs = append(pairs, query.UpdateSetPair{Path: path, E: expr}) pairs = append(pairs, statement.UpdateSetPair{Path: path, E: expr})
firstPair = false firstPair = false
} }

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"github.com/genjidb/genji/document" "github.com/genjidb/genji/document"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/genjidb/genji/internal/stream" "github.com/genjidb/genji/internal/stream"
"github.com/genjidb/genji/internal/testutil" "github.com/genjidb/genji/internal/testutil"
@@ -75,7 +75,7 @@ func TestParserUpdate(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Len(t, q.Statements, 1) require.Len(t, q.Statements, 1)
stmt := q.Statements[0].(*query.UpdateStmt) stmt := q.Statements[0].(*statement.UpdateStmt)
require.False(t, stmt.IsReadOnly()) require.False(t, stmt.IsReadOnly())
require.EqualValues(t, test.expected, stmt.ToStream().Stream) require.EqualValues(t, test.expected, stmt.ToStream().Stream)
}) })

View File

@@ -9,7 +9,7 @@ import (
"github.com/genjidb/genji/engine/memoryengine" "github.com/genjidb/genji/engine/memoryengine"
"github.com/genjidb/genji/internal/database" "github.com/genjidb/genji/internal/database"
"github.com/genjidb/genji/internal/expr" "github.com/genjidb/genji/internal/expr"
"github.com/genjidb/genji/internal/query" "github.com/genjidb/genji/internal/query/statement"
"github.com/genjidb/genji/internal/sql/parser" "github.com/genjidb/genji/internal/sql/parser"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -54,7 +54,7 @@ func Exec(tx *database.Transaction, q string, params ...expr.Param) error {
}) })
} }
func Query(tx *database.Transaction, q string, params ...expr.Param) (*query.Result, error) { func Query(tx *database.Transaction, q string, params ...expr.Param) (*statement.Result, error) {
pq, err := parser.ParseQuery(q) pq, err := parser.ParseQuery(q)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -68,7 +68,7 @@ func MustExec(t *testing.T, tx *database.Transaction, q string, params ...expr.P
require.NoError(t, err) require.NoError(t, err)
} }
func MustQuery(t *testing.T, tx *database.Transaction, q string, params ...expr.Param) *query.Result { func MustQuery(t *testing.T, tx *database.Transaction, q string, params ...expr.Param) *statement.Result {
res, err := Query(tx, q, params...) res, err := Query(tx, q, params...)
require.NoError(t, err) require.NoError(t, err)
return res return res