s3browser-backend/internal/gql/graphqlTypes.go

278 lines
6.8 KiB
Go

package gql
import (
"fmt"
"path/filepath"
"time"
"github.com/graph-gophers/dataloader"
"github.com/graphql-go/graphql"
"github.com/graphql-go/graphql/language/ast"
helper "git.kapelle.org/niklas/s3browser/internal/helper"
types "git.kapelle.org/niklas/s3browser/internal/types"
)
var graphqlDirType *graphql.Object
var graphqlFileType *graphql.Object
var graphqlLoginResultType *graphql.Object
var objIDType *graphql.Scalar
//GraphqlTypes create all graphql types and stores the in the global variables
func GraphqlTypes() {
var dateTimeType = graphql.NewScalar(graphql.ScalarConfig{
Name: "DateTime",
Description: "DateTime is a DateTime in ISO 8601 format",
Serialize: func(value interface{}) interface{} {
switch value := value.(type) {
case time.Time:
return value.Format(time.RFC3339)
}
return "INVALID"
},
ParseValue: func(value interface{}) interface{} {
switch tvalue := value.(type) {
case string:
if tval, err := time.Parse(time.RFC3339, tvalue); err != nil {
return nil
} else {
return tval
}
}
return nil
},
ParseLiteral: func(valueAST ast.Value) interface{} {
switch valueAST := valueAST.(type) {
case *ast.StringValue:
if tval, err := time.Parse(time.RFC3339, valueAST.Value); err != nil {
return nil
} else {
return tval
}
}
return nil
},
})
objIDType = graphql.NewScalar(graphql.ScalarConfig{
Name: "objID",
Description: `String representing a bucket, key and version combination.
Looks like this: "bucketName:/name/of/key" or "bucketName@version:/name/of/key"`,
Serialize: func(value interface{}) interface{} {
switch value := value.(type) {
case types.ID:
return value.String()
}
return "INVALID"
},
ParseValue: func(value interface{}) interface{} {
switch tvalue := value.(type) {
case string:
return types.ParseID(tvalue)
}
return nil
},
ParseLiteral: func(valueAST ast.Value) interface{} {
switch valueAST := valueAST.(type) {
case *ast.StringValue:
return types.ParseID(valueAST.Value)
}
return nil
},
})
graphqlDirType = graphql.NewObject(graphql.ObjectConfig{
Name: "Directory",
Description: "Represents a directory",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.NewNonNull(objIDType),
},
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(types.Directory)
if !ok {
return nil, fmt.Errorf("Failed to parse source for resolve")
}
return filepath.Base(source.ID.Key), nil
},
},
},
})
graphqlFileType = graphql.NewObject(graphql.ObjectConfig{
Name: "File",
Description: "Represents a file, not a directory",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.NewNonNull(objIDType),
Description: "The uniqe ID of the file. Represents the path and the s3 key.",
},
"name": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(types.File)
if !ok {
return nil, fmt.Errorf("Failed to parse source for resolve")
}
return filepath.Base(source.ID.Key), nil
},
},
"size": &graphql.Field{
Type: graphql.NewNonNull(graphql.Int),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
file, err := loadFile(p)
if err != nil {
return nil, err
}
return file.Size, nil
},
},
"contentType": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
file, err := loadFile(p)
if err != nil {
return nil, err
}
return file.ContentType, nil
},
},
"etag": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
file, err := loadFile(p)
if err != nil {
return nil, err
}
return file.ETag, nil
},
},
"lastModified": &graphql.Field{
Type: dateTimeType,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
file, err := loadFile(p)
if err != nil {
return nil, err
}
return file.LastModified, nil
},
},
"parent": &graphql.Field{
Type: graphqlDirType,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(types.File)
if !ok {
return nil, fmt.Errorf("Failed to parse Source for parent resolve")
}
parent := source.ID.Parent()
if parent == nil {
return nil, nil
}
return types.Directory{
ID: *source.ID.Parent(),
}, nil
},
},
},
})
graphqlDirType.AddFieldConfig("files", &graphql.Field{
Type: graphql.NewList(graphqlFileType),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(types.Directory)
if !ok {
return nil, fmt.Errorf("Failed to parse Source for files resolve")
}
loader := p.Context.Value("loader").(map[string]*dataloader.Loader)
thunk := loader["getFiles"].Load(p.Context, source.ID)
return thunk()
},
})
graphqlDirType.AddFieldConfig("directorys", &graphql.Field{
Type: graphql.NewList(graphqlDirType),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(types.Directory)
if !ok {
return nil, fmt.Errorf("Failed to parse Source for directories resolve")
}
loader := p.Context.Value("loader").(map[string]*dataloader.Loader)
thunk := loader["getDirs"].Load(p.Context, source.ID)
return thunk()
},
})
graphqlDirType.AddFieldConfig("parent", &graphql.Field{
Type: graphqlDirType,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(types.Directory)
if !ok {
return nil, fmt.Errorf("Failed to parse Source for directories resolve")
}
return types.Directory{
ID: helper.GetParentDir(source.ID),
}, nil
},
})
graphqlLoginResultType = graphql.NewObject(graphql.ObjectConfig{
Name: "LoginResut",
Description: "Result of a login",
Fields: graphql.Fields{
"token": &graphql.Field{
Type: graphql.String,
Description: "JWT token if login was successful",
},
"successful": &graphql.Field{
Type: graphql.NewNonNull(graphql.Boolean),
Description: "If the login was successful",
},
},
})
}
//loadFile helper func for using the dataloader to get a file
func loadFile(p graphql.ResolveParams) (*types.File, error) {
source, ok := p.Source.(types.File)
if !ok {
return nil, fmt.Errorf("Failed to parse source for resolve")
}
loader := p.Context.Value("loader").(map[string]*dataloader.Loader)
thunk := loader["getFile"].Load(p.Context, source.ID)
result, err := thunk()
if err != nil {
return nil, err
}
file, ok := result.(*types.File)
if !ok {
return nil, fmt.Errorf("Failed to load file")
}
return file, err
}