object.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package domain
  2. import (
  3. "git.sxidc.com/go-framework/baize/framework/core/tag/check"
  4. "git.sxidc.com/go-tools/utils/reflectutils"
  5. "git.sxidc.com/go-tools/utils/strutils"
  6. "git.sxidc.com/go-tools/utils/template"
  7. "github.com/iancoleman/strcase"
  8. "github.com/pkg/errors"
  9. "reflect"
  10. )
  11. // Object 领域对象接口
  12. type Object interface {
  13. // DomainCNName 返回领域的中文名称
  14. DomainCNName() string
  15. // DomainCamelName 返回领域的大写驼峰式名称
  16. DomainCamelName() string
  17. }
  18. // HasField 校验领域对象中是否有某一个字段
  19. // 参数:
  20. // - object: 领域对象
  21. // - fieldName: 字段名
  22. // 返回值:
  23. // - 是否存在
  24. func HasField(object Object, fieldName string) bool {
  25. return hasField(object, fieldName)
  26. }
  27. // CheckField 校验领域对象某一字段的字段校验结果
  28. // 参数:
  29. // - result: 使用check.Struct返回的字段校验结果
  30. // - domainCNName: 领域中文名,可以使用DomainCNName()方法的返回值
  31. // - fieldName: 字段名
  32. // 返回值:
  33. // - 错误
  34. func CheckField(result check.Result, domainCNName string, fieldName string) error {
  35. err := result.CheckFields(fieldName)
  36. if err != nil {
  37. return errors.New(domainCNName + ": " + err.Error())
  38. }
  39. return nil
  40. }
  41. // CheckFields 校验领域对象多个字段的字段校验结果
  42. // 参数:
  43. // - result: 使用check.Struct返回的字段校验结果
  44. // - domainCNName: 领域中文名,可以使用DomainCNName()方法的返回值
  45. // - fieldNames: 多个字段名
  46. // 返回值:
  47. // - 错误
  48. func CheckFields(result check.Result, domainCNName string, fieldNames []string) error {
  49. err := result.CheckFields(fieldNames...)
  50. if err != nil {
  51. return errors.New(domainCNName + ":\n" + err.Error())
  52. }
  53. return nil
  54. }
  55. // SetField 设置领域对象对应字段的值
  56. // 类型参数:
  57. // - T: 字段值的类型
  58. // 参数:
  59. // - object: 领域对象
  60. // - fieldName: 要设置值的字段名
  61. // - value: 设置的值
  62. // 返回值:
  63. // - 错误
  64. func SetField[T any](object Object, fieldName string, value T) error {
  65. if object == nil {
  66. return errors.New("领域对象为nil")
  67. }
  68. fieldValue, err := getFieldValue(object, fieldName)
  69. if err != nil {
  70. return err
  71. }
  72. if !fieldValue.IsValid() || !fieldValue.CanSet() {
  73. return errors.New("领域对象" + fieldValue.Type().String() + "的字段" + fieldName + "无法赋值")
  74. }
  75. fieldValue.Set(reflect.ValueOf(value))
  76. return nil
  77. }
  78. // Field 获取领域对象对应字段的值
  79. // 类型参数:
  80. // - T: 字段值的类型
  81. // 参数:
  82. // - object: 领域对象
  83. // - fieldName: 要获取值的字段名
  84. // 返回值:
  85. // - 错误
  86. func Field[T any](object Object, fieldName string) (T, error) {
  87. zero := reflectutils.Zero[T]()
  88. if object == nil {
  89. return zero, errors.New("领域对象为nil")
  90. }
  91. fieldValue, err := getFieldValue(object, fieldName)
  92. if err != nil {
  93. return zero, err
  94. }
  95. if !fieldValue.IsValid() {
  96. return zero, errors.New("领域对象" + fieldValue.Type().String() + "的字段" + fieldName + "无法赋值")
  97. }
  98. retValue, ok := fieldValue.Interface().(T)
  99. if !ok {
  100. return zero, errors.New("转换字段类型失败")
  101. }
  102. return retValue, nil
  103. }
  104. // ToConcrete 将领域对象转换为具体类型
  105. // 类型参数:
  106. // - T: 要转换到的类型
  107. // 参数:
  108. // - object: 领域对象
  109. // 返回值:
  110. // - 转换出的类型
  111. // - 错误
  112. func ToConcrete[T Object](object Object) (T, error) {
  113. zero := reflectutils.Zero[T]()
  114. if object == nil {
  115. return zero, errors.New("领域对象为nil")
  116. }
  117. concrete, ok := object.(T)
  118. if !ok {
  119. return zero, errors.New("领域对象转化失败")
  120. }
  121. return concrete, nil
  122. }
  123. // TableName 基于领域对象生成表名,实际是将领域对象的驼峰式名称转换为蛇形复数形式,如classes
  124. // 参数:
  125. // - schema: 数据库的schema
  126. // - object: 领域对象
  127. // 返回值:
  128. // - 表名
  129. func TableName(schema string, object Object) string {
  130. if strutils.IsStringEmpty(schema) {
  131. return template.Plural(strcase.ToSnake(template.Id(object.DomainCamelName())))
  132. } else {
  133. return schema + "." + template.Plural(strcase.ToSnake(template.Id(object.DomainCamelName())))
  134. }
  135. }
  136. // RelationTableName 生成两个领域对象的关联表名,实际是将两个领域对象的驼峰式名称转换为蛇形并使用and连接,如:class_and_student
  137. // 参数:
  138. // - schema: 数据库的schema
  139. // - left: 左领域对象
  140. // - right: 右领域对象
  141. // 返回值:
  142. // - 关联表名
  143. func RelationTableName(schema string, left Object, right Object) string {
  144. if strutils.IsStringEmpty(schema) {
  145. return strcase.ToSnake(template.Id(left.DomainCamelName())) + "_and_" + strcase.ToSnake(template.Id(right.DomainCamelName()))
  146. } else {
  147. return schema + "." + strcase.ToSnake(template.Id(left.DomainCamelName())) + "_and_" + strcase.ToSnake(template.Id(right.DomainCamelName()))
  148. }
  149. }
  150. // ColumnName 生成对应字段的列名,实际为字段名转换为蛇形,如StudentNum会转化为student_num
  151. // 参数:
  152. // - fieldName: 字段名
  153. // 返回值:
  154. // - 列名
  155. func ColumnName(fieldName string) string {
  156. return strcase.ToSnake(template.Id(fieldName))
  157. }
  158. // RelationColumnName 基于领域对象生成关联列名,实际为字段名转换为蛇形后加_id,如Student生成的关联列名为student_id
  159. // 参数:
  160. // - object: 领域对象
  161. // 返回值:
  162. // - 关联列名
  163. func RelationColumnName(object Object) string {
  164. return strcase.ToSnake(template.Id(object.DomainCamelName())) + "_id"
  165. }
  166. // RelativeDomainPath 基于领域对象生成领域URL路径,实际为字段名转换为左小写驼峰式前面加/,如Student生成的领域URL路径为/student
  167. // 参数:
  168. // - object: 领域对象
  169. // 返回值:
  170. // - 领域URL路径
  171. func RelativeDomainPath(object Object) string {
  172. return "/" + strcase.ToLowerCamel(template.Id(object.DomainCamelName()))
  173. }
  174. // SnakeDomainName 基于领域对象生成蛇形领域名称,如Student生成的蛇形领域名称为/student
  175. // 参数:
  176. // - object: 领域对象
  177. // 返回值:
  178. // - 蛇形领域名称
  179. func SnakeDomainName(object Object) string {
  180. return strcase.ToSnake(template.Id(object.DomainCamelName()))
  181. }
  182. func hasField(object Object, fieldName string) bool {
  183. if object == nil {
  184. return false
  185. }
  186. objectValue := reflect.ValueOf(object)
  187. if !reflectutils.IsValueStructOrStructPointer(objectValue) {
  188. return false
  189. }
  190. fieldValue := reflectutils.PointerValueElem(objectValue).FieldByName(fieldName)
  191. if !fieldValue.IsValid() {
  192. return false
  193. }
  194. return true
  195. }
  196. func getFieldValue(object Object, fieldName string) (*reflect.Value, error) {
  197. if object == nil {
  198. return nil, errors.New("领域对象为nil")
  199. }
  200. objectValue := reflect.ValueOf(object)
  201. if !reflectutils.IsValueStructOrStructPointer(objectValue) {
  202. return nil, errors.New("领域对象必须是结构或结构指针")
  203. }
  204. fieldValue := reflectutils.PointerValueElem(objectValue).FieldByName(fieldName)
  205. return &fieldValue, nil
  206. }