diff --git a/internal/mutations.go b/internal/mutations.go new file mode 100644 index 0000000..4c74b7d --- /dev/null +++ b/internal/mutations.go @@ -0,0 +1,77 @@ +package s3browser + +import ( + "context" + "fmt" + + "github.com/minio/minio-go/v7" +) + +func deleteMutation(ctx context.Context, id string) error { + s3Client, ok := ctx.Value("s3Client").(*minio.Client) + + if !ok { + return fmt.Errorf("Failed to get s3Client from context") + } + + // TODO: it is posible to remove multiple objects with a single call. + // Is it better to batch this? + return s3Client.RemoveObject(ctx, bucketName, id, minio.RemoveObjectOptions{}) +} + +func copyMutation(ctx context.Context, src, dest string) (*File, error) { + s3Client, ok := ctx.Value("s3Client").(*minio.Client) + + if !ok { + return nil, fmt.Errorf("Failed to get s3Client from context") + } + + info, err := s3Client.CopyObject(ctx, minio.CopyDestOptions{ + Bucket: bucketName, + Object: dest, + }, minio.CopySrcOptions{ + Bucket: bucketName, + Object: src, + }) + + if err != nil { + return nil, err + } + + return &File{ + ID: info.Key, + }, nil + +} + +func moveMutation(ctx context.Context, src, dest string) (*File, error) { + s3Client, ok := ctx.Value("s3Client").(*minio.Client) + + if !ok { + return nil, fmt.Errorf("Failed to get s3Client from context") + } + + // There is no (spoon) move. Only copy and delete + info, err := s3Client.CopyObject(ctx, minio.CopyDestOptions{ + Bucket: bucketName, + Object: dest, + }, minio.CopySrcOptions{ + Bucket: bucketName, + Object: src, + }) + + if err != nil { + return nil, err + } + + err = deleteMutation(ctx, src) + + if err != nil { + return nil, err + } + + return &File{ + ID: info.Key, + }, nil + +} diff --git a/internal/schema.go b/internal/schema.go index 83dc539..0c6549f 100644 --- a/internal/schema.go +++ b/internal/schema.go @@ -10,7 +10,7 @@ import ( // graphqlSchema generate the schema with its root query and mutation func graphqlSchema() (graphql.Schema, error) { - fields := graphql.Fields{ + queryFields := graphql.Fields{ "files": &graphql.Field{ Type: graphql.NewNonNull(graphql.NewList(graphqlFileType)), Args: graphql.FieldConfigArgument{ @@ -67,13 +67,84 @@ func graphqlSchema() (graphql.Schema, error) { }, } + mutationFields := graphql.Fields{ + "delete": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "id": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.ID), + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + id, ok := p.Args["id"].(string) + if !ok { + return nil, fmt.Errorf("Failed to parse args") + } + + return id, deleteMutation(p.Context, id) + }, + }, + "copy": &graphql.Field{ + Type: graphqlFileType, + Args: graphql.FieldConfigArgument{ + "src": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.ID), + }, + "dest": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.ID), + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + src, ok := p.Args["src"].(string) + if !ok { + return nil, fmt.Errorf("Failed to parse args") + } + dest, ok := p.Args["dest"].(string) + if !ok { + return nil, fmt.Errorf("Failed to parse args") + } + + return copyMutation(p.Context, src, dest) + }, + }, + "move": &graphql.Field{ + Type: graphqlFileType, + Args: graphql.FieldConfigArgument{ + "src": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.ID), + }, + "dest": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.ID), + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + src, ok := p.Args["src"].(string) + if !ok { + return nil, fmt.Errorf("Failed to parse args") + } + dest, ok := p.Args["dest"].(string) + if !ok { + return nil, fmt.Errorf("Failed to parse args") + } + + return moveMutation(p.Context, src, dest) + }, + }, + } + rootQuery := graphql.ObjectConfig{ Name: "RootQuery", - Fields: fields, + Fields: queryFields, + } + + rootMutation := graphql.ObjectConfig{ + Name: "RootMutation", + Fields: mutationFields, } schemaConfig := graphql.SchemaConfig{ - Query: graphql.NewObject(rootQuery), + Query: graphql.NewObject(rootQuery), + Mutation: graphql.NewObject(rootMutation), } return graphql.NewSchema(schemaConfig)