diff --git a/pkg/expr/expr_test.go b/pkg/expr/expr_test.go index f8909daadd2af1854100982d7a81f3cf86692f42..7ae9d7e8b6276da558565b8bd30ebc629bfa32f0 100644 --- a/pkg/expr/expr_test.go +++ b/pkg/expr/expr_test.go @@ -1,11 +1,13 @@ package expr import ( + "context" "fmt" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestIsExpression(t *testing.T) { @@ -58,3 +60,75 @@ func TestIsExpression(t *testing.T) { }) } } + +type testEnvStruct struct { + ID string `expr:"id"` + Size int `expr:"size"` + Data interface{} `expr:"data"` +} + +func (s *testEnvStruct) Equal(other *testEnvStruct) bool { + return s.ID == other.ID +} + +func TestExpr_Example(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + exp string + env map[string]interface{} + wantErr bool + wantResult interface{} + }{ + { + name: "get field by expr tag", + exp: "s.id", + env: map[string]interface{}{"s": &testEnvStruct{ID: "id1"}}, + wantResult: "id1", + }, + { + name: "get field by field name", + exp: "s.ID", + env: map[string]interface{}{"s": &testEnvStruct{ID: "id1"}}, + wantResult: "id1", + }, + { + name: "get nested field", + exp: "m.s.size", + env: map[string]interface{}{"m": map[string]interface{}{"s": &testEnvStruct{Size: 1}}}, + wantResult: 1, + }, + { + name: "check field", + exp: "s.data.size < 100", + env: map[string]interface{}{"s": &testEnvStruct{Data: &testEnvStruct{Size: 0}}}, + wantResult: true, + }, + { + name: "use method", + exp: "s1.Equal(s2)", + env: map[string]interface{}{"s1": &testEnvStruct{ID: "id1"}, "s2": &testEnvStruct{ID: "id2"}}, + wantResult: false, + }, + { + name: "field not exists", + exp: "s.not_exists", + env: map[string]interface{}{"s": &testEnvStruct{}}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := Eval(ctx, tt.exp, tt.env) + if tt.wantErr { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tt.wantResult, result) + }) + } +} diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go index 1dde0f3795e303cac0a0499e30d68d84d6be1234..fe9b9cdcf6e007a8c56aec1e32d96dfe18f32110 100644 --- a/pkg/expr/mongo_test.go +++ b/pkg/expr/mongo_test.go @@ -76,6 +76,7 @@ func TestConvertToMongo(t *testing.T) { {"in", "In(s, [1,2,3])", nil, bson.M{"s": bson.M{"$in": []interface{}{1, 2, 3}}}, false}, {"in", "In(s, 1)", nil, bson.M{"s": bson.M{"$in": []interface{}{1}}}, false}, {"text search or id", "id", nil, nil, true}, + {"struct env", "db_item.id == env_item.id", map[string]interface{}{"env_item": &testEnvStruct{ID: "id1"}}, bson.M{"db_item.id": "id1"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/files/file.go b/pkg/files/file.go index 5700309d4e180d8a242eccc87bf8ed4581ff39bd..d2236b83368e3d5efc763fd6f7e53664e15cc827 100644 --- a/pkg/files/file.go +++ b/pkg/files/file.go @@ -16,13 +16,13 @@ const ( // File - описание файла РІ системе хранения perxis type File struct { - ID string `mapstructure:"id,omitempty" json:"id" expr:"id"` // Уникальный идентификатор файла РІ хранилище - Name string `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty" expr:"name"` // РРјСЏ файла - Size int `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty" expr:"size"` // Размер файла + ID string `mapstructure:"id,omitempty" json:"id" expr:"id"` // Уникальный идентификатор файла РІ хранилище + Name string `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty" expr:"name"` // РРјСЏ файла + Size int `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty" expr:"size"` // Размер файла MimeType string `mapstructure:"mimeType,omitempty" json:"mimeType" bson:"mimeType,omitempty" expr:"mime_type"` // Mime-type файла - URL string `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty" expr:"url"` // Адрес для загрузки файла - Key string `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty" expr:"key"` // Ключ для хранения файла РІ хранилище - File fs.File `mapstructure:"-" json:"-" bson:"-"` // Файл для загрузки(РёР· файловой системы) + URL string `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty" expr:"url"` // Адрес для загрузки файла + Key string `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty" expr:"key"` // Ключ для хранения файла РІ хранилище + File fs.File `mapstructure:"-" json:"-" bson:"-"` // Файл для загрузки(РёР· файловой системы) } func (f File) Clone() *File { diff --git a/pkg/files/file_test.go b/pkg/files/file_test.go index 14fb89ce8c054d57ea708a10eb27318b474ff99c..617bed4c09ef95ab58874d856a36c5584abd4589 100644 --- a/pkg/files/file_test.go +++ b/pkg/files/file_test.go @@ -1,9 +1,11 @@ package files import ( + "context" "testing" "text/template" + "git.perx.ru/perxis/perxis-go/pkg/expr" "github.com/stretchr/testify/require" ) @@ -55,3 +57,35 @@ func TestFile_SetURLWithTemplate(t *testing.T) { }) } } + +func TestFile_InExpr(t *testing.T) { + ctx := context.Background() + + tests := []struct { + exp string + env map[string]interface{} + wantResult interface{} + wantErr bool + }{ + {"f.id", map[string]interface{}{"f": &File{ID: "some_id"}}, "some_id", false}, + {"f.name", map[string]interface{}{"f": &File{Name: "some_name"}}, "some_name", false}, + {"f.size", map[string]interface{}{"f": &File{Size: 1}}, 1, false}, + {"f.mime_type", map[string]interface{}{"f": &File{MimeType: "some_mime_type"}}, "some_mime_type", false}, + {"f.url", map[string]interface{}{"f": &File{URL: "some_url"}}, "some_url", false}, + {"f.key", map[string]interface{}{"f": &File{Key: "some_key"}}, "some_key", false}, + {"f.not_exists", map[string]interface{}{"f": &File{}}, "", true}, + } + + for _, tt := range tests { + t.Run(tt.exp, func(t *testing.T) { + result, err := expr.Eval(ctx, tt.exp, tt.env) + if tt.wantErr { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tt.wantResult, result) + }) + } +} diff --git a/pkg/items/item.go b/pkg/items/item.go index 7c34d2bb3563b338d6c3cb0baf97c4e49f58b535..2e76469c7b0a63d4cddf4ad3cd74961f1932a458 100644 --- a/pkg/items/item.go +++ b/pkg/items/item.go @@ -398,6 +398,16 @@ func (i *Item) Get(field string) (any, error) { return i.getItemData(field) } +// Delete удаляет значение поля Data +func (i *Item) Delete(field string) error { + // Если data == nil, то нет необходимости выполнять удаление + if i.Data == nil { + return nil + } + + return data.Delete(field, i.Data) +} + // GetSystemField возвращает описание поля для системных аттрибутов Item func GetSystemField(fld string) (*field.Field, error) { switch fld { diff --git a/pkg/items/item_test.go b/pkg/items/item_test.go index fb54fc501f45281bbafd37983de3b8638d5692d4..dfcc16ee1c7b40441b5df54acc48a12b276669ca 100644 --- a/pkg/items/item_test.go +++ b/pkg/items/item_test.go @@ -25,6 +25,42 @@ func TestItem_Set(t *testing.T) { } +func TestItem_DeleteItemData(t *testing.T) { + tests := []struct { + name string + item *Item + field string + want map[string]any + wantErr assert.ErrorAssertionFunc + }{ + { + name: "Simple", + item: &Item{Data: map[string]any{"a": "b", "c": "d"}}, + field: "a", + want: map[string]any{"c": "d"}, + wantErr: assert.NoError, + }, + { + name: "Item data is nil", + item: &Item{Data: nil}, + field: "a", + want: nil, + wantErr: assert.NoError, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.item.Delete(tc.field) + assert.NoError(t, err) + if !tc.wantErr(t, err) { + return + } + assert.Equal(t, tc.want, tc.item.Data) + }) + } +} + func TestGetField(t *testing.T) { sch := schema.New( "a", field.String(), diff --git a/pkg/references/reference_test.go b/pkg/references/reference_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5e79de47ab96cc9e48b8ba0eb644f9519e9ee914 --- /dev/null +++ b/pkg/references/reference_test.go @@ -0,0 +1,41 @@ +package references + +import ( + "context" + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/expr" + "github.com/stretchr/testify/require" +) + +func TestReference_InExpr(t *testing.T) { + ctx := context.Background() + + tests := []struct { + exp string + env map[string]interface{} + wantResult interface{} + wantErr bool + }{ + {"r.id", map[string]interface{}{"r": &Reference{ID: "some_id"}}, "some_id", false}, + {"r.collection_id", map[string]interface{}{"r": &Reference{CollectionID: "some_coll_id"}}, "some_coll_id", false}, + {"r.disabled", map[string]interface{}{"r": &Reference{Disabled: true}}, true, false}, + {"r.String()", map[string]interface{}{"r": &Reference{ID: "id", CollectionID: "collID"}}, "collID.id", false}, + {"r1.Equal(r2)", map[string]interface{}{"r1": &Reference{"id", "collID", false}, "r2": &Reference{"id", "collID", false}}, true, false}, + {"r.IsValid()", map[string]interface{}{"r": &Reference{}}, false, false}, + {"r.not_exists", map[string]interface{}{"r": &Reference{}}, false, true}, + } + + for _, tt := range tests { + t.Run(tt.exp, func(t *testing.T) { + result, err := expr.Eval(ctx, tt.exp, tt.env) + if tt.wantErr { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tt.wantResult, result) + }) + } +}