Files
chaisql/db_test.go
2024-02-20 09:39:14 +04:00

257 lines
7.5 KiB
Go

package chai_test
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/chaisql/chai"
"github.com/chaisql/chai/internal/testutil"
"github.com/stretchr/testify/require"
)
func ExampleTx() {
db, err := chai.Open(":memory:")
if err != nil {
panic(err)
}
defer db.Close()
conn, err := db.Connect()
if err != nil {
panic(err)
}
defer conn.Close()
tx, err := conn.Begin(true)
if err != nil {
panic(err)
}
defer tx.Rollback()
err = tx.Exec("CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
if err != nil {
panic(err)
}
err = tx.Exec("INSERT INTO user (id, name, age) VALUES (?, ?, ?)", 10, "foo", 15)
if err != nil {
panic(err)
}
r, err := tx.QueryRow("SELECT id, name, age FROM user WHERE name = ?", "foo")
if err != nil {
panic(fmt.Sprintf("%+v", err))
}
var u User
err = r.StructScan(&u)
if err != nil {
panic(err)
}
fmt.Println(u)
var id uint64
var name string
var age uint8
err = r.Scan(&id, &name, &age)
if err != nil {
panic(err)
}
fmt.Println(id, name, age)
err = tx.Commit()
if err != nil {
panic(err)
}
// Output: {10 foo 15}
// 10 foo 15
}
func TestOpen(t *testing.T) {
dir, err := os.MkdirTemp("", "chai")
require.NoError(t, err)
defer os.RemoveAll(dir)
db, err := chai.Open(filepath.Join(dir, "testdb"))
require.NoError(t, err)
err = db.Exec(`
CREATE TABLE tableA (a INTEGER UNIQUE NOT NULL, b DOUBLE PRIMARY KEY);
CREATE TABLE tableB (a TEXT NOT NULL DEFAULT 'hello', PRIMARY KEY (a));
CREATE TABLE tableC (a INTEGER, b INTEGER);
CREATE INDEX tableC_a_b_idx ON tableC(a, b);
CREATE SEQUENCE seqD INCREMENT BY 10 CYCLE MINVALUE 100 NO MAXVALUE START 500;
INSERT INTO tableB (a) VALUES (1);
INSERT INTO tableC (a, b) VALUES (1, NEXT VALUE FOR seqD);
`)
require.NoError(t, err)
err = db.Close()
require.NoError(t, err)
// ensure tables are loaded properly
db, err = chai.Open(filepath.Join(dir, "testdb"))
require.NoError(t, err)
defer db.Close()
conn, err := db.Connect()
require.NoError(t, err)
defer conn.Close()
res1, err := conn.Query("SELECT * FROM __chai_catalog")
require.NoError(t, err)
defer res1.Close()
var count int
want := []string{
`{"name":"__chai_catalog", "namespace":1, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE __chai_catalog (name TEXT NOT NULL, type TEXT NOT NULL, namespace BIGINT, sql TEXT, rowid_sequence_name TEXT, owner_table_name TEXT, owner_table_columns TEXT, CONSTRAINT __chai_catalog_pk PRIMARY KEY (name))", "type":"table"}`,
`{"name":"__chai_sequence", "namespace":2, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE __chai_sequence (name TEXT NOT NULL, seq BIGINT, CONSTRAINT __chai_sequence_pk PRIMARY KEY (name))", "type":"table"}`,
`{"name":"__chai_store_seq", "namespace":null, "owner_table_columns":null, "owner_table_name":"__chai_catalog", "rowid_sequence_name":null, "sql":"CREATE SEQUENCE __chai_store_seq MAXVALUE 9223372036837998591 START WITH 10 CACHE 0", "type":"sequence"}`,
`{"name":"seqD", "namespace":null, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE SEQUENCE seqD INCREMENT BY 10 MINVALUE 100 START WITH 500 CYCLE", "type":"sequence"}`,
`{"name":"tableA", "namespace":10, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE tableA (a INTEGER NOT NULL, b DOUBLE NOT NULL, CONSTRAINT tableA_a_unique UNIQUE (a), CONSTRAINT tableA_pk PRIMARY KEY (b))", "type":"table"}`,
`{"name":"tableA_a_idx", "namespace":11, "owner_table_columns":"a", "owner_table_name":"tableA", "rowid_sequence_name":null, "sql":"CREATE UNIQUE INDEX tableA_a_idx ON tableA (a)", "type":"index"}`,
`{"name":"tableB", "namespace":12, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":null, "sql":"CREATE TABLE tableB (a TEXT NOT NULL DEFAULT \"hello\", CONSTRAINT tableB_pk PRIMARY KEY (a))", "type":"table"}`,
`{"name":"tableC", "namespace":13, "owner_table_columns":null, "owner_table_name":null, "rowid_sequence_name":"tableC_seq", "sql":"CREATE TABLE tableC (a INTEGER, b INTEGER)", "type":"table"}`,
`{"name":"tableC_a_b_idx", "namespace":14, "owner_table_columns":null, "owner_table_name":"tableC", "rowid_sequence_name":null, "sql":"CREATE INDEX tableC_a_b_idx ON tableC (a, b)", "type":"index"}`,
`{"name":"tableC_seq", "namespace":null, "owner_table_columns":null, "owner_table_name":"tableC", "rowid_sequence_name":null, "sql":"CREATE SEQUENCE tableC_seq CACHE 64", "type":"sequence"}`,
}
err = res1.Iterate(func(r *chai.Row) error {
count++
if count > len(want) {
return fmt.Errorf("more than %d relations", len(want))
}
testutil.RequireJSONEq(t, r, want[count-1])
return nil
})
require.NoError(t, err)
d, err := db.QueryRow("SELECT * FROM tableB")
require.NoError(t, err)
testutil.RequireJSONEq(t, d, `{"a": "1"}`)
d, err = db.QueryRow("SELECT * FROM __chai_sequence")
require.NoError(t, err)
testutil.RequireJSONEq(t, d, `{"name":"__chai_store_seq", "seq":14}`)
d, err = db.QueryRow("SELECT * FROM __chai_sequence OFFSET 1")
require.NoError(t, err)
testutil.RequireJSONEq(t, d, `{"name": "seqD", "seq": 500}`)
}
func TestQueryRow(t *testing.T) {
db, err := chai.Open(":memory:")
require.NoError(t, err)
require.NoError(t, err)
conn, err := db.Connect()
require.NoError(t, err)
defer conn.Close()
tx, err := conn.Begin(true)
require.NoError(t, err)
err = tx.Exec(`
CREATE TABLE test(a INTEGER PRIMARY KEY, b TEXT NOT NULL);
INSERT INTO test (a, b) VALUES (1, 'foo'), (2, 'bar')
`)
require.NoError(t, err)
require.NoError(t, tx.Commit())
t.Run("Should return the first row", func(t *testing.T) {
var a int
var b string
r, err := db.QueryRow("SELECT * FROM test")
require.NoError(t, err)
err = r.Scan(&a, &b)
require.NoError(t, err)
require.Equal(t, 1, a)
require.Equal(t, "foo", b)
conn, err := db.Connect()
require.NoError(t, err)
defer conn.Close()
tx, err := conn.Begin(false)
require.NoError(t, err)
defer tx.Rollback()
r, err = tx.QueryRow("SELECT * FROM test")
require.NoError(t, err)
err = r.Scan(&a, &b)
require.NoError(t, err)
require.Equal(t, 1, a)
require.Equal(t, "foo", b)
})
t.Run("Should return an error if no row", func(t *testing.T) {
r, err := db.QueryRow("SELECT * FROM test WHERE a > 100")
require.True(t, chai.IsNotFoundError(err))
require.Nil(t, r)
conn, err := db.Connect()
require.NoError(t, err)
defer conn.Close()
tx, err := conn.Begin(false)
require.NoError(t, err)
defer tx.Rollback()
r, err = tx.QueryRow("SELECT * FROM test WHERE a > 100")
require.True(t, chai.IsNotFoundError(err))
require.Nil(t, r)
})
}
func TestIterateDeepCopy(t *testing.T) {
db, err := chai.Open(":memory:")
require.NoError(t, err)
defer db.Close()
err = db.Exec(`
CREATE TABLE foo (
a integer primary key,
b text not null
);
INSERT INTO foo (a, b) VALUES
(1, 'sample text 1'),
(2, 'sample text 2');
`)
require.NoError(t, err)
conn, err := db.Connect()
require.NoError(t, err)
defer conn.Close()
res, err := conn.Query(`SELECT * FROM foo ORDER BY a DESC`)
require.NoError(t, err)
type item struct {
A int
B string
}
var items []*item
err = res.Iterate(func(r *chai.Row) error {
var i item
err := r.StructScan(&i)
require.NoError(t, err)
items = append(items, &i)
return nil
})
require.NoError(t, err)
require.Equal(t, len(items), 2)
require.Equal(t, &item{A: 2, B: "sample text 2"}, items[0])
require.Equal(t, &item{A: 1, B: "sample text 1"}, items[1])
}