diff --git a/internal/types/types.go b/internal/types/types.go new file mode 100644 index 0000000..e27dbbc --- /dev/null +++ b/internal/types/types.go @@ -0,0 +1,96 @@ +// Copyright 2024 Matthew Rich . All rights reserved. + +package types + +import ( + "errors" + "fmt" + "net/url" + "strings" + "path/filepath" +) + +var ( + ErrUnknownType = errors.New("Unknown type") +) + +//type Name string //`json:"type"` + +type Factory[Product any] func(*url.URL) Product +type RegistryTypeMap[Product any] map[string]Factory[Product] + +type Types[Product any] struct { + registry RegistryTypeMap[Product] +} + +func New[Product any]() *Types[Product] { + return &Types[Product]{registry: make(map[string]Factory[Product])} +} + +func (t *Types[Product]) Register(names []string, factory Factory[Product]) { + for _,name := range names { + t.registry[name] = factory + } +} + +func (t *Types[Product]) FromExtension(path string) (Factory[Product], error) { + elements := strings.Split(path, ".") + numberOfElements := len(elements) + if numberOfElements > 2 { + if src := t.Get(strings.Join(elements[numberOfElements - 2: numberOfElements - 1], ".")); src != nil { + return src, nil + } + } + if src := t.Get(elements[numberOfElements - 1]); src != nil { + return src, nil + } + return nil, fmt.Errorf("%w: %s", ErrUnknownType, path) +} + +func (t *Types[Product]) New(uri string) (result Product, err error) { + u, e := url.Parse(uri) + if u == nil || e != nil { + err = fmt.Errorf("%w: %s", ErrUnknownType, e) + return + } + + if u.Scheme == "" { + u.Scheme = "file" + } + + path := filepath.Join(u.Hostname(), u.Path) + if d, lookupErr := t.FromExtension(path); d != nil { + return d(u), lookupErr + } + + if r, ok := t.registry[u.Scheme]; ok { + return r(u), nil + } + err = fmt.Errorf("%w: %s", ErrUnknownType, u.Scheme) + return +} + +func (t *Types[Product]) Has(typename string) bool { + if _, ok := t.registry[typename]; ok { + return true + } + return false +} + +func (t *Types[Product]) Get(typename string) Factory[Product] { + if d, ok := t.registry[typename]; ok { + return d + } + return nil +} + +/* +func (n *Name) UnmarshalJSON(b []byte) error { + TypeName := strings.Trim(string(b), "\"") + if SourceTypes.Has(TypeName) { + *n = TypeName(TypeName) + return nil + } + return fmt.Errorf("%w: %s", ErrUnknownType, TypeName) +} +*/ diff --git a/internal/types/types_test.go b/internal/types/types_test.go new file mode 100644 index 0000000..c457a12 --- /dev/null +++ b/internal/types/types_test.go @@ -0,0 +1,63 @@ +// Copyright 2024 Matthew Rich . All rights reserved. + +package types + +import ( +_ "context" +_ "encoding/json" + "github.com/stretchr/testify/assert" + "net/url" + "testing" +) + +func TestNewSourceTypes(t *testing.T) { + testTypes := New[int]() + assert.NotNil(t, testTypes) +} + +func TestNewSourceTypesRegister(t *testing.T) { + + testTypes := New[int]() + assert.NotNil(t, testTypes) + + testTypes.Register([]string{"foo"}, func(*url.URL) int { return 100 }) + + r, e := testTypes.New("foo://") + assert.Nil(t, e) + assert.Equal(t, 100, r) +} + +func TestTypesFromURI(t *testing.T) { + testTypes := New[string]() + assert.NotNil(t, testTypes) + + testTypes.Register([]string{"foo"}, func(*url.URL) string { return "test" }) + + r, e := testTypes.New("foo://bar") + assert.Nil(t, e) + assert.Equal(t, "test", r) +} + +func TestTypesHasType(t *testing.T) { + testTypes := New[string]() + assert.NotNil(t, testTypes) + + testTypes.Register([]string{"foo"}, func(*url.URL) string { return "hastest" }) + + assert.True(t, testTypes.Has("foo")) +} + +/* +func TestTypeName(t *testing.T) { + testTypes.Register([]string{"file"}, func(*url.URL) string { return "typetest" }) + + type fDocSourceName struct { + Name TypeName `json:"type"` + } + fTypeName := &fDocSourceName{} + jsonType := `{ "type": "file" }` + e := json.Unmarshal([]byte(jsonType), &fTypeName) + assert.Nil(t, e) + assert.Equal(t, "file", string(fTypeName.Name)) +} +*/