package field import ( "context" "fmt" "reflect" "strconv" "git.perx.ru/perxis/perxis-go/pkg/errors" "github.com/hashicorp/go-multierror" ) var arrayType = &ArrayType{} type ArrayParameters struct { Item *Field `json:"item"` } func (ArrayParameters) Type() Type { return arrayType } func (p ArrayParameters) Clone(reset bool) Parameters { return &ArrayParameters{Item: p.Item.Clone(reset)} } func (a ArrayParameters) GetField(f *Field, name string) *Field { f.SetFieldState("Item", a.Item) if name == "" || name == "Item" { return a.Item } return a.Item.GetField(name) } func (a ArrayParameters) ListFields(f *Field, filterFunc ...FieldFilterFunc) []*Field { f.SetFieldState("Item", a.Item) return []*Field{a.Item} } type ArrayType struct{} func (ArrayType) Name() string { return "array" } func (ArrayType) NewParameters() Parameters { return &ArrayParameters{} } func (ArrayType) IsEmpty(v interface{}) bool { arr, _ := v.([]interface{}) // todo: нужно возвращать ошибку? return len(arr) == 0 } //func (ArrayType) Decode(ctx *Context.Context, field *Field, v interface{}) (interface{}, error) { // params, ok := field.Params.(*ArrayParameters) // if !ok { // return nil, errors.New("field parameters required") // } // // arr, ok := v.([]interface{}) // if !ok { // return nil, fmt.Errorf("[]interface{} required") // } // // m := make([]interface{}, 0, len(arr)) // // for _, i := range arr { // item, err := Decode(ctx, params.Item, i) // if err != nil { // return nil, err // } // m = append(m, item) // } // // return m, nil //} // //func (ArrayType) Encode(ctx *Context.Context, field *Field, v interface{}) (interface{}, error) { // params, ok := field.Params.(*ArrayParameters) // if !ok { // return nil, errors.New("field parameters required") // } // // arr, ok := v.([]interface{}) // if !ok { // return nil, fmt.Errorf("[]interface{} required") // } // // m := make([]interface{}, 0, len(arr)) // // for _, i := range arr { // item, err := params.Item.Encode(ctx, i) // if err != nil { // return nil, err // } // m = append(m, item) // } // // return m, nil //} //func (ArrayType) Validate(ctx *Context.Context, field *Field, v interface{}) error { // params, ok := field.Params.(*ArrayParameters) // if !ok { // return errors.New("field parameters required") // } // // m, ok := v.([]interface{}) // if !ok { // return errors.New("[]interface{} is required") // } // for _, i := range m { // err := params.Item.Validate(ctx, i) // if err != nil { // return err // } // } // return nil //} func (ArrayType) Walk(ctx context.Context, field *Field, v interface{}, fn WalkFunc, opts *WalkOptions) (interface{}, bool, error) { var changed bool params, ok := field.Params.(*ArrayParameters) if !ok { return nil, false, errors.New("field parameters required") } // В массиве нет в данных и не выполняется обход по схеме if !opts.WalkSchema && v == nil { return nil, false, nil } arr, ok := v.([]interface{}) if !ok && v != nil { return nil, false, fmt.Errorf("incorrect type: \"%s\", expected \"[]interface{}\"", reflect.ValueOf(v).Kind()) } // Выполняется обход по схеме if opts.WalkSchema && len(arr) == 0 { _, _, _ = params.Item.Walk(ctx, nil, fn, WalkOpts(opts)) return nil, false, nil } m := make([]interface{}, 0, len(arr)) var merr *multierror.Error for i, value := range arr { valueNew, valueChanged, err := params.Item.Walk(ctx, value, fn, WalkOpts(opts)) if err != nil { merr = multierror.Append(merr, errors.WithField(err, strconv.Itoa(i))) } if valueChanged { m = append(m, valueNew) changed = true } else { m = append(m, value) } } if merr != nil { merr.ErrorFormat = func(i []error) string { return fmt.Sprintf("%d error(s)", len(i)) } return nil, false, merr } return m, changed, nil } func Array(item *Field, o ...interface{}) *Field { return NewField(&ArrayParameters{Item: item}, o...) }