diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/go-gorp/gorp/db.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/go-gorp/gorp/db.go | 619 |
1 files changed, 0 insertions, 619 deletions
diff --git a/Godeps/_workspace/src/github.com/go-gorp/gorp/db.go b/Godeps/_workspace/src/github.com/go-gorp/gorp/db.go deleted file mode 100644 index 8bba07cf6..000000000 --- a/Godeps/_workspace/src/github.com/go-gorp/gorp/db.go +++ /dev/null @@ -1,619 +0,0 @@ -// Copyright 2012 James Cooper. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -// Package gorp provides a simple way to marshal Go structs to and from -// SQL databases. It uses the database/sql package, and should work with any -// compliant database/sql driver. -// -// Source code and project home: -// https://github.com/go-gorp/gorp - -package gorp - -import ( - "bytes" - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "time" -) - -// DbMap is the root gorp mapping object. Create one of these for each -// database schema you wish to map. Each DbMap contains a list of -// mapped tables. -// -// Example: -// -// dialect := gorp.MySQLDialect{"InnoDB", "UTF8"} -// dbmap := &gorp.DbMap{Db: db, Dialect: dialect} -// -type DbMap struct { - // Db handle to use with this map - Db *sql.DB - - // Dialect implementation to use with this map - Dialect Dialect - - TypeConverter TypeConverter - - tables []*TableMap - logger GorpLogger - logPrefix string -} - -func (m *DbMap) CreateIndex() error { - - var err error - dialect := reflect.TypeOf(m.Dialect) - for _, table := range m.tables { - for _, index := range table.indexes { - - s := bytes.Buffer{} - s.WriteString("create") - if index.Unique { - s.WriteString(" unique") - } - s.WriteString(" index") - s.WriteString(fmt.Sprintf(" %s on %s", index.IndexName, table.TableName)) - if dname := dialect.Name(); dname == "PostgresDialect" && index.IndexType != "" { - s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType)) - } - s.WriteString(" (") - for x, col := range index.columns { - if x > 0 { - s.WriteString(", ") - } - s.WriteString(m.Dialect.QuoteField(col)) - } - s.WriteString(")") - - if dname := dialect.Name(); dname == "MySQLDialect" && index.IndexType != "" { - s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType)) - } - s.WriteString(";") - _, err = m.Exec(s.String()) - if err != nil { - break - } - } - } - return err -} - -func (t *TableMap) DropIndex(name string) error { - - var err error - dialect := reflect.TypeOf(t.dbmap.Dialect) - for _, idx := range t.indexes { - if idx.IndexName == name { - s := bytes.Buffer{} - s.WriteString(fmt.Sprintf("DROP INDEX %s", idx.IndexName)) - - if dname := dialect.Name(); dname == "MySQLDialect" { - s.WriteString(fmt.Sprintf(" %s %s", t.dbmap.Dialect.DropIndexSuffix(), t.TableName)) - } - s.WriteString(";") - _, e := t.dbmap.Exec(s.String()) - if e != nil { - err = e - } - break - } - } - t.ResetSql() - return err -} - -// AddTable registers the given interface type with gorp. The table name -// will be given the name of the TypeOf(i). You must call this function, -// or AddTableWithName, for any struct type you wish to persist with -// the given DbMap. -// -// This operation is idempotent. If i's type is already mapped, the -// existing *TableMap is returned -func (m *DbMap) AddTable(i interface{}) *TableMap { - return m.AddTableWithName(i, "") -} - -// AddTableWithName has the same behavior as AddTable, but sets -// table.TableName to name. -func (m *DbMap) AddTableWithName(i interface{}, name string) *TableMap { - return m.AddTableWithNameAndSchema(i, "", name) -} - -// AddTableWithNameAndSchema has the same behavior as AddTable, but sets -// table.TableName to name. -func (m *DbMap) AddTableWithNameAndSchema(i interface{}, schema string, name string) *TableMap { - t := reflect.TypeOf(i) - if name == "" { - name = t.Name() - } - - // check if we have a table for this type already - // if so, update the name and return the existing pointer - for i := range m.tables { - table := m.tables[i] - if table.gotype == t { - table.TableName = name - return table - } - } - - tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m} - var primaryKey []*ColumnMap - tmap.Columns, primaryKey = m.readStructColumns(t) - m.tables = append(m.tables, tmap) - if len(primaryKey) > 0 { - tmap.keys = append(tmap.keys, primaryKey...) - } - - return tmap -} - -func (m *DbMap) readStructColumns(t reflect.Type) (cols []*ColumnMap, primaryKey []*ColumnMap) { - primaryKey = make([]*ColumnMap, 0) - n := t.NumField() - for i := 0; i < n; i++ { - f := t.Field(i) - if f.Anonymous && f.Type.Kind() == reflect.Struct { - // Recursively add nested fields in embedded structs. - subcols, subpk := m.readStructColumns(f.Type) - // Don't append nested fields that have the same field - // name as an already-mapped field. - for _, subcol := range subcols { - shouldAppend := true - for _, col := range cols { - if !subcol.Transient && subcol.fieldName == col.fieldName { - shouldAppend = false - break - } - } - if shouldAppend { - cols = append(cols, subcol) - } - } - if subpk != nil { - primaryKey = append(primaryKey, subpk...) - } - } else { - // Tag = Name { ',' Option } - // Option = OptionKey [ ':' OptionValue ] - cArguments := strings.Split(f.Tag.Get("db"), ",") - columnName := cArguments[0] - var maxSize int - var defaultValue string - var isAuto bool - var isPK bool - for _, argString := range cArguments[1:] { - argString = strings.TrimSpace(argString) - arg := strings.SplitN(argString, ":", 2) - - // check mandatory/unexpected option values - switch arg[0] { - case "size", "default": - // options requiring value - if len(arg) == 1 { - panic(fmt.Sprintf("missing option value for option %v on field %v", arg[0], f.Name)) - } - default: - // options where value is invalid (currently all other options) - if len(arg) == 2 { - panic(fmt.Sprintf("unexpected option value for option %v on field %v", arg[0], f.Name)) - } - } - - switch arg[0] { - case "size": - maxSize, _ = strconv.Atoi(arg[1]) - case "default": - defaultValue = arg[1] - case "primarykey": - isPK = true - case "autoincrement": - isAuto = true - default: - panic(fmt.Sprintf("Unrecognized tag option for field %v: %v", f.Name, arg)) - } - } - if columnName == "" { - columnName = f.Name - } - - gotype := f.Type - value := reflect.New(gotype).Interface() - if m.TypeConverter != nil { - // Make a new pointer to a value of type gotype and - // pass it to the TypeConverter's FromDb method to see - // if a different type should be used for the column - // type during table creation. - scanner, useHolder := m.TypeConverter.FromDb(value) - if useHolder { - value = scanner.Holder - gotype = reflect.TypeOf(value) - } - } - if typer, ok := value.(SqlTyper); ok { - gotype = reflect.TypeOf(typer.SqlType()) - } else if valuer, ok := value.(driver.Valuer); ok { - // Only check for driver.Valuer if SqlTyper wasn't - // found. - v, err := valuer.Value() - if err == nil && v != nil { - gotype = reflect.TypeOf(v) - } - } - cm := &ColumnMap{ - ColumnName: columnName, - DefaultValue: defaultValue, - Transient: columnName == "-", - fieldName: f.Name, - gotype: gotype, - isPK: isPK, - isAutoIncr: isAuto, - MaxSize: maxSize, - } - if isPK { - primaryKey = append(primaryKey, cm) - } - // Check for nested fields of the same field name and - // override them. - shouldAppend := true - for index, col := range cols { - if !col.Transient && col.fieldName == cm.fieldName { - cols[index] = cm - shouldAppend = false - break - } - } - if shouldAppend { - cols = append(cols, cm) - } - } - - } - return -} - -// CreateTables iterates through TableMaps registered to this DbMap and -// executes "create table" statements against the database for each. -// -// This is particularly useful in unit tests where you want to create -// and destroy the schema automatically. -func (m *DbMap) CreateTables() error { - return m.createTables(false) -} - -// CreateTablesIfNotExists is similar to CreateTables, but starts -// each statement with "create table if not exists" so that existing -// tables do not raise errors -func (m *DbMap) CreateTablesIfNotExists() error { - return m.createTables(true) -} - -func (m *DbMap) createTables(ifNotExists bool) error { - var err error - for i := range m.tables { - table := m.tables[i] - sql := table.SqlForCreate(ifNotExists) - _, err = m.Exec(sql) - if err != nil { - break - } - } - return err -} - -// DropTable drops an individual table. -// Returns an error when the table does not exist. -func (m *DbMap) DropTable(table interface{}) error { - t := reflect.TypeOf(table) - return m.dropTable(t, false) -} - -// DropTableIfExists drops an individual table when the table exists. -func (m *DbMap) DropTableIfExists(table interface{}) error { - t := reflect.TypeOf(table) - return m.dropTable(t, true) -} - -// DropTables iterates through TableMaps registered to this DbMap and -// executes "drop table" statements against the database for each. -func (m *DbMap) DropTables() error { - return m.dropTables(false) -} - -// DropTablesIfExists is the same as DropTables, but uses the "if exists" clause to -// avoid errors for tables that do not exist. -func (m *DbMap) DropTablesIfExists() error { - return m.dropTables(true) -} - -// Goes through all the registered tables, dropping them one by one. -// If an error is encountered, then it is returned and the rest of -// the tables are not dropped. -func (m *DbMap) dropTables(addIfExists bool) (err error) { - for _, table := range m.tables { - err = m.dropTableImpl(table, addIfExists) - if err != nil { - return err - } - } - return err -} - -// Implementation of dropping a single table. -func (m *DbMap) dropTable(t reflect.Type, addIfExists bool) error { - table := tableOrNil(m, t) - if table == nil { - return fmt.Errorf("table %s was not registered", table.TableName) - } - - return m.dropTableImpl(table, addIfExists) -} - -func (m *DbMap) dropTableImpl(table *TableMap, ifExists bool) (err error) { - tableDrop := "drop table" - if ifExists { - tableDrop = m.Dialect.IfTableExists(tableDrop, table.SchemaName, table.TableName) - } - _, err = m.Exec(fmt.Sprintf("%s %s;", tableDrop, m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName))) - return err -} - -// TruncateTables iterates through TableMaps registered to this DbMap and -// executes "truncate table" statements against the database for each, or in the case of -// sqlite, a "delete from" with no "where" clause, which uses the truncate optimization -// (http://www.sqlite.org/lang_delete.html) -func (m *DbMap) TruncateTables() error { - var err error - for i := range m.tables { - table := m.tables[i] - _, e := m.Exec(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName))) - if e != nil { - err = e - } - } - return err -} - -// Insert runs a SQL INSERT statement for each element in list. List -// items must be pointers. -// -// Any interface whose TableMap has an auto-increment primary key will -// have its last insert id bound to the PK field on the struct. -// -// The hook functions PreInsert() and/or PostInsert() will be executed -// before/after the INSERT statement if the interface defines them. -// -// Panics if any interface in the list has not been registered with AddTable -func (m *DbMap) Insert(list ...interface{}) error { - return insert(m, m, list...) -} - -// Update runs a SQL UPDATE statement for each element in list. List -// items must be pointers. -// -// The hook functions PreUpdate() and/or PostUpdate() will be executed -// before/after the UPDATE statement if the interface defines them. -// -// Returns the number of rows updated. -// -// Returns an error if SetKeys has not been called on the TableMap -// Panics if any interface in the list has not been registered with AddTable -func (m *DbMap) Update(list ...interface{}) (int64, error) { - return update(m, m, nil, list...) -} - -// UpdateColumns runs a SQL UPDATE statement for each element in list. List -// items must be pointers. -// -// Only the columns accepted by filter are included in the UPDATE. -// -// The hook functions PreUpdate() and/or PostUpdate() will be executed -// before/after the UPDATE statement if the interface defines them. -// -// Returns the number of rows updated. -// -// Returns an error if SetKeys has not been called on the TableMap -// Panics if any interface in the list has not been registered with AddTable -func (m *DbMap) UpdateColumns(filter ColumnFilter, list ...interface{}) (int64, error) { - return update(m, m, filter, list...) -} - -// Delete runs a SQL DELETE statement for each element in list. List -// items must be pointers. -// -// The hook functions PreDelete() and/or PostDelete() will be executed -// before/after the DELETE statement if the interface defines them. -// -// Returns the number of rows deleted. -// -// Returns an error if SetKeys has not been called on the TableMap -// Panics if any interface in the list has not been registered with AddTable -func (m *DbMap) Delete(list ...interface{}) (int64, error) { - return delete(m, m, list...) -} - -// Get runs a SQL SELECT to fetch a single row from the table based on the -// primary key(s) -// -// i should be an empty value for the struct to load. keys should be -// the primary key value(s) for the row to load. If multiple keys -// exist on the table, the order should match the column order -// specified in SetKeys() when the table mapping was defined. -// -// The hook function PostGet() will be executed after the SELECT -// statement if the interface defines them. -// -// Returns a pointer to a struct that matches or nil if no row is found. -// -// Returns an error if SetKeys has not been called on the TableMap -// Panics if any interface in the list has not been registered with AddTable -func (m *DbMap) Get(i interface{}, keys ...interface{}) (interface{}, error) { - return get(m, m, i, keys...) -} - -// Select runs an arbitrary SQL query, binding the columns in the result -// to fields on the struct specified by i. args represent the bind -// parameters for the SQL statement. -// -// Column names on the SELECT statement should be aliased to the field names -// on the struct i. Returns an error if one or more columns in the result -// do not match. It is OK if fields on i are not part of the SQL -// statement. -// -// The hook function PostGet() will be executed after the SELECT -// statement if the interface defines them. -// -// Values are returned in one of two ways: -// 1. If i is a struct or a pointer to a struct, returns a slice of pointers to -// matching rows of type i. -// 2. If i is a pointer to a slice, the results will be appended to that slice -// and nil returned. -// -// i does NOT need to be registered with AddTable() -func (m *DbMap) Select(i interface{}, query string, args ...interface{}) ([]interface{}, error) { - return hookedselect(m, m, i, query, args...) -} - -// Exec runs an arbitrary SQL statement. args represent the bind parameters. -// This is equivalent to running: Exec() using database/sql -func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) { - if m.logger != nil { - now := time.Now() - defer m.trace(now, query, args...) - } - return exec(m, query, args...) -} - -// SelectInt is a convenience wrapper around the gorp.SelectInt function -func (m *DbMap) SelectInt(query string, args ...interface{}) (int64, error) { - return SelectInt(m, query, args...) -} - -// SelectNullInt is a convenience wrapper around the gorp.SelectNullInt function -func (m *DbMap) SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error) { - return SelectNullInt(m, query, args...) -} - -// SelectFloat is a convenience wrapper around the gorp.SelectFloat function -func (m *DbMap) SelectFloat(query string, args ...interface{}) (float64, error) { - return SelectFloat(m, query, args...) -} - -// SelectNullFloat is a convenience wrapper around the gorp.SelectNullFloat function -func (m *DbMap) SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error) { - return SelectNullFloat(m, query, args...) -} - -// SelectStr is a convenience wrapper around the gorp.SelectStr function -func (m *DbMap) SelectStr(query string, args ...interface{}) (string, error) { - return SelectStr(m, query, args...) -} - -// SelectNullStr is a convenience wrapper around the gorp.SelectNullStr function -func (m *DbMap) SelectNullStr(query string, args ...interface{}) (sql.NullString, error) { - return SelectNullStr(m, query, args...) -} - -// SelectOne is a convenience wrapper around the gorp.SelectOne function -func (m *DbMap) SelectOne(holder interface{}, query string, args ...interface{}) error { - return SelectOne(m, m, holder, query, args...) -} - -// Begin starts a gorp Transaction -func (m *DbMap) Begin() (*Transaction, error) { - if m.logger != nil { - now := time.Now() - defer m.trace(now, "begin;") - } - tx, err := m.Db.Begin() - if err != nil { - return nil, err - } - return &Transaction{m, tx, false}, nil -} - -// TableFor returns the *TableMap corresponding to the given Go Type -// If no table is mapped to that type an error is returned. -// If checkPK is true and the mapped table has no registered PKs, an error is returned. -func (m *DbMap) TableFor(t reflect.Type, checkPK bool) (*TableMap, error) { - table := tableOrNil(m, t) - if table == nil { - return nil, fmt.Errorf("no table found for type: %v", t.Name()) - } - - if checkPK && len(table.keys) < 1 { - e := fmt.Sprintf("gorp: no keys defined for table: %s", - table.TableName) - return nil, errors.New(e) - } - - return table, nil -} - -// Prepare creates a prepared statement for later queries or executions. -// Multiple queries or executions may be run concurrently from the returned statement. -// This is equivalent to running: Prepare() using database/sql -func (m *DbMap) Prepare(query string) (*sql.Stmt, error) { - if m.logger != nil { - now := time.Now() - defer m.trace(now, query, nil) - } - return m.Db.Prepare(query) -} - -func tableOrNil(m *DbMap, t reflect.Type) *TableMap { - for i := range m.tables { - table := m.tables[i] - if table.gotype == t { - return table - } - } - return nil -} - -func (m *DbMap) tableForPointer(ptr interface{}, checkPK bool) (*TableMap, reflect.Value, error) { - ptrv := reflect.ValueOf(ptr) - if ptrv.Kind() != reflect.Ptr { - e := fmt.Sprintf("gorp: passed non-pointer: %v (kind=%v)", ptr, - ptrv.Kind()) - return nil, reflect.Value{}, errors.New(e) - } - elem := ptrv.Elem() - etype := reflect.TypeOf(elem.Interface()) - t, err := m.TableFor(etype, checkPK) - if err != nil { - return nil, reflect.Value{}, err - } - - return t, elem, nil -} - -func (m *DbMap) queryRow(query string, args ...interface{}) *sql.Row { - if m.logger != nil { - now := time.Now() - defer m.trace(now, query, args...) - } - return m.Db.QueryRow(query, args...) -} - -func (m *DbMap) query(query string, args ...interface{}) (*sql.Rows, error) { - if m.logger != nil { - now := time.Now() - defer m.trace(now, query, args...) - } - return m.Db.Query(query, args...) -} - -func (m *DbMap) trace(started time.Time, query string, args ...interface{}) { - if m.logger != nil { - var margs = argsString(args...) - m.logger.Printf("%s%s [%s] (%v)", m.logPrefix, query, margs, (time.Now().Sub(started))) - } -} |