diff --git a/doc.go b/doc.go index 371f4b31..4ebb178d 100644 --- a/doc.go +++ b/doc.go @@ -13,10 +13,34 @@ First, we should new a engine for a database Method NewEngine's parameters is the same as sql.Open. It depends drivers' implementation. Generally, one engine is enough. -engine.Get(...) -engine.Insert(...) -engine.Find(...) -engine.Iterate(...) -engine.Delete(...) +There are 7 major methods and many helpful methods to use to operate database. + +1. Insert one or multipe records to database + + engine.Insert(...) + +2. Query one record from database + + engine.Get(...) + +3. Query multiple records from database + + engine.Find(...) + +4. Query multiple records and record by record handle + + engine.Iterate(...) + +5. Update one or more records + + engine.Update(...) + +6. Delete one or more records + + engine.Delete(...) + +7. Count records + + engine.Count(...) */ package xorm diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 5dee8938..53f564e1 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -391,6 +391,9 @@ Having的参数字符串 * NoAutoTime() 如果此方法执行,则此次生成的语句中Created和Updated字段将不自动赋值为当前时间 +* NoCache() +如果此方法执行,则此次生成的语句则在非缓存模式下执行 + * UseBool(...string) 当从一个struct来生成查询条件或更新字段时,xorm会判断struct的field是否为0,"",nil,如果为以上则不当做查询条件或者更新内容。因为bool类型只有true和false两种值,因此默认所有bool类型不会作为查询条件或者更新字段。如果可以使用此方法,如果默认不传参数,则所有的bool字段都将会被使用,如果参数不为空,则参数中指定的为字段名,则这些字段对应的bool值将被使用。 diff --git a/engine.go b/engine.go index 8d479edb..2658cab9 100644 --- a/engine.go +++ b/engine.go @@ -37,6 +37,8 @@ type dialect interface { GetIndexes(tableName string) (map[string]*Index, error) } +// Engine is the major struct of xorm, it means a database manager. +// Commonly, an application only need one engine type Engine struct { Mapper IMapper TagIdentifier string @@ -122,7 +124,7 @@ func (engine *Engine) NoCache() *Session { // Set a table use a special cacher func (engine *Engine) MapCacher(bean interface{}, cacher Cacher) { t := rType(bean) - engine.AutoMapType(t) + engine.autoMapType(t) engine.Tables[t].Cacher = cacher } @@ -143,11 +145,6 @@ func (engine *Engine) Close() error { return engine.Pool.Close(engine) } -// Test method is deprecated, use Ping() method. -func (engine *Engine) Test() error { - return engine.Ping() -} - // Ping tests if database is alive. func (engine *Engine) Ping() error { session := engine.NewSession() @@ -184,20 +181,29 @@ func (engine *Engine) LogWarn(contents ...interface{}) { } } -// execute sql +// Sql method let's you manualy write raw sql and operate +// For example: +// +// engine.Sql("select * from user").Find(&users) +// +// This code will execute "select * from user" and set the records to users +// func (engine *Engine) Sql(querystring string, args ...interface{}) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Sql(querystring, args...) } +// Default if your struct has "created" or "updated" filed tag, the fields +// will automatically be filled with current time when Insert or Update +// invoked. Call NoAutoTime if you dont' want to fill automatically. func (engine *Engine) NoAutoTime() *Session { session := engine.NewSession() session.IsAutoClose = true return session.NoAutoTime() } -// retrieve all tables, columns, indexes' informations from database. +// Retrieve all tables, columns, indexes' informations from database. func (engine *Engine) DBMetas() ([]*Table, error) { tables, err := engine.dialect.GetTables() if err != nil { @@ -266,60 +272,82 @@ func (engine *Engine) StoreEngine(storeEngine string) *Session { return session.StoreEngine(storeEngine) } +// use for distinct columns. Caution: when you are using cache, +// distinct will not be cached because cache system need id, +// but distinct will not provide id func (engine *Engine) Distinct(columns ...string) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Distinct(columns...) } +// only use the paramters as select or update columns func (engine *Engine) Cols(columns ...string) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Cols(columns...) } +// Xorm automatically retrieve condition according struct, but +// if struct has bool field, it will ignore them. So use UseBool +// to tell system to do not ignore them. +// If no paramters, it will use all the bool field of struct, or +// it will use paramters's columns func (engine *Engine) UseBool(columns ...string) *Session { session := engine.NewSession() session.IsAutoClose = true return session.UseBool(columns...) } +// Only not use the paramters as select or update columns func (engine *Engine) Omit(columns ...string) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Omit(columns...) } +// This method will generate "column IN (?, ?)" func (engine *Engine) In(column string, args ...interface{}) *Session { session := engine.NewSession() session.IsAutoClose = true return session.In(column, args...) } +// Temporarily change the Get, Find, Update's table func (engine *Engine) Table(tableNameOrBean interface{}) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Table(tableNameOrBean) } +// This method will generate "LIMIT start, limit" func (engine *Engine) Limit(limit int, start ...int) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Limit(limit, start...) } +// Method Desc will generate "ORDER BY column1 DESC, column2 DESC" +// This will func (engine *Engine) Desc(colNames ...string) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Desc(colNames...) } +// Method Asc will generate "ORDER BY column1 DESC, column2 Asc" +// This method can chainable use. +// +// engine.Desc("name").Asc("age").Find(&users) +// // SELECT * FROM user ORDER BY name DESC, age ASC +// func (engine *Engine) Asc(colNames ...string) *Session { session := engine.NewSession() session.IsAutoClose = true return session.Asc(colNames...) } +// Method OrderBy will generate "ORDER BY order" func (engine *Engine) OrderBy(order string) *Session { session := engine.NewSession() session.IsAutoClose = true @@ -345,21 +373,20 @@ func (engine *Engine) Having(conditions string) *Session { return session.Having(conditions) } -// -func (engine *Engine) AutoMapType(t reflect.Type) *Table { +func (engine *Engine) autoMapType(t reflect.Type) *Table { engine.mutex.Lock() defer engine.mutex.Unlock() table, ok := engine.Tables[t] if !ok { - table = engine.MapType(t) + table = engine.mapType(t) engine.Tables[t] = table } return table } -func (engine *Engine) AutoMap(bean interface{}) *Table { +func (engine *Engine) autoMap(bean interface{}) *Table { t := rType(bean) - return engine.AutoMapType(t) + return engine.autoMapType(t) } func (engine *Engine) newTable() *Table { @@ -371,7 +398,7 @@ func (engine *Engine) newTable() *Table { return table } -func (engine *Engine) MapType(t reflect.Type) *Table { +func (engine *Engine) mapType(t reflect.Type) *Table { table := engine.newTable() table.Name = engine.Mapper.Obj2Table(t.Name()) table.Type = t @@ -395,7 +422,7 @@ func (engine *Engine) MapType(t reflect.Type) *Table { } if (strings.ToUpper(tags[0]) == "EXTENDS") && (fieldType.Kind() == reflect.Struct) { - parentTable := engine.MapType(fieldType) + parentTable := engine.mapType(fieldType) for name, col := range parentTable.Columns { col.FieldName = fmt.Sprintf("%v.%v", fieldType.Name(), col.FieldName) table.Columns[name] = col @@ -540,36 +567,36 @@ func (engine *Engine) MapType(t reflect.Type) *Table { } // Map a struct to a table -func (engine *Engine) Map(beans ...interface{}) (e error) { +func (engine *Engine) mapping(beans ...interface{}) (e error) { engine.mutex.Lock() defer engine.mutex.Unlock() for _, bean := range beans { t := rType(bean) - engine.Tables[t] = engine.MapType(t) + engine.Tables[t] = engine.mapType(t) } return } -// Is a table has any reocrd +// If a table has any reocrd func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) { t := rType(bean) if t.Kind() != reflect.Struct { return false, errors.New("bean should be a struct or struct's point") } - engine.AutoMapType(t) + engine.autoMapType(t) session := engine.NewSession() defer session.Close() rows, err := session.Count(bean) return rows > 0, err } -// Is a table is exist +// If a table is exist func (engine *Engine) IsTableExist(bean interface{}) (bool, error) { t := rType(bean) if t.Kind() != reflect.Struct { return false, errors.New("bean should be a struct or struct's point") } - table := engine.AutoMapType(t) + table := engine.autoMapType(t) session := engine.NewSession() defer session.Close() has, err := session.isTableExist(table.Name) @@ -596,7 +623,7 @@ func (engine *Engine) ClearCacheBean(bean interface{}, id int64) error { if t.Kind() != reflect.Struct { return errors.New("error params") } - table := engine.AutoMap(bean) + table := engine.autoMap(bean) if table.Cacher != nil { table.Cacher.ClearIds(table.Name) table.Cacher.DelBean(table.Name, id) @@ -611,7 +638,7 @@ func (engine *Engine) ClearCache(beans ...interface{}) error { if t.Kind() != reflect.Struct { return errors.New("error params") } - table := engine.AutoMap(bean) + table := engine.autoMap(bean) if table.Cacher != nil { table.Cacher.ClearIds(table.Name) table.Cacher.ClearBeans(table.Name) @@ -620,12 +647,12 @@ func (engine *Engine) ClearCache(beans ...interface{}) error { return nil } -// Sync the new struct change to database, this method will automatically add +// Sync the new struct changes to database, this method will automatically add // table, column, index, unique. but will not delete or change anything. // If you change some field, you should change the database manually. func (engine *Engine) Sync(beans ...interface{}) error { for _, bean := range beans { - table := engine.AutoMap(bean) + table := engine.autoMap(bean) s := engine.NewSession() defer s.Close() @@ -715,7 +742,7 @@ func (engine *Engine) Sync(beans ...interface{}) error { return nil } -func (engine *Engine) UnMap(beans ...interface{}) (e error) { +func (engine *Engine) unMap(beans ...interface{}) (e error) { engine.mutex.Lock() defer engine.mutex.Unlock() for _, bean := range beans { @@ -728,7 +755,7 @@ func (engine *Engine) UnMap(beans ...interface{}) (e error) { } // Drop all mapped table -func (engine *Engine) DropAll() error { +func (engine *Engine) dropAll() error { session := engine.NewSession() defer session.Close() @@ -781,7 +808,7 @@ func (engine *Engine) DropTables(beans ...interface{}) error { return session.Commit() } -func (engine *Engine) CreateAll() error { +func (engine *Engine) createAll() error { session := engine.NewSession() defer session.Close() return session.CreateAll() @@ -823,6 +850,7 @@ func (engine *Engine) Delete(bean interface{}) (int64, error) { return session.Delete(bean) } +// Get retrieve one record from table func (engine *Engine) Get(bean interface{}) (bool, error) { session := engine.NewSession() defer session.Close() diff --git a/iterator.go b/iterator.go deleted file mode 100644 index f679ae18..00000000 --- a/iterator.go +++ /dev/null @@ -1,35 +0,0 @@ -package xorm - -import ( - "database/sql" -) - -type Iterator struct { - session *Session - startId int - rows *sql.Rows -} - -func (iter *Iterator) IsValid() bool { - return iter.session != nil && iter.rows != nil -} - -/* -func (iter *Iterator) Next(bean interface{}) (bool, error) { - if !iter.IsValid() { - return errors.New("iterator is not valied.") - } - if iter.rows.Next() { - iter.rows.Scan(...) - } -}*/ - -// close the iterator -func (iter *Iterator) Close() { - if iter.rows != nil { - iter.rows.Close() - } - if iter.session != nil && iter.session.IsAutoClose { - iter.session.Close() - } -} diff --git a/session.go b/session.go index 4622e7b0..e6ed808d 100644 --- a/session.go +++ b/session.go @@ -248,7 +248,7 @@ func (session *Session) scanMapIntoStruct(obj interface{}, objMap map[string][]b return errors.New("Expected a pointer to a struct") } - table := session.Engine.AutoMapType(rType(obj)) + table := session.Engine.autoMapType(rType(obj)) for key, data := range objMap { if _, ok := table.Columns[key]; !ok { @@ -329,7 +329,7 @@ func (session *Session) Exec(sql string, args ...interface{}) (sql.Result, error // this function create a table according a bean func (session *Session) CreateTable(bean interface{}) error { - session.Statement.RefTable = session.Engine.AutoMap(bean) + session.Statement.RefTable = session.Engine.autoMap(bean) err := session.newDb() if err != nil { @@ -344,7 +344,7 @@ func (session *Session) CreateTable(bean interface{}) error { } func (session *Session) CreateIndexes(bean interface{}) error { - session.Statement.RefTable = session.Engine.AutoMap(bean) + session.Statement.RefTable = session.Engine.autoMap(bean) err := session.newDb() if err != nil { @@ -366,7 +366,7 @@ func (session *Session) CreateIndexes(bean interface{}) error { } func (session *Session) CreateUniques(bean interface{}) error { - session.Statement.RefTable = session.Engine.AutoMap(bean) + session.Statement.RefTable = session.Engine.autoMap(bean) err := session.newDb() if err != nil { @@ -450,7 +450,7 @@ func (session *Session) DropTable(bean interface{}) error { if t.Kind() == reflect.String { session.Statement.AltTableName = bean.(string) } else if t.Kind() == reflect.Struct { - session.Statement.RefTable = session.Engine.AutoMap(bean) + session.Statement.RefTable = session.Engine.autoMap(bean) } else { return errors.New("Unsupported type") } @@ -715,7 +715,7 @@ func (session *Session) Iterate(bean interface{}, fun IterFunc) error { var sql string var args []interface{} - session.Statement.RefTable = session.Engine.AutoMap(bean) + session.Statement.RefTable = session.Engine.autoMap(bean) if session.Statement.RawSQL == "" { sql, args = session.Statement.genGetSql(bean) } else { @@ -780,7 +780,7 @@ func (session *Session) Get(bean interface{}) (bool, error) { session.Statement.Limit(1) var sql string var args []interface{} - session.Statement.RefTable = session.Engine.AutoMap(bean) + session.Statement.RefTable = session.Engine.autoMap(bean) if session.Statement.RawSQL == "" { sql, args = session.Statement.genGetSql(bean) } else { @@ -871,12 +871,12 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) if session.Statement.RefTable == nil { if sliceElementType.Kind() == reflect.Ptr { if sliceElementType.Elem().Kind() == reflect.Struct { - table = session.Engine.AutoMapType(sliceElementType.Elem()) + table = session.Engine.autoMapType(sliceElementType.Elem()) } else { return errors.New("slice type") } } else if sliceElementType.Kind() == reflect.Struct { - table = session.Engine.AutoMapType(sliceElementType) + table = session.Engine.autoMapType(sliceElementType) } else { return errors.New("slice type") } @@ -1306,7 +1306,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error bean := sliceValue.Index(0).Interface() sliceElementType := rType(bean) - table := session.Engine.AutoMapType(sliceElementType) + table := session.Engine.autoMapType(sliceElementType) session.Statement.RefTable = table size := sliceValue.Len() @@ -1538,7 +1538,7 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data v = x fieldValue.Set(reflect.ValueOf(v)) } else if session.Statement.UseCascade { - table := session.Engine.AutoMapType(fieldValue.Type()) + table := session.Engine.autoMapType(fieldValue.Type()) if table != nil { x, err := strconv.ParseInt(string(data), 10, 64) if err != nil { @@ -1656,7 +1656,7 @@ func (session *Session) value2Interface(col *Column, fieldValue reflect.Value) ( } func (session *Session) innerInsert(bean interface{}) (int64, error) { - table := session.Engine.AutoMap(bean) + table := session.Engine.autoMap(bean) session.Statement.RefTable = table colNames, args, err := table.genCols(session, bean, false, false) @@ -1931,7 +1931,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 var table *Table if t.Kind() == reflect.Struct { - table = session.Engine.AutoMap(bean) + table = session.Engine.autoMap(bean) session.Statement.RefTable = table if session.Statement.ColumnStr == "" { @@ -2078,7 +2078,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) { defer session.Close() } - table := session.Engine.AutoMap(bean) + table := session.Engine.autoMap(bean) session.Statement.RefTable = table colNames, args := buildConditions(session.Engine, table, bean, true, session.Statement.allUseBool, session.Statement.boolColumnMap) diff --git a/statement.go b/statement.go index 96841078..10a8492d 100644 --- a/statement.go +++ b/statement.go @@ -98,7 +98,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) { if t.Kind() == reflect.String { statement.AltTableName = tableNameOrBean.(string) } else if t.Kind() == reflect.Struct { - statement.RefTable = statement.Engine.AutoMapType(t) + statement.RefTable = statement.Engine.autoMapType(t) } } @@ -166,7 +166,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, includeVers val = t } } else { - engine.AutoMapType(fieldValue.Type()) + engine.autoMapType(fieldValue.Type()) if table, ok := engine.Tables[fieldValue.Type()]; ok { pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumn().FieldName) if pkField.Int() != 0 { @@ -431,7 +431,7 @@ func (s *Statement) genDropSQL() string { } func (statement Statement) genGetSql(bean interface{}) (string, []interface{}) { - table := statement.Engine.AutoMap(bean) + table := statement.Engine.autoMap(bean) statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, @@ -469,7 +469,7 @@ func (s *Statement) genAddUniqueStr(uqeName string, cols []string) (string, []in } func (statement Statement) genCountSql(bean interface{}) (string, []interface{}) { - table := statement.Engine.AutoMap(bean) + table := statement.Engine.autoMap(bean) statement.RefTable = table colNames, args := buildConditions(statement.Engine, table, bean, true, statement.allUseBool, statement.boolColumnMap)