From 8566612ddee4be15f67ca409a166d188bcfdaa40 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 31 Jul 2011 18:20:36 -0700 Subject: [PATCH] db WIP Change-Id: I41d53d4345623955698f5664047dce2c1f429616 --- lib/go/camli/db/db.go | 16 +++- lib/go/camli/db/db_test.go | 32 +++++++ lib/go/camli/db/dbimpl/dbimpl.go | 4 +- lib/go/camli/db/testdb_test.go | 143 +++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 lib/go/camli/db/db_test.go create mode 100644 lib/go/camli/db/testdb_test.go diff --git a/lib/go/camli/db/db.go b/lib/go/camli/db/db.go index dbe3bc607..dc72fa291 100644 --- a/lib/go/camli/db/db.go +++ b/lib/go/camli/db/db.go @@ -72,7 +72,21 @@ func (db *DB) Prepare(query string) (*Stmt, os.Error) { } func (db *DB) Exec(query string, args ...interface{}) os.Error { - panic("TODO: implement") + conn, err := db.conn() + if err != nil { + return err + } + defer conn.Close() + // TODO(bradfitz): check to see if conn implements optional + // dbimpl.ConnExecer interface and use that instead of + // Prepare+Exec + stmt, err := conn.Prepare(query) + if err != nil { + return err + } + defer stmt.Close() + _, err = stmt.Exec(args) + return err } func (db *DB) Query(query string, args ...interface{}) (*Rows, os.Error) { diff --git a/lib/go/camli/db/db_test.go b/lib/go/camli/db/db_test.go new file mode 100644 index 000000000..a4eaa0ec1 --- /dev/null +++ b/lib/go/camli/db/db_test.go @@ -0,0 +1,32 @@ +/* +Copyright 2011 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package db + +import ( + "testing" +) + +func TestDb(t *testing.T) { + db, err := Open("test", "foo") + if err != nil { + t.Fatalf("Open: %v", err) + } + err = db.Exec("INSERT INTO foo SET col=?", "colval") + if err != nil { + t.Logf("Exec: %v", err) + } +} diff --git a/lib/go/camli/db/dbimpl/dbimpl.go b/lib/go/camli/db/dbimpl/dbimpl.go index 38f38a67f..6f874bb3f 100644 --- a/lib/go/camli/db/dbimpl/dbimpl.go +++ b/lib/go/camli/db/dbimpl/dbimpl.go @@ -33,7 +33,7 @@ type Driver interface { type Conn interface { Prepare(query string) (Stmt, os.Error) - Close() + Close() os.Error Begin() (Tx, os.Error) } @@ -43,7 +43,7 @@ type Result interface { } type Stmt interface { - Close() + Close() os.Error NumInput() int Exec(args []interface{}) (Result, os.Error) Query(args []interface{}) (Rows, os.Error) diff --git a/lib/go/camli/db/testdb_test.go b/lib/go/camli/db/testdb_test.go new file mode 100644 index 000000000..9377083c3 --- /dev/null +++ b/lib/go/camli/db/testdb_test.go @@ -0,0 +1,143 @@ +/* +Copyright 2011 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package db + +import ( + "fmt" + "os" + "sync" + + "camli/db/dbimpl" +) + +type testDriver struct { + mu sync.Mutex + dbs map[string]*testDB +} + +type testDB struct { + name string + + mu sync.Mutex + free []*testConn +} + +type testConn struct { + db *testDB // where to return ourselves to + + currTx *testTx +} + +type testTx struct { + c *testConn +} + +type testStmt struct { + q string + c *testConn +} + +var driver dbimpl.Driver = &testDriver{} + +func init() { + Register("test", driver) +} + +func (d *testDriver) Open(name string) (dbimpl.Conn, os.Error) { + d.mu.Lock() + defer d.mu.Unlock() + if d.dbs == nil { + d.dbs = make(map[string]*testDB) + } + db, ok := d.dbs[name] + if !ok { + db = &testDB{name: name} + d.dbs[name] = db + } + return db.conn() +} + +func (db *testDB) returnConn(c *testConn) { + db.mu.Lock() + defer db.mu.Unlock() + db.free = append(db.free, c) +} + +func (db *testDB) conn() (dbimpl.Conn, os.Error) { + db.mu.Lock() + defer db.mu.Unlock() + if len(db.free) > 0 { + conn := db.free[len(db.free)-1] + db.free = db.free[:len(db.free)-1] + return conn, nil + } + return &testConn{db: db}, nil +} + +func (c *testConn) Begin() (dbimpl.Tx, os.Error) { + if c.currTx != nil { + return nil, os.NewError("already in a transaction") + } + c.currTx = &testTx{c: c} + return c.currTx, nil +} + +func (c *testConn) Close() os.Error { + if c.currTx != nil { + return os.NewError("can't close; in a Transaction") + } + if c.db == nil { + return os.NewError("can't close; already closed") + } + c.db.returnConn(c) + c.db = nil + return nil +} + +func (c *testConn) Prepare(query string) (dbimpl.Stmt, os.Error) { + fmt.Printf("Prepare: %q\n", query) + return &testStmt{q: query, c: c}, nil +} + +func (s *testStmt) Close() os.Error { + return nil +} + +func (s *testStmt) Exec(args []interface{}) (dbimpl.Result, os.Error) { + fmt.Printf("EXEC(%#v)\n", args) + return nil, os.NewError("TODO: implement") +} + +func (s *testStmt) Query(args []interface{}) (dbimpl.Rows, os.Error) { + println("QUERY") + fmt.Println(args...) + return nil, os.NewError("TODO: implement") +} + +func (s *testStmt) NumInput() int { + return 0 +} + +func (tx *testTx) Commit() os.Error { + tx.c.currTx = nil + return nil +} + +func (tx *testTx) Rollback() os.Error { + tx.c.currTx = nil + return nil +}