From c542d56b190048ce028791e21673bc7cd20a0b1f Mon Sep 17 00:00:00 2001
From: ko_oler <kooler89@gmail.com>
Date: Mon, 5 Feb 2024 15:59:37 +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=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?=
 =?UTF-8?q?=D0=B0=20bson?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 id/bson.go         |  40 +++++++++
 id/bson_test.go    | 200 +++++++++++++++++++++++++++++++++++++++++++++
 id/client.go       |   2 +-
 id/collection.go   |   2 +-
 id/environment.go  |   2 +-
 id/field.go        |   2 +-
 id/id.go           |   2 +-
 id/item.go         |   2 +-
 id/json_test.go    |   5 +-
 id/organization.go |   2 +-
 id/revision.go     |   2 +-
 id/role.go         |   2 +-
 id/schema.go       |   2 +-
 id/service.go      |   2 +-
 id/space.go        |   2 +-
 id/user.go         |   2 +-
 16 files changed, 255 insertions(+), 16 deletions(-)
 create mode 100644 id/bson.go
 create mode 100644 id/bson_test.go

diff --git a/id/bson.go b/id/bson.go
new file mode 100644
index 00000000..8f8cae7d
--- /dev/null
+++ b/id/bson.go
@@ -0,0 +1,40 @@
+package id
+
+import (
+	"fmt"
+
+	"git.perx.ru/perxis/perxis-go/pkg/errors"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/bsonrw"
+	"go.mongodb.org/mongo-driver/bson/bsontype"
+)
+
+//func (id *ID) MarshalBSON() ([]byte, error) {
+//	return bson.Marshal(id.String())
+//}
+
+func (id *ID) MarshalBSONValue() (bsontype.Type, []byte, error) {
+	data := id.String()
+	return bson.MarshalValue(data)
+}
+
+func (id *ID) UnmarshalBSONValue(btype bsontype.Type, data []byte) error {
+	if btype != bson.TypeString {
+		return errors.New("cannot unmarshal non-string bson value to MyTime")
+	}
+	dec, err := bson.NewDecoder(bsonrw.NewBSONValueReader(btype, data))
+	if err != nil {
+		return err
+	}
+	fmt.Println(string(data))
+	var str string
+	if err = dec.Decode(&str); err != nil {
+		return err
+	}
+	t, err := Parse(str)
+	if err != nil {
+		return err
+	}
+	*id = *t
+	return nil
+}
diff --git a/id/bson_test.go b/id/bson_test.go
new file mode 100644
index 00000000..112eab72
--- /dev/null
+++ b/id/bson_test.go
@@ -0,0 +1,200 @@
+package id
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"go.mongodb.org/mongo-driver/bson"
+)
+
+func TestID_MarshalBSON(t *testing.T) {
+	tests := []struct {
+		name string
+		id   ID
+		want string
+	}{
+		{
+			name: "OrganizationID",
+			id:   ID{Descriptor: &OrganizationID{OrganizationID: "1"}},
+			want: `"/orgs/1"`,
+		},
+		{
+			name: "UserID",
+			id:   ID{Descriptor: &UserID{UserID: "1"}},
+			want: `"/users/1"`,
+		},
+		{
+			name: "ServiceID",
+			id:   ID{Descriptor: &ServiceID{ServiceID: "1"}},
+			want: `"/services/1"`,
+		},
+		{
+			name: "SpaceID",
+			id:   ID{Descriptor: &SpaceID{SpaceID: "1"}},
+			want: `"/spaces/1"`,
+		},
+		{
+			name: "EnvironmentID",
+			id:   ID{Descriptor: &EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}},
+			want: `"/spaces/1/envs/1"`,
+		},
+		{
+			name: "ClientID",
+			id:   ID{Descriptor: &ClientID{ClientID: "1", SpaceID: SpaceID{SpaceID: "1"}}},
+			want: `"/spaces/1/clients/1"`,
+		},
+		{
+			name: "RoleID",
+			id:   ID{Descriptor: &RoleID{RoleID: "1", SpaceID: SpaceID{SpaceID: "1"}}},
+			want: `"/spaces/1/roles/1"`,
+		},
+		{
+			name: "CollectionID",
+			id:   ID{Descriptor: &CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}},
+			want: `"/spaces/1/envs/1/cols/1"`,
+		},
+		{
+			name: "SchemaID",
+			id:   ID{Descriptor: &SchemaID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}},
+			want: `"/spaces/1/envs/1/schema/1"`,
+		},
+		{
+			name: "ItemID",
+			id:   ID{Descriptor: &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: "RevisionID",
+			id:   ID{Descriptor: &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: "FieldID",
+			id:   ID{Descriptor: &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) {
+			got, err := bson.Marshal(tt.id)
+			require.NoError(t, err)
+			assert.Equal(t, tt.want, string(got))
+		})
+	}
+}
+
+func TestID_UnmarshalBSON(t *testing.T) {
+	tests := []struct {
+		id   string
+		want ID
+		b    []byte
+	}{
+		{
+			id:   "OrganizationID",
+			want: ID{Descriptor: &OrganizationID{OrganizationID: "1"}},
+			b:    []byte(`"/orgs/1"`),
+		},
+		{
+			id:   "UserID",
+			want: ID{Descriptor: &UserID{UserID: "1"}},
+			b:    []byte(`"/users/1"`),
+		},
+		{
+			id:   "ServiceID",
+			want: ID{Descriptor: &ServiceID{ServiceID: "1"}},
+			b:    []byte(`"/services/1"`),
+		},
+		{
+			id:   "SpaceID",
+			want: ID{Descriptor: &SpaceID{SpaceID: "1"}},
+			b:    []byte(`"/spaces/1"`),
+		},
+		{
+			id:   "EnvironmentID",
+			want: ID{Descriptor: &EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}},
+			b:    []byte(`"/spaces/1/envs/1"`),
+		},
+		{
+			id:   "ClientID",
+			want: ID{Descriptor: &ClientID{ClientID: "1", SpaceID: SpaceID{SpaceID: "1"}}},
+			b:    []byte(`"/spaces/1/clients/1"`),
+		},
+		{
+			id:   "RoleID",
+			want: ID{Descriptor: &RoleID{RoleID: "1", SpaceID: SpaceID{SpaceID: "1"}}},
+			b:    []byte(`"/spaces/1/roles/1"`),
+		},
+		{
+			id:   "CollectionID",
+			want: ID{Descriptor: &CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}},
+			b:    []byte(`"/spaces/1/envs/1/cols/1"`),
+		},
+		{
+			id:   "SchemaID",
+			want: ID{Descriptor: &SchemaID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}},
+			b:    []byte(`"/spaces/1/envs/1/schema/1"`),
+		},
+		{
+			id:   "ItemID",
+			want: ID{Descriptor: &ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}},
+			b:    []byte(`"/spaces/1/envs/1/cols/1/items/1"`),
+		},
+		{
+			id:   "RevisionID",
+			want: ID{Descriptor: &RevisionID{RevisionID: "1", ItemID: ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}}},
+			b:    []byte(`"/spaces/1/envs/1/cols/1/items/1/revs/1"`),
+		},
+		{
+			id:   "FieldID",
+			want: ID{Descriptor: &FieldID{FieldName: "1", ItemID: ItemID{ItemID: "1", CollectionID: CollectionID{CollectionID: "1", EnvironmentID: EnvironmentID{EnvironmentID: "1", SpaceID: SpaceID{SpaceID: "1"}}}}}},
+			b:    []byte(`"/spaces/1/envs/1/cols/1/items/1/fields/1"`),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.id, func(t *testing.T) {
+			var i ID
+
+			//require.NoError(t, i.UnmarshalBSON(tt.b))
+			assert.Equal(t, tt.want, i)
+		})
+	}
+}
+
+func TestID_BSON(t *testing.T) {
+	type data struct {
+		ID     *ID
+		Text   string
+		Number int
+	}
+
+	test1 := &data{
+		ID:     &ID{Descriptor: &SpaceID{SpaceID: Space}},
+		Text:   "text",
+		Number: 1,
+	}
+
+	b, err := bson.Marshal(test1)
+	require.NoError(t, err)
+	str := string(b)
+	_ = str
+
+	test2 := new(data)
+	err = bson.Unmarshal(b, &test2)
+	require.NoError(t, err)
+	assert.Equal(t, test1, test2, "после Unmarshal объект должен совпадать с исходным")
+
+	test1 = &data{
+		ID:     &ID{Descriptor: &OrganizationID{OrganizationID: Organization}},
+		Text:   "text2",
+		Number: 2,
+	}
+
+	b, err = bson.Marshal(test1)
+	require.NoError(t, err)
+
+	test2 = new(data)
+	err = bson.Unmarshal(b, &test2)
+	require.NoError(t, err)
+	assert.Equal(t, test1, test2, "после Unmarshal объект должен совпадать с исходным")
+}
diff --git a/id/client.go b/id/client.go
index 623ef05c..ed730d32 100644
--- a/id/client.go
+++ b/id/client.go
@@ -7,7 +7,7 @@ const (
 
 type ClientID struct {
 	SpaceID
-	ClientID string `json:"client_id"`
+	ClientID string `json:"client_id,omitempty" bson:"client_id,omitempty"`
 }
 
 func (t *ClientID) Type() string { return Client }
diff --git a/id/collection.go b/id/collection.go
index 26057019..9829c7e6 100644
--- a/id/collection.go
+++ b/id/collection.go
@@ -7,7 +7,7 @@ const (
 
 type CollectionID struct {
 	EnvironmentID
-	CollectionID string `json:"col_id"`
+	CollectionID string `json:"col_id,omitempty" bson:"col_id, omitempty"`
 }
 
 func (t *CollectionID) Type() string { return Collection }
diff --git a/id/environment.go b/id/environment.go
index f1bbb540..e2acdb61 100644
--- a/id/environment.go
+++ b/id/environment.go
@@ -7,7 +7,7 @@ const (
 
 type EnvironmentID struct {
 	SpaceID
-	EnvironmentID string `json:"env_id"`
+	EnvironmentID string `json:"env_id,omitempty" bson:"env_id,omitempty"`
 }
 
 func (t *EnvironmentID) Type() string { return Environment }
diff --git a/id/field.go b/id/field.go
index dbba11d7..e0336141 100644
--- a/id/field.go
+++ b/id/field.go
@@ -7,7 +7,7 @@ const (
 
 type FieldID struct {
 	ItemID
-	FieldName string `json:"field_name"`
+	FieldName string `json:"field_name,omitempty" bson:"field_name,omitempty"`
 }
 
 func (t *FieldID) Type() string { return Field }
diff --git a/id/id.go b/id/id.go
index d333b618..f580c52f 100644
--- a/id/id.go
+++ b/id/id.go
@@ -124,7 +124,7 @@ func (id *ID) FromMap(m map[string]any) error {
 	case Field:
 		id.Descriptor = new(FieldID)
 	default:
-		return errors.New("type of ID not specified in map")
+		return errors.New("unknown type")
 	}
 	_ = id.Descriptor.FromMap(m)
 	return nil
diff --git a/id/item.go b/id/item.go
index d32f0ccc..add303f6 100644
--- a/id/item.go
+++ b/id/item.go
@@ -7,7 +7,7 @@ const (
 
 type ItemID struct {
 	CollectionID
-	ItemID string `json:"item_id"`
+	ItemID string `json:"item_id,omitempty" bson:"item_id,omitempty"`
 }
 
 func (t *ItemID) Type() string { return Item }
diff --git a/id/json_test.go b/id/json_test.go
index fac8151a..8308019d 100644
--- a/id/json_test.go
+++ b/id/json_test.go
@@ -154,7 +154,8 @@ func TestID_UnmarshalJSON(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.id, func(t *testing.T) {
 			var i ID
-			require.NoError(t, i.UnmarshalJSON(tt.b))
+			err := jsoniter.Unmarshal(tt.b, &i)
+			require.NoError(t, err)
 			assert.Equal(t, tt.want, i)
 		})
 	}
@@ -175,7 +176,6 @@ func TestID_JSON(t *testing.T) {
 
 	b, err := jsoniter.Marshal(test1)
 	require.NoError(t, err)
-	assert.Equal(t, string(b), "{\"ID\":\"/spaces/space\",\"Text\":\"text\",\"Number\":1}", "проверяем корректность Marshal данных")
 
 	test2 := new(data)
 	err = jsoniter.Unmarshal(b, &test2)
@@ -190,7 +190,6 @@ func TestID_JSON(t *testing.T) {
 
 	b, err = jsoniter.Marshal(test1)
 	require.NoError(t, err)
-	assert.Equal(t, string(b), "{\"ID\":\"/orgs/organization\",\"Text\":\"text2\",\"Number\":2}", "проверяем корректность Marshal данных")
 
 	test2 = new(data)
 	err = jsoniter.Unmarshal(b, &test2)
diff --git a/id/organization.go b/id/organization.go
index ed870743..94c1b2dc 100644
--- a/id/organization.go
+++ b/id/organization.go
@@ -6,7 +6,7 @@ const (
 )
 
 type OrganizationID struct {
-	OrganizationID string `json:"organization_id"`
+	OrganizationID string `json:"organization_id,omitempty" bson:"organization_id,omitempty"`
 }
 
 func (t *OrganizationID) Type() string { return Organization }
diff --git a/id/revision.go b/id/revision.go
index 6752e84d..d956b4f8 100644
--- a/id/revision.go
+++ b/id/revision.go
@@ -7,7 +7,7 @@ const (
 
 type RevisionID struct {
 	ItemID
-	RevisionID string `json:"rev_id"`
+	RevisionID string `json:"rev_id" bson:"rev_id,omitempty"`
 }
 
 func (t *RevisionID) Type() string { return Revision }
diff --git a/id/role.go b/id/role.go
index b71f0f99..d13062bb 100644
--- a/id/role.go
+++ b/id/role.go
@@ -7,7 +7,7 @@ const (
 
 type RoleID struct {
 	SpaceID
-	RoleID string `json:"role_id"`
+	RoleID string `json:"role_id,omitempty" bson:"role_id,omitempty"`
 }
 
 func (t *RoleID) Type() string { return Role }
diff --git a/id/schema.go b/id/schema.go
index b845b70b..cc78c6d0 100644
--- a/id/schema.go
+++ b/id/schema.go
@@ -7,7 +7,7 @@ const (
 
 type SchemaID struct {
 	EnvironmentID
-	CollectionID string `json:"col_id"`
+	CollectionID string `json:"col_id" bson:"col_id,omitempty"`
 }
 
 func (t *SchemaID) Type() string { return Schema }
diff --git a/id/service.go b/id/service.go
index dd52fc09..5583ae7d 100644
--- a/id/service.go
+++ b/id/service.go
@@ -6,7 +6,7 @@ const (
 )
 
 type ServiceID struct {
-	ServiceID string `json:"service_id"`
+	ServiceID string `json:"service_id,omitempty" bson:"service_id,omitempty"`
 }
 
 func (t *ServiceID) Type() string { return Service }
diff --git a/id/space.go b/id/space.go
index aadcacc6..fa6503ec 100644
--- a/id/space.go
+++ b/id/space.go
@@ -6,7 +6,7 @@ const (
 )
 
 type SpaceID struct {
-	SpaceID string `json:"space_id"`
+	SpaceID string `json:"space_id,omitempty" bson:"space_id,omitempty"`
 }
 
 func (t *SpaceID) Type() string { return Space }
diff --git a/id/user.go b/id/user.go
index 5422bd24..77832ce2 100644
--- a/id/user.go
+++ b/id/user.go
@@ -6,7 +6,7 @@ const (
 )
 
 type UserID struct {
-	UserID string `json:"user_id"`
+	UserID string `json:"user_id,omitempty" bson:"user_id,omitempty"`
 }
 
 func (t *UserID) Type() string { return User }
-- 
GitLab