mydb/internal/sqladapter/exql/statement_test.go

704 lines
17 KiB
Go
Raw Normal View History

2023-09-18 15:15:42 +08:00
package exql
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTruncateTable(t *testing.T) {
stmt := Statement{
Type: Truncate,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `TRUNCATE TABLE "table_name"`, s)
}
func TestDropTable(t *testing.T) {
stmt := Statement{
Type: DropTable,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `DROP TABLE "table_name"`, s)
}
func TestDropDatabase(t *testing.T) {
stmt := Statement{
Type: DropDatabase,
Database: &Database{Name: "table_name"},
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `DROP DATABASE "table_name"`, s)
}
func TestCount(t *testing.T) {
stmt := Statement{
Type: Count,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT COUNT(1) AS _t FROM "table_name"`, s)
}
func TestCountRelation(t *testing.T) {
stmt := Statement{
Type: Count,
Table: TableWithName("information_schema.tables"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT COUNT(1) AS _t FROM "information_schema"."tables"`, s)
}
func TestCountWhere(t *testing.T) {
stmt := Statement{
Type: Count,
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "a"}, Operator: "=", Value: &Raw{Value: "7"}},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT COUNT(1) AS _t FROM "table_name" WHERE ("a" = 7)`, s)
}
func TestSelectStarFrom(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "table_name"`, s)
}
func TestSelectStarFromAlias(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("table.name AS foo"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "table"."name" AS "foo"`, s)
}
func TestSelectStarFromRawWhere(t *testing.T) {
{
stmt := Statement{
Type: Select,
Table: TableWithName("table.name AS foo"),
Where: WhereConditions(
&Raw{Value: "foo.id = bar.foo_id"},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "table"."name" AS "foo" WHERE (foo.id = bar.foo_id)`, s)
}
{
stmt := Statement{
Type: Select,
Table: TableWithName("table.name AS foo"),
Where: WhereConditions(
&Raw{Value: "foo.id = bar.foo_id"},
&Raw{Value: "baz.id = exp.baz_id"},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "table"."name" AS "foo" WHERE (foo.id = bar.foo_id AND baz.id = exp.baz_id)`, s)
}
}
func TestSelectStarFromMany(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("first.table AS foo, second.table as BAR, third.table aS baz"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "first"."table" AS "foo", "second"."table" AS "BAR", "third"."table" AS "baz"`, s)
}
func TestSelectTableStarFromMany(t *testing.T) {
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo.name"},
&Column{Name: "BAR.*"},
&Column{Name: "baz.last_name"},
),
Table: TableWithName("first.table AS foo, second.table as BAR, third.table aS baz"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo"."name", "BAR".*, "baz"."last_name" FROM "first"."table" AS "foo", "second"."table" AS "BAR", "third"."table" AS "baz"`, s)
}
func TestSelectArtistNameFrom(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("artist"),
Columns: JoinColumns(
&Column{Name: "artist.name"},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "artist"."name" FROM "artist"`, s)
}
func TestSelectJoin(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("artist a"),
Columns: JoinColumns(
&Column{Name: "a.name"},
),
Joins: JoinConditions(&Join{
Table: TableWithName("books b"),
On: OnConditions(
&ColumnValue{
Column: ColumnWithName("b.author_id"),
Operator: `=`,
Value: NewValue(ColumnWithName("a.id")),
},
),
}),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "a"."name" FROM "artist" AS "a" JOIN "books" AS "b" ON ("b"."author_id" = "a"."id")`, s)
}
func TestSelectJoinUsing(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("artist a"),
Columns: JoinColumns(
&Column{Name: "a.name"},
),
Joins: JoinConditions(&Join{
Table: TableWithName("books b"),
Using: UsingColumns(
ColumnWithName("artist_id"),
ColumnWithName("country"),
),
}),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "a"."name" FROM "artist" AS "a" JOIN "books" AS "b" USING ("artist_id", "country")`, s)
}
func TestSelectUnfinishedJoin(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("artist a"),
Columns: JoinColumns(
&Column{Name: "a.name"},
),
Joins: JoinConditions(&Join{}),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "a"."name" FROM "artist" AS "a"`, s)
}
func TestSelectNaturalJoin(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName("artist"),
Joins: JoinConditions(&Join{
Table: TableWithName("books"),
}),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "artist" NATURAL JOIN "books"`, s)
}
func TestSelectRawFrom(t *testing.T) {
stmt := Statement{
Type: Select,
Table: TableWithName(`artist`),
Columns: JoinColumns(
&Column{Name: `artist.name`},
&Column{Name: &Raw{Value: `CONCAT(artist.name, " ", artist.last_name)`}},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "artist"."name", CONCAT(artist.name, " ", artist.last_name) FROM "artist"`, s)
}
func TestSelectFieldsFrom(t *testing.T) {
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name"`, s)
}
func TestSelectFieldsFromWithLimitOffset(t *testing.T) {
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Limit: 42,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" LIMIT 42`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Offset: 17,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" OFFSET 17`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Limit: 42,
Offset: 17,
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" LIMIT 42 OFFSET 17`, s)
}
}
func TestStatementGroupBy(t *testing.T) {
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
GroupBy: GroupByColumns(
&Column{Name: "foo"},
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" GROUP BY "foo"`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
GroupBy: GroupByColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" GROUP BY "foo", "bar"`, s)
}
}
func TestSelectFieldsFromWithOrderBy(t *testing.T) {
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
OrderBy: JoinWithOrderBy(
JoinSortColumns(
&SortColumn{Column: &Column{Name: "foo"}},
),
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" ORDER BY "foo"`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
OrderBy: JoinWithOrderBy(
JoinSortColumns(
&SortColumn{Column: &Column{Name: "foo"}, Order: Order_Ascendent},
),
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" ORDER BY "foo" ASC`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
OrderBy: JoinWithOrderBy(
JoinSortColumns(
&SortColumn{Column: &Column{Name: "foo"}, Order: Order_Descendent},
),
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" ORDER BY "foo" DESC`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
OrderBy: JoinWithOrderBy(
JoinSortColumns(
&SortColumn{Column: &Column{Name: "foo"}, Order: Order_Descendent},
&SortColumn{Column: &Column{Name: "bar"}, Order: Order_Ascendent},
&SortColumn{Column: &Column{Name: "baz"}, Order: Order_Descendent},
),
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" ORDER BY "foo" DESC, "bar" ASC, "baz" DESC`, s)
}
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
OrderBy: JoinWithOrderBy(
JoinSortColumns(
&SortColumn{Column: &Column{Name: &Raw{Value: "FOO()"}}, Order: Order_Descendent},
&SortColumn{Column: &Column{Name: &Raw{Value: "BAR()"}}, Order: Order_Ascendent},
),
),
Table: TableWithName("table_name"),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" ORDER BY FOO() DESC, BAR() ASC`, s)
}
}
func TestSelectFieldsFromWhere(t *testing.T) {
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "baz"}, Operator: "=", Value: NewValue(99)},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" WHERE ("baz" = '99')`, s)
}
}
func TestSelectFieldsFromWhereLimitOffset(t *testing.T) {
{
stmt := Statement{
Type: Select,
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "baz"}, Operator: "=", Value: NewValue(99)},
),
Limit: 10,
Offset: 23,
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT "foo", "bar", "baz" FROM "table_name" WHERE ("baz" = '99') LIMIT 10 OFFSET 23`, s)
}
}
func TestDelete(t *testing.T) {
stmt := Statement{
Type: Delete,
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "baz"}, Operator: "=", Value: NewValue(99)},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `DELETE FROM "table_name" WHERE ("baz" = '99')`, s)
}
func TestUpdate(t *testing.T) {
{
stmt := Statement{
Type: Update,
Table: TableWithName("table_name"),
ColumnValues: JoinColumnValues(
&ColumnValue{Column: &Column{Name: "foo"}, Operator: "=", Value: NewValue(76)},
),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "baz"}, Operator: "=", Value: NewValue(99)},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `UPDATE "table_name" SET "foo" = '76' WHERE ("baz" = '99')`, s)
}
{
stmt := Statement{
Type: Update,
Table: TableWithName("table_name"),
ColumnValues: JoinColumnValues(
&ColumnValue{Column: &Column{Name: "foo"}, Operator: "=", Value: NewValue(76)},
&ColumnValue{Column: &Column{Name: "bar"}, Operator: "=", Value: NewValue(&Raw{Value: "88"})},
),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "baz"}, Operator: "=", Value: NewValue(99)},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `UPDATE "table_name" SET "foo" = '76', "bar" = 88 WHERE ("baz" = '99')`, s)
}
}
func TestInsert(t *testing.T) {
stmt := Statement{
Type: Insert,
Table: TableWithName("table_name"),
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Values: NewValueGroup(
&Value{V: "1"},
&Value{V: 2},
&Value{V: &Raw{Value: "3"}},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `INSERT INTO "table_name" ("foo", "bar", "baz") VALUES ('1', '2', 3)`, s)
}
func TestInsertMultiple(t *testing.T) {
stmt := Statement{
Type: Insert,
Table: TableWithName("table_name"),
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Values: JoinValueGroups(
NewValueGroup(
NewValue("1"),
NewValue("2"),
NewValue(&Raw{Value: "3"}),
),
NewValueGroup(
NewValue(&Raw{Value: "4"}),
NewValue(&Raw{Value: "5"}),
NewValue(&Raw{Value: "6"}),
),
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `INSERT INTO "table_name" ("foo", "bar", "baz") VALUES ('1', '2', 3), (4, 5, 6)`, s)
}
func TestInsertReturning(t *testing.T) {
stmt := Statement{
Type: Insert,
Table: TableWithName("table_name"),
Returning: ReturningColumns(
ColumnWithName("id"),
),
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Values: NewValueGroup(
&Value{V: "1"},
&Value{V: 2},
&Value{V: &Raw{Value: "3"}},
),
}
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `INSERT INTO "table_name" ("foo", "bar", "baz") VALUES ('1', '2', 3) RETURNING "id"`, s)
}
func TestRawSQLStatement(t *testing.T) {
stmt := RawSQL(`SELECT * FROM "foo" ORDER BY "bar"`)
s := mustTrim(stmt.Compile(defaultTemplate))
assert.Equal(t, `SELECT * FROM "foo" ORDER BY "bar"`, s)
}
func BenchmarkStatementSimpleQuery(b *testing.B) {
stmt := Statement{
Type: Count,
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "a"}, Operator: "=", Value: NewValue(&Raw{Value: "7"})},
),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = stmt.Compile(defaultTemplate)
}
}
func BenchmarkStatementSimpleQueryHash(b *testing.B) {
stmt := Statement{
Type: Count,
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "a"}, Operator: "=", Value: NewValue(&Raw{Value: "7"})},
),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = stmt.Hash()
}
}
func BenchmarkStatementSimpleQueryNoCache(b *testing.B) {
for i := 0; i < b.N; i++ {
stmt := Statement{
Type: Count,
Table: TableWithName("table_name"),
Where: WhereConditions(
&ColumnValue{Column: &Column{Name: "a"}, Operator: "=", Value: NewValue(&Raw{Value: "7"})},
),
}
_, _ = stmt.Compile(defaultTemplate)
}
}
func BenchmarkStatementComplexQuery(b *testing.B) {
stmt := Statement{
Type: Insert,
Table: TableWithName("table_name"),
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Values: NewValueGroup(
&Value{V: "1"},
&Value{V: 2},
&Value{V: &Raw{Value: "3"}},
),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = stmt.Compile(defaultTemplate)
}
}
func BenchmarkStatementComplexQueryNoCache(b *testing.B) {
for i := 0; i < b.N; i++ {
stmt := Statement{
Type: Insert,
Table: TableWithName("table_name"),
Columns: JoinColumns(
&Column{Name: "foo"},
&Column{Name: "bar"},
&Column{Name: "baz"},
),
Values: NewValueGroup(
&Value{V: "1"},
&Value{V: 2},
&Value{V: &Raw{Value: "3"}},
),
}
_, _ = stmt.Compile(defaultTemplate)
}
}