feat: 新增 DuckDB 方言支持及 SQLite3 自动注册 IF 函数
- 新增 dialect/duckdb 方言,支持 DuckDB SQL 语法 - 新增 schema/dialect/duckdb DDL 操作支持 - dialect/sqlite3: 注册 sqlite3_with_if 驱动,连接时自动注册 IF() 函数 - engine: MakeConnection 对 sqlite3 自动使用带 IF 支持的驱动 - engine: 新增 DBConfig DuckDB 配置项及相关 Option 函数 - 统一各方言测试引用路径
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
package duckdb_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
dbv2 "git.fsdpf.net/go/db"
|
||||
"git.fsdpf.net/go/db/dialect/duckdb"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDialectOptions(t *testing.T) {
|
||||
opts := duckdb.DialectOptions()
|
||||
assert.NotNil(t, opts)
|
||||
assert.Equal(t, '"', opts.QuoteRune)
|
||||
assert.True(t, opts.IncludePlaceholderNum)
|
||||
assert.Equal(t, []byte("$"), opts.PlaceHolderFragment)
|
||||
assert.True(t, opts.SupportsReturn)
|
||||
assert.True(t, opts.SupportsConflictTarget)
|
||||
assert.True(t, opts.SupportsWithCTE)
|
||||
assert.True(t, opts.SupportsDistinctOn)
|
||||
assert.True(t, opts.SupportsWindowFunction)
|
||||
}
|
||||
|
||||
func TestDialectRegistration(t *testing.T) {
|
||||
// Verify the dialect is registered
|
||||
dialect := dbv2.GetDialect("duckdb")
|
||||
assert.NotNil(t, dialect)
|
||||
}
|
||||
|
||||
func TestSelectSQL(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.From("users")
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `SELECT * FROM "users"`, sql)
|
||||
|
||||
ds = db.From("users").Select("id", "name")
|
||||
sql, _, err = ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `SELECT "id", "name" FROM "users"`, sql)
|
||||
|
||||
ds = db.From("users").Where(dbv2.C("id").Eq(1))
|
||||
sql, _, err = ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `SELECT * FROM "users" WHERE ("id" = 1)`, sql)
|
||||
}
|
||||
|
||||
func TestPreparedStatement(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.From("users").Prepared(true).Where(dbv2.C("id").Eq(1))
|
||||
sql, args, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `SELECT * FROM "users" WHERE ("id" = $1)`, sql)
|
||||
assert.Equal(t, []interface{}{int64(1)}, args)
|
||||
|
||||
ds = db.From("users").Prepared(true).Where(dbv2.C("name").Eq("John"))
|
||||
sql, args, err = ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `SELECT * FROM "users" WHERE ("name" = $1)`, sql)
|
||||
assert.Equal(t, []interface{}{"John"}, args)
|
||||
}
|
||||
|
||||
func TestInsertSQL(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.Insert("users").Rows(dbv2.Record{"id": 1, "name": "John"})
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sql, `INSERT INTO "users"`)
|
||||
assert.Contains(t, sql, `"id"`)
|
||||
assert.Contains(t, sql, `"name"`)
|
||||
}
|
||||
|
||||
func TestUpdateSQL(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.Update("users").Set(dbv2.Record{"name": "Jane"}).Where(dbv2.C("id").Eq(1))
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sql, `UPDATE "users"`)
|
||||
assert.Contains(t, sql, `"name"`)
|
||||
assert.Contains(t, sql, `WHERE ("id" = 1)`)
|
||||
}
|
||||
|
||||
func TestDeleteSQL(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.Delete("users").Where(dbv2.C("id").Eq(1))
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `DELETE FROM "users" WHERE ("id" = 1)`, sql)
|
||||
}
|
||||
|
||||
func TestJoinSQL(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.From("users").
|
||||
Join(dbv2.T("orders"), dbv2.On(dbv2.Ex{"users.id": dbv2.I("orders.user_id")})).
|
||||
Select("users.name", "orders.total")
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sql, `FROM "users"`)
|
||||
assert.Contains(t, sql, `INNER JOIN "orders"`)
|
||||
assert.Contains(t, sql, `ON ("users"."id" = "orders"."user_id")`)
|
||||
}
|
||||
|
||||
func TestWindowFunction(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
ds := db.From("sales").
|
||||
Select(
|
||||
"product",
|
||||
"amount",
|
||||
dbv2.ROW_NUMBER().Over(dbv2.W().PartitionBy("product").OrderBy(dbv2.C("amount").Desc())).As("rank"),
|
||||
)
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sql, `ROW_NUMBER()`)
|
||||
assert.Contains(t, sql, `OVER`)
|
||||
assert.Contains(t, sql, `PARTITION BY`)
|
||||
}
|
||||
|
||||
func TestCTE(t *testing.T) {
|
||||
db := dbv2.Dialect("duckdb")
|
||||
|
||||
cte := db.From("users").Where(dbv2.C("active").IsTrue())
|
||||
ds := db.From("active_users").With("active_users", cte).Select("*")
|
||||
sql, _, err := ds.ToSQL()
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, sql, `WITH active_users AS`)
|
||||
assert.Contains(t, sql, `SELECT * FROM "users" WHERE ("active" IS TRUE)`)
|
||||
}
|
||||
Reference in New Issue
Block a user