fielder.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. package rest
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "reflect"
  7. "strings"
  8. "git.ali33.ru/fcg-xvii/go-tools/json"
  9. )
  10. type IRestFielder interface {
  11. RestFields(fieldName string, names FieldList) (any, IErrorArgs)
  12. }
  13. func FieldFromName(name string) *Field {
  14. return &Field{
  15. Name: name,
  16. }
  17. }
  18. func FieldFromIface(val any) *Field {
  19. res := &Field{}
  20. if m, check := json.IsMap(val); check {
  21. res.Name = strings.TrimSpace(m.String("name", ""))
  22. if names := m.Slice("fields", nil); len(names) > 0 {
  23. res.Names = FieldListFromSlice(names)
  24. }
  25. } else {
  26. if str, check := val.(string); check {
  27. res.Name = str
  28. }
  29. }
  30. return res
  31. }
  32. // Field реализует ...
  33. type Field struct {
  34. Name string
  35. Names FieldList
  36. }
  37. func (s *Field) IsEmpty() bool {
  38. return len(s.Name) == 0
  39. }
  40. func (s *Field) IsObject() bool {
  41. return len(s.Names) > 0
  42. }
  43. func (s *Field) String() string {
  44. res := "{ " + s.Name
  45. if len(s.Names) > 0 {
  46. res += " [ "
  47. l := make([]string, len(s.Names))
  48. for i, name := range s.Names {
  49. l[i] = name.String()
  50. }
  51. res += strings.Join(l, ", ")
  52. res += " ] "
  53. }
  54. res += " }"
  55. return res
  56. }
  57. //////////////////////////////////////////////
  58. func FieldListFromNames(names ...string) FieldList {
  59. res := make(FieldList, 0, len(names))
  60. for _, name := range names {
  61. res = append(res, FieldFromName(name))
  62. }
  63. return res
  64. }
  65. func FieldListFromSlice(f []any) FieldList {
  66. res := make(FieldList, 0, len(f))
  67. for _, v := range f {
  68. if fd := FieldFromIface(v); !fd.IsEmpty() {
  69. res = append(res, fd)
  70. }
  71. }
  72. return res
  73. }
  74. func FieldListFromObjects(f ...any) FieldList {
  75. return FieldListFromSlice(f)
  76. }
  77. type FieldList []*Field
  78. func (s FieldList) Field(name string) (*Field, bool) {
  79. for _, f := range s {
  80. if f.Name == name {
  81. return f, true
  82. }
  83. }
  84. return nil, false
  85. }
  86. // IFielder реализует интерфейс завершения формирования полей объекта в "ручном" режиме.
  87. // RestFields будет вызван после завершения автматического формирования полей объекта
  88. // result - массив с полями, сформированными автоматически, в него можно вносить правки
  89. // files - глобальный массив файловых дескрипторов, который будет передан в ответе клиенту
  90. type IFielderPost interface {
  91. RestFieldsPost(result json.Map, files map[string]IReadCloserLen, names FieldList)
  92. }
  93. type IFieldChecker interface {
  94. RestFieldCheck(fieldName string) bool
  95. }
  96. func fieldsDefault(t reflect.Type) (res FieldList) {
  97. for i := 0; i < t.NumField(); i++ {
  98. fType := t.Field(i)
  99. // проверяем тег, если он есть
  100. tag := fType.Tag.Get("rest")
  101. if len(tag) > 0 && (strings.Contains(tag, "default") || strings.Contains(tag, "fixed")) {
  102. res = append(
  103. res,
  104. &Field{
  105. Name: fType.Name,
  106. },
  107. )
  108. }
  109. }
  110. return
  111. }
  112. func fieldsFixed(t reflect.Type) (res FieldNamesList) {
  113. for i := 0; i < t.NumField(); i++ {
  114. fType := t.Field(i)
  115. // проверяем тег, если он есть
  116. tag := fType.Tag.Get("rest")
  117. if len(tag) > 0 && strings.Contains(tag, "fixed") {
  118. res = append(res, fType.Name)
  119. }
  120. }
  121. return
  122. }
  123. func parseName(val reflect.Value) (res *Field, err error) {
  124. switch val.Kind() {
  125. case reflect.String:
  126. return &Field{
  127. Name: val.String(),
  128. }, nil
  129. case reflect.Map:
  130. jm := make(json.Map)
  131. jmVal := reflect.ValueOf(jm)
  132. if !val.CanConvert(jmVal.Type()) {
  133. err = fmt.Errorf("expected map[string]any")
  134. }
  135. jm = val.Convert(jmVal.Type()).Interface().(json.Map)
  136. name := jm.String("name", "")
  137. if len(name) == 0 {
  138. err = fmt.Errorf("name is empty")
  139. return
  140. }
  141. fields := jm.Slice("names", nil)
  142. res = &Field{
  143. Name: name,
  144. Names: FieldListFromSlice(fields),
  145. }
  146. return
  147. default:
  148. err = fmt.Errorf("invalid request %s", val.Kind())
  149. }
  150. return
  151. }
  152. func StructTypeName(val reflect.Value) string {
  153. t := val.Type()
  154. return t.PkgPath() + "." + t.Name()
  155. }
  156. func fieldVal(val reflect.Value, fieldName string, files RequestFiles, names FieldList) (res reflect.Value, err IErrorArgs) {
  157. switch val.Kind() {
  158. case reflect.Ptr, reflect.Interface:
  159. return fieldVal(val.Elem(), fieldName, files, names)
  160. case reflect.Struct:
  161. // check fielder interface
  162. if f, check := val.Interface().(IRestFielder); check {
  163. rVal, err := f.RestFields(fieldName, names)
  164. if err != nil {
  165. return reflect.Value{}, err
  166. }
  167. return reflect.ValueOf(rVal), nil
  168. }
  169. // check fieler addr
  170. if val.CanAddr() {
  171. // check fielder interface
  172. if f, check := val.Addr().Interface().(IRestFielder); check {
  173. rVal, err := f.RestFields(fieldName, names)
  174. if err != nil {
  175. return reflect.Value{}, err
  176. }
  177. return reflect.ValueOf(rVal), nil
  178. }
  179. }
  180. // check public fields exists
  181. if val.NumField() == 0 {
  182. res = reflect.ValueOf(fmt.Sprint(val.Interface()))
  183. return
  184. }
  185. // parse struct public fields
  186. if len(names) == 0 {
  187. names = fieldsDefault(val.Type())
  188. }
  189. jm := json.Map{}
  190. addFieldVal := func(name *Field) bool {
  191. var field reflect.Value
  192. for i := 0; i < val.NumField(); i++ {
  193. f := val.Type().Field(i)
  194. if f.Name == name.Name {
  195. tag := f.Tag.Get("rest")
  196. if len(tag) > 0 && strings.Contains(tag, "ignore") {
  197. return true
  198. }
  199. field = val.Field(i)
  200. break
  201. }
  202. }
  203. if !field.IsValid() {
  204. // возвращаем true потому что поле может быть кастомным и объявлено позже, если объект реализовн как интерфейс RestFileldsPost
  205. return true
  206. }
  207. var fVal reflect.Value
  208. if fVal, err = fieldVal(
  209. field,
  210. fmt.Sprintf("%v.%v", fieldName, name.Name),
  211. files,
  212. name.Names,
  213. ); err != nil {
  214. return false
  215. }
  216. if fVal.IsValid() {
  217. stn := StructTypeName(field)
  218. con, check := fieldConverters[stn]
  219. if check {
  220. jm[name.Name] = con.Pack(field.Interface())
  221. } else {
  222. jm[name.Name] = fVal.Interface()
  223. }
  224. } else {
  225. jm[name.Name] = nil
  226. }
  227. return true
  228. }
  229. for _, name := range names {
  230. if !addFieldVal(name) {
  231. return
  232. }
  233. }
  234. // fields fixed
  235. fFixed := fieldsFixed(val.Type())
  236. for _, fixed := range fFixed {
  237. if !jm.KeyExists(fixed) {
  238. addFieldVal(FieldFromName(fixed))
  239. }
  240. }
  241. // post (когда результирующий объект уже сформирован)
  242. if fielder, check := val.Interface().(IFielderPost); check {
  243. fielder.RestFieldsPost(jm, files, names)
  244. } else if val.CanAddr() {
  245. if fielder, check := val.Addr().Interface().(IFielderPost); check {
  246. fielder.RestFieldsPost(jm, files, names)
  247. }
  248. }
  249. res = reflect.ValueOf(jm)
  250. return
  251. case reflect.Slice:
  252. sl := make([]any, val.Len())
  253. for i := 0; i < val.Len(); i++ {
  254. fName := fmt.Sprintf("%v[%v]", fieldName, i)
  255. var rVal reflect.Value
  256. rVal, err = fieldVal(
  257. val.Index(i),
  258. fName,
  259. files,
  260. names,
  261. )
  262. if err != nil {
  263. return
  264. }
  265. sl[i] = rVal.Interface()
  266. }
  267. res = reflect.ValueOf(sl)
  268. return
  269. case reflect.Map:
  270. res = reflect.MakeMap(val.Type())
  271. for _, key := range val.MapKeys() {
  272. fName := fmt.Sprintf("%v[%v]", fieldName, key.String())
  273. var rVal reflect.Value
  274. iVal := val.MapIndex(key)
  275. rVal, err = fieldVal(iVal, fName, files, nil)
  276. if err != nil {
  277. return
  278. }
  279. res.SetMapIndex(key, rVal)
  280. }
  281. return
  282. default:
  283. res = val
  284. return
  285. }
  286. }
  287. func FieldsAny(obj any, files RequestFiles, names FieldList) (any, IErrorArgs) {
  288. sVal := reflect.ValueOf(obj)
  289. rVal, err := fieldVal(sVal.Elem(), "", files, names)
  290. if err != nil {
  291. return nil, err
  292. }
  293. return rVal.Interface(), nil
  294. }
  295. // Fields позволяет получить значения объекта в json
  296. func Fields(obj any, files RequestFiles, names FieldList) (json.Map, IErrorArgs) {
  297. sVal := reflect.ValueOf(obj)
  298. log.Println(sVal)
  299. rVal, err := fieldVal(sVal.Elem(), "", files, names)
  300. if err != nil {
  301. return nil, err
  302. }
  303. res, check := rVal.Interface().(json.Map)
  304. if !check {
  305. return nil, ErrorMessage("ErrFields", "Empty object")
  306. }
  307. return res, nil
  308. }
  309. type FieldNamesList []string
  310. func (s FieldNamesList) Exists(name string) bool {
  311. for _, fName := range s {
  312. if fName == name {
  313. return true
  314. }
  315. }
  316. return false
  317. }
  318. // GetStructFields возвращает список полей структуры
  319. func FieldNames(s any) (FieldNamesList, error) {
  320. // Получаем тип и проверяем, что это структура
  321. t := reflect.TypeOf(s)
  322. if t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface {
  323. return FieldNames(reflect.ValueOf(s).Elem().Interface())
  324. } else if t.Kind() != reflect.Struct {
  325. return nil, errors.New("expected struct last type")
  326. }
  327. // Создаем срез для хранения имен полей
  328. var fields []string
  329. // Перебираем поля структуры
  330. for i := 0; i < t.NumField(); i++ {
  331. field := t.Field(i)
  332. fields = append(fields, field.Name)
  333. }
  334. return fields, nil
  335. }
  336. /////////////////////////////////////////////
  337. func OutFields(req IRequestIn, obj any, files RequestFiles, names FieldList) IRequestOut {
  338. if files == nil {
  339. files = make(RequestFiles)
  340. }
  341. if len(names) == 0 {
  342. names = req.Fields()
  343. }
  344. m, err := Fields(obj, files, names)
  345. if err != nil {
  346. return req.OutError(err)
  347. }
  348. return req.OutSuccess(m, files)
  349. }