From b95b2da0bf0cf0d7be14cebecec3e89a58b22f58 Mon Sep 17 00:00:00 2001 From: ko_oler <kooler89@gmail.com> Date: Thu, 1 Feb 2024 14:51:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20marshall/unmarshall=20=D0=B4=D0=BB=D1=8F=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- id/json.go | 58 ++++++++++++++++- id/json_test.go | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ id/role.go | 2 +- 3 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 id/json_test.go diff --git a/id/json.go b/id/json.go index 04fa39fa..9c468ceb 100644 --- a/id/json.go +++ b/id/json.go @@ -1,3 +1,59 @@ package id -// TODO: Сохранение/чтение в JSON (в строку) +import ( + "encoding/json" + "reflect" + + jsoniter "github.com/json-iterator/go" +) + +var knownImplementations = []ID{ + &SpaceID{}, + &EnvironmentID{}, + &CollectionID{}, + &ClientID{}, + &RoleID{}, + &SchemaID{}, + &ItemID{}, + &RevisionID{}, + &FieldID{}, + &OrganizationID{}, + &ServiceID{}, + &UserID{}, +} + +type JSONID struct { + Value ID `json:"value"` +} + +func (t *JSONID) UnmarshalJSON(b []byte) error { + var data struct { + Type string + Value json.RawMessage + } + if err := jsoniter.Unmarshal(b, &data); err != nil { + return err + } + for _, knownImplementation := range knownImplementations { + if knownImplementation.Type() == data.Type { + knownType := reflect.TypeOf(knownImplementation) + target := reflect.New(knownType) + if err := jsoniter.Unmarshal(data.Value, target.Interface()); err != nil { + return err + } + t.Value = target.Elem().Interface().(ID) + return nil + } + } + return nil +} + +func (t *JSONID) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + Value any + }{ + Type: reflect.TypeOf(t.Value).String(), + Value: t.Value, + }) +} diff --git a/id/json_test.go b/id/json_test.go new file mode 100644 index 00000000..7974a13d --- /dev/null +++ b/id/json_test.go @@ -0,0 +1,163 @@ +package id + +import ( + "testing" + + jsoniter "github.com/json-iterator/go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestJSONID_MarshalJSON(t *testing.T) { + tests := []struct { + name string + Value ID + want string + }{ + { + name: Organization, + Value: &OrganizationID{OrganizationID: "1"}, + want: "/orgs/1", + }, + { + name: User, + Value: &UserID{UserID: "1"}, + want: "/users/1", + }, + { + name: Service, + Value: &ServiceID{ServiceID: "1"}, + want: "/services/1", + }, + { + name: Space, + Value: &SpaceID{SpaceID: "1"}, + want: "/spaces/1", + }, + { + name: Environment, + Value: &EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}, + want: "/spaces/1/envs/1", + }, + { + name: Client, + Value: &ClientID{ClientID: "1", SpaceID: SpaceID{SpaceID: "1"}}, + want: "/spaces/1/clients/1", + }, + { + name: Role, + Value: &RoleID{RoleID: "1", SpaceID: SpaceID{SpaceID: "1"}}, + want: "/spaces/1/roles/1", + }, + { + name: Collection, + Value: &CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}, + want: "/spaces/1/envs/1/cols/1", + }, + { + name: Schema, + Value: &SchemaID{SchemaID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}, + want: "/spaces/1/envs/1/schema/1", + }, + { + name: Item, + Value: &ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}, + want: "/spaces/1/envs/1/cols/1/items/1", + }, + { + name: Revision, + Value: &RevisionID{RevisionID: "1", ItemID: ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}}, + want: "/spaces/1/envs/1/cols/1/items/1/revs/1", + }, + { + name: Field, + Value: &FieldID{FieldName: "1", ItemID: ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}}, + want: "/spaces/1/envs/1/cols/1/items/1/fields/1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var j JSONID + j.Value = tt.Value + got, err := jsoniter.Marshal(&tt.Value) + require.NoError(t, err) + assert.Equalf(t, tt.want, string(got), "MarshalJSON()") + }) + } +} + +func TestJSONID_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + Value ID + b []byte + }{ + { + name: Organization, + Value: &OrganizationID{OrganizationID: "1"}, + b: []byte(`{"type": "organization", "value": "/orgs/1"}`), + }, + { + name: User, + Value: &UserID{UserID: "1"}, + b: []byte(`{"type": "user", "value": "/users/1"}`), + }, + { + name: Service, + Value: &ServiceID{ServiceID: "1"}, + b: []byte(`{"type": "service", "value": "/services/1"}`), + }, + { + name: Space, + Value: &SpaceID{SpaceID: "1"}, + b: []byte(`{"type": "space", "value": "/spaces/1"}`), + }, + { + name: Environment, + Value: &EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}, + b: []byte(`{"type": "environment", "value": "/spaces/1/envs/1"}`), + }, + { + name: Client, + Value: &ClientID{ClientID: "1", SpaceID: SpaceID{SpaceID: "1"}}, + b: []byte(`{"type": "client", "value": "/spaces/1/clients/1"}`), + }, + { + name: Role, + Value: &RoleID{RoleID: "1", SpaceID: SpaceID{SpaceID: "1"}}, + b: []byte(`{"type": "role", "value": "/spaces/1/roles/1"}`), + }, + { + name: Collection, + Value: &CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}, + b: []byte(`{"type": "collection", "value": "/spaces/1/envs/1/cols/1"}`), + }, + { + name: Schema, + Value: &SchemaID{SchemaID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}, + b: []byte(`{"type": "schema", "value": "/spaces/1/envs/1/schema/1"}`), + }, + { + name: Item, + Value: &ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}, + b: []byte(`{"type": "item", "value": "/spaces/1/envs/1/cols/1/items/1"}`), + }, + { + name: Revision, + Value: &RevisionID{RevisionID: "1", ItemID: ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}}, + b: []byte(`{"type": "revision", "value": "/spaces/1/envs/1/cols/1/items/1/revs/1"}`), + }, + { + name: Field, + Value: &FieldID{FieldName: "1", ItemID: ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}}, + b: []byte(`{"type": "field", "value": "/spaces/1/envs/1/cols/1/items/1/fields/1"}`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var j JSONID + require.NoError(t, j.UnmarshalJSON(tt.b)) + assert.Equal(t, j.Value, tt.Value) + }) + } +} diff --git a/id/role.go b/id/role.go index 273f5e1e..9dbfcd95 100644 --- a/id/role.go +++ b/id/role.go @@ -14,7 +14,7 @@ type RoleID struct { RoleID string `json:"role_id"` } -func (t *RoleID) Type() string { return Client } +func (t *RoleID) Type() string { return Role } func (t *RoleID) String() string { return Join(t.SpaceID.String(), RolesPrefix, t.RoleID) -- GitLab