Skip to content
Snippets Groups Projects
Commit 73c14d86 authored by Pavel Antonov's avatar Pavel Antonov :asterisk:
Browse files

Merge branch 'feature/PRXS-2766-MultilangSearch-SingleLocal' into 'master'

Добавлен метод для определения, является ли поле SingleLocale

See merge request perxis/perxis-go!307
parents 640758f8 cfde23af
Branches
Tags
No related merge requests found
Showing
with 375 additions and 73 deletions
...@@ -47,6 +47,8 @@ func TestEqualSchema(t *testing.T) { ...@@ -47,6 +47,8 @@ func TestEqualSchema(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
s2 := schema.New() s2 := schema.New()
err = json.Unmarshal(b, s2) err = json.Unmarshal(b, s2)
s1.ClearState()
s2.ClearState()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, s1.Field, s2.Field) require.Equal(t, s1.Field, s2.Field)
} }
......
...@@ -22,6 +22,27 @@ type FileParameters struct { ...@@ -22,6 +22,27 @@ type FileParameters struct {
func (p FileParameters) Type() field.Type { return p.t } func (p FileParameters) Type() field.Type { return p.t }
func (p *FileParameters) Clone(reset bool) field.Parameters { return p } func (p *FileParameters) Clone(reset bool) field.Parameters { return p }
func (p FileParameters) GetField(f *field.Field, name string) *field.Field {
var fld *field.Field
switch name {
case "id", "name", "mimeType", "url", "key":
fld = field.String()
case "size":
fld = field.Number(field.NumberFormatInt)
}
return f.SetFieldState(name, fld)
}
func (p FileParameters) ListFields(f *field.Field, filter ...field.FieldFilterFunc) []*field.Field {
return []*field.Field{
f.SetFieldState("id", field.String()),
f.SetFieldState("name", field.String()),
f.SetFieldState("mimeType", field.String()),
f.SetFieldState("size", field.Number(field.NumberFormatInt)),
f.SetFieldState("url", field.String()),
f.SetFieldState("key", field.String()),
}
}
type FileType struct { type FileType struct {
fs Files fs Files
...@@ -145,17 +166,6 @@ func (t *FileType) IsEmpty(v interface{}) bool { ...@@ -145,17 +166,6 @@ func (t *FileType) IsEmpty(v interface{}) bool {
return !ok || f.ID == "" return !ok || f.ID == ""
} }
func (p FileParameters) GetField(path string) (fld *field.Field) {
switch path {
case "id", "name", "mimeType", "url", "key":
return field.String()
case "size":
return field.Number(field.NumberFormatInt)
default:
return nil
}
}
func init() { func init() {
// По умолчанию без FS // По умолчанию без FS
// Если нужны подписанные URL, и загрузка на FS, нужно зарегистрировать корректный типа // Если нужны подписанные URL, и загрузка на FS, нужно зарегистрировать корректный типа
......
...@@ -72,6 +72,7 @@ func TestGetField(t *testing.T) { ...@@ -72,6 +72,7 @@ func TestGetField(t *testing.T) {
), ),
"arr", field.Array(field.Object("a", field.Time())), "arr", field.Array(field.Object("a", field.Time())),
) )
sch.ClearState()
tests := []struct { tests := []struct {
name string name string
......
...@@ -18,7 +18,6 @@ type ReferenceParameters struct { ...@@ -18,7 +18,6 @@ type ReferenceParameters struct {
} }
func (p ReferenceParameters) Type() field.Type { return &ReferenceType{} } func (p ReferenceParameters) Type() field.Type { return &ReferenceType{} }
func (p ReferenceParameters) Clone(reset bool) field.Parameters { func (p ReferenceParameters) Clone(reset bool) field.Parameters {
if p.AllowedCollections != nil { if p.AllowedCollections != nil {
cols := make([]string, 0, len(p.AllowedCollections)) cols := make([]string, 0, len(p.AllowedCollections))
...@@ -27,6 +26,10 @@ func (p ReferenceParameters) Clone(reset bool) field.Parameters { ...@@ -27,6 +26,10 @@ func (p ReferenceParameters) Clone(reset bool) field.Parameters {
} }
return &p return &p
} }
func (p ReferenceParameters) GetField(f *field.Field, name string) *field.Field { return nil }
func (p ReferenceParameters) ListFields(f *field.Field, filter ...field.FieldFilterFunc) []*field.Field {
return nil
}
type ReferenceType struct{} type ReferenceType struct{}
......
...@@ -22,6 +22,22 @@ func (p ArrayParameters) Clone(reset bool) Parameters { ...@@ -22,6 +22,22 @@ func (p ArrayParameters) Clone(reset bool) Parameters {
return &ArrayParameters{Item: p.Item.Clone(reset)} 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{} type ArrayType struct{}
func (ArrayType) Name() string { func (ArrayType) Name() string {
......
...@@ -12,6 +12,8 @@ type BoolParameters struct{} ...@@ -12,6 +12,8 @@ type BoolParameters struct{}
func (b BoolParameters) Type() Type { return boolType } func (b BoolParameters) Type() Type { return boolType }
func (b *BoolParameters) Clone(reset bool) Parameters { return b } func (b *BoolParameters) Clone(reset bool) Parameters { return b }
func (b BoolParameters) GetField(f *Field, name string) *Field { return nil }
func (b BoolParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
type BoolType struct{} type BoolType struct{}
......
...@@ -49,6 +49,17 @@ type Include struct { ...@@ -49,6 +49,17 @@ type Include struct {
Optional bool `json:"optional,omitempty"` Optional bool `json:"optional,omitempty"`
} }
// State - состояние поля времени выполнения
type State struct {
Name string
DataPath string
SchemaPath string
SingleLocale bool
Parent *Field
Inlined bool
HasInline bool
}
type Field struct { type Field struct {
Title string `json:"title,omitempty"` // Название поля (Например: name) Title string `json:"title,omitempty"` // Название поля (Например: name)
Description string `json:"description,omitempty"` // Описание поле (Например: User name) Description string `json:"description,omitempty"` // Описание поле (Например: User name)
...@@ -63,6 +74,7 @@ type Field struct { ...@@ -63,6 +74,7 @@ type Field struct {
Options Options `json:"options,omitempty"` // Дополнительные опции Options Options `json:"options,omitempty"` // Дополнительные опции
Condition string `json:"condition,omitempty"` // Условие отображения поля Condition string `json:"condition,omitempty"` // Условие отображения поля
AdditionalValues bool `json:"additional_values,omitempty"` // Разрешает дополнительные значения вне ограничений правил AdditionalValues bool `json:"additional_values,omitempty"` // Разрешает дополнительные значения вне ограничений правил
State *State `json:"-"` // Состояние поля времени выполнения
} }
// TODO: Replace with Named field??? // TODO: Replace with Named field???
...@@ -84,6 +96,32 @@ func NewField(params Parameters, opts ...interface{}) *Field { ...@@ -84,6 +96,32 @@ func NewField(params Parameters, opts ...interface{}) *Field {
return f return f
} }
// GetState возвращает состояние поля времени выполнения
func (f Field) GetState() *State {
return f.State
}
// ClearState очищает состояние поля и всех вложенных полей
//
// Схемы нельзя сравнивать с активным состоянием с помощью `reflect.DeepEqual` или `assert.Equal`.
// Предварительно нужно сделать `ClearState`.
// После очистки состояния полей не будут рассчитываться. Для повторного включения состояния используйте `EnableState`
func (f *Field) ClearState() *Field {
f.State = nil
for _, fld := range f.ListFields() {
fld.ClearState()
}
return f
}
// EnableState включает расчет состояния поля и всех вложенных полей
//
// Без включения состояния поля, невозможно получить доступ к данным времени выполнения
// schema.New включает состояние для схемы при создании
func (f *Field) EnableState() {
f.State = &State{}
}
func (f Field) GetType() Type { func (f Field) GetType() Type {
return f.Params.Type() return f.Params.Type()
} }
...@@ -164,6 +202,10 @@ func (f Field) SetSingleLocale(r bool) *Field { ...@@ -164,6 +202,10 @@ func (f Field) SetSingleLocale(r bool) *Field {
return &f return &f
} }
func (f Field) IsSingleLocale() bool {
return f.SingleLocale || (f.State != nil && f.State.SingleLocale)
}
func (f Field) SetIndexed(r bool) *Field { func (f Field) SetIndexed(r bool) *Field {
f.Indexed = r f.Indexed = r
return &f return &f
...@@ -257,46 +299,91 @@ func (f *Field) Prepare() error { ...@@ -257,46 +299,91 @@ func (f *Field) Prepare() error {
return nil return nil
} }
// GetField возвращает поле по строковому пути func (f *Field) SetFieldState(name string, fld *Field) *Field {
func (f *Field) GetField(path string) *Field { if f != nil && fld != nil && f.State != nil && fld.State == nil {
if path == "" { fld.State = f.getFieldState(name, fld)
switch params := f.Params.(type) { }
case *ArrayParameters: return fld
// Возвращаем поле Item если путь указан как "arr."
return params.Item
} }
// GetFieldState возвращает состояние вложенного поля
func (f *Field) getFieldState(name string, fld *Field) *State {
if f.State == nil {
return nil return nil
} }
state := State{
SchemaPath: name,
DataPath: name,
Name: name,
}
dataPath := f.State.DataPath
switch params := f.Params.(type) { switch params := f.Params.(type) {
case *ObjectParameters: case *ObjectParameters:
pp := strings.SplitN(path, FieldSeparator, 2) if params.Inline {
last := strings.LastIndex(dataPath, ".")
if last > 0 {
dataPath = dataPath[:last]
} else {
dataPath = ""
}
state.Inlined = true
}
if dataPath != "" {
state.DataPath = dataPath + FieldSeparator + state.DataPath
}
for k, v := range params.Fields { case *ArrayParameters:
state.DataPath = dataPath // Remove item from path
}
p, ok := v.Params.(*ObjectParameters) state.SingleLocale = f.IsSingleLocale() || fld.SingleLocale
if ok && p.Inline {
f := v.GetField(path) if f.State.SchemaPath != "" {
if f != nil { state.SchemaPath = f.State.SchemaPath + FieldSeparator + state.SchemaPath
return f
} }
state.Parent = f
state.HasInline = f.State.HasInline || state.Inlined
return &state
} }
if k == pp[0] { func (f *Field) GetFieldByName(name string) *Field {
if len(pp) == 1 { return f.Params.GetField(f, name)
return v }
// GetField возвращает поле по строковому пути
func (f *Field) GetField(path string) *Field {
name := ""
parts := strings.SplitN(path, FieldSeparator, 2)
if len(parts) > 0 {
name = parts[0]
} }
return v.GetField(pp[1])
fld := f.GetFieldByName(name)
if fld != nil && len(parts) > 1 {
return fld.GetField(parts[1])
} }
return fld
} }
case Fielder:
return params.GetField(path)
case *ArrayParameters: // ListFields возвращает массив вложенных полей данного поля
return params.Item.GetField(path) func (f *Field) ListFields(filter ...FieldFilterFunc) []*Field {
fields := f.Params.ListFields(f, filter...)
return fields
} }
return nil // ListFieldsRecursive возвращает массив всех вложенных полей рекурсивно
func (f *Field) ListFieldsRecursive(filter ...FieldFilterFunc) []*Field {
fields := f.ListFields(filter...)
for _, fld := range fields {
fields = append(fields, fld.ListFieldsRecursive(filter...)...)
}
return fields
} }
// GetFieldsPath возвращает полный путь для массива полей // GetFieldsPath возвращает полный путь для массива полей
...@@ -311,6 +398,8 @@ type FilterFunc func(*Field, string) bool ...@@ -311,6 +398,8 @@ type FilterFunc func(*Field, string) bool
func GetAll(field *Field, path string) bool { return true } func GetAll(field *Field, path string) bool { return true }
// GetFields возвращает массив полей с путем???
// DEPRECATED: использовать ListFields или ListFieldsRecursive
func (f *Field) GetFields(filterFunc FilterFunc, pathPrefix ...string) (res []PathField) { func (f *Field) GetFields(filterFunc FilterFunc, pathPrefix ...string) (res []PathField) {
var path string var path string
...@@ -382,22 +471,26 @@ func getFieldsObject(path string, params *ObjectParameters, filterFunc FilterFun ...@@ -382,22 +471,26 @@ func getFieldsObject(path string, params *ObjectParameters, filterFunc FilterFun
return res return res
} }
// GetNestedFields возвращает вложенные поля
// DEPRECATED: использовать ListFields
func (f *Field) GetNestedFields() []*Field { func (f *Field) GetNestedFields() []*Field {
switch params := f.Params.(type) { return f.ListFields()
case *ObjectParameters:
flds := make([]*Field, 0, len(params.Fields)) //switch params := f.Params.(type) {
for _, v := range params.Fields { //case *ObjectParameters:
if v == nil { // flds := make([]*Field, 0, len(params.Fields))
continue // for _, v := range params.Fields {
} // if v == nil {
flds = append(flds, v) // continue
} // }
return flds // flds = append(flds, v)
case *ArrayParameters: // }
return []*Field{params.Item} // return flds
} //case *ArrayParameters:
// return []*Field{params.Item}
return nil //}
//
//return nil
} }
// Clone создает копию поля // Clone создает копию поля
......
...@@ -61,6 +61,8 @@ func (f *Field) UnmarshalJSON(b []byte) error { ...@@ -61,6 +61,8 @@ func (f *Field) UnmarshalJSON(b []byte) error {
} }
} }
j.FieldData.State = f.State
*f = Field(j.FieldData) *f = Field(j.FieldData)
f.Params = params f.Params = params
_ = f.Prepare() _ = f.Prepare()
......
package field
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestField_GetField(t *testing.T) {
sch := Object(
"f1", Object(
"a", String(),
"b", String().SetSingleLocale(true),
),
"f3", Object( // inline object
true,
"a", String(),
"b", Object(true, "c", String()),
).SetSingleLocale(true),
"f4", Array(Object("a", String())),
"f5", Array(String()),
"f6", Object(true, "f6", Object("a", String())),
)
sch.EnableState()
tests := []struct {
name string
path string
want *State
}{
{"Object", "f1", &State{Name: "f1", DataPath: "f1", SchemaPath: "f1", Parent: sch}},
{"Object field", "f1.a", &State{Name: "a", DataPath: "f1.a", SchemaPath: "f1.a", Parent: sch.GetField("f1")}},
{"Field with SingleLocale", "f1.b", &State{Name: "b", DataPath: "f1.b", SchemaPath: "f1.b", Parent: sch.GetField("f1"), SingleLocale: true}},
{"Object with SingleLocale", "f3", &State{Name: "f3", DataPath: "f3", SchemaPath: "f3", Parent: sch, SingleLocale: true}},
{"Inline", "a", &State{Name: "a", DataPath: "a", SchemaPath: "f3.a", Parent: sch.GetField("f3"), SingleLocale: true, Inlined: true, HasInline: true}},
{"Inline of inline", "c", &State{Name: "c", DataPath: "c", SchemaPath: "f3.b.c", Parent: sch.GetField("f3.b"), SingleLocale: true, Inlined: true, HasInline: true}},
{"Inline of inline (direct)", "f3.b.c", &State{Name: "c", DataPath: "c", SchemaPath: "f3.b.c", Parent: sch.GetField("f3.b"), SingleLocale: true, Inlined: true, HasInline: true}},
{"Array of Objects", "f4", &State{Name: "f4", DataPath: "f4", SchemaPath: "f4", Parent: sch}},
{"Array of Objects (Item)", "f4.Item", &State{Name: "Item", DataPath: "f4", SchemaPath: "f4.Item", Parent: sch.GetField("f4")}},
{"Array of Objects (Item field)", "f4.Item.a", &State{Name: "a", DataPath: "f4.a", SchemaPath: "f4.Item.a", Parent: sch.GetField("f4.Item")}},
{"Array of Objects (Item field direct)", "f4.a", &State{Name: "a", DataPath: "f4.a", SchemaPath: "f4.Item.a", Parent: sch.GetField("f4.Item")}},
{"Array of Strings", "f5", &State{Name: "f5", DataPath: "f5", SchemaPath: "f5", Parent: sch}},
{"Array of Strings (Item)", "f5.Item", &State{Name: "Item", DataPath: "f5", SchemaPath: "f5.Item", Parent: sch.GetField("f5")}},
{"Inline Same name not found", "f6.a", nil},
{"Inline Same name (direct)", "f6.f6.a", &State{Name: "a", DataPath: "f6.a", SchemaPath: "f6.f6.a", Parent: sch.GetField("f6.f6"), HasInline: true}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := sch.GetField(tt.path)
var st *State
if got != nil {
st = got.State
}
assert.Equal(t, tt.want, st)
sch.ClearState()
sch.EnableState()
if got != nil {
assert.Nil(t, got.State)
}
})
}
}
func TestField_ListFieldsRecursive(t *testing.T) {
sch := Object(
"f1", Object(
"f1a", String(),
"f1b", String().SetSingleLocale(true),
),
"f2", String(),
"f3", Object( // inline object
true,
"f3a", String(),
"f3b", Object(true, "f3bc", String()),
).SetSingleLocale(true),
"f4", Array(Object("f4a", String())),
"f5", Array(String()),
"f6", Object(true, "f6", Object("f6a", String())),
)
sch.EnableState()
fields := sch.ListFieldsRecursive()
assert.Len(t, fields, 16)
for _, f := range fields {
assert.NotNil(t, f.State)
assert.NotEmpty(t, f.State.Name)
}
}
func TestField_CloneWithState(t *testing.T) {
f := Object("a", String())
fld := f.Clone(false)
assert.Nil(t, fld.State)
f.EnableState()
fld = f.Clone(false)
assert.NotNil(t, fld.State)
}
...@@ -16,6 +16,8 @@ type LocationParameters struct{} ...@@ -16,6 +16,8 @@ type LocationParameters struct{}
func (p LocationParameters) Type() Type { return locationType } func (p LocationParameters) Type() Type { return locationType }
func (p LocationParameters) Clone(reset bool) Parameters { return &LocationParameters{} } func (p LocationParameters) Clone(reset bool) Parameters { return &LocationParameters{} }
func (p LocationParameters) GetField(f *Field, name string) *Field { return nil }
func (p LocationParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
func (p LocationParameters) GetMongoIndexes(path string, f *Field) []mongo.IndexModel { func (p LocationParameters) GetMongoIndexes(path string, f *Field) []mongo.IndexModel {
var add, geo mongo.IndexModel var add, geo mongo.IndexModel
......
...@@ -24,6 +24,8 @@ type NumberParameters struct { ...@@ -24,6 +24,8 @@ type NumberParameters struct {
func (NumberParameters) Type() Type { return numberType } func (NumberParameters) Type() Type { return numberType }
func (p NumberParameters) Clone(reset bool) Parameters { return &p } func (p NumberParameters) Clone(reset bool) Parameters { return &p }
func (p NumberParameters) GetField(f *Field, name string) *Field { return nil }
func (p NumberParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
type NumberType struct{} type NumberType struct{}
......
...@@ -36,6 +36,39 @@ func (p ObjectParameters) Clone(reset bool) Parameters { ...@@ -36,6 +36,39 @@ func (p ObjectParameters) Clone(reset bool) Parameters {
return &p return &p
} }
func (p ObjectParameters) GetField(f *Field, name string) *Field {
// Поиск поля в текущем объекте
if fld, ok := p.Fields[name]; ok {
return f.SetFieldState(name, fld)
}
// Поиск поля во вложенных Inline объектах
for k, v := range p.Fields {
if p, ok := v.Params.(*ObjectParameters); ok {
if p.Inline {
v = f.SetFieldState(k, v)
if fld := v.GetFieldByName(name); fld != nil {
return fld
}
}
}
}
return nil
}
func (p ObjectParameters) ListFields(f *Field, filterFunc ...FieldFilterFunc) []*Field {
var fields []*Field
for k, fld := range p.Fields {
f.SetFieldState(k, fld)
if !ApplyFilterFunc(filterFunc, fld) {
continue
}
fields = append(fields, fld)
}
return fields
}
// IsInlineObject определяет являться ли поле name инлайн объектом // IsInlineObject определяет являться ли поле name инлайн объектом
func (p ObjectParameters) IsInlineObject(name string) bool { func (p ObjectParameters) IsInlineObject(name string) bool {
fld, ok := p.Fields[name] fld, ok := p.Fields[name]
......
...@@ -14,6 +14,8 @@ type PrimaryKeyParameters struct{} ...@@ -14,6 +14,8 @@ type PrimaryKeyParameters struct{}
func (p PrimaryKeyParameters) Type() Type { return primaryKeyType } func (p PrimaryKeyParameters) Type() Type { return primaryKeyType }
func (p *PrimaryKeyParameters) Clone(reset bool) Parameters { return p } func (p *PrimaryKeyParameters) Clone(reset bool) Parameters { return p }
func (p PrimaryKeyParameters) GetField(f *Field, name string) *Field { return nil }
func (p PrimaryKeyParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
type PrimaryKeyType struct{} type PrimaryKeyType struct{}
......
...@@ -12,6 +12,8 @@ type StringParameters struct{} ...@@ -12,6 +12,8 @@ type StringParameters struct{}
func (s StringParameters) Type() Type { return stringType } func (s StringParameters) Type() Type { return stringType }
func (s *StringParameters) Clone(reset bool) Parameters { return s } func (s *StringParameters) Clone(reset bool) Parameters { return s }
func (s StringParameters) GetField(f *Field, name string) *Field { return nil }
func (s StringParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
type StringType struct{} type StringType struct{}
......
...@@ -19,6 +19,8 @@ type TimeParameters struct { ...@@ -19,6 +19,8 @@ type TimeParameters struct {
func (p TimeParameters) Type() Type { return timeType } func (p TimeParameters) Type() Type { return timeType }
func (p TimeParameters) Clone(reset bool) Parameters { return &p } func (p TimeParameters) Clone(reset bool) Parameters { return &p }
func (p TimeParameters) GetField(f *Field, name string) *Field { return nil }
func (p TimeParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
func (p TimeParameters) GetLayout() string { func (p TimeParameters) GetLayout() string {
if p.Layout != "" { if p.Layout != "" {
......
...@@ -15,6 +15,8 @@ type TimestampParameters struct{} ...@@ -15,6 +15,8 @@ type TimestampParameters struct{}
func (t TimestampParameters) Type() Type { return timestampType } func (t TimestampParameters) Type() Type { return timestampType }
func (t *TimestampParameters) Clone(reset bool) Parameters { return t } func (t *TimestampParameters) Clone(reset bool) Parameters { return t }
func (t TimestampParameters) GetField(f *Field, name string) *Field { return nil }
func (t TimestampParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
type TimestampType struct{} type TimestampType struct{}
......
...@@ -10,10 +10,23 @@ var ( ...@@ -10,10 +10,23 @@ var (
registry sync.Map registry sync.Map
) )
type FieldFilterFunc func(f *Field) bool
func ApplyFilterFunc(filterFunc []FieldFilterFunc, fld *Field) bool {
for _, f := range filterFunc {
if !f(fld) {
return false
}
}
return true
}
// Parameters - интерфейс который должен реализовывать параметр конкретного типа // Parameters - интерфейс который должен реализовывать параметр конкретного типа
type Parameters interface { type Parameters interface {
Type() Type Type() Type
Clone(reset bool) Parameters Clone(reset bool) Parameters
GetField(f *Field, name string) *Field
ListFields(f *Field, filter ...FieldFilterFunc) []*Field
} }
// Type - тип поля, отвечает за получение, кодирование и декодирование параметров для данного типа // Type - тип поля, отвечает за получение, кодирование и декодирование параметров для данного типа
......
...@@ -16,6 +16,8 @@ type UnknownParameters struct { ...@@ -16,6 +16,8 @@ type UnknownParameters struct {
func (UnknownParameters) Type() Type { return unknownType } func (UnknownParameters) Type() Type { return unknownType }
func (p UnknownParameters) Clone(reset bool) Parameters { return &p } func (p UnknownParameters) Clone(reset bool) Parameters { return &p }
func (p UnknownParameters) GetField(f *Field, name string) *Field { return nil }
func (p UnknownParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
type UnknownType struct{} type UnknownType struct{}
......
...@@ -19,7 +19,9 @@ type Schema struct { ...@@ -19,7 +19,9 @@ type Schema struct {
} }
func New(kv ...interface{}) *Schema { func New(kv ...interface{}) *Schema {
return &Schema{Field: *field.Object(kv...)} s := &Schema{Field: *field.Object(kv...)}
s.Field.EnableState()
return s
} }
func NewFromField(f *field.Field) *Schema { func NewFromField(f *field.Field) *Schema {
...@@ -46,6 +48,11 @@ func (s *Schema) Clone(reset bool) *Schema { ...@@ -46,6 +48,11 @@ func (s *Schema) Clone(reset bool) *Schema {
} }
} }
func (s *Schema) ClearState() *Schema {
s.Field.ClearState()
return s
}
func (s *Schema) Equal(sch *Schema) bool { func (s *Schema) Equal(sch *Schema) bool {
if s == sch { if s == sch {
return true return true
...@@ -86,7 +93,10 @@ func (s *Schema) ConvertTypes() error { ...@@ -86,7 +93,10 @@ func (s *Schema) ConvertTypes() error {
if err != nil { if err != nil {
return errors.Wrap(err, "marshal schema") return errors.Wrap(err, "marshal schema")
} }
// сохраняем состояние cхемы
state := s.Field.State
*s = *New() *s = *New()
s.Field.State = state
return errors.Wrap(s.UnmarshalJSON(b), "unmarshal schema") return errors.Wrap(s.UnmarshalJSON(b), "unmarshal schema")
} }
......
...@@ -70,6 +70,8 @@ func TestSchema_UnmarshalJSON(t *testing.T) { ...@@ -70,6 +70,8 @@ func TestSchema_UnmarshalJSON(t *testing.T) {
if err := schema.UnmarshalJSON(tt.b); (err != nil) != tt.wantErr { if err := schema.UnmarshalJSON(tt.b); (err != nil) != tt.wantErr {
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
} }
schema.ClearState()
tt.want.ClearState()
assert.Equal(t, tt.want, schema) assert.Equal(t, tt.want, schema)
}) })
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment