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 //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: return valueAST.Value } return nil }, }) graphqlDirType = graphql.NewObject(graphql.ObjectConfig{ Name: "Directory", Description: "Represents a directory", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.ID), }, "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), nil }, }, }, }) graphqlFileType = graphql.NewObject(graphql.ObjectConfig{ Name: "File", Description: "Represents a file, not a directory", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.ID), 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), 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") } basename := helper.GetPathFromId(source.ID) return types.Directory{ ID: basename, }, 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, dataloader.StringKey(helper.NomalizeID(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, dataloader.StringKey(helper.NomalizeID(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, dataloader.StringKey(helper.NomalizeID(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 }