From c188a027e601bc21946af230f9c547e986bd8337 Mon Sep 17 00:00:00 2001
From: Danis Kirasirov <dbgbbu@gmail.com>
Date: Tue, 6 Aug 2024 13:11:40 +0300
Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?=
 =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B0=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7?=
 =?UTF-8?q?=D0=BA=D0=B0=20Item=20=D0=B8=D0=B7=20=D1=84=D0=B0=D0=B9=D0=BB?=
 =?UTF-8?q?=D0=BE=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pkg/items/convert.go              | 81 +++++++++++++++++++++++++++++++
 pkg/items/item.go                 | 16 +++---
 pkg/items/test/assets/invalid.txt |  0
 pkg/items/test/assets/item.json   | 25 ++++++++++
 pkg/items/test/assets/items.yaml  | 37 ++++++++++++++
 pkg/items/test/convert_test.go    | 40 +++++++++++++++
 pkg/schema/schema.go              |  4 +-
 7 files changed, 193 insertions(+), 10 deletions(-)
 create mode 100644 pkg/items/convert.go
 create mode 100644 pkg/items/test/assets/invalid.txt
 create mode 100644 pkg/items/test/assets/item.json
 create mode 100644 pkg/items/test/assets/items.yaml
 create mode 100644 pkg/items/test/convert_test.go

diff --git a/pkg/items/convert.go b/pkg/items/convert.go
new file mode 100644
index 00000000..b2bdb3b3
--- /dev/null
+++ b/pkg/items/convert.go
@@ -0,0 +1,81 @@
+package items
+
+import (
+	"errors"
+	"io"
+	"io/fs"
+	"path/filepath"
+
+	jsoniter "github.com/json-iterator/go"
+	"gopkg.in/yaml.v3"
+)
+
+func FromYAML(r io.Reader) (result []*Item, err error) {
+	decoder := yaml.NewDecoder(r)
+	for {
+		var item *Item
+		err = decoder.Decode(&item)
+		if errors.Is(err, io.EOF) {
+			break
+		}
+		if err != nil {
+			return nil, err
+		}
+
+		result = append(result, item)
+	}
+
+	return result, nil
+}
+
+func FromJSON(r io.Reader) (*Item, error) {
+	data, err := io.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	result := new(Item)
+	err = jsoniter.Unmarshal(data, result)
+	return result, err
+}
+
+func FromFile(file fs.File) ([]*Item, error) {
+	stat, err := file.Stat()
+	if err != nil {
+		return nil, err
+	}
+
+	switch filepath.Ext(stat.Name()) {
+	case ".json":
+		item, err := FromJSON(file)
+		if err != nil {
+			return nil, err
+		}
+		return []*Item{item}, nil
+
+	case ".yaml", ".yml":
+		return FromYAML(file)
+	}
+
+	return nil, errors.New("item must be in JSON or YAML format")
+}
+
+// FromFS возвращает все валидные записи в переданной файловой системе
+func FromFS(fsys fs.FS) (result []*Item, err error) {
+	if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, _ error) error {
+		file, err := fsys.Open(path)
+		if err != nil {
+			return err
+		}
+		defer file.Close()
+
+		if items, err := FromFile(file); err == nil {
+			result = append(result, items...)
+		}
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
diff --git a/pkg/items/item.go b/pkg/items/item.go
index c808c719..de1cd0e8 100644
--- a/pkg/items/item.go
+++ b/pkg/items/item.go
@@ -92,15 +92,15 @@ type Permissions struct {
 
 type Item struct {
 	ID           string                 `json:"id" bson:"_id"` // ID - Идентификатор записи. Автоматически генерируется системой при сохранении первой ревизии.
-	SpaceID      string                 `json:"spaceId" bson:"-"`
-	EnvID        string                 `json:"envId" bson:"-"`
-	CollectionID string                 `json:"collectionId" bson:"-"`
+	SpaceID      string                 `json:"spaceId" bson:"-" yaml:"space_id"`
+	EnvID        string                 `json:"envId" bson:"-" yaml:"env_id"`
+	CollectionID string                 `json:"collectionId" bson:"-" yaml:"collection_id"`
 	State        State                  `json:"state" bson:"state"`
-	CreatedRevAt time.Time              `json:"createdRevAt,omitempty" bson:"created_rev_at,omitempty"`
-	CreatedBy    string                 `json:"createdBy,omitempty" bson:"created_by,omitempty"`
-	CreatedAt    time.Time              `json:"createdAt,omitempty" bson:"created_at,omitempty"`
-	UpdatedAt    time.Time              `json:"updatedAt,omitempty" bson:"updated_at,omitempty"`
-	UpdatedBy    string                 `json:"updatedBy,omitempty" bson:"updated_by,omitempty"`
+	CreatedRevAt time.Time              `json:"createdRevAt,omitempty" bson:"created_rev_at,omitempty" yaml:"created_rev_at,omitempty"`
+	CreatedBy    string                 `json:"createdBy,omitempty" bson:"created_by,omitempty" yaml:"created_by,omitempty"`
+	CreatedAt    time.Time              `json:"createdAt,omitempty" bson:"created_at,omitempty" yaml:"created_at,omitempty"`
+	UpdatedAt    time.Time              `json:"updatedAt,omitempty" bson:"updated_at,omitempty" yaml:"updated_at,omitempty"`
+	UpdatedBy    string                 `json:"updatedBy,omitempty" bson:"updated_by,omitempty" yaml:"updated_by,omitempty"`
 	Data         map[string]interface{} `json:"data" bson:"data"`
 
 	// При создании или обновлении идентификатор локали в котором создается запись, опционально.
diff --git a/pkg/items/test/assets/invalid.txt b/pkg/items/test/assets/invalid.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/items/test/assets/item.json b/pkg/items/test/assets/item.json
new file mode 100644
index 00000000..8a60d91c
--- /dev/null
+++ b/pkg/items/test/assets/item.json
@@ -0,0 +1,25 @@
+{
+  "id": "item3",
+  "collectionId": "collID",
+  "envId": "envID",
+  "spaceId": "spaceID",
+  "state": 1,
+  "data": {
+    "obj": {
+      "str": "Hello"
+    },
+    "arr": [
+      "str1",
+      "str2"
+    ]
+  },
+  "translations": {
+    "ru": {
+      "obj": {
+        "str": "Привет"
+      }
+    }
+  },
+  "hidden": true,
+  "template": true
+}
\ No newline at end of file
diff --git a/pkg/items/test/assets/items.yaml b/pkg/items/test/assets/items.yaml
new file mode 100644
index 00000000..19c49de5
--- /dev/null
+++ b/pkg/items/test/assets/items.yaml
@@ -0,0 +1,37 @@
+---
+id: item1
+collection_id: collID
+env_id: envID
+space_id: spaceID
+state: 1
+data:
+  obj:
+    str: Hello
+  arr:
+    - str1
+    - str2
+translations:
+  ru:
+    obj:
+      str: Привет
+hidden: true
+template: true
+
+---
+id: item2
+collection_id: collID
+env_id: envID
+space_id: spaceID
+state: 1
+data:
+  obj:
+    str: Hello
+  arr:
+    - str1
+    - str2
+translations:
+  ru:
+    obj:
+      str: Привет
+hidden: true
+template: true
\ No newline at end of file
diff --git a/pkg/items/test/convert_test.go b/pkg/items/test/convert_test.go
new file mode 100644
index 00000000..6a63a7e7
--- /dev/null
+++ b/pkg/items/test/convert_test.go
@@ -0,0 +1,40 @@
+package test
+
+import (
+	"os"
+	"testing"
+
+	"git.perx.ru/perxis/perxis-go/pkg/items"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestFromFS(t *testing.T) {
+	i1 := &items.Item{
+		ID:           "item1",
+		CollectionID: "collID",
+		EnvID:        "envID",
+		SpaceID:      "spaceID",
+		State:        items.StatePublished,
+		Data: map[string]interface{}{
+			"obj": map[string]interface{}{"str": "Hello"},
+			"arr": []interface{}{"str1", "str2"},
+		},
+		Translations: map[string]map[string]interface{}{
+			"ru": {"obj": map[string]interface{}{"str": "Привет"}},
+		},
+		Hidden:   true,
+		Template: true,
+	}
+
+	i2 := *i1
+	i2.ID = "item2"
+
+	i3 := *i1
+	i3.ID = "item3"
+
+	r, err := items.FromFS(os.DirFS("assets"))
+	require.NoError(t, err)
+	require.Len(t, r, 3)
+	assert.ElementsMatch(t, []*items.Item{i1, &i2, &i3}, r)
+}
diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go
index 5de8e1c7..b05b8fc3 100644
--- a/pkg/schema/schema.go
+++ b/pkg/schema/schema.go
@@ -59,8 +59,8 @@ func FromFS(fsys fs.FS) (result []*Schema, err error) {
 		}
 		defer file.Close()
 
-		if schema, err := FromFile(file); err == nil {
-			result = append(result, schema...)
+		if schemas, err := FromFile(file); err == nil {
+			result = append(result, schemas...)
 		}
 		return nil
 	}); err != nil {
-- 
GitLab