table.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package orm
  2. import (
  3. "fmt"
  4. "math"
  5. "reflect"
  6. "strconv"
  7. "sync"
  8. "github.com/go-openapi/inflect"
  9. )
  10. type table struct {
  11. rt reflect.Type
  12. rv reflect.Value
  13. l *sync.RWMutex
  14. tFn, cFn MapperFn
  15. cols columns
  16. rels relations
  17. mapped bool
  18. }
  19. func (t *table) Make() MappableInterface {
  20. return reflect.New(t.getType()).Interface().(MappableInterface)
  21. }
  22. func (t *table) CallMethod(i MappableInterface, n string, args ...interface{}) ([]interface{}, error) {
  23. var ret []interface{}
  24. if t.getValue(true).MethodByName(n).IsValid() {
  25. fn := reflect.ValueOf(i).MethodByName(n)
  26. fnt := fn.Type()
  27. in := []reflect.Value{}
  28. if fnt.IsVariadic() && len(args) < (fnt.NumIn()-1) {
  29. return ret, fmt.Errorf("To few arguments to «%s». Got «%d», expected «%d»", n, len(args), fnt.NumIn()-1)
  30. } else if !fnt.IsVariadic() && len(args) != fnt.NumIn() {
  31. return ret, fmt.Errorf("To few arguments to «%s». Got «%d», expected «%d»", n, len(args), fnt.NumIn()-1)
  32. }
  33. for x := 0; x < len(args); x++ {
  34. var inType reflect.Type
  35. if fnt.IsVariadic() && x >= fnt.NumIn()-1 {
  36. inType = fnt.In(fnt.NumIn() - 1).Elem()
  37. } else {
  38. inType = fnt.In(x)
  39. }
  40. argv := reflect.ValueOf(args[x])
  41. if !argv.IsValid() || !argv.Type().ConvertibleTo(inType) {
  42. switch inType.Kind() {
  43. case
  44. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  45. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  46. var val uint64 = 0
  47. argx := args[x].([]uint8)
  48. for xi := len(argx) - 1; xi >= 0; xi-- {
  49. val += uint64(math.Pow(10, float64(len(argx)-xi-1))) * uint64(argx[xi]-'0')
  50. }
  51. args[x] = val
  52. return t.CallMethod(i, n, args...)
  53. case reflect.Float32, reflect.Float64:
  54. if val, err := strconv.ParseFloat(string(args[x].([]byte)), 64); err == nil {
  55. args[x] = val
  56. return t.CallMethod(i, n, args...)
  57. }
  58. case reflect.Complex64, reflect.Complex128:
  59. // Not implemented
  60. return ret, fmt.Errorf("Complex not implemented")
  61. }
  62. return ret, fmt.Errorf("Invalid argument to «%s». Got %s, expected %s", n, argv.String(), inType.String())
  63. }
  64. in = append(in, argv.Convert(inType))
  65. }
  66. var err error = nil
  67. out := fn.Call(in)[0:fnt.NumOut()]
  68. for _, val := range out {
  69. switch val.Kind() {
  70. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  71. ret = append(ret, val.Uint())
  72. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  73. ret = append(ret, val.Int())
  74. case reflect.Float32, reflect.Float64:
  75. ret = append(ret, val.Float())
  76. case reflect.String:
  77. ret = append(ret, val.String())
  78. case reflect.Interface:
  79. if !val.IsNil() && val.CanInterface() && val.Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {
  80. err = val.Interface().(error)
  81. }
  82. }
  83. }
  84. return ret, err
  85. }
  86. return ret, fmt.Errorf("Invalid method «%s» on «%s»", n, t.getType())
  87. }
  88. // getPrimaryKey tries to find primary key
  89. func (t *table) getPrimaryKey() *column {
  90. var pkey *column = nil
  91. if c := t.hasTaggedColumn("primary"); c != nil {
  92. pkey = c
  93. } else if c := t.hasColumn("Id"); c != nil {
  94. pkey = c
  95. }
  96. return pkey
  97. }
  98. func (t *table) getRelations() map[relType][]relation {
  99. return t.rels.rmap
  100. }
  101. func (t *table) getColumns() columns {
  102. return t.cols
  103. }
  104. // hasTaggetColumn checks for a collumn tagget as
  105. func (t *table) hasTaggedColumn(ct string) *column {
  106. for _, col := range t.cols {
  107. if col.hasTag(ct) {
  108. return &col
  109. }
  110. }
  111. return nil
  112. }
  113. // hasColumn checks for a column by name
  114. func (t *table) hasColumn(c string) *column {
  115. for _, col := range t.cols {
  116. if col.ref == t.cFn(c) {
  117. return &col
  118. }
  119. }
  120. return nil
  121. }
  122. // addField from struct; both «relations» and «columns»
  123. // Communicates over a channel, to do relation mapping
  124. func (t *table) addField(f field, cbCh chan<- mapperCallback) {
  125. if f.hasTags("omit", "-") {
  126. return // Skip "omitted" and "dashed" fields
  127. }
  128. switch f.getType() {
  129. case Relation:
  130. // Make callback to itself, relations should be mapped after columns
  131. cbCh <- mapperCallback{
  132. from: t.getStructName(),
  133. to: t.getStructName(),
  134. fn: func(self *table) {
  135. // Get Primary Key
  136. pkey := self.getPrimaryKey()
  137. // Or at least try to
  138. if pkey == nil {
  139. return
  140. }
  141. // Predict related table name
  142. rtbl := f.getFieldType()
  143. // And check for tag
  144. if tag, ok := f.getTag("table"); ok {
  145. rtbl = tag
  146. }
  147. // Predict column name
  148. cn := f.getFieldName() + "Id"
  149. // And check for tag
  150. if tag, ok := f.getTag("fkey"); ok {
  151. cn = tag
  152. }
  153. /*
  154. if self.getStructName() == "PlatformCalendar" {
  155. fmt.Println(self.getStructName(), f.getFieldType(), cn)
  156. }
  157. */
  158. // Check if it contains reference itself
  159. if c := self.hasColumn(cn); c != nil {
  160. // Make a call to load related table into scope;
  161. // we need its addr and must be loaded from mapper
  162. cbCh <- mapperCallback{
  163. from: self.getStructName(),
  164. to: rtbl,
  165. fn: func(tbl *table) {
  166. key := tbl.getPrimaryKey()
  167. self.rels.addRelation(belongsTo, relation{tbl, f, *key, *c})
  168. },
  169. }
  170. } else {
  171. // Or predict column name in related table
  172. cn = self.getStructName() + "Id"
  173. // Check for reference tag
  174. if tag, ok := f.getTag("ref"); ok {
  175. cn = tag
  176. }
  177. // Make a callback to the related table to check for relationg
  178. cbCh <- mapperCallback{
  179. from: self.getStructName(),
  180. to: rtbl,
  181. fn: func(tbl *table) {
  182. // Check for relation on column mane
  183. if c := tbl.hasColumn(cn); c != nil {
  184. // Predict the relations is «hasOne»
  185. has := hasOne
  186. // Try to predict (or simply guess) with pluralization, if «hasMany»
  187. if inflect.Pluralize(f.getFieldName()) == f.getFieldName() {
  188. has = hasMany
  189. }
  190. // Override with tagging if specified
  191. if tag, ok := f.getTag("has"); ok {
  192. switch tag {
  193. case "many":
  194. has = hasMany
  195. case "one":
  196. has = hasOne
  197. }
  198. }
  199. self.rels.addRelation(has, relation{tbl, f, *c, *pkey})
  200. }
  201. },
  202. }
  203. }
  204. return
  205. },
  206. }
  207. default: // Add column
  208. switch f.getKind() {
  209. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  210. fallthrough // Support all Uint types
  211. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  212. fallthrough // Support all Int types
  213. case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
  214. fallthrough // Support all Float and Complex types
  215. case reflect.String, reflect.Bool:
  216. // Support string and boolean
  217. // Map column name
  218. dbf := t.cFn(f.getFieldName())
  219. // override with tagging
  220. if tag, ok := f.getTag("field"); ok {
  221. dbf = t.cFn(tag)
  222. }
  223. t.cols = append(t.cols, column{
  224. f, dbf,
  225. })
  226. default:
  227. fmt.Println(t.getStructName(), "not supporting", f)
  228. }
  229. }
  230. }
  231. // getType returns the reflect.Type of the «table»
  232. func (t *table) getType() reflect.Type {
  233. return t.rt
  234. }
  235. // getValue returns the reflect.Value of the «table»
  236. func (t *table) getValue(ptr ...bool) reflect.Value {
  237. if len(ptr) > 0 && ptr[0] {
  238. return t.rv
  239. }
  240. return t.rv.Elem()
  241. }
  242. // isMapped returns true when columns is mapped
  243. // Not relations! They will be mapped in separate routines
  244. func (t *table) isMapped() bool {
  245. return t.mapped
  246. }
  247. // Lock read lock
  248. func (t *table) Lock() *table {
  249. t.l.RLock()
  250. return t
  251. }
  252. // Unlock read lock
  253. func (t *table) Unlock() {
  254. t.l.RUnlock()
  255. }
  256. // lock write lock
  257. func (t *table) lock() *table {
  258. t.l.Lock()
  259. return t
  260. }
  261. // unlock write lock
  262. func (t *table) unlock() {
  263. t.l.Unlock()
  264. }
  265. // getStructName returns the name of the struct
  266. func (t *table) getStructName() string {
  267. return t.getType().Name()
  268. }
  269. // getName returns the mapped table name
  270. // as identified in the database
  271. func (t *table) getName(q bool) string {
  272. if q {
  273. return SqlFlavor.Quote(t.getName(false))
  274. }
  275. return t.tFn(t.getType().Name())
  276. }
  277. func (t *table) getNameAs(q bool) string {
  278. return t.getName(q) + " AS " + t.getAlias(q)
  279. }
  280. func (t *table) getAlias(q bool) string {
  281. if q {
  282. return SqlFlavor.Quote(t.getAlias(false))
  283. }
  284. return t.getStructName()
  285. }
  286. // tables is simply a collection of tables
  287. type tables map[string]*table