improved docs & resolved #

14
This commit is contained in:
Lunny Xiao 2013-11-22 14:11:07 +08:00
parent f9bb47b03d
commit 605ec87f65
9 changed files with 168 additions and 48 deletions

View File

@ -11,7 +11,9 @@ import (
)
const (
// default cache expired time
CacheExpired = 60 * time.Minute
// not use now
CacheMaxMemory = 256
// evey ten minutes to clear all expired nodes
CacheGcInterval = 10 * time.Minute
@ -19,12 +21,15 @@ const (
CacheGcMaxRemoved = 20
)
// CacheStore is a interface to store cache
type CacheStore interface {
Put(key, value interface{}) error
Get(key interface{}) (interface{}, error)
Del(key interface{}) error
}
// MemoryStore implements CacheStore provide local machine
// memory store
type MemoryStore struct {
store map[interface{}]interface{}
mutex sync.RWMutex
@ -58,6 +63,7 @@ func (s *MemoryStore) Del(key interface{}) error {
return nil
}
// Cacher is an interface to provide cache
type Cacher interface {
GetIds(tableName, sql string) interface{}
GetBean(tableName string, id int64) interface{}
@ -122,9 +128,9 @@ func NewLRUCacher2(store CacheStore, expired time.Duration, max int) *LRUCacher
return newLRUCacher(store, expired, 0, max)
}
func NewLRUCacher3(store CacheStore, expired time.Duration, maxSize int) *LRUCacher {
return newLRUCacher(store, expired, maxSize, 0)
}
//func NewLRUCacher3(store CacheStore, expired time.Duration, maxSize int) *LRUCacher {
// return newLRUCacher(store, expired, maxSize, 0)
//}
// RunGC run once every m.GcInterval
func (m *LRUCacher) RunGC() {

View File

@ -354,19 +354,21 @@ func (engine *Engine) OrderBy(order string) *Session {
return session.OrderBy(order)
}
//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
// The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (engine *Engine) Join(join_operator, tablename, condition string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
return session.Join(join_operator, tablename, condition)
}
// Generate Group By statement
func (engine *Engine) GroupBy(keys string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
return session.GroupBy(keys)
}
// Generate Having statement
func (engine *Engine) Having(conditions string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
@ -763,7 +765,7 @@ func (engine *Engine) dropAll() error {
if err != nil {
return err
}
err = session.DropAll()
err = session.dropAll()
if err != nil {
session.Rollback()
return err
@ -811,64 +813,83 @@ func (engine *Engine) DropTables(beans ...interface{}) error {
func (engine *Engine) createAll() error {
session := engine.NewSession()
defer session.Close()
return session.CreateAll()
return session.createAll()
}
// Exec raw sql
func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error) {
session := engine.NewSession()
defer session.Close()
return session.Exec(sql, args...)
}
// Exec a raw sql and return records as []map[string][]byte
func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
session := engine.NewSession()
defer session.Close()
return session.Query(sql, paramStr...)
}
// Insert one or more records
func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.Insert(beans...)
}
// Insert only one record
func (engine *Engine) InsertOne(bean interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.InsertOne(bean)
}
// Update records, bean's non-empty fields are updated contents,
// condiBean' non-empty filds are conditions
// CAUTION:
// 1.bool will defaultly be updated content nor conditions
// You should call UseBool if you have bool to use.
// 2.float32 & float64 may be not inexact as conditions
func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.Update(bean, condiBeans...)
}
// Delete records, bean's non-empty fields are conditions
func (engine *Engine) Delete(bean interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()
return session.Delete(bean)
}
// Get retrieve one record from table
// Get retrieve one record from table, bean's non-empty fields
// are conditions
func (engine *Engine) Get(bean interface{}) (bool, error) {
session := engine.NewSession()
defer session.Close()
return session.Get(bean)
}
// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
session := engine.NewSession()
defer session.Close()
return session.Find(beans, condiBeans...)
}
// Iterate record by record handle records from table, bean's non-empty fields
// are conditions.
func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error {
session := engine.NewSession()
defer session.Close()
return session.Iterate(bean, fun)
}
// Count counts the records. bean's non-empty fields
// are conditions.
func (engine *Engine) Count(bean interface{}) (int64, error) {
session := engine.NewSession()
defer session.Close()

View File

@ -5,10 +5,12 @@ import (
"strings"
)
// Filter is an interface to filter SQL
type Filter interface {
Do(sql string, session *Session) string
}
// PgSeqFilter filter SQL replace ?, ? ... to $1, $2 ...
type PgSeqFilter struct {
}
@ -25,6 +27,7 @@ func (s *PgSeqFilter) Do(sql string, session *Session) string {
return res
}
// QuoteFilter filter SQL replace ` to database's own quote character
type QuoteFilter struct {
}
@ -32,6 +35,7 @@ func (s *QuoteFilter) Do(sql string, session *Session) string {
return strings.Replace(sql, "`", session.Engine.QuoteStr(), -1)
}
// IdFilter filter SQL replace (id) to primary key column name
type IdFilter struct {
}

View File

@ -44,3 +44,20 @@ func structName(v reflect.Type) string {
}
return v.Name()
}
func sliceEq(left, right []string) bool {
for _, l := range left {
var find bool
for _, r := range right {
if l == r {
find = true
break
}
}
if !find {
return false
}
}
return true
}

View File

@ -11,6 +11,8 @@ type IMapper interface {
Table2Obj(string) string
}
// SameMapper implements IMapper and provides same name between struct and
// database table
type SameMapper struct {
}
@ -22,6 +24,8 @@ func (m SameMapper) Table2Obj(t string) string {
return t
}
// SnakeMapper implements IMapper and provides name transaltion between
// struct and database table
type SnakeMapper struct {
}

View File

@ -23,10 +23,8 @@ func (vs values) Get(k string) (v string) {
return vs[k]
}
type Error error
func errorf(s string, args ...interface{}) {
panic(Error(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))))
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
}
func parseOpts(name string, o values) {

View File

@ -94,16 +94,25 @@ func (session *Session) Cols(columns ...string) *Session {
return session
}
// 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 (session *Session) UseBool(columns ...string) *Session {
session.Statement.UseBool(columns...)
return session
}
// 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 (session *Session) Distinct(columns ...string) *Session {
session.Statement.Distinct(columns...)
return session
}
// Only not use the paramters as select or update columns
func (session *Session) Omit(columns ...string) *Session {
session.Statement.Omit(columns...)
return session
@ -163,7 +172,7 @@ func (session *Session) Charset(charset string) *Session {
return session
}
// Method Cascade
// Method Cascade indicates if loading sub Struct
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
if len(trueOrFalse) >= 1 {
session.Statement.UseCascade = trueOrFalse[0]
@ -184,11 +193,13 @@ func (session *Session) Join(join_operator, tablename, condition string) *Sessio
return session
}
// Generate Group By statement
func (session *Session) GroupBy(keys string) *Session {
session.Statement.GroupBy(keys)
return session
}
// Generate Having statement
func (session *Session) Having(conditions string) *Session {
session.Statement.Having(conditions)
return session
@ -205,6 +216,7 @@ func (session *Session) newDb() error {
return nil
}
// Begin a transaction
func (session *Session) Begin() error {
err := session.newDb()
if err != nil {
@ -224,6 +236,7 @@ func (session *Session) Begin() error {
return nil
}
// When using transaction, you can rollback if any error
func (session *Session) Rollback() error {
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
session.Engine.LogSQL("ROLL BACK")
@ -233,6 +246,7 @@ func (session *Session) Rollback() error {
return nil
}
// When using transaction, Commit will commit all operations.
func (session *Session) Commit() error {
if !session.IsAutoCommit && !session.IsCommitedOrRollbacked {
session.Engine.LogSQL("COMMIT")
@ -314,6 +328,7 @@ func (session *Session) exec(sql string, args ...interface{}) (sql.Result, error
return session.Tx.Exec(sql, args...)
}
// Exec raw sql
func (session *Session) Exec(sql string, args ...interface{}) (sql.Result, error) {
err := session.newDb()
if err != nil {
@ -343,6 +358,7 @@ func (session *Session) CreateTable(bean interface{}) error {
return session.createOneTable()
}
// create indexes
func (session *Session) CreateIndexes(bean interface{}) error {
session.Statement.RefTable = session.Engine.autoMap(bean)
@ -365,6 +381,7 @@ func (session *Session) CreateIndexes(bean interface{}) error {
return nil
}
// create uniques
func (session *Session) CreateUniques(bean interface{}) error {
session.Statement.RefTable = session.Engine.autoMap(bean)
@ -393,7 +410,8 @@ func (session *Session) createOneTable() error {
return err
}
func (session *Session) CreateAll() error {
// to be deleted
func (session *Session) createAll() error {
err := session.newDb()
if err != nil {
return err
@ -413,6 +431,7 @@ func (session *Session) CreateAll() error {
return nil
}
// drop indexes
func (session *Session) DropIndexes(bean interface{}) error {
err := session.newDb()
if err != nil {
@ -700,8 +719,12 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter
return nil
}
// IterFunc only use by Iterate
type IterFunc func(idx int, bean interface{}) error
// Iterate record by record handle records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
err := session.newDb()
if err != nil {
@ -765,7 +788,8 @@ func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
return nil
}
// get retrieve one record from database
// get retrieve one record from database, bean's non-empty fields
// will be as conditions
func (session *Session) Get(bean interface{}) (bool, error) {
err := session.newDb()
if err != nil {
@ -814,6 +838,8 @@ func (session *Session) Get(bean interface{}) (bool, error) {
}
}
// Count counts the records. bean's non-empty fields
// are conditions.
func (session *Session) Count(bean interface{}) (int64, error) {
err := session.newDb()
if err != nil {
@ -851,6 +877,9 @@ func (session *Session) Count(bean interface{}) (int64, error) {
return int64(total), err
}
// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
err := session.newDb()
if err != nil {
@ -959,7 +988,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
return nil
}
// test if database is ok
// Test if database is ok
func (session *Session) Ping() error {
err := session.newDb()
if err != nil {
@ -1021,23 +1050,6 @@ func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bo
return len(results) > 0, err
}
func sliceEq(left, right []string) bool {
for _, l := range left {
var find bool
for _, r := range right {
if l == r {
find = true
break
}
}
if !find {
return false
}
}
return true
}
// find if index is exist according cols
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
indexes, err := session.Engine.dialect.GetIndexes(tableName)
@ -1106,7 +1118,8 @@ func (session *Session) addUnique(tableName, uqeName string) error {
return err
}
func (session *Session) DropAll() error {
// To be deleted
func (session *Session) dropAll() error {
err := session.newDb()
if err != nil {
return err
@ -1240,6 +1253,7 @@ func (session *Session) query(sql string, paramStr ...interface{}) (resultsSlice
return query(session.Db, sql, paramStr...)
}
// Exec a raw sql and return records as []map[string][]byte
func (session *Session) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
err = session.newDb()
if err != nil {
@ -1399,6 +1413,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
return res.RowsAffected()
}
// Insert multiple records
func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
err := session.newDb()
if err != nil {
@ -1914,6 +1929,12 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error {
return nil
}
// Update records, bean's non-empty fields are updated contents,
// condiBean' non-empty filds are conditions
// CAUTION:
// 1.bool will defaultly be updated content nor conditions
// You should call UseBool if you have bool to use.
// 2.float32 & float64 may be not inexact as conditions
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
err := session.newDb()
if err != nil {
@ -2068,6 +2089,7 @@ func (session *Session) cacheDelete(sql string, args ...interface{}) error {
return nil
}
// Delete records, bean's non-empty fields are conditions
func (session *Session) Delete(bean interface{}) (int64, error) {
err := session.newDb()
if err != nil {

View File

@ -9,6 +9,7 @@ import (
"time"
)
// statement save all the sql info for executing SQL
type Statement struct {
RefTable *Table
Engine *Engine
@ -39,6 +40,7 @@ type Statement struct {
boolColumnMap map[string]bool
}
// init
func (statement *Statement) Init() {
statement.RefTable = nil
statement.Start = 0
@ -65,41 +67,51 @@ func (statement *Statement) Init() {
statement.boolColumnMap = make(map[string]bool)
}
func (statement *Statement) Sql(querystring string, args ...interface{}) {
// add the raw sql statement
func (statement *Statement) Sql(querystring string, args ...interface{}) *Statement {
statement.RawSQL = querystring
statement.RawParams = args
return statement
}
func (statement *Statement) Where(querystring string, args ...interface{}) {
// add Where statment
func (statement *Statement) Where(querystring string, args ...interface{}) *Statement {
statement.WhereStr = querystring
statement.Params = args
return statement
}
func (statement *Statement) And(querystring string, args ...interface{}) {
// add Where & and statment
func (statement *Statement) And(querystring string, args ...interface{}) *Statement {
if statement.WhereStr != "" {
statement.WhereStr = fmt.Sprintf("(%v) AND (%v)", statement.WhereStr, querystring)
} else {
statement.WhereStr = querystring
}
statement.Params = append(statement.Params, args...)
return statement
}
func (statement *Statement) Or(querystring string, args ...interface{}) {
// add Where & Or statment
func (statement *Statement) Or(querystring string, args ...interface{}) *Statement {
if statement.WhereStr != "" {
statement.WhereStr = fmt.Sprintf("(%v) OR (%v)", statement.WhereStr, querystring)
} else {
statement.WhereStr = querystring
}
statement.Params = append(statement.Params, args...)
return statement
}
func (statement *Statement) Table(tableNameOrBean interface{}) {
// tempororily set table name
func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
t := rType(tableNameOrBean)
if t.Kind() == reflect.String {
statement.AltTableName = tableNameOrBean.(string)
} else if t.Kind() == reflect.Struct {
statement.RefTable = statement.Engine.autoMapType(t)
}
return statement
}
// Auto generating conditions according a struct
@ -225,6 +237,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{}, includeVers
return colNames, args
}
// return current tableName
func (statement *Statement) TableName() string {
if statement.AltTableName != "" {
return statement.AltTableName
@ -236,7 +249,8 @@ func (statement *Statement) TableName() string {
return ""
}
func (statement *Statement) Id(id int64) {
// Generate "Where id = ? " statment
func (statement *Statement) Id(id int64) *Statement {
if statement.WhereStr == "" {
statement.WhereStr = "(id)=?"
statement.Params = []interface{}{id}
@ -244,9 +258,11 @@ func (statement *Statement) Id(id int64) {
statement.WhereStr = statement.WhereStr + " AND (id)=?"
statement.Params = append(statement.Params, id)
}
return statement
}
func (statement *Statement) In(column string, args ...interface{}) {
// Generate "Where column IN (?) " statment
func (statement *Statement) In(column string, args ...interface{}) *Statement {
inStr := fmt.Sprintf("%v IN (%v)", column, strings.Join(makeArray("?", len(args)), ","))
if statement.WhereStr == "" {
statement.WhereStr = inStr
@ -255,6 +271,7 @@ func (statement *Statement) In(column string, args ...interface{}) {
statement.WhereStr = statement.WhereStr + " AND " + inStr
statement.Params = append(statement.Params, args...)
}
return statement
}
func col2NewCols(columns ...string) []string {
@ -270,20 +287,25 @@ func col2NewCols(columns ...string) []string {
return newColumns
}
func (statement *Statement) Distinct(columns ...string) {
// Generate "Distince col1, col2 " statment
func (statement *Statement) Distinct(columns ...string) *Statement {
statement.IsDistinct = true
statement.Cols(columns...)
return statement
}
func (statement *Statement) Cols(columns ...string) {
// Generate "col1, col2" statement
func (statement *Statement) Cols(columns ...string) *Statement {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
statement.columnMap[nc] = true
}
statement.ColumnStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
return statement
}
func (statement *Statement) UseBool(columns ...string) {
// indicates that use bool fields as update contents and query contiditions
func (statement *Statement) UseBool(columns ...string) *Statement {
if len(columns) > 0 {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
@ -292,8 +314,10 @@ func (statement *Statement) UseBool(columns ...string) {
} else {
statement.allUseBool = true
}
return statement
}
// do not use the columns
func (statement *Statement) Omit(columns ...string) {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
@ -302,37 +326,47 @@ func (statement *Statement) Omit(columns ...string) {
statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", ")))
}
// Generate LIMIT limit statement
func (statement *Statement) Top(limit int) *Statement {
statement.Limit(limit)
return statement
}
func (statement *Statement) Limit(limit int, start ...int) {
// Generate LIMIT start, limit statement
func (statement *Statement) Limit(limit int, start ...int) *Statement {
statement.LimitN = limit
if len(start) > 0 {
statement.Start = start[0]
}
return statement
}
func (statement *Statement) OrderBy(order string) {
// Generate "Order By order" statement
func (statement *Statement) OrderBy(order string) *Statement {
statement.OrderStr = order
return statement
}
//The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (statement *Statement) Join(join_operator, tablename, condition string) {
func (statement *Statement) Join(join_operator, tablename, condition string) *Statement {
if statement.JoinStr != "" {
statement.JoinStr = statement.JoinStr + fmt.Sprintf("%v JOIN %v ON %v", join_operator, tablename, condition)
} else {
statement.JoinStr = fmt.Sprintf("%v JOIN %v ON %v", join_operator, tablename, condition)
}
return statement
}
func (statement *Statement) GroupBy(keys string) {
// Generate "Group By keys" statement
func (statement *Statement) GroupBy(keys string) *Statement {
statement.GroupByStr = keys
return statement
}
func (statement *Statement) Having(conditions string) {
// Generate "Having conditions" statement
func (statement *Statement) Having(conditions string) *Statement {
statement.HavingStr = fmt.Sprintf("HAVING %v", conditions)
return statement
}
func (statement *Statement) genColumnStr() string {

View File

@ -6,6 +6,7 @@ import (
"time"
)
// xorm SQL types
type SQLType struct {
Name string
DefaultLength int
@ -143,6 +144,7 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
return
}
// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
name := strings.ToUpper(st.Name)
switch name {
@ -174,18 +176,21 @@ const (
UniqueType
)
// database index
type Index struct {
Name string
Type int
Cols []string
}
// add columns which will be composite index
func (index *Index) AddColumn(cols ...string) {
for _, col := range cols {
index.Cols = append(index.Cols, col)
}
}
// new an index
func NewIndex(name string, indexType int) *Index {
return &Index{name, indexType, make([]string, 0)}
}
@ -196,6 +201,7 @@ const (
ONLYFROMDB
)
// database column
type Column struct {
Name string
FieldName string
@ -214,6 +220,7 @@ type Column struct {
IsVersion bool
}
// generate column description string according dialect
func (col *Column) String(d dialect) string {
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
@ -240,6 +247,7 @@ func (col *Column) String(d dialect) string {
return sql
}
// return col's filed of struct's value
func (col *Column) ValueOf(bean interface{}) reflect.Value {
var fieldValue reflect.Value
if strings.Contains(col.FieldName, ".") {
@ -256,6 +264,7 @@ func (col *Column) ValueOf(bean interface{}) reflect.Value {
return fieldValue
}
// database table
type Table struct {
Name string
Type reflect.Type
@ -269,10 +278,12 @@ type Table struct {
Cacher Cacher
}
// if has primary key, return column
func (table *Table) PKColumn() *Column {
return table.Columns[table.PrimaryKey]
}
// add a column to table
func (table *Table) AddColumn(col *Column) {
table.ColumnsSeq = append(table.ColumnsSeq, col.Name)
table.Columns[col.Name] = col
@ -290,6 +301,7 @@ func (table *Table) AddColumn(col *Column) {
}
}
// add an index or an unique to table
func (table *Table) AddIndex(index *Index) {
table.Indexes[index.Name] = index
}
@ -343,6 +355,8 @@ func (table *Table) genCols(session *Session, bean interface{}, useCol bool, inc
return colNames, args, nil
}
// Conversion is an interface. A type implements Conversion will according
// the custom method to fill into database and retrieve from database.
type Conversion interface {
FromDB([]byte) error
ToDB() ([]byte, error)