package rest_gorm import ( "fmt" "log" "reflect" "git.ali33.ru/fcg-xvii/go-tools/json" "git.ali33.ru/fcg-xvii/rest" "gorm.io/gorm" "gorm.io/gorm/clause" ) type List struct { Conditions rest.ConditionList `json:"Conditions" swagger:"items=$ref:rest.Condition"` Orders []*rest.Order `json:"Orders" swagger:"items=$ref:rest.Order"` Offset int `json:"Offset"` Limit int `json:"Limit"` } func (s *List) Prepare() { if s.Limit <= 0 || s.Limit > 20 { s.Limit = 20 } } func (s *List) Result(pg *gorm.DB, fields rest.FieldNamesList, res any) (count int64, err rest.IErrorArgs) { s.Prepare() for i, cond := range s.Conditions { if !cond.Logic.IsValid() { err = rest.ErrorFiled(cond.Field, "Unexpected logic") return } if !cond.Operator.IsValid() { err = rest.ErrorFiled(cond.Field, "Unexpected operator") return } if !fields.Exists(cond.Field) { err = rest.ErrorFiled(cond.Field, "Unexpected field") return } if cond.Value != nil { q := fmt.Sprintf("%s %s ?", CamelToSnake(cond.Field), cond.Operator) if i == 0 || cond.Logic == rest.LogicAND { pg = pg.Where(q, cond.Value) } else { pg = pg.Or(q, cond.Value) } } else { if cond.Operator != "" && cond.Operator != rest.OperatorNot { err = rest.ErrorFiled(cond.Field, "Expected empty operator or not") } q := fmt.Sprintf("%s is %s null", CamelToSnake(cond.Field), cond.Operator) if i == 0 || cond.Logic == rest.LogicAND { pg = pg.Where(q) } else { pg = pg.Or(q) } } } // count if dbRes := pg.Count(&count); dbRes.Error != nil { err = rest.ErrorFiled("ErrDB", dbRes.Error.Error()) return } // offset limit pg = pg.Offset(s.Offset).Limit(s.Limit) // orders for _, order := range s.Orders { pg = pg.Order( clause.OrderByColumn{ Column: clause.Column{ Name: CamelToSnake(order.Name), }, Desc: !order.IsAsc, }, ) } if pg = pg.Find(res); pg.Error != nil { err = rest.ErrorFiled("ErrDB", pg.Error.Error()) return } log.Println(res) return } func toAnySlice(slice any) []any { v := reflect.ValueOf(slice) log.Println("kk", v.Kind()) if v.Kind() == reflect.Ptr { v = v.Elem() } // Check if the input is a slice if v.Kind() != reflect.Slice { return nil } result := make([]any, v.Len()) for i := 0; i < v.Len(); i++ { result[i] = v.Index(i).Interface() } return result } func (s *List) ResultAnswer(pg *gorm.DB, fields rest.FieldNamesList, res any, offset, limit int) (*ResultList, rest.IErrorArgs) { count, err := s.Result(pg, fields, res) if err != nil { return nil, err } log.Println("---", res) rList := &ResultList{ Items: toAnySlice(res), Offset: offset, Limit: limit, Count: count, } return rList, nil } func (s *List) ResultOut(pg *gorm.DB, model any, req rest.IRequestIn) rest.IRequestOut { fieldNames, err := rest.FieldNames(model) if err != nil { return req.OutError(rest.ErrorMessage("ErrFileds", err.Error())) } // preload if pg, err = Preload(model, req.Fields(), pg); err != nil { return req.OutError(rest.ErrorMessage("ErrPreload", err.Error())) } // Определяем тип элемента напрямую без использования reflect.ValueOf elemType := reflect.TypeOf(model) log.Println(elemType) // Создаем срез нужного типа sl := reflect.MakeSlice(reflect.SliceOf(elemType), 0, 0) // Создаем указатель на этот срез slPtr := reflect.New(sl.Type()) // Устанавливаем значение созданного среза в указатель slPtr.Elem().Set(sl) // Передаем указатель на срез return s.ResultOutNames(pg, fieldNames, slPtr.Interface(), req) } func (s *List) ResultOutNames(pg *gorm.DB, fields rest.FieldNamesList, res any, req rest.IRequestIn) rest.IRequestOut { rList, err := s.ResultAnswer(pg, fields, res, s.Offset, s.Limit) if err != nil { return req.OutError(err) } return rList.Out(req) } type ResultList struct { Items []any `json:"Items" rest:"fixed"` Offset int `json:"Offset" rest:"fixed"` Limit int `json:"Limit" rest:"fixed"` Count int64 `json:"Count" rest:"fixed"` } func (s *ResultList) Map(req rest.IRequestIn) (json.Map, rest.IErrorArgs) { fields := req.Fields() ml := make([]json.Map, 0, len(s.Items)) for _, item := range s.Items { it, ierr := rest.Fields(item, nil, fields) if ierr != nil { return nil, ierr } ml = append(ml, it) } res := json.Map{ "Items": ml, "Offset": s.Offset, "Limit": s.Limit, "Count": s.Count, } return res, nil } func (s *ResultList) Out(req rest.IRequestIn) rest.IRequestOut { m, ierr := s.Map(req) if ierr != nil { return req.OutError(ierr) } return req.OutSuccess(m, nil) }