package query_test import ( "bytes" "database/sql" "testing" "github.com/asdine/genji" "github.com/asdine/genji/database" "github.com/asdine/genji/document" "github.com/asdine/genji/engine/memoryengine" "github.com/stretchr/testify/require" ) func TestInsertStmt(t *testing.T) { tests := []struct { name string query string fails bool expected string params []interface{} }{ {"Values / No columns", `INSERT INTO test VALUES ("a", 'b', 'c')`, true, ``, nil}, {"Values / With columns", `INSERT INTO test (a, b, c) VALUES ('a', 'b', 'c')`, false, "1,a,b,c\n", nil}, {"Values / Ident", `INSERT INTO test (a) VALUES (a)`, true, ``, nil}, {"Values / Ident string", `INSERT INTO test (a) VALUES ("a")`, true, ``, nil}, {"Values / With fields ident string", `INSERT INTO test (a, "foo bar") VALUES ('c', 'd')`, false, "1,c,d\n", nil}, {"Values / Positional Params", "INSERT INTO test (a, b, c) VALUES (?, 'e', ?)", false, "1,d,e,f\n", []interface{}{"d", "f"}}, {"Values / Named Params", "INSERT INTO test (a, b, c) VALUES ($d, 'e', $f)", false, "1,d,e,f\n", []interface{}{sql.Named("f", "f"), sql.Named("d", "d")}}, {"Values / Invalid params", "INSERT INTO test (a, b, c) VALUES ('d', ?)", true, "", []interface{}{'e'}}, {"Values / List", `INSERT INTO test (a, b, c) VALUES ("a", 'b', (1, 2, 3))`, true, "", nil}, {"Documents", "INSERT INTO test VALUES {a: 'a', b: 2.3, c: 1 = 1}", false, "1,a,2.3,true\n", nil}, {"Documents / Positional Params", "INSERT INTO test VALUES {a: ?, b: 2.3, c: ?}", false, "1,a,2.3,true\n", []interface{}{"a", true}}, {"Documents / Named Params", "INSERT INTO test VALUES {a: $a, b: 2.3, c: $c}", false, "1,1,2.3,true\n", []interface{}{sql.Named("c", true), sql.Named("a", 1)}}, {"Documents / List ", "INSERT INTO test VALUES {a: (1, 2, 3)}", true, "", nil}, {"Documents / strings", `INSERT INTO test VALUES {'a': 'a', b: 2.3}`, true, "", nil}, {"Documents / double quotes", `INSERT INTO test VALUES {"a": "b"}`, false, "1,b\n", nil}, } for _, test := range tests { testFn := func(withIndexes bool) func(t *testing.T) { return func(t *testing.T) { db, err := genji.New(memoryengine.NewEngine()) 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 key(), * FROM test") require.NoError(t, err) defer st.Close() var buf bytes.Buffer err = document.IteratorToCSV(&buf, st) require.NoError(t, err) require.Equal(t, test.expected, buf.String()) } } t.Run("No Index/"+test.name, testFn(false)) t.Run("With Index/"+test.name, testFn(true)) } t.Run("with primary key", func(t *testing.T) { db, err := genji.New(memoryengine.NewEngine()) require.NoError(t, err) defer db.Close() err = db.Exec("CREATE TABLE test (foo INTEGER PRIMARY KEY)") require.NoError(t, err) err = db.Exec(`INSERT INTO test (bar) VALUES (1)`) require.Error(t, err) err = db.Exec(`INSERT INTO test (bar, foo) VALUES (1, 2)`) require.NoError(t, err) err = db.Exec(`INSERT INTO test (bar, foo) VALUES (1, 2)`) require.Equal(t, err, database.ErrDuplicateRecord) }) t.Run("with shadowing", func(t *testing.T) { db, err := genji.New(memoryengine.NewEngine()) require.NoError(t, err) defer db.Close() err = db.Exec("CREATE TABLE test") require.NoError(t, err) err = db.Exec(`INSERT INTO test ("key()", "key") VALUES (1, 2)`) require.NoError(t, err) }) }