Skip to content
Snippets Groups Projects
Commit 0255aad0 authored by Danis Kirasirov's avatar Danis Kirasirov :8ball: Committed by Pavel Antonov
Browse files

feat(schema): Реализован функционал для загрузки схем из файлов

Close #PRXS-2731
parent bb9a96a1
Branches
Tags
No related merge requests found
......@@ -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
}
......@@ -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)
})
}
}
......@@ -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...)
}
......@@ -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)
// 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 nil, err
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
}
......
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], "Они одинаковые, но в разных форматах")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment