mirror of
https://github.com/chaisql/chai.git
synced 2025-09-26 19:51:21 +08:00
241 lines
8.0 KiB
Go
241 lines
8.0 KiB
Go
package parser_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/chaisql/chai/internal/expr"
|
|
"github.com/chaisql/chai/internal/query/statement"
|
|
"github.com/chaisql/chai/internal/sql/parser"
|
|
"github.com/chaisql/chai/internal/stream"
|
|
"github.com/chaisql/chai/internal/stream/path"
|
|
"github.com/chaisql/chai/internal/stream/rows"
|
|
"github.com/chaisql/chai/internal/stream/table"
|
|
"github.com/chaisql/chai/internal/testutil"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestParserInsert(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
s string
|
|
expected *stream.Stream
|
|
fails bool
|
|
}{
|
|
{"Values / With fields", "INSERT INTO test (a, b) VALUES ('c', 'd')",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
)).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Values / With too many values", "INSERT INTO test (a, b) VALUES ('c', 'd', 'e')",
|
|
nil, true},
|
|
{"Values / Multiple", "INSERT INTO test (a, b) VALUES ('c', 'd'), ('e', 'f')",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("e"),
|
|
testutil.TextValue("f"),
|
|
},
|
|
},
|
|
)).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Values / Returning", "INSERT INTO test (a, b) VALUES ('c', 'd') RETURNING *, a, b as B",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
)).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(expr.Wildcard{}, testutil.ParseNamedExpr(t, "a"), testutil.ParseNamedExpr(t, "b", "B"))),
|
|
false},
|
|
{"Values / With fields / Wrong values", "INSERT INTO test (a, b) VALUES {a: 1}, ('e', 'f')",
|
|
nil, true},
|
|
{"Values / Without fields / Wrong values", "INSERT INTO test VALUES {a: 1}, ('e', 'f')",
|
|
nil, true},
|
|
{"Values / ON CONFLICT DO NOTHING", "INSERT INTO test (a, b) VALUES ('c', 'd') ON CONFLICT DO NOTHING RETURNING *",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
)).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKeyOnConflictDoNothing("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(expr.Wildcard{})),
|
|
false},
|
|
{"Values / ON CONFLICT IGNORE", "INSERT INTO test (a, b) VALUES ('c', 'd') ON CONFLICT IGNORE RETURNING *",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
)).Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKeyOnConflictDoNothing("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(expr.Wildcard{})),
|
|
false},
|
|
{"Values / ON CONFLICT DO REPLACE", "INSERT INTO test (a, b) VALUES ('c', 'd') ON CONFLICT DO REPLACE RETURNING *",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
)).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKeyOnConflict("test", stream.New(table.Replace("test")))).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(expr.Wildcard{})),
|
|
false},
|
|
{"Values / ON CONFLICT REPLACE", "INSERT INTO test (a, b) VALUES ('c', 'd') ON CONFLICT REPLACE RETURNING *",
|
|
stream.New(rows.Emit(
|
|
[]string{"a", "b"},
|
|
expr.Row{
|
|
Columns: []string{"a", "b"},
|
|
Exprs: []expr.Expr{
|
|
testutil.TextValue("c"),
|
|
testutil.TextValue("d"),
|
|
},
|
|
},
|
|
)).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKeyOnConflict("test", stream.New(table.Replace("test")))).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(expr.Wildcard{})),
|
|
false},
|
|
{"Values / ON CONFLICT BLA", "INSERT INTO test (a, b) VALUES ('c', 'd') ON CONFLICT BLA RETURNING *",
|
|
nil, true},
|
|
{"Values / ON CONFLICT DO BLA", "INSERT INTO test (a, b) VALUES ('c', 'd') ON CONFLICT DO BLA RETURNING *",
|
|
nil, true},
|
|
{"Select / Without fields", "INSERT INTO test SELECT * FROM foo",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(expr.Wildcard{})).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Select / Without fields / With projection", "INSERT INTO test SELECT c, d FROM foo",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "c"), testutil.ParseNamedExpr(t, "d"))).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Select / With fields", "INSERT INTO test (a, b) SELECT * FROM foo",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(expr.Wildcard{})).
|
|
Pipe(path.PathsRename("a", "b")).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Select / With fields / With projection", "INSERT INTO test (a, b) SELECT c, d FROM foo",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "c"), testutil.ParseNamedExpr(t, "d"))).
|
|
Pipe(path.PathsRename("a", "b")).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Select / With fields / With projection / different fields", "INSERT INTO test (a, b) SELECT c, d FROM foo",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "c"), testutil.ParseNamedExpr(t, "d"))).
|
|
Pipe(path.PathsRename("a", "b")).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(stream.Discard()),
|
|
false},
|
|
{"Select / With fields / With projection / different fields / Returning", "INSERT INTO test (a, b) SELECT c, d FROM foo RETURNING a",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "c"), testutil.ParseNamedExpr(t, "d"))).
|
|
Pipe(path.PathsRename("a", "b")).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKey("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "a"))),
|
|
false},
|
|
{"Select / With fields / With projection / different fields / On conflict / Returning", "INSERT INTO test (a, b) SELECT c, d FROM foo ON CONFLICT DO NOTHING RETURNING a",
|
|
stream.New(table.Scan("foo")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "c"), testutil.ParseNamedExpr(t, "d"))).
|
|
Pipe(path.PathsRename("a", "b")).
|
|
Pipe(table.Validate("test")).
|
|
Pipe(table.GenerateKeyOnConflictDoNothing("test")).
|
|
Pipe(table.Insert("test")).
|
|
Pipe(rows.Project(testutil.ParseNamedExpr(t, "a"))),
|
|
false},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
db, tx, cleanup := testutil.NewTestTx(t)
|
|
defer cleanup()
|
|
|
|
testutil.MustExec(t, db, tx, "CREATE TABLE test(a TEXT PRIMARY KEY, b TEXT); CREATE TABLE foo(c TEXT PRIMARY KEY, d TEXT);")
|
|
|
|
stmts, err := parser.ParseQuery(test.s)
|
|
if test.fails {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, stmts, 1)
|
|
|
|
stmt, err := stmts[0].(statement.Preparer).Prepare(&statement.Context{
|
|
DB: db,
|
|
Conn: tx.Connection(),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, test.expected.String(), stmt.(*statement.InsertStmt).Stream.String())
|
|
})
|
|
}
|
|
}
|