| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 | package ormimport (	"fmt"	"math"	"reflect"	"strconv"	"sync"	"github.com/go-openapi/inflect")type table struct {	rt       reflect.Type	rv       reflect.Value	l        *sync.RWMutex	tFn, cFn MapperFn	cols     columns	rels     relations	mapped   bool}func (t *table) Make() MappableInterface {	return reflect.New(t.getType()).Interface().(MappableInterface)}func (t *table) CallMethod(i MappableInterface, n string, args ...interface{}) ([]interface{}, error) {	var ret []interface{}	if t.getValue(true).MethodByName(n).IsValid() {		fn := reflect.ValueOf(i).MethodByName(n)		fnt := fn.Type()		in := []reflect.Value{}		if fnt.IsVariadic() && len(args) < (fnt.NumIn()-1) {			return ret, fmt.Errorf("To few arguments to «%s». Got «%d», expected «%d»", n, len(args), fnt.NumIn()-1)		} else if !fnt.IsVariadic() && len(args) != fnt.NumIn() {			return ret, fmt.Errorf("To few arguments to «%s». Got «%d», expected «%d»", n, len(args), fnt.NumIn()-1)		}		for x := 0; x < len(args); x++ {			var inType reflect.Type			if fnt.IsVariadic() && x >= fnt.NumIn()-1 {				inType = fnt.In(fnt.NumIn() - 1).Elem()			} else {				inType = fnt.In(x)			}			argv := reflect.ValueOf(args[x])			if !argv.IsValid() || !argv.Type().ConvertibleTo(inType) {				switch inType.Kind() {				case					reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,					reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:					var val uint64 = 0					argx := args[x].([]uint8)					for xi := len(argx) - 1; xi >= 0; xi-- {						val += uint64(math.Pow(10, float64(len(argx)-xi-1))) * uint64(argx[xi]-'0')					}					args[x] = val					return t.CallMethod(i, n, args...)				case reflect.Float32, reflect.Float64:					if val, err := strconv.ParseFloat(string(args[x].([]byte)), 64); err == nil {						args[x] = val						return t.CallMethod(i, n, args...)					}				case reflect.Complex64, reflect.Complex128:					// Not implemented					return ret, fmt.Errorf("Complex not implemented")				}				return ret, fmt.Errorf("Invalid argument to «%s». Got %s, expected %s", n, argv.String(), inType.String())			}			in = append(in, argv.Convert(inType))		}		var err error = nil		out := fn.Call(in)[0:fnt.NumOut()]		for _, val := range out {			switch val.Kind() {			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:				ret = append(ret, val.Uint())			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:				ret = append(ret, val.Int())			case reflect.Float32, reflect.Float64:				ret = append(ret, val.Float())			case reflect.String:				ret = append(ret, val.String())			case reflect.Interface:				if !val.IsNil() && val.CanInterface() && val.Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {					err = val.Interface().(error)				}			}		}		return ret, err	}	return ret, fmt.Errorf("Invalid method «%s» on «%s»", n, t.getType())}// getPrimaryKey tries to find primary keyfunc (t *table) getPrimaryKey() *column {	var pkey *column = nil	if c := t.hasTaggedColumn("primary"); c != nil {		pkey = c	} else if c := t.hasColumn("Id"); c != nil {		pkey = c	}	return pkey}func (t *table) getRelations() map[relType][]relation {	return t.rels.rmap}func (t *table) getColumns() columns {	return t.cols}// hasTaggetColumn checks for a collumn tagget asfunc (t *table) hasTaggedColumn(ct string) *column {	for _, col := range t.cols {		if col.hasTag(ct) {			return &col		}	}	return nil}// hasColumn checks for a column by namefunc (t *table) hasColumn(c string) *column {	for _, col := range t.cols {		if col.ref == t.cFn(c) {			return &col		}	}	return nil}// addField from struct; both «relations» and «columns»// Communicates over a channel, to do relation mappingfunc (t *table) addField(f field, cbCh chan<- mapperCallback) {	if f.hasTags("omit", "-") {		return // Skip "omitted" and "dashed" fields	}	switch f.getType() {	case Relation:		// Make callback to itself, relations should be mapped after columns		cbCh <- mapperCallback{			from: t.getStructName(),			to:   t.getStructName(),			fn: func(self *table) {				// Get Primary Key				pkey := self.getPrimaryKey()				// Or at least try to				if pkey == nil {					return				}				// Predict related table name				rtbl := f.getFieldType()				// And check for tag				if tag, ok := f.getTag("table"); ok {					rtbl = tag				}				// Predict column name				cn := f.getFieldName() + "Id"				// And check for tag				if tag, ok := f.getTag("fkey"); ok {					cn = tag				}				/*					if self.getStructName() == "PlatformCalendar" {						fmt.Println(self.getStructName(), f.getFieldType(), cn)					}				*/				// Check if it contains reference itself				if c := self.hasColumn(cn); c != nil {					// Make a call to load related table into scope;					// we need its addr and must be loaded from mapper					cbCh <- mapperCallback{						from: self.getStructName(),						to:   rtbl,						fn: func(tbl *table) {							key := tbl.getPrimaryKey()							self.rels.addRelation(belongsTo, relation{tbl, f, *key, *c})						},					}				} else {					// Or predict column name in related table					cn = self.getStructName() + "Id"					// Check for reference tag					if tag, ok := f.getTag("ref"); ok {						cn = tag					}					// Make a callback to the related table to check for relationg					cbCh <- mapperCallback{						from: self.getStructName(),						to:   rtbl,						fn: func(tbl *table) {							// Check for relation on column mane							if c := tbl.hasColumn(cn); c != nil {								// Predict the relations is «hasOne»								has := hasOne								// Try to predict (or simply guess) with pluralization, if «hasMany»								if inflect.Pluralize(f.getFieldName()) == f.getFieldName() {									has = hasMany								}								// Override with tagging if specified								if tag, ok := f.getTag("has"); ok {									switch tag {									case "many":										has = hasMany									case "one":										has = hasOne									}								}								self.rels.addRelation(has, relation{tbl, f, *c, *pkey})							}						},					}				}				return			},		}	default: // Add column		switch f.getKind() {		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:			fallthrough // Support all Uint types		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:			fallthrough // Support all Int types		case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:			fallthrough // Support all Float and Complex types		case reflect.String, reflect.Bool:			// Support string and boolean			// Map column name			dbf := t.cFn(f.getFieldName())			// override with tagging			if tag, ok := f.getTag("field"); ok {				dbf = t.cFn(tag)			}			t.cols = append(t.cols, column{				f, dbf,			})		default:			fmt.Println(t.getStructName(), "not supporting", f)		}	}}// getType returns the reflect.Type of the «table»func (t *table) getType() reflect.Type {	return t.rt}// getValue returns the reflect.Value of the «table»func (t *table) getValue(ptr ...bool) reflect.Value {	if len(ptr) > 0 && ptr[0] {		return t.rv	}	return t.rv.Elem()}// isMapped returns true when columns is mapped// Not relations! They will be mapped in separate routinesfunc (t *table) isMapped() bool {	return t.mapped}// Lock read lockfunc (t *table) Lock() *table {	t.l.RLock()	return t}// Unlock read lockfunc (t *table) Unlock() {	t.l.RUnlock()}// lock write lockfunc (t *table) lock() *table {	t.l.Lock()	return t}// unlock write lockfunc (t *table) unlock() {	t.l.Unlock()}// getStructName returns the name of the structfunc (t *table) getStructName() string {	return t.getType().Name()}// getName returns the mapped table name// as identified in the databasefunc (t *table) getName(q bool) string {	if q {		return SqlFlavor.Quote(t.getName(false))	}	return t.tFn(t.getType().Name())}func (t *table) getNameAs(q bool) string {	return t.getName(q) + " AS " + t.getAlias(q)}func (t *table) getAlias(q bool) string {	if q {		return SqlFlavor.Quote(t.getAlias(false))	}	return t.getStructName()}// tables is simply a collection of tablestype tables map[string]*table
 |