From 21882e76f55e4566f2cbaa600bea55bbf261fc33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net> Date: Wed, 17 Sep 2014 15:24:40 -0500 Subject: [PATCH] SQLite3: Adding support for the 'schema' package and removing golint's complaints. --- sqlite/_example/main.go | 1 + sqlite/collection.go | 79 +++++------ sqlite/database.go | 293 ++++++++++++++++++++++++++-------------- sqlite/database_test.go | 230 +++++++++++++++---------------- sqlite/result.go | 134 +++++++++--------- sqlite/tx.go | 18 ++- 6 files changed, 423 insertions(+), 332 deletions(-) diff --git a/sqlite/_example/main.go b/sqlite/_example/main.go index b24d8925..0c5e1541 100644 --- a/sqlite/_example/main.go +++ b/sqlite/_example/main.go @@ -13,6 +13,7 @@ var settings = db.Settings{ Database: `example.db`, // Path to database file. } +// Birthday struct example. type Birthday struct { // Maps the "Name" property to the "name" column of the "birthdays" table. Name string `field:"name"` diff --git a/sqlite/collection.go b/sqlite/collection.go index 3269d91d..9c377ac0 100644 --- a/sqlite/collection.go +++ b/sqlite/collection.go @@ -92,18 +92,18 @@ func interfaceArgs(value interface{}) (args []interface{}) { return nil } - value_v := reflect.ValueOf(value) + v := reflect.ValueOf(value) - switch value_v.Type().Kind() { + switch v.Type().Kind() { case reflect.Slice: var i, total int - total = value_v.Len() + total = v.Len() if total > 0 { args = make([]interface{}, total) for i = 0; i < total; i++ { - args[i] = toInternal(value_v.Index(i).Interface()) + args[i] = toInternal(v.Index(i).Interface()) } return args @@ -138,34 +138,34 @@ func conditionValues(cond db.Cond) (columnValues sqlgen.ColumnValues, args []int switch value := value.(type) { case db.Func: // Catches functions. - value_i := interfaceArgs(value.Args) + v := interfaceArgs(value.Args) columnValue.Operator = value.Name - if value_i == nil { + if v == nil { // A function with no arguments. columnValue.Value = sqlgen.Value{sqlgen.Raw{`()`}} } else { // A function with one or more arguments. - columnValue.Value = sqlgen.Value{sqlgen.Raw{fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(value_i)-1))}} + columnValue.Value = sqlgen.Value{sqlgen.Raw{fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1))}} } - args = append(args, value_i...) + args = append(args, v...) default: // Catches everything else. - value_i := interfaceArgs(value) - l := len(value_i) - if value_i == nil || l == 0 { + v := interfaceArgs(value) + l := len(v) + if v == nil || l == 0 { // Nil value given. columnValue.Value = sqlgen.Value{sqlgen.Raw{`NULL`}} } else { if l > 1 { // Array value given. - columnValue.Value = sqlgen.Value{sqlgen.Raw{fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(value_i)-1))}} + columnValue.Value = sqlgen.Value{sqlgen.Raw{fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1))}} } else { // Single value given. columnValue.Value = sqlPlaceholder } - args = append(args, value_i...) + args = append(args, v...) } } @@ -175,11 +175,11 @@ func conditionValues(cond db.Cond) (columnValues sqlgen.ColumnValues, args []int return columnValues, args } -func (self *table) Find(terms ...interface{}) db.Result { +func (c *table) Find(terms ...interface{}) db.Result { where, arguments := whereValues(terms) result := &result{ - table: self, + table: c, where: where, arguments: arguments, } @@ -187,9 +187,9 @@ func (self *table) Find(terms ...interface{}) db.Result { return result } -func (self *table) tableN(i int) string { - if len(self.names) > i { - chunks := strings.SplitN(self.names[i], " ", 2) +func (c *table) tableN(i int) string { + if len(c.names) > i { + chunks := strings.SplitN(c.names[i], " ", 2) if len(chunks) > 0 { return chunks[0] } @@ -198,11 +198,11 @@ func (self *table) tableN(i int) string { } // Deletes all the rows within the collection. -func (self *table) Truncate() error { +func (c *table) Truncate() error { - _, err := self.source.doExec(sqlgen.Statement{ + _, err := c.source.doExec(sqlgen.Statement{ Type: sqlgen.SqlTruncate, - Table: sqlgen.Table{self.tableN(0)}, + Table: sqlgen.Table{c.tableN(0)}, }) if err != nil { @@ -213,12 +213,12 @@ func (self *table) Truncate() error { } // Appends an item (map or struct) into the collection. -func (self *table) Append(item interface{}) (interface{}, error) { +func (c *table) Append(item interface{}) (interface{}, error) { var arguments []interface{} var columns sqlgen.Columns var values sqlgen.Values - cols, vals, err := self.FieldValues(item, toInternal) + cols, vals, err := c.FieldValues(item, toInternal) // Error ocurred, stop appending. if err != nil { @@ -244,9 +244,9 @@ func (self *table) Append(item interface{}) (interface{}, error) { } } - row, err := self.source.doExec(sqlgen.Statement{ + row, err := c.source.doExec(sqlgen.Statement{ Type: sqlgen.SqlInsert, - Table: sqlgen.Table{self.tableN(0)}, + Table: sqlgen.Table{c.tableN(0)}, Columns: columns, Values: values, }, arguments...) @@ -262,15 +262,15 @@ func (self *table) Append(item interface{}) (interface{}, error) { } // Returns true if the collection exists. -func (self *table) Exists() bool { - if err := self.source.tableExists(self.names...); err != nil { +func (c *table) Exists() bool { + if err := c.source.tableExists(c.names...); err != nil { return false } return true } -func (self *table) Name() string { - return strings.Join(self.names, `, `) +func (c *table) Name() string { + return strings.Join(c.names, `, `) } // Converts a Go value into internal database representation. @@ -286,38 +286,31 @@ func toInternal(val interface{}) interface{} { if t.Valid { if t.Bool { return toInternal(t.Bool) - } else { - return false } - } else { - return sqlgen.Value{sqlgen.Raw{sqlNull}} + return false } + return sqlgen.Value{sqlgen.Raw{sqlNull}} case sql.NullFloat64: if t.Valid { if t.Float64 != 0.0 { return toInternal(t.Float64) - } else { - return float64(0) } - } else { - return sqlgen.Value{sqlgen.Raw{sqlNull}} + return float64(0) } + return sqlgen.Value{sqlgen.Raw{sqlNull}} case sql.NullInt64: if t.Valid { if t.Int64 != 0 { return toInternal(t.Int64) - } else { - return 0 } - } else { - return sqlgen.Value{sqlgen.Raw{sqlNull}} + return 0 } + return sqlgen.Value{sqlgen.Raw{sqlNull}} case sql.NullString: if t.Valid { return toInternal(t.String) - } else { - return sqlgen.Value{sqlgen.Raw{sqlNull}} } + return sqlgen.Value{sqlgen.Raw{sqlNull}} case bool: if t == true { return `1` diff --git a/sqlite/database.go b/sqlite/database.go index 603033d1..2f752a1b 100644 --- a/sqlite/database.go +++ b/sqlite/database.go @@ -27,21 +27,24 @@ import ( "os" "strings" "time" - + // Importing SQLite3 driver. _ "github.com/mattn/go-sqlite3" "upper.io/cache" "upper.io/db" + "upper.io/db/util/schema" "upper.io/db/util/sqlgen" "upper.io/db/util/sqlutil" ) -// Public adapters name under which this adapter registers itself. -const Adapter = `sqlite` +const ( + // Adapter is the public name of the adapter. + Adapter = `sqlite` +) var ( - // Format for saving dates. + // DateFormat defines the format used for storing dates. DateFormat = "2006-01-02 15:04:05" - // Format for saving times. + // TimeFormat defines the format used for storing time values. TimeFormat = "%d:%02d:%02d.%d" ) @@ -52,13 +55,13 @@ var ( ) type source struct { - config db.Settings - session *sql.DB - collections map[string]db.Collection - tx *sql.Tx + config db.Settings + session *sql.DB + tx *tx + schema *schema.DatabaseSchema } -type columnSchema_t struct { +type columnSchemaT struct { Name string `db:"name"` } @@ -113,7 +116,29 @@ func init() { db.Register(Adapter, &source{}) } -func (self *source) doExec(stmt sqlgen.Statement, args ...interface{}) (sql.Result, error) { +func (s *source) populateSchema() (err error) { + var collections []string + + s.schema = schema.NewDatabaseSchema() + + s.schema.Name = s.config.Database + + // The Collections() call will populate schema if its nil. + if collections, err = s.Collections(); err != nil { + return err + } + + for i := range collections { + // Populate each collection. + if _, err = s.Collection(collections[i]); err != nil { + return err + } + } + + return err +} + +func (s *source) doExec(stmt sqlgen.Statement, args ...interface{}) (sql.Result, error) { var query string var res sql.Result var err error @@ -126,22 +151,22 @@ func (self *source) doExec(stmt sqlgen.Statement, args ...interface{}) (sql.Resu debugLog(query, args, err, start, end) }() - if self.session == nil { + if s.session == nil { return nil, db.ErrNotConnected } query = stmt.Compile(template) - if self.tx != nil { - res, err = self.tx.Exec(query, args...) + if s.tx != nil { + res, err = s.tx.sqlTx.Exec(query, args...) } else { - res, err = self.session.Exec(query, args...) + res, err = s.session.Exec(query, args...) } return res, err } -func (self *source) doQuery(stmt sqlgen.Statement, args ...interface{}) (*sql.Rows, error) { +func (s *source) doQuery(stmt sqlgen.Statement, args ...interface{}) (*sql.Rows, error) { var rows *sql.Rows var query string var err error @@ -154,22 +179,22 @@ func (self *source) doQuery(stmt sqlgen.Statement, args ...interface{}) (*sql.Ro debugLog(query, args, err, start, end) }() - if self.session == nil { + if s.session == nil { return nil, db.ErrNotConnected } query = stmt.Compile(template) - if self.tx != nil { - rows, err = self.tx.Query(query, args...) + if s.tx != nil { + rows, err = s.tx.sqlTx.Query(query, args...) } else { - rows, err = self.session.Query(query, args...) + rows, err = s.session.Query(query, args...) } return rows, err } -func (self *source) doQueryRow(stmt sqlgen.Statement, args ...interface{}) (*sql.Row, error) { +func (s *source) doQueryRow(stmt sqlgen.Statement, args ...interface{}) (*sql.Row, error) { var query string var row *sql.Row var err error @@ -182,22 +207,22 @@ func (self *source) doQueryRow(stmt sqlgen.Statement, args ...interface{}) (*sql debugLog(query, args, err, start, end) }() - if self.session == nil { + if s.session == nil { return nil, db.ErrNotConnected } query = stmt.Compile(template) - if self.tx != nil { - row = self.tx.QueryRow(query, args...) + if s.tx != nil { + row = s.tx.sqlTx.QueryRow(query, args...) } else { - row = self.session.QueryRow(query, args...) + row = s.session.QueryRow(query, args...) } return row, err } -func (self *source) doRawQuery(query string, args ...interface{}) (*sql.Rows, error) { +func (s *source) doRawQuery(query string, args ...interface{}) (*sql.Rows, error) { var rows *sql.Rows var err error var start, end int64 @@ -209,33 +234,33 @@ func (self *source) doRawQuery(query string, args ...interface{}) (*sql.Rows, er debugLog(query, args, err, start, end) }() - if self.session == nil { + if s.session == nil { return nil, db.ErrNotConnected } - if self.tx != nil { - rows, err = self.tx.Query(query, args...) + if s.tx != nil { + rows, err = s.tx.sqlTx.Query(query, args...) } else { - rows, err = self.session.Query(query, args...) + rows, err = s.session.Query(query, args...) } return rows, err } // Returns the string name of the database. -func (self *source) Name() string { - return self.config.Database +func (s *source) Name() string { + return s.config.Database } // Ping verifies a connection to the database is still alive, // establishing a connection if necessary. -func (self *source) Ping() error { - return self.session.Ping() +func (s *source) Ping() error { + return s.session.Ping() } -func (self *source) clone() (*source, error) { +func (s *source) clone() (*source, error) { src := &source{} - src.Setup(self.config) + src.Setup(s.config) if err := src.Open(); err != nil { return nil, err @@ -244,51 +269,54 @@ func (self *source) clone() (*source, error) { return src, nil } -func (self *source) Clone() (db.Database, error) { - return self.clone() +func (s *source) Clone() (db.Database, error) { + return s.clone() } -func (self *source) Transaction() (db.Tx, error) { +func (s *source) Transaction() (db.Tx, error) { var err error var clone *source var sqlTx *sql.Tx - if sqlTx, err = self.session.Begin(); err != nil { + if sqlTx, err = s.session.Begin(); err != nil { return nil, err } - if clone, err = self.clone(); err != nil { + if clone, err = s.clone(); err != nil { return nil, err } - tx := &tx{clone} + tx := &tx{source: clone, sqlTx: sqlTx} - clone.tx = sqlTx + clone.tx = tx return tx, nil } // Stores database settings. -func (self *source) Setup(config db.Settings) error { - self.config = config - self.collections = make(map[string]db.Collection) - return self.Open() +func (s *source) Setup(config db.Settings) error { + s.config = config + return s.Open() } // Returns the underlying *sql.DB instance. -func (self *source) Driver() interface{} { - return self.session +func (s *source) Driver() interface{} { + return s.session } // Attempts to connect to a database using the stored settings. -func (self *source) Open() error { +func (s *source) Open() error { var err error - if self.config.Database == "" { + if s.config.Database == `` { return db.ErrMissingDatabaseName } - if self.session, err = sql.Open(`sqlite3`, fmt.Sprintf(`file:%s?cache=shared`, self.config.Database)); err != nil { + if s.session, err = sql.Open(`sqlite3`, fmt.Sprintf(`file:%s?cache=shared`, s.config.Database)); err != nil { + return err + } + + if err = s.populateSchema(); err != nil { return err } @@ -296,64 +324,101 @@ func (self *source) Open() error { } // Closes the current database session. -func (self *source) Close() error { - if self.session != nil { - return self.session.Close() +func (s *source) Close() error { + if s.session != nil { + return s.session.Close() } return nil } // Changes the active database. -func (self *source) Use(database string) error { - self.config.Database = database - return self.Open() +func (s *source) Use(database string) error { + s.config.Database = database + return s.Open() } // Drops the currently active database. -func (self *source) Drop() error { +func (s *source) Drop() error { - _, err := self.doQuery(sqlgen.Statement{ + _, err := s.doQuery(sqlgen.Statement{ Type: sqlgen.SqlDropDatabase, - Database: sqlgen.Database{self.config.Database}, + Database: sqlgen.Database{s.config.Database}, }) return err } -// Returns a list of all tables within the currently active database. -func (self *source) Collections() ([]string, error) { - var collections []string - var collection string +// Collections() Returns a list of non-system tables/collections contained +// within the currently active database. +func (s *source) Collections() (collections []string, err error) { + + tablesInSchema := len(s.schema.Tables) + + // Is schema already populated? + if tablesInSchema > 0 { + // Pulling table names from schema. + return s.schema.Tables, nil + } + + // Schema is empty. - rows, err := self.doQuery(sqlgen.Statement{ + // Querying table names. + stmt := sqlgen.Statement{ Type: sqlgen.SqlSelect, Columns: sqlgen.Columns{ - {"tbl_name"}, + {`tbl_name`}, }, - Table: sqlgen.Table{"sqlite_master"}, + Table: sqlgen.Table{`sqlite_master`}, Where: sqlgen.Where{ - sqlgen.ColumnValue{sqlgen.Column{"type"}, "=", sqlgen.Value{"table"}}, + sqlgen.ColumnValue{ + sqlgen.Column{`type`}, + `=`, + sqlgen.Value{`table`}, + }, }, - }) + } - if err != nil { + // Executing statement. + var rows *sql.Rows + if rows, err = s.doQuery(stmt); err != nil { return nil, err } defer rows.Close() + collections = []string{} + + var name string + for rows.Next() { - rows.Scan(&collection) - collections = append(collections, collection) + // Getting table name. + if err = rows.Scan(&name); err != nil { + return nil, err + } + + // Adding table entry to schema. + s.schema.AddTable(name) + + // Adding table to collections array. + collections = append(collections, name) } return collections, nil } -func (self *source) tableExists(names ...string) error { - for _, name := range names { +func (s *source) tableExists(names ...string) error { + var stmt sqlgen.Statement + var err error + var rows *sql.Rows + + for i := range names { + + if s.schema.HasTable(names[i]) { + // We already know this table exists. + continue + } - rows, err := self.doQuery(sqlgen.Statement{ + stmt = sqlgen.Statement{ Type: sqlgen.SqlSelect, Table: sqlgen.Table{`sqlite_master`}, Columns: sqlgen.Columns{ @@ -363,9 +428,9 @@ func (self *source) tableExists(names ...string) error { sqlgen.ColumnValue{sqlgen.Column{`type`}, `=`, sqlPlaceholder}, sqlgen.ColumnValue{sqlgen.Column{`tbl_name`}, `=`, sqlPlaceholder}, }, - }, `table`, name) + } - if err != nil { + if rows, err = s.doQuery(stmt, `table`, names[i]); err != nil { return db.ErrCollectionDoesNotExist } @@ -379,46 +444,68 @@ func (self *source) tableExists(names ...string) error { return nil } +func (s *source) tableColumns(tableName string) ([]string, error) { + + // Making sure this table is allocated. + tableSchema := s.schema.Table(tableName) + + if len(tableSchema.Columns) > 0 { + return tableSchema.Columns, nil + } + + q := fmt.Sprintf(`PRAGMA TABLE_INFO('%s')`, tableName) + + rows, err := s.doRawQuery(q) + + tableFields := []columnSchemaT{} + + if err = sqlutil.FetchRows(rows, &tableFields); err != nil { + return nil, err + } + + s.schema.TableInfo[tableName].Columns = make([]string, 0, len(tableFields)) + + for i := range tableFields { + s.schema.TableInfo[tableName].Columns = append(s.schema.TableInfo[tableName].Columns, tableFields[i].Name) + } + + return s.schema.TableInfo[tableName].Columns, nil +} + // Returns a collection instance by name. -func (self *source) Collection(names ...string) (db.Collection, error) { +func (s *source) Collection(names ...string) (db.Collection, error) { + var err error if len(names) == 0 { return nil, db.ErrMissingCollectionName } + if s.tx != nil { + if s.tx.done { + return nil, sql.ErrTxDone + } + } + col := &table{ - source: self, + source: s, names: names, } - var columns_t []columnSchema_t - for _, name := range names { - chunks := strings.SplitN(name, " ", 2) - - if len(chunks) > 0 { - - name = chunks[0] + chunks := strings.SplitN(name, ` `, 2) - if err := self.tableExists(name); err != nil { - return nil, err - } - - rows, err := self.doRawQuery(fmt.Sprintf(`PRAGMA TABLE_INFO('%s')`, name)) - - if err != nil { - return nil, err - } + if len(chunks) == 0 { + return nil, db.ErrMissingCollectionName + } - if err = sqlutil.FetchRows(rows, &columns_t); err != nil { - return nil, err - } + tableName := chunks[0] - col.Columns = make([]string, 0, len(columns_t)) + if err := s.tableExists(tableName); err != nil { + return nil, err + } - for _, column := range columns_t { - col.Columns = append(col.Columns, strings.ToLower(column.Name)) - } + if col.Columns, err = s.tableColumns(tableName); err != nil { + return nil, err } } diff --git a/sqlite/database_test.go b/sqlite/database_test.go index 57a527e1..5d0e36bc 100644 --- a/sqlite/database_test.go +++ b/sqlite/database_test.go @@ -163,11 +163,11 @@ func TestAppend(t *testing.T) { } // Attempt to append a map. - item_m := map[string]string{ + itemMap := map[string]string{ "name": "Ozzie", } - if id, err = artist.Append(item_m); err != nil { + if id, err = artist.Append(itemMap); err != nil { t.Fatal(err) } @@ -176,13 +176,13 @@ func TestAppend(t *testing.T) { } // Attempt to append a struct. - item_s := struct { + itemStruct := struct { Name string `db:"name"` }{ "Flea", } - if id, err = artist.Append(item_s); err != nil { + if id, err = artist.Append(itemStruct); err != nil { t.Fatal(err) } @@ -191,13 +191,13 @@ func TestAppend(t *testing.T) { } // Append to append a tagged struct. - item_t := struct { + itemStruct2 := struct { ArtistName string `db:"name"` }{ "Slash", } - if id, err = artist.Append(item_t); err != nil { + if id, err = artist.Append(itemStruct2); err != nil { t.Fatal(err) } @@ -229,15 +229,15 @@ func TestNullableFields(t *testing.T) { defer sess.Close() - type test_t struct { - Id int64 `db:"id,omitempty"` + type testType struct { + ID int64 `db:"id,omitempty"` NullStringTest sql.NullString `db:"_string"` NullInt64Test sql.NullInt64 `db:"_int64"` NullFloat64Test sql.NullFloat64 `db:"_float64"` NullBoolTest sql.NullBool `db:"_bool"` } - var test test_t + var test testType if col, err = sess.Collection(`data_types`); err != nil { t.Fatal(err) @@ -248,13 +248,13 @@ func TestNullableFields(t *testing.T) { } // Testing insertion of invalid nulls. - test = test_t{ + test = testType{ NullStringTest: sql.NullString{"", false}, NullInt64Test: sql.NullInt64{0, false}, NullFloat64Test: sql.NullFloat64{0.0, false}, NullBoolTest: sql.NullBool{false, false}, } - if id, err = col.Append(test_t{}); err != nil { + if id, err = col.Append(testType{}); err != nil { t.Fatal(err) } @@ -280,7 +280,7 @@ func TestNullableFields(t *testing.T) { // } // Testing insertion of valid nulls. - test = test_t{ + test = testType{ NullStringTest: sql.NullString{"", true}, NullInt64Test: sql.NullInt64{0, true}, NullFloat64Test: sql.NullFloat64{0.0, true}, @@ -320,7 +320,7 @@ func TestGroup(t *testing.T) { t.Fatal(err) } - type stats_t struct { + type statsType struct { Numeric int `db:"numeric"` Value int `db:"value"` } @@ -339,7 +339,7 @@ func TestGroup(t *testing.T) { // Adding row append. for i := 0; i < 1000; i++ { numeric, value := rand.Intn(10), rand.Intn(100) - if _, err = stats.Append(stats_t{numeric, value}); err != nil { + if _, err = stats.Append(statsType{numeric, value}); err != nil { t.Fatal(err) } } @@ -415,22 +415,22 @@ func TestResultFetch(t *testing.T) { } // Dumping into a map. - row_m := map[string]interface{}{} + rowMap := map[string]interface{}{} res = artist.Find() for { - err = res.Next(&row_m) + err = res.Next(&rowMap) if err == db.ErrNoMoreRows { break } if err == nil { - if to.Int64(row_m["id"]) == 0 { + if to.Int64(rowMap["id"]) == 0 { t.Fatalf("Expecting a not null ID.") } - if to.String(row_m["name"]) == "" { + if to.String(rowMap["name"]) == "" { t.Fatalf("Expecting a name.") } } else { @@ -441,25 +441,25 @@ func TestResultFetch(t *testing.T) { res.Close() // Dumping into an struct with no tags. - row_s := struct { - Id uint64 + rowStruct := struct { + ID uint64 Name string }{} res = artist.Find() for { - err = res.Next(&row_s) + err = res.Next(&rowStruct) if err == db.ErrNoMoreRows { break } if err == nil { - if row_s.Id == 0 { + if rowStruct.ID == 0 { t.Fatalf("Expecting a not null ID.") } - if row_s.Name == "" { + if rowStruct.Name == "" { t.Fatalf("Expecting a name.") } } else { @@ -470,7 +470,7 @@ func TestResultFetch(t *testing.T) { res.Close() // Dumping into a tagged struct. - row_t := struct { + rowStruct2 := struct { Value1 uint64 `field:"id"` Value2 string `field:"name"` }{} @@ -478,17 +478,17 @@ func TestResultFetch(t *testing.T) { res = artist.Find() for { - err = res.Next(&row_t) + err = res.Next(&rowStruct2) if err == db.ErrNoMoreRows { break } if err == nil { - if row_t.Value1 == 0 { + if rowStruct2.Value1 == 0 { t.Fatalf("Expecting a not null ID.") } - if row_t.Value2 == "" { + if rowStruct2.Value2 == "" { t.Fatalf("Expecting a name.") } } else { @@ -499,63 +499,63 @@ func TestResultFetch(t *testing.T) { res.Close() // Dumping into an slice of maps. - all_rows_m := []map[string]interface{}{} + allRowsMap := []map[string]interface{}{} res = artist.Find() - if err = res.All(&all_rows_m); err != nil { + if err = res.All(&allRowsMap); err != nil { t.Fatal(err) } - if len(all_rows_m) != 3 { + if len(allRowsMap) != 3 { t.Fatalf("Expecting 3 items.") } - for _, single_row_m := range all_rows_m { - if to.Int64(single_row_m["id"]) == 0 { + for _, singleRowMap := range allRowsMap { + if to.Int64(singleRowMap["id"]) == 0 { t.Fatalf("Expecting a not null ID.") } } // Dumping into an slice of structs. - all_rows_s := []struct { - Id uint64 + allRowsStruct := []struct { + ID uint64 Name string }{} res = artist.Find() - if err = res.All(&all_rows_s); err != nil { + if err = res.All(&allRowsStruct); err != nil { t.Fatal(err) } - if len(all_rows_s) != 3 { + if len(allRowsStruct) != 3 { t.Fatalf("Expecting 3 items.") } - for _, single_row_s := range all_rows_s { - if single_row_s.Id == 0 { + for _, singleRowStruct := range allRowsStruct { + if singleRowStruct.ID == 0 { t.Fatalf("Expecting a not null ID.") } } // Dumping into an slice of tagged structs. - all_rows_t := []struct { + allRowsStruct2 := []struct { Value1 uint64 `field:"id"` Value2 string `field:"name"` }{} res = artist.Find() - if err = res.All(&all_rows_t); err != nil { + if err = res.All(&allRowsStruct2); err != nil { t.Fatal(err) } - if len(all_rows_t) != 3 { + if len(allRowsStruct2) != 3 { t.Fatalf("Expecting 3 items.") } - for _, single_row_t := range all_rows_t { - if single_row_t.Value1 == 0 { + for _, singleRowStruct2 := range allRowsStruct2 { + if singleRowStruct2.Value1 == 0 { t.Fatalf("Expecting a not null ID.") } } @@ -579,7 +579,7 @@ func TestUpdate(t *testing.T) { // Defining destination struct value := struct { - Id uint64 + ID uint64 Name string }{} @@ -591,11 +591,11 @@ func TestUpdate(t *testing.T) { } // Updating set with a map - row_m := map[string]interface{}{ + rowMap := map[string]interface{}{ "name": strings.ToUpper(value.Name), } - if err = res.Update(row_m); err != nil { + if err = res.Update(rowMap); err != nil { t.Fatal(err) } @@ -605,16 +605,16 @@ func TestUpdate(t *testing.T) { } // Verifying. - if value.Name != row_m["name"] { + if value.Name != rowMap["name"] { t.Fatalf("Expecting a modification.") } // Updating set with a struct - row_s := struct { + rowStruct := struct { Name string }{strings.ToLower(value.Name)} - if err = res.Update(row_s); err != nil { + if err = res.Update(rowStruct); err != nil { t.Fatal(err) } @@ -624,16 +624,16 @@ func TestUpdate(t *testing.T) { } // Verifying - if value.Name != row_s.Name { + if value.Name != rowStruct.Name { t.Fatalf("Expecting a modification.") } // Updating set with a tagged struct - row_t := struct { + rowStruct2 := struct { Value1 string `db:"name"` }{strings.Replace(value.Name, "z", "Z", -1)} - if err = res.Update(row_t); err != nil { + if err = res.Update(rowStruct2); err != nil { t.Fatal(err) } @@ -643,7 +643,7 @@ func TestUpdate(t *testing.T) { } // Verifying - if value.Name != row_t.Value1 { + if value.Name != rowStruct2.Value1 { t.Fatalf("Expecting a modification.") } } @@ -666,14 +666,14 @@ func TestFunction(t *testing.T) { t.Fatal(err) } - row_s := struct { - Id uint64 + rowStruct := struct { + ID uint64 Name string }{} res = artist.Find(db.Cond{"id NOT IN": []int{0, -1}}) - if err = res.One(&row_s); err != nil { + if err = res.One(&rowStruct); err != nil { t.Fatal(err) } @@ -687,7 +687,7 @@ func TestFunction(t *testing.T) { res = artist.Find(db.Cond{"id": db.Func{"NOT IN", []int{0, -1}}}) - if err = res.One(&row_s); err != nil { + if err = res.One(&rowStruct); err != nil { t.Fatal(err) } @@ -737,20 +737,20 @@ func TestRawRelations(t *testing.T) { var publication db.Collection var review db.Collection - type artist_t struct { - Id int64 `db:"id,omitempty"` + type artistT struct { + ID int64 `db:"id,omitempty"` Name string `db:"name"` } - type publication_t struct { - Id int64 `db:"id,omitempty"` + type publicationType struct { + ID int64 `db:"id,omitempty"` Title string `db:"title"` - AuthorId int64 `db:"author_id"` + AuthorID int64 `db:"author_id"` } - type review_t struct { - Id int64 `db:"id,omitempty"` - PublicationId int64 `db:"publication_id"` + type reviewType struct { + ID int64 `db:"id,omitempty"` + PublicationID int64 `db:"publication_id"` Name string `db:"name"` Comments string `db:"comments"` Created time.Time `db:"created"` @@ -790,85 +790,85 @@ func TestRawRelations(t *testing.T) { } // Adding some artists. - var miyazakiId interface{} - miyazaki := artist_t{Name: `Hayao Miyazaki`} - if miyazakiId, err = artist.Append(miyazaki); err != nil { + var miyazakiID interface{} + miyazaki := artistT{Name: `Hayao Miyazaki`} + if miyazakiID, err = artist.Append(miyazaki); err != nil { t.Fatal(err) } - miyazaki.Id = miyazakiId.(int64) + miyazaki.ID = miyazakiID.(int64) - var asimovId interface{} - asimov := artist_t{Name: `Isaac Asimov`} - if asimovId, err = artist.Append(asimov); err != nil { + var asimovID interface{} + asimov := artistT{Name: `Isaac Asimov`} + if asimovID, err = artist.Append(asimov); err != nil { t.Fatal(err) } - var marquezId interface{} - marquez := artist_t{Name: `Gabriel GarcÃa Márquez`} - if marquezId, err = artist.Append(marquez); err != nil { + var marquezID interface{} + marquez := artistT{Name: `Gabriel GarcÃa Márquez`} + if marquezID, err = artist.Append(marquez); err != nil { t.Fatal(err) } // Adding some publications. - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `Tonari no Totoro`, - AuthorId: miyazakiId.(int64), + AuthorID: miyazakiID.(int64), }) - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `Howl's Moving Castle`, - AuthorId: miyazakiId.(int64), + AuthorID: miyazakiID.(int64), }) - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `Ponyo`, - AuthorId: miyazakiId.(int64), + AuthorID: miyazakiID.(int64), }) - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `Memoria de mis Putas Tristes`, - AuthorId: marquezId.(int64), + AuthorID: marquezID.(int64), }) - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `El Coronel no tiene quien le escriba`, - AuthorId: marquezId.(int64), + AuthorID: marquezID.(int64), }) - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `El Amor en los tiempos del Cólera`, - AuthorId: marquezId.(int64), + AuthorID: marquezID.(int64), }) - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `I, Robot`, - AuthorId: asimovId.(int64), + AuthorID: asimovID.(int64), }) - var foundationId interface{} - foundationId, err = publication.Append(publication_t{ + var foundationID interface{} + foundationID, err = publication.Append(publicationType{ Title: `Foundation`, - AuthorId: asimovId.(int64), + AuthorID: asimovID.(int64), }) if err != nil { t.Fatal(err) } - publication.Append(publication_t{ + publication.Append(publicationType{ Title: `The Robots of Dawn`, - AuthorId: asimovId.(int64), + AuthorID: asimovID.(int64), }) // Adding reviews for foundation. - review.Append(review_t{ - PublicationId: foundationId.(int64), + review.Append(reviewType{ + PublicationID: foundationID.(int64), Name: "John Doe", Comments: "I love The Foundation series.", Created: time.Now(), }) - review.Append(review_t{ - PublicationId: foundationId.(int64), + review.Append(reviewType{ + PublicationID: foundationID.(int64), Name: "Edr Pls", Comments: "The Foundation series made me fall in love with Isaac Asimov.", Created: time.Now(), @@ -888,13 +888,13 @@ func TestRawRelations(t *testing.T) { "a.name AS artist_name", ) - type artistPublication_t struct { - Id int64 `db:"id"` + type artistPublicationType struct { + ID int64 `db:"id"` PublicationTitle string `db:"publication_title"` ArtistName string `db:"artist_name"` } - all := []artistPublication_t{} + all := []artistPublicationType{} if err = res.All(&all); err != nil { t.Fatal(err) @@ -911,10 +911,10 @@ func TestRawQuery(t *testing.T) { var err error var drv *sql.DB - type publication_t struct { - Id int64 `db:"id,omitempty"` + type publicationType struct { + ID int64 `db:"id,omitempty"` Title string `db:"title"` - AuthorId int64 `db:"author_id"` + AuthorID int64 `db:"author_id"` } if sess, err = db.Open(Adapter, settings); err != nil { @@ -941,7 +941,7 @@ func TestRawQuery(t *testing.T) { t.Fatal(err) } - var all []publication_t + var all []publicationType if err = sqlutil.FetchRows(rows, &all); err != nil { t.Fatal(err) @@ -957,8 +957,8 @@ func TestTransactionsAndRollback(t *testing.T) { var sess db.Database var err error - type artist_t struct { - Id int64 `db:"id,omitempty"` + type artistT struct { + ID int64 `db:"id,omitempty"` Name string `db:"name"` } @@ -984,7 +984,7 @@ func TestTransactionsAndRollback(t *testing.T) { } // Simple transaction - if _, err = artist.Append(artist_t{1, "First"}); err != nil { + if _, err = artist.Append(artistT{1, "First"}); err != nil { t.Fatal(err) } @@ -1007,17 +1007,17 @@ func TestTransactionsAndRollback(t *testing.T) { } // Won't fail. - if _, err = artist.Append(artist_t{2, "Second"}); err != nil { + if _, err = artist.Append(artistT{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. - if _, err = artist.Append(artist_t{3, "Third"}); err != nil { + if _, err = artist.Append(artistT{3, "Third"}); err != nil { t.Fatal(err) } // Will fail. - if _, err = artist.Append(artist_t{1, "Duplicated"}); err == nil { + if _, err = artist.Append(artistT{1, "Duplicated"}); err == nil { t.Fatal("Should have failed, as we have already inserted ID 1.") } @@ -1053,12 +1053,12 @@ func TestTransactionsAndRollback(t *testing.T) { } // Won't fail. - if _, err = artist.Append(artist_t{2, "Second"}); err != nil { + if _, err = artist.Append(artistT{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. - if _, err = artist.Append(artist_t{3, "Third"}); err != nil { + if _, err = artist.Append(artistT{3, "Third"}); err != nil { t.Fatal(err) } @@ -1094,12 +1094,12 @@ func TestTransactionsAndRollback(t *testing.T) { } // Won't fail. - if _, err = artist.Append(artist_t{2, "Second"}); err != nil { + if _, err = artist.Append(artistT{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. - if _, err = artist.Append(artist_t{3, "Third"}); err != nil { + if _, err = artist.Append(artistT{3, "Third"}); err != nil { t.Fatal(err) } diff --git a/sqlite/result.go b/sqlite/result.go index 8e50383a..3abe4357 100644 --- a/sqlite/result.go +++ b/sqlite/result.go @@ -31,7 +31,7 @@ import ( "upper.io/db/util/sqlutil" ) -type counter_t struct { +type counter struct { Total uint64 `db:"_t"` } @@ -48,46 +48,46 @@ type result struct { } // Executes a SELECT statement that can feed Next(), All() or One(). -func (self *result) setCursor() error { +func (r *result) setCursor() error { var err error // We need a cursor, if the cursor does not exists yet then we create one. - if self.cursor == nil { - self.cursor, err = self.table.source.doQuery(sqlgen.Statement{ + if r.cursor == nil { + r.cursor, err = r.table.source.doQuery(sqlgen.Statement{ Type: sqlgen.SqlSelect, - Table: sqlgen.Table{self.table.Name()}, - Columns: self.columns, - Limit: self.limit, - Offset: self.offset, - Where: self.where, - OrderBy: self.orderBy, - GroupBy: self.groupBy, - }, self.arguments...) + Table: sqlgen.Table{r.table.Name()}, + Columns: r.columns, + Limit: r.limit, + Offset: r.offset, + Where: r.where, + OrderBy: r.orderBy, + GroupBy: r.groupBy, + }, r.arguments...) } return err } // Sets conditions for reducing the working set. -func (self *result) Where(terms ...interface{}) db.Result { - self.where, self.arguments = whereValues(terms) - return self +func (r *result) Where(terms ...interface{}) db.Result { + r.where, r.arguments = whereValues(terms) + return r } // Determines the maximum limit of results to be returned. -func (self *result) Limit(n uint) db.Result { - self.limit = sqlgen.Limit(n) - return self +func (r *result) Limit(n uint) db.Result { + r.limit = sqlgen.Limit(n) + return r } // Determines how many documents will be skipped before starting to grab // results. -func (self *result) Skip(n uint) db.Result { - self.offset = sqlgen.Offset(n) - return self +func (r *result) Skip(n uint) db.Result { + r.offset = sqlgen.Offset(n) + return r } // Used to group results that have the same value in the same column or // columns. -func (self *result) Group(fields ...interface{}) db.Result { +func (r *result) Group(fields ...interface{}) db.Result { groupByColumns := make(sqlgen.GroupBy, 0, len(fields)) @@ -100,15 +100,15 @@ func (self *result) Group(fields ...interface{}) db.Result { } } - self.groupBy = groupByColumns + r.groupBy = groupByColumns - return self + return r } // Determines sorting of results according to the provided names. Fields may be // prefixed by - (minus) which means descending order, ascending order would be // used otherwise. -func (self *result) Sort(fields ...interface{}) db.Result { +func (r *result) Sort(fields ...interface{}) db.Result { sortColumns := make(sqlgen.SortColumns, 0, len(fields)) @@ -140,105 +140,105 @@ func (self *result) Sort(fields ...interface{}) db.Result { sortColumns = append(sortColumns, sort) } - self.orderBy.SortColumns = sortColumns + r.orderBy.SortColumns = sortColumns - return self + return r } // Retrieves only the given fields. -func (self *result) Select(fields ...interface{}) db.Result { - self.columns = make(sqlgen.Columns, 0, len(fields)) +func (r *result) Select(fields ...interface{}) db.Result { + r.columns = make(sqlgen.Columns, 0, len(fields)) l := len(fields) for i := 0; i < l; i++ { switch value := fields[i].(type) { case db.Raw: - self.columns = append(self.columns, sqlgen.Column{sqlgen.Raw{fmt.Sprintf(`%v`, value.Value)}}) + r.columns = append(r.columns, sqlgen.Column{sqlgen.Raw{fmt.Sprintf(`%v`, value.Value)}}) default: - self.columns = append(self.columns, sqlgen.Column{value}) + r.columns = append(r.columns, sqlgen.Column{value}) } } - return self + return r } // Dumps all results into a pointer to an slice of structs or maps. -func (self *result) All(dst interface{}) error { +func (r *result) All(dst interface{}) error { var err error - if self.cursor != nil { + if r.cursor != nil { return db.ErrQueryIsPending } // Current cursor. - err = self.setCursor() + err = r.setCursor() if err != nil { return err } - defer self.Close() + defer r.Close() // Fetching all results within the cursor. - err = sqlutil.FetchRows(self.cursor, dst) + err = sqlutil.FetchRows(r.cursor, dst) return err } // Fetches only one result from the resultset. -func (self *result) One(dst interface{}) error { +func (r *result) One(dst interface{}) error { var err error - if self.cursor != nil { + if r.cursor != nil { return db.ErrQueryIsPending } - defer self.Close() + defer r.Close() - err = self.Next(dst) + err = r.Next(dst) return err } // Fetches the next result from the resultset. -func (self *result) Next(dst interface{}) error { +func (r *result) Next(dst interface{}) error { var err error // Current cursor. - err = self.setCursor() + err = r.setCursor() if err != nil { - self.Close() + r.Close() } // Fetching the next result from the cursor. - err = sqlutil.FetchRow(self.cursor, dst) + err = sqlutil.FetchRow(r.cursor, dst) if err != nil { - self.Close() + r.Close() } return err } // Removes the matching items from the collection. -func (self *result) Remove() error { +func (r *result) Remove() error { var err error - _, err = self.table.source.doExec(sqlgen.Statement{ + _, err = r.table.source.doExec(sqlgen.Statement{ Type: sqlgen.SqlDelete, - Table: sqlgen.Table{self.table.Name()}, - Where: self.where, - }, self.arguments...) + Table: sqlgen.Table{r.table.Name()}, + Where: r.where, + }, r.arguments...) return err } // Updates matching items from the collection with values of the given map or // struct. -func (self *result) Update(values interface{}) error { +func (r *result) Update(values interface{}) error { - ff, vv, err := self.table.FieldValues(values, toInternal) + ff, vv, err := r.table.FieldValues(values, toInternal) total := len(ff) @@ -248,37 +248,37 @@ func (self *result) Update(values interface{}) error { cvs = append(cvs, sqlgen.ColumnValue{sqlgen.Column{ff[i]}, "=", sqlPlaceholder}) } - vv = append(vv, self.arguments...) + vv = append(vv, r.arguments...) - _, err = self.table.source.doExec(sqlgen.Statement{ + _, err = r.table.source.doExec(sqlgen.Statement{ Type: sqlgen.SqlUpdate, - Table: sqlgen.Table{self.table.Name()}, + Table: sqlgen.Table{r.table.Name()}, ColumnValues: cvs, - Where: self.where, + Where: r.where, }, vv...) return err } // Closes the result set. -func (self *result) Close() error { +func (r *result) Close() error { var err error - if self.cursor != nil { - err = self.cursor.Close() - self.cursor = nil + if r.cursor != nil { + err = r.cursor.Close() + r.cursor = nil } return err } // Counting the elements that will be returned. -func (self *result) Count() (uint64, error) { - var count counter_t +func (r *result) Count() (uint64, error) { + var count counter - rows, err := self.table.source.doQuery(sqlgen.Statement{ + rows, err := r.table.source.doQuery(sqlgen.Statement{ Type: sqlgen.SqlSelectCount, - Table: sqlgen.Table{self.table.Name()}, - Where: self.where, - }, self.arguments...) + Table: sqlgen.Table{r.table.Name()}, + Where: r.where, + }, r.arguments...) if err != nil { return 0, err diff --git a/sqlite/tx.go b/sqlite/tx.go index 4386d404..9f4c622e 100644 --- a/sqlite/tx.go +++ b/sqlite/tx.go @@ -21,14 +21,24 @@ package sqlite +import ( + "database/sql" +) + type tx struct { *source + sqlTx *sql.Tx + done bool } -func (self *tx) Commit() error { - return self.source.tx.Commit() +func (t *tx) Commit() (err error) { + err = t.sqlTx.Commit() + if err == nil { + t.done = true + } + return err } -func (self *tx) Rollback() error { - return self.source.tx.Rollback() +func (t *tx) Rollback() error { + return t.sqlTx.Rollback() } -- GitLab