struct.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. // Copyright 2018 Huan Du. All rights reserved.
  2. // Licensed under the MIT license that can be found in the LICENSE file.
  3. package sqlbuilder
  4. import (
  5. "bytes"
  6. "reflect"
  7. "strings"
  8. )
  9. var (
  10. // DBTag is the struct tag to describe the name for a field in struct.
  11. DBTag = "db"
  12. // FieldTag is the struct tag to describe the tag name for a field in struct.
  13. // Use "," to separate different tags.
  14. FieldTag = "fieldtag"
  15. // FieldOpt is the options for a struct field.
  16. // As db column can contain "," in theory, field options should be provided in a separated tag.
  17. FieldOpt = "fieldopt"
  18. )
  19. const (
  20. fieldOptWithQuote = "withquote"
  21. fieldOptOmitEmpty = "omitempty"
  22. )
  23. // Struct represents a struct type.
  24. //
  25. // All methods in Struct are thread-safe.
  26. // We can define a global variable to hold a Struct and use it in any goroutine.
  27. type Struct struct {
  28. Flavor Flavor
  29. structType reflect.Type
  30. fieldAlias map[string]string
  31. taggedFields map[string][]string
  32. quotedFields map[string]struct{}
  33. omitEmptyFields map[string]struct{}
  34. }
  35. // NewStruct analyzes type information in structValue
  36. // and creates a new Struct with all structValue fields.
  37. // If structValue is not a struct, NewStruct returns a dummy Sturct.
  38. func NewStruct(structValue interface{}) *Struct {
  39. t := reflect.TypeOf(structValue)
  40. t = dereferencedType(t)
  41. s := &Struct{
  42. Flavor: DefaultFlavor,
  43. }
  44. if t.Kind() != reflect.Struct {
  45. return s
  46. }
  47. s.structType = t
  48. s.fieldAlias = map[string]string{}
  49. s.taggedFields = map[string][]string{}
  50. s.quotedFields = map[string]struct{}{}
  51. s.omitEmptyFields = map[string]struct{}{}
  52. s.parse(t)
  53. return s
  54. }
  55. // For sets the default flavor of s.
  56. func (s *Struct) For(flavor Flavor) *Struct {
  57. s.Flavor = flavor
  58. return s
  59. }
  60. func (s *Struct) parse(t reflect.Type) {
  61. l := t.NumField()
  62. for i := 0; i < l; i++ {
  63. field := t.Field(i)
  64. if field.Anonymous {
  65. ft := dereferencedType(field.Type)
  66. s.parse(ft)
  67. continue
  68. }
  69. // Parse DBTag.
  70. dbtag := field.Tag.Get(DBTag)
  71. alias := dbtag
  72. if dbtag == "-" {
  73. continue
  74. }
  75. if dbtag == "" {
  76. alias = field.Name
  77. s.fieldAlias[field.Name] = field.Name
  78. } else {
  79. s.fieldAlias[dbtag] = field.Name
  80. }
  81. // Parse FieldTag.
  82. fieldtag := field.Tag.Get(FieldTag)
  83. tags := strings.Split(fieldtag, ",")
  84. for _, t := range tags {
  85. if t != "" {
  86. s.taggedFields[t] = append(s.taggedFields[t], alias)
  87. }
  88. }
  89. s.taggedFields[""] = append(s.taggedFields[""], alias)
  90. // Parse FieldOpt.
  91. fieldopt := field.Tag.Get(FieldOpt)
  92. opts := strings.Split(fieldopt, ",")
  93. for _, opt := range opts {
  94. switch opt {
  95. case fieldOptWithQuote:
  96. s.quotedFields[alias] = struct{}{}
  97. case fieldOptOmitEmpty:
  98. s.omitEmptyFields[alias] = struct{}{}
  99. }
  100. }
  101. }
  102. }
  103. // SelectFrom creates a new `SelectBuilder` with table name.
  104. // By default, all exported fields of the s are listed as columns in SELECT.
  105. //
  106. // Caller is responsible to set WHERE condition to find right record.
  107. func (s *Struct) SelectFrom(table string) *SelectBuilder {
  108. return s.SelectFromForTag(table, "")
  109. }
  110. // SelectFromForTag creates a new `SelectBuilder` with table name for a specified tag.
  111. // By default, all fields of the s tagged with tag are listed as columns in SELECT.
  112. //
  113. // Caller is responsible to set WHERE condition to find right record.
  114. func (s *Struct) SelectFromForTag(table string, tag string) *SelectBuilder {
  115. sb := s.Flavor.NewSelectBuilder()
  116. sb.From(table)
  117. if s.taggedFields == nil {
  118. return sb
  119. }
  120. fields, ok := s.taggedFields[tag]
  121. if ok {
  122. fields = s.quoteFields(fields)
  123. buf := &bytes.Buffer{}
  124. cols := make([]string, 0, len(fields))
  125. for _, field := range fields {
  126. buf.WriteString(table)
  127. buf.WriteRune('.')
  128. buf.WriteString(field)
  129. cols = append(cols, buf.String())
  130. buf.Reset()
  131. }
  132. sb.Select(cols...)
  133. } else {
  134. sb.Select("*")
  135. }
  136. return sb
  137. }
  138. // Update creates a new `UpdateBuilder` with table name.
  139. // By default, all exported fields of the s is assigned in UPDATE with the field values from value.
  140. // If value's type is not the same as that of s, Update returns a dummy `UpdateBuilder` with table name.
  141. //
  142. // Caller is responsible to set WHERE condition to match right record.
  143. func (s *Struct) Update(table string, value interface{}) *UpdateBuilder {
  144. return s.UpdateForTag(table, "", value)
  145. }
  146. // UpdateForTag creates a new `UpdateBuilder` with table name.
  147. // By default, all fields of the s tagged with tag is assigned in UPDATE with the field values from value.
  148. // If value's type is not the same as that of s, UpdateForTag returns a dummy `UpdateBuilder` with table name.
  149. //
  150. // Caller is responsible to set WHERE condition to match right record.
  151. func (s *Struct) UpdateForTag(table string, tag string, value interface{}) *UpdateBuilder {
  152. ub := s.Flavor.NewUpdateBuilder()
  153. ub.Update(table)
  154. if s.taggedFields == nil {
  155. return ub
  156. }
  157. fields, ok := s.taggedFields[tag]
  158. if !ok {
  159. return ub
  160. }
  161. v := reflect.ValueOf(value)
  162. v = dereferencedValue(v)
  163. if v.Type() != s.structType {
  164. return ub
  165. }
  166. quoted := s.quoteFields(fields)
  167. assignments := make([]string, 0, len(fields))
  168. for i, f := range fields {
  169. name := s.fieldAlias[f]
  170. val := v.FieldByName(name)
  171. if isEmptyValue(val) {
  172. if _, ok := s.omitEmptyFields[f]; ok {
  173. continue
  174. }
  175. } else {
  176. val = dereferencedValue(val)
  177. }
  178. data := val.Interface()
  179. assignments = append(assignments, ub.Assign(quoted[i], data))
  180. }
  181. ub.Set(assignments...)
  182. return ub
  183. }
  184. // InsertInto creates a new `InsertBuilder` with table name using verb INSERT INTO.
  185. // By default, all exported fields of s are set as columns by calling `InsertBuilder#Cols`,
  186. // and value is added as a list of values by calling `InsertBuilder#Values`.
  187. //
  188. // InsertInto never returns any error.
  189. // If the type of any item in value is not expected, it will be ignored.
  190. // If value is an empty slice, `InsertBuilder#Values` will not be called.
  191. func (s *Struct) InsertInto(table string, value ...interface{}) *InsertBuilder {
  192. return s.InsertIntoForTag(table, "", value...)
  193. }
  194. // InsertIgnoreInto creates a new `InsertBuilder` with table name using verb INSERT IGNORE INTO.
  195. // By default, all exported fields of s are set as columns by calling `InsertBuilder#Cols`,
  196. // and value is added as a list of values by calling `InsertBuilder#Values`.
  197. //
  198. // InsertIgnoreInto never returns any error.
  199. // If the type of any item in value is not expected, it will be ignored.
  200. // If value is an empty slice, `InsertBuilder#Values` will not be called.
  201. func (s *Struct) InsertIgnoreInto(table string, value ...interface{}) *InsertBuilder {
  202. return s.InsertIgnoreIntoForTag(table, "", value...)
  203. }
  204. // ReplaceInto creates a new `InsertBuilder` with table name using verb REPLACE INTO.
  205. // By default, all exported fields of s are set as columns by calling `InsertBuilder#Cols`,
  206. // and value is added as a list of values by calling `InsertBuilder#Values`.
  207. //
  208. // ReplaceInto never returns any error.
  209. // If the type of any item in value is not expected, it will be ignored.
  210. // If value is an empty slice, `InsertBuilder#Values` will not be called.
  211. func (s *Struct) ReplaceInto(table string, value ...interface{}) *InsertBuilder {
  212. return s.ReplaceIntoForTag(table, "", value...)
  213. }
  214. // buildColsAndValuesForTag uses ib to set exported fields tagged with tag as columns
  215. // and add value as a list of values.
  216. func (s *Struct) buildColsAndValuesForTag(ib *InsertBuilder, tag string, value ...interface{}) {
  217. if s.taggedFields == nil {
  218. return
  219. }
  220. fields, ok := s.taggedFields[tag]
  221. if !ok {
  222. return
  223. }
  224. vs := make([]reflect.Value, 0, len(value))
  225. for _, item := range value {
  226. v := reflect.ValueOf(item)
  227. v = dereferencedValue(v)
  228. if v.Type() == s.structType {
  229. vs = append(vs, v)
  230. }
  231. }
  232. if len(vs) == 0 {
  233. return
  234. }
  235. cols := make([]string, 0, len(fields))
  236. values := make([][]interface{}, len(vs))
  237. for _, f := range fields {
  238. cols = append(cols, f)
  239. name := s.fieldAlias[f]
  240. for i, v := range vs {
  241. data := v.FieldByName(name).Interface()
  242. values[i] = append(values[i], data)
  243. }
  244. }
  245. cols = s.quoteFields(cols)
  246. ib.Cols(cols...)
  247. for _, value := range values {
  248. ib.Values(value...)
  249. }
  250. }
  251. // InsertIntoForTag creates a new `InsertBuilder` with table name using verb INSERT INTO.
  252. // By default, exported fields tagged with tag are set as columns by calling `InsertBuilder#Cols`,
  253. // and value is added as a list of values by calling `InsertBuilder#Values`.
  254. //
  255. // InsertIntoForTag never returns any error.
  256. // If the type of any item in value is not expected, it will be ignored.
  257. // If value is an empty slice, `InsertBuilder#Values` will not be called.
  258. func (s *Struct) InsertIntoForTag(table string, tag string, value ...interface{}) *InsertBuilder {
  259. ib := s.Flavor.NewInsertBuilder()
  260. ib.InsertInto(table)
  261. s.buildColsAndValuesForTag(ib, tag, value...)
  262. return ib
  263. }
  264. // InsertIgnoreIntoForTag creates a new `InsertBuilder` with table name using verb INSERT IGNORE INTO.
  265. // By default, exported fields tagged with tag are set as columns by calling `InsertBuilder#Cols`,
  266. // and value is added as a list of values by calling `InsertBuilder#Values`.
  267. //
  268. // InsertIgnoreIntoForTag never returns any error.
  269. // If the type of any item in value is not expected, it will be ignored.
  270. // If value is an empty slice, `InsertBuilder#Values` will not be called.
  271. func (s *Struct) InsertIgnoreIntoForTag(table string, tag string, value ...interface{}) *InsertBuilder {
  272. ib := s.Flavor.NewInsertBuilder()
  273. ib.InsertIgnoreInto(table)
  274. s.buildColsAndValuesForTag(ib, tag, value...)
  275. return ib
  276. }
  277. // ReplaceIntoForTag creates a new `InsertBuilder` with table name using verb REPLACE INTO.
  278. // By default, exported fields tagged with tag are set as columns by calling `InsertBuilder#Cols`,
  279. // and value is added as a list of values by calling `InsertBuilder#Values`.
  280. //
  281. // ReplaceIntoForTag never returns any error.
  282. // If the type of any item in value is not expected, it will be ignored.
  283. // If value is an empty slice, `InsertBuilder#Values` will not be called.
  284. func (s *Struct) ReplaceIntoForTag(table string, tag string, value ...interface{}) *InsertBuilder {
  285. ib := s.Flavor.NewInsertBuilder()
  286. ib.ReplaceInto(table)
  287. s.buildColsAndValuesForTag(ib, tag, value...)
  288. return ib
  289. }
  290. // DeleteFrom creates a new `DeleteBuilder` with table name.
  291. //
  292. // Caller is responsible to set WHERE condition to match right record.
  293. func (s *Struct) DeleteFrom(table string) *DeleteBuilder {
  294. db := s.Flavor.NewDeleteBuilder()
  295. db.DeleteFrom(table)
  296. return db
  297. }
  298. // Addr takes address of all exported fields of the s from the value.
  299. // The returned result can be used in `Row#Scan` directly.
  300. func (s *Struct) Addr(value interface{}) []interface{} {
  301. return s.AddrForTag("", value)
  302. }
  303. // AddrForTag takes address of all fields of the s tagged with tag from the value.
  304. // The returned result can be used in `Row#Scan` directly.
  305. //
  306. // If tag is not defined in s in advance,
  307. func (s *Struct) AddrForTag(tag string, value interface{}) []interface{} {
  308. fields, ok := s.taggedFields[tag]
  309. if !ok {
  310. return nil
  311. }
  312. return s.AddrWithCols(fields, value)
  313. }
  314. // AddrWithCols takes address of all columns defined in cols from the value.
  315. // The returned result can be used in `Row#Scan` directly.
  316. func (s *Struct) AddrWithCols(cols []string, value interface{}) []interface{} {
  317. v := reflect.ValueOf(value)
  318. v = dereferencedValue(v)
  319. if v.Type() != s.structType {
  320. return nil
  321. }
  322. for _, c := range cols {
  323. if _, ok := s.fieldAlias[c]; !ok {
  324. return nil
  325. }
  326. }
  327. addrs := make([]interface{}, 0, len(cols))
  328. for _, c := range cols {
  329. name := s.fieldAlias[c]
  330. data := v.FieldByName(name).Addr().Interface()
  331. addrs = append(addrs, data)
  332. }
  333. return addrs
  334. }
  335. func (s *Struct) quoteFields(fields []string) []string {
  336. // Try best not to allocate new slice.
  337. if len(s.quotedFields) == 0 {
  338. return fields
  339. }
  340. needQuote := false
  341. for _, field := range fields {
  342. if _, ok := s.quotedFields[field]; ok {
  343. needQuote = true
  344. break
  345. }
  346. }
  347. if !needQuote {
  348. return fields
  349. }
  350. quoted := make([]string, 0, len(fields))
  351. for _, field := range fields {
  352. if _, ok := s.quotedFields[field]; ok {
  353. quoted = append(quoted, s.Flavor.Quote(field))
  354. } else {
  355. quoted = append(quoted, field)
  356. }
  357. }
  358. return quoted
  359. }
  360. func dereferencedType(t reflect.Type) reflect.Type {
  361. for k := t.Kind(); k == reflect.Ptr || k == reflect.Interface; k = t.Kind() {
  362. t = t.Elem()
  363. }
  364. return t
  365. }
  366. func dereferencedValue(v reflect.Value) reflect.Value {
  367. for k := v.Kind(); k == reflect.Ptr || k == reflect.Interface; k = v.Kind() {
  368. v = v.Elem()
  369. }
  370. return v
  371. }
  372. func isEmptyValue(value reflect.Value) bool {
  373. switch value.Kind() {
  374. case reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice:
  375. return value.IsNil()
  376. case reflect.Bool:
  377. return !value.Bool()
  378. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  379. return value.Int() == 0
  380. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  381. return value.Uint() == 0
  382. case reflect.String:
  383. return value.String() == ""
  384. case reflect.Float32, reflect.Float64:
  385. return value.Float() == 0
  386. }
  387. return false
  388. }