mirror of
https://github.com/chaisql/chai.git
synced 2025-10-04 15:22:51 +08:00
188 lines
5.5 KiB
Go
188 lines
5.5 KiB
Go
package statement_test
|
|
|
|
import (
|
|
"bytes"
|
|
"database/sql"
|
|
"testing"
|
|
|
|
"github.com/genjidb/genji"
|
|
"github.com/genjidb/genji/internal/testutil"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestInsertStmt(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
query string
|
|
fails bool
|
|
expected string
|
|
params []interface{}
|
|
}{
|
|
{"Values / Positional Params", "INSERT INTO test (a, b, c) VALUES (?, 'e', ?)", false, `[{"pk()":1,"a":"d","b":"e","c":"f"}]`, []interface{}{"d", "f"}},
|
|
{"Values / Named Params", "INSERT INTO test (a, b, c) VALUES ($d, 'e', $f)", false, `[{"pk()":1,"a":"d","b":"e","c":"f"}]`, []interface{}{sql.Named("f", "f"), sql.Named("d", "d")}},
|
|
{"Values / Invalid params", "INSERT INTO test (a, b, c) VALUES ('d', ?)", true, "", []interface{}{'e'}},
|
|
{"Documents / Named Params", "INSERT INTO test VALUES {a: $a, b: 2.3, c: $c}", false, `[{"pk()":1,"a":1,"b":2.3,"c":true}]`, []interface{}{sql.Named("c", true), sql.Named("a", 1)}},
|
|
{"Documents / List ", "INSERT INTO test VALUES {a: [1, 2, 3]}", false, `[{"pk()":1,"a":[1,2,3]}]`, nil},
|
|
{"Select / same table", "INSERT INTO test SELECT * FROM test", true, ``, nil},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
testFn := func(withIndexes bool) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
db, err := genji.Open(":memory:")
|
|
require.NoError(t, err)
|
|
defer db.Close()
|
|
|
|
err = db.Exec("CREATE TABLE test")
|
|
require.NoError(t, err)
|
|
if withIndexes {
|
|
err = db.Exec(`
|
|
CREATE INDEX idx_a ON test (a);
|
|
CREATE INDEX idx_b ON test (b);
|
|
CREATE INDEX idx_c ON test (c);
|
|
`)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err = db.Exec(test.query, test.params...)
|
|
if test.fails {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
st, err := db.Query("SELECT pk(), * FROM test")
|
|
require.NoError(t, err)
|
|
defer st.Close()
|
|
|
|
var buf bytes.Buffer
|
|
err = testutil.IteratorToJSONArray(&buf, st)
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, test.expected, buf.String())
|
|
}
|
|
}
|
|
|
|
t.Run("No Index/"+test.name, testFn(false))
|
|
t.Run("With Index/"+test.name, testFn(true))
|
|
}
|
|
|
|
t.Run("with struct param", func(t *testing.T) {
|
|
db, err := genji.Open(":memory:")
|
|
require.NoError(t, err)
|
|
defer db.Close()
|
|
|
|
err = db.Exec("CREATE TABLE test")
|
|
require.NoError(t, err)
|
|
|
|
type foo struct {
|
|
A string
|
|
B string `genji:"b-b"`
|
|
}
|
|
|
|
err = db.Exec("INSERT INTO test VALUES ?", &foo{A: "a", B: "b"})
|
|
require.NoError(t, err)
|
|
res, err := db.Query("SELECT * FROM test")
|
|
defer res.Close()
|
|
|
|
require.NoError(t, err)
|
|
var buf bytes.Buffer
|
|
err = testutil.IteratorToJSONArray(&buf, res)
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, `[{"a": "a", "b-b": "b"}]`, buf.String())
|
|
})
|
|
|
|
t.Run("with RETURNING", func(t *testing.T) {
|
|
db, err := genji.Open(":memory:")
|
|
require.NoError(t, err)
|
|
defer db.Close()
|
|
|
|
err = db.Exec(`CREATE TABLE test`)
|
|
require.NoError(t, err)
|
|
|
|
d, err := db.QueryDocument(`insert into test (a) VALUES (1) RETURNING *, pk(), a AS A`)
|
|
require.NoError(t, err)
|
|
testutil.RequireDocJSONEq(t, d, `{"a": 1, "pk()": 1, "A": 1}`)
|
|
})
|
|
|
|
t.Run("ensure rollback", func(t *testing.T) {
|
|
db, err := genji.Open(":memory:")
|
|
require.NoError(t, err)
|
|
defer db.Close()
|
|
|
|
err = db.Exec(`CREATE TABLE test(a int unique)`)
|
|
require.NoError(t, err)
|
|
|
|
err = db.Exec(`insert into test (a) VALUES (1), (1)`)
|
|
require.Error(t, err)
|
|
|
|
res, err := db.Query("SELECT * FROM test")
|
|
require.NoError(t, err)
|
|
defer res.Close()
|
|
|
|
testutil.RequireStreamEq(t, ``, res)
|
|
})
|
|
|
|
// t.Run("without RETURNING", func(t *testing.T) {
|
|
// db, err := genji.Open(":memory:")
|
|
// require.NoError(t, err)
|
|
// defer db.Close()
|
|
|
|
// err = db.Exec(`CREATE TABLE test`)
|
|
// require.NoError(t, err)
|
|
|
|
// _, err = db.QueryDocument(`insert into test (a) VALUES (1)`)
|
|
// require.Equal(t, errs.ErrDocumentNotFound, err)
|
|
// })
|
|
}
|
|
|
|
func TestInsertSelect(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
query string
|
|
fails bool
|
|
expected string
|
|
params []interface{}
|
|
}{
|
|
{"Same table", `INSERT INTO foo SELECT * FROM foo`, true, ``, nil},
|
|
{"No fields / No projection", `INSERT INTO foo SELECT * FROM bar`, false, `[{"pk()":1, "a":1, "b":10}]`, nil},
|
|
{"No fields / Projection", `INSERT INTO foo SELECT a FROM bar`, false, `[{"pk()":1, "a":1}]`, nil},
|
|
{"With fields / No Projection", `INSERT INTO foo (a, b) SELECT * FROM bar`, false, `[{"pk()":1, "a":1, "b":10}]`, nil},
|
|
{"With fields / Projection", `INSERT INTO foo (c, d) SELECT a, b FROM bar`, false, `[{"pk()":1, "c":1, "d":10}]`, nil},
|
|
{"Too many fields / No Projection", `INSERT INTO foo (c) SELECT * FROM bar`, true, ``, nil},
|
|
{"Too many fields / Projection", `INSERT INTO foo (c, d) SELECT a, b, c FROM bar`, true, ``, nil},
|
|
{"Too few fields / No Projection", `INSERT INTO foo (c, d, e) SELECT * FROM bar`, true, ``, nil},
|
|
{"Too few fields / Projection", `INSERT INTO foo (c, d) SELECT a FROM bar`, true, ``, nil},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
db, err := genji.Open(":memory:")
|
|
require.NoError(t, err)
|
|
defer db.Close()
|
|
|
|
err = db.Exec(`
|
|
CREATE TABLE foo;
|
|
CREATE TABLE bar;
|
|
INSERT INTO bar (a, b) VALUES (1, 10)
|
|
`)
|
|
require.NoError(t, err)
|
|
|
|
err = db.Exec(test.query, test.params...)
|
|
if test.fails {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
st, err := db.Query("SELECT pk(), * FROM foo")
|
|
require.NoError(t, err)
|
|
defer st.Close()
|
|
|
|
var buf bytes.Buffer
|
|
err = testutil.IteratorToJSONArray(&buf, st)
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, test.expected, buf.String())
|
|
})
|
|
}
|
|
}
|