package resolvers // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. import ( "context" "errors" "strings" "time" "git.aiterp.net/stufflog/server/graph/graphcore" "git.aiterp.net/stufflog/server/graph/graphutil" "git.aiterp.net/stufflog/server/graph/loaders" "git.aiterp.net/stufflog/server/internal/slerrors" "git.aiterp.net/stufflog/server/models" ) func (r *issueTaskResolver) EstimatedUnits(ctx context.Context, obj *models.IssueTask) (*int, error) { // TODO: Data loader activity, err := loaders.ActivityLoaderFromContext(ctx).Load(obj.ActivityID) if err != nil { return nil, err } if !activity.Countable || activity.UnitIsTimeSpent { return nil, nil } return &obj.EstimatedUnits, nil } func (r *issueTaskResolver) Issue(ctx context.Context, obj *models.IssueTask) (*models.Issue, error) { return loaders.IssueLoaderFromContext(ctx).Load(obj.IssueID) } func (r *issueTaskResolver) Activity(ctx context.Context, obj *models.IssueTask) (*models.Activity, error) { return loaders.ActivityLoaderFromContext(ctx).Load(obj.ActivityID) } func (r *issueTaskResolver) Status(ctx context.Context, obj *models.IssueTask) (*models.ProjectStatus, error) { // The project ID is always the prefix before the first dash in the issue ID. split := strings.SplitN(obj.IssueID, "-", 2) if len(split) == 0 { return nil, errors.New("invalid issue ID") } projectID := split[0] // Shortcut: if description isn't needed, resolve this with issue's properties. if !graphutil.SelectsAnyField(ctx, "description") { return &models.ProjectStatus{ ProjectID: projectID, Stage: obj.StatusStage, Name: obj.StatusName, Description: "FAKE", }, nil } // Find it in the database. TODO: DataLoader status, err := r.Database.ProjectStatuses().Find(ctx, projectID, obj.StatusName) if slerrors.IsNotFound(err) { return &models.ProjectStatus{ ProjectID: projectID, Stage: obj.StatusStage, Name: obj.StatusName, Description: "(Deleted or unknown status)", }, nil } else if err != nil { return nil, err } // If the stage doesn't match, sneakily correct it for next time. if status.Stage != obj.StatusStage { updatedTask := *obj updatedTask.StatusStage = status.Stage _ = r.Database.IssueTasks().Save(ctx, updatedTask) } return status, nil } func (r *issueTaskResolver) RemainingTime(ctx context.Context, obj *models.IssueTask) (time.Duration, error) { loader := loaders.LogsByIssueLoaderFromContext(ctx) logs, err := loader.Load(obj.IssueID) if err != nil { return 0, err } remaining := obj.EstimatedTime for _, log := range logs { if task := log.Task(obj.ID); task != nil { remaining -= task.Duration } } return remaining, nil } func (r *issueTaskResolver) RemainingUnits(ctx context.Context, obj *models.IssueTask) (*int, error) { activity, err := loaders.ActivityLoaderFromContext(ctx).Load(obj.ActivityID) if err != nil { return nil, err } if !activity.Countable || activity.UnitIsTimeSpent { return nil, nil } loader := loaders.LogsByIssueLoaderFromContext(ctx) logs, err := loader.Load(obj.IssueID) if err != nil { return nil, err } remaining := obj.EstimatedUnits for _, log := range logs { if task := log.Task(obj.ID); task != nil && task.Units != nil { remaining -= *task.Units } } return &remaining, nil } // IssueTask returns graphcore.IssueTaskResolver implementation. func (r *Resolver) IssueTask() graphcore.IssueTaskResolver { return &issueTaskResolver{r} } type issueTaskResolver struct{ *Resolver }