diff --git a/pkg/collections/collection.go b/pkg/collections/collection.go index 85ab01999816f8ab986c69495d737ce3f1e8160e..6583b4239912413dce66e4e4685fbe4868411e2a 100644 --- a/pkg/collections/collection.go +++ b/pkg/collections/collection.go @@ -3,6 +3,7 @@ package collections import ( "time" + "git.perx.ru/perxis/perxis-go/pkg/optional" "git.perx.ru/perxis/perxis-go/pkg/permission" "git.perx.ru/perxis/perxis-go/pkg/schema" ) @@ -199,3 +200,39 @@ func GetCollectionsIDs(collections []*Collection) []string { } return res } + +func FromSchemaMetadata(schemas ...*schema.Schema) []*Collection { + result := make([]*Collection, 0, len(schemas)) + for _, sch := range schemas { + coll := &Collection{Schema: sch} + + coll.ID = sch.Metadata["collection_id"] + coll.Name = sch.Metadata["collection_name"] + + if single, ok := sch.Metadata["collection_single"]; ok && single == "true" { + coll.Single = optional.True + } + if system, ok := sch.Metadata["collection_system"]; ok && system == "true" { + coll.System = optional.True + } + if nodata, ok := sch.Metadata["collection_nodata"]; ok && nodata == "true" { + coll.NoData = optional.True + } + if hidden, ok := sch.Metadata["collection_hidden"]; ok && hidden == "true" { + coll.Hidden = true + } + + if _, ok := sch.Metadata["collection_view_id"]; ok { + coll.View = &View{ + SpaceID: sch.Metadata["collection_view_space"], + EnvID: sch.Metadata["collection_view_env"], + CollectionID: sch.Metadata["collection_view_id"], + Filter: sch.Metadata["collection_view_filter"], + } + } + + result = append(result, coll) + } + + return result +} diff --git a/pkg/collections/collection_test.go b/pkg/collections/collection_test.go index 79e16a8e6a397418ef2418979bf0e38947b730c8..b98f6a14878b7e881f6a25ec51045e8b2101a6f0 100644 --- a/pkg/collections/collection_test.go +++ b/pkg/collections/collection_test.go @@ -3,6 +3,9 @@ package collections import ( "testing" + "git.perx.ru/perxis/perxis-go/pkg/optional" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "git.perx.ru/perxis/perxis-go/pkg/schema/field" "github.com/stretchr/testify/require" ) @@ -100,3 +103,84 @@ func TestView_Equal(t *testing.T) { }) } } + +func TestFromSchemaMetadata(t *testing.T) { + testCases := []struct { + name string + schemas []*schema.Schema + want []*Collection + }{ + { + name: "Nil", + schemas: nil, + want: []*Collection{}, + }, + { + name: "Empty", + schemas: []*schema.Schema{}, + want: []*Collection{}, + }, + { + name: "Without metadata", + schemas: []*schema.Schema{schema.New("a", field.String())}, + want: []*Collection{{Schema: schema.New("a", field.String())}}, + }, + { + name: "With metadata", + schemas: []*schema.Schema{schema.New("a", field.String()).WithMetadata( + "collection_id", "collID", + "collection_name", "collName", + "collection_single", "true", + "collection_system", "true", + "collection_nodata", "true", + "collection_hidden", "true", + "collection_view_space", "viewSpaceID", + "collection_view_env", "viewEnvID", + "collection_view_id", "viewCollID", + "collection_view_filter", "viewFilter", + )}, + want: []*Collection{{ + ID: "collID", + Name: "collName", + Single: optional.True, + System: optional.True, + NoData: optional.True, + Hidden: true, + Schema: schema.New("a", field.String()).WithMetadata("collection_id", "collID", "collection_name", "collName", "collection_single", "true", "collection_system", "true", "collection_nodata", "true", "collection_hidden", "true", "collection_view_space", "viewSpaceID", "collection_view_env", "viewEnvID", "collection_view_id", "viewCollID", "collection_view_filter", "viewFilter"), + View: &View{ + SpaceID: "viewSpaceID", + EnvID: "viewEnvID", + CollectionID: "viewCollID", + Filter: "viewFilter", + }, + }}, + }, + { + name: "Multiple", + schemas: []*schema.Schema{ + schema.New("a", field.String()).WithMetadata("collection_id", "collID"), + schema.New("b", field.String()).WithMetadata("collection_name", "collName"), + }, + want: []*Collection{ + { + ID: "collID", + Name: "", + Schema: schema.New("a", field.String()).WithMetadata("collection_id", "collID"), + }, + { + + ID: "", + Name: "collName", + Schema: schema.New("b", field.String()).WithMetadata("collection_name", "collName"), + }, + }, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + result := FromSchemaMetadata(tt.schemas...) + require.Equal(t, tt.want, result) + }) + } +} diff --git a/pkg/extension/extension.go b/pkg/extension/extension.go index ae7878d56de53f423ea86c28fa2f263cef6cbd03..c5c1dd4cd32987fc0649d1fd8278e93fe794530a 100644 --- a/pkg/extension/extension.go +++ b/pkg/extension/extension.go @@ -2,6 +2,7 @@ package extension import ( "context" + "io/fs" "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/content" @@ -95,3 +96,22 @@ func UpdateCollectionStrategy(s *setup.Setup, exist, collection *collections.Col } return setup.DefaultUpdateCollectionStrategyFn(s, exist, collection) } + +// CollectionsFromAssets инициализирует коллекции РёР· файловой системы +// Р’ качестве файловой системы РјРѕР¶РЅРѕ использовать файлы РћРЎ `filesystem := os.DirFS("assets/schemas")` +// Рли файловую систему, встроенную РІ исполняемый файл РїСЂРё компиляции: +// +// //go:embed assets/schemas/* +// var filesystem embed.FS +func CollectionsFromAssets(filesystem fs.FS, extension string) []*collections.Collection { + schemas, err := schema.FromFS(filesystem) + if err != nil { + panic(err) + } + + for _, schema := range schemas { + schema.WithMetadata(MetadataKey, extension) + } + + return collections.FromSchemaMetadata(schemas...) +} diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index 1c3567e12756ac434de98a2dd7d25bb9b5f19ccb..4fec4c174684745be718abf4c2a595f7fe1ae3fe 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -2,7 +2,7 @@ package schema import ( "context" - "os" + "io/fs" "path/filepath" "reflect" @@ -29,14 +29,13 @@ func NewFromField(f *field.Field) *Schema { // FromFile инициализирует Рё возвращает объект схемы РёР· файла // Поддерживаются форматы JSON Рё YAML -func FromFile(path string) (*Schema, error) { - file, err := os.Open(path) +func FromFile(file fs.File) (*Schema, error) { + stat, err := file.Stat() if err != nil { return nil, err } - defer file.Close() - switch filepath.Ext(path) { + switch filepath.Ext(stat.Name()) { case ".json": return FromJSON(file) case ".yaml", ".yml": @@ -46,19 +45,23 @@ func FromFile(path string) (*Schema, error) { return nil, errors.New("schema must be in JSON or YAML format") } -// FromFiles возвращает РІСЃРµ валидные схемы РІ переданной директории -func FromFiles(path string) ([]*Schema, error) { - files, err := os.ReadDir(path) - if err != nil { - return nil, err - } +// FromFS возвращает РІСЃРµ валидные схемы РІ переданной файловой системе +func FromFS(fsys fs.FS) (result []*Schema, 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() - result := make([]*Schema, 0, len(files)) - for _, file := range files { - if schema, err := FromFile(filepath.Join(path, file.Name())); err == nil { + if schema, err := FromFile(file); err == nil { result = append(result, schema) } + return nil + }); err != nil { + return nil, err } + return result, nil } diff --git a/pkg/schema/test/convert_test.go b/pkg/schema/test/convert_test.go index 51ab33a6751440672c8a9a0dc0038f11898749b2..1f6149ce375f4f4863483c8392e849a85db6e0f8 100644 --- a/pkg/schema/test/convert_test.go +++ b/pkg/schema/test/convert_test.go @@ -1,6 +1,7 @@ package test import ( + "os" "testing" "git.perx.ru/perxis/perxis-go/pkg/extension" @@ -23,10 +24,6 @@ func TestFromFile(t *testing.T) { path: "assets/not_schema.txt", wantErr: "schema must be in JSON or YAML format", }, - { - path: "non/existent.json", - wantErr: "open non/existent.json: no such file or directory", - }, { path: "assets/invalid.json", wantErr: "error unmarshal json into field", @@ -41,7 +38,10 @@ func TestFromFile(t *testing.T) { }, } { t.Run(tt.path, func(t *testing.T) { - result, err := schema.FromFile(tt.path) + file, err := os.Open(tt.path) + require.NoError(t, err) + + result, err := schema.FromFile(file) if tt.wantErr != "" { require.Error(t, err) assert.ErrorContains(t, err, tt.wantErr) @@ -56,14 +56,14 @@ func TestFromFile(t *testing.T) { func TestFromFiles(t *testing.T) { t.Run("Non-existen path", func(t *testing.T) { - schemas, err := schema.FromFiles("non-existen") + schemas, err := schema.FromFS(os.DirFS("non-existen")) require.Error(t, err) require.ErrorContains(t, err, "no such file or directory") require.Nil(t, schemas) }) t.Run("Success", func(t *testing.T) { - schemas, err := schema.FromFiles("assets") + schemas, err := schema.FromFS(os.DirFS("assets")) require.NoError(t, err) require.Len(t, schemas, 2, "Р’ директории хранятся РґРІРµ корректные схемы") require.Equal(t, schemas[0], schemas[1], "РћРЅРё одинаковые, РЅРѕ РІ разных форматах")