github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/formationtemplate/resolver.go (about)

     1  package formationtemplate
     2  
     3  import (
     4  	"context"
     5  
     6  	dataloader "github.com/kyma-incubator/compass/components/director/internal/dataloaders"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/model"
     9  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    10  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    11  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    12  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    13  )
    14  
    15  // FormationTemplateConverter converts between the graphql and model
    16  //go:generate mockery --name=FormationTemplateConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    17  type FormationTemplateConverter interface {
    18  	FromInputGraphQL(in *graphql.FormationTemplateInput) (*model.FormationTemplateInput, error)
    19  	ToGraphQL(in *model.FormationTemplate) (*graphql.FormationTemplate, error)
    20  	MultipleToGraphQL(in []*model.FormationTemplate) ([]*graphql.FormationTemplate, error)
    21  	FromModelInputToModel(in *model.FormationTemplateInput, id string, tenantID string) *model.FormationTemplate
    22  }
    23  
    24  // FormationTemplateService represents the FormationTemplate service layer
    25  //go:generate mockery --name=FormationTemplateService --output=automock --outpkg=automock --case=underscore --disable-version-string
    26  type FormationTemplateService interface {
    27  	Create(ctx context.Context, in *model.FormationTemplateInput) (string, error)
    28  	Get(ctx context.Context, id string) (*model.FormationTemplate, error)
    29  	List(ctx context.Context, pageSize int, cursor string) (*model.FormationTemplatePage, error)
    30  	Update(ctx context.Context, id string, in *model.FormationTemplateInput) error
    31  	Delete(ctx context.Context, id string) error
    32  	ListWebhooksForFormationTemplate(ctx context.Context, formationTemplateID string) ([]*model.Webhook, error)
    33  }
    34  
    35  // WebhookConverter converts between the graphql and model
    36  //go:generate mockery --name=WebhookConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    37  type WebhookConverter interface {
    38  	MultipleToGraphQL(in []*model.Webhook) ([]*graphql.Webhook, error)
    39  	MultipleInputFromGraphQL(in []*graphql.WebhookInput) ([]*model.WebhookInput, error)
    40  }
    41  
    42  // FormationConstraintService represents the FormationConstraint service layer
    43  //go:generate mockery --name=FormationConstraintService --output=automock --outpkg=automock --case=underscore --disable-version-string
    44  type FormationConstraintService interface {
    45  	ListByFormationTemplateIDs(ctx context.Context, formationTemplateIDs []string) ([][]*model.FormationConstraint, error)
    46  }
    47  
    48  // FormationConstraintConverter represents the FormationConstraint converter
    49  //go:generate mockery --name=FormationConstraintConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    50  type FormationConstraintConverter interface {
    51  	MultipleToGraphQL(in []*model.FormationConstraint) []*graphql.FormationConstraint
    52  }
    53  
    54  // Resolver is the FormationTemplate resolver
    55  type Resolver struct {
    56  	transact persistence.Transactioner
    57  
    58  	formationTemplateSvc         FormationTemplateService
    59  	converter                    FormationTemplateConverter
    60  	webhookConverter             WebhookConverter
    61  	formationConstraintSvc       FormationConstraintService
    62  	formationConstraintConverter FormationConstraintConverter
    63  }
    64  
    65  // NewResolver creates FormationTemplate resolver
    66  func NewResolver(transact persistence.Transactioner, converter FormationTemplateConverter, formationTemplateSvc FormationTemplateService, webhookConverter WebhookConverter, formationConstraintSvc FormationConstraintService, formationConstraintConverter FormationConstraintConverter) *Resolver {
    67  	return &Resolver{
    68  		transact:                     transact,
    69  		converter:                    converter,
    70  		formationTemplateSvc:         formationTemplateSvc,
    71  		webhookConverter:             webhookConverter,
    72  		formationConstraintSvc:       formationConstraintSvc,
    73  		formationConstraintConverter: formationConstraintConverter,
    74  	}
    75  }
    76  
    77  // FormationTemplates pagination lists all FormationTemplates based on `first` and `after`
    78  func (r *Resolver) FormationTemplates(ctx context.Context, first *int, after *graphql.PageCursor) (*graphql.FormationTemplatePage, error) {
    79  	var cursor string
    80  	if after != nil {
    81  		cursor = string(*after)
    82  	}
    83  	if first == nil {
    84  		return nil, apperrors.NewInvalidDataError("missing required parameter 'first'")
    85  	}
    86  
    87  	tx, err := r.transact.Begin()
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
    92  
    93  	ctx = persistence.SaveToContext(ctx, tx)
    94  
    95  	formationTemplatePage, err := r.formationTemplateSvc.List(ctx, *first, cursor)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	gqlFormationTemplate, err := r.converter.MultipleToGraphQL(formationTemplatePage.Data)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	err = tx.Commit()
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	return &graphql.FormationTemplatePage{
   111  		Data:       gqlFormationTemplate,
   112  		TotalCount: formationTemplatePage.TotalCount,
   113  		PageInfo: &graphql.PageInfo{
   114  			StartCursor: graphql.PageCursor(formationTemplatePage.PageInfo.StartCursor),
   115  			EndCursor:   graphql.PageCursor(formationTemplatePage.PageInfo.EndCursor),
   116  			HasNextPage: formationTemplatePage.PageInfo.HasNextPage,
   117  		},
   118  	}, nil
   119  }
   120  
   121  // FormationTemplate queries the FormationTemplate matching ID `id`
   122  func (r *Resolver) FormationTemplate(ctx context.Context, id string) (*graphql.FormationTemplate, error) {
   123  	tx, err := r.transact.Begin()
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   128  
   129  	ctx = persistence.SaveToContext(ctx, tx)
   130  
   131  	formationTemplate, err := r.formationTemplateSvc.Get(ctx, id)
   132  	if err != nil {
   133  		if apperrors.IsNotFoundError(err) {
   134  			return nil, tx.Commit()
   135  		}
   136  		return nil, err
   137  	}
   138  
   139  	gqlFormationTemplate, err := r.converter.ToGraphQL(formationTemplate)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	err = tx.Commit()
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	return gqlFormationTemplate, nil
   150  }
   151  
   152  // CreateFormationTemplate creates a FormationTemplate using `in`
   153  func (r *Resolver) CreateFormationTemplate(ctx context.Context, in graphql.FormationTemplateInput) (*graphql.FormationTemplate, error) {
   154  	tx, err := r.transact.Begin()
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   159  
   160  	ctx = persistence.SaveToContext(ctx, tx)
   161  
   162  	if err = in.Validate(); err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	convertedIn, err := r.converter.FromInputGraphQL(&in)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	log.C(ctx).Debugf("Creating a Formation Template with name %q", in.Name)
   172  	id, err := r.formationTemplateSvc.Create(ctx, convertedIn)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	formationTemplate, err := r.formationTemplateSvc.Get(ctx, id)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  
   182  	gqlFormationTemplate, err := r.converter.ToGraphQL(formationTemplate)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	if err = tx.Commit(); err != nil {
   188  		return nil, err
   189  	}
   190  
   191  	return gqlFormationTemplate, nil
   192  }
   193  
   194  // DeleteFormationTemplate deletes the FormationTemplate matching ID `id`
   195  func (r *Resolver) DeleteFormationTemplate(ctx context.Context, id string) (*graphql.FormationTemplate, error) {
   196  	tx, err := r.transact.Begin()
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   201  
   202  	ctx = persistence.SaveToContext(ctx, tx)
   203  
   204  	formationTemplate, err := r.formationTemplateSvc.Get(ctx, id)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	log.C(ctx).Debugf("Deleting a Formation Template with id %q", id)
   210  	err = r.formationTemplateSvc.Delete(ctx, id)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	gqlFormationTemplate, err := r.converter.ToGraphQL(formationTemplate)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	err = tx.Commit()
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	return gqlFormationTemplate, nil
   226  }
   227  
   228  // UpdateFormationTemplate updates the FormationTemplate matching ID `id` using `in`
   229  func (r *Resolver) UpdateFormationTemplate(ctx context.Context, id string, in graphql.FormationTemplateInput) (*graphql.FormationTemplate, error) {
   230  	tx, err := r.transact.Begin()
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   235  
   236  	ctx = persistence.SaveToContext(ctx, tx)
   237  
   238  	if err = in.Validate(); err != nil {
   239  		return nil, err
   240  	}
   241  
   242  	convertedIn, err := r.converter.FromInputGraphQL(&in)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  
   247  	log.C(ctx).Debugf("Updating a Formation Template with id %q", id)
   248  	err = r.formationTemplateSvc.Update(ctx, id, convertedIn)
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  
   253  	formationTemplate, err := r.formationTemplateSvc.Get(ctx, id)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	gqlFormationTemplate, err := r.converter.ToGraphQL(formationTemplate)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	err = tx.Commit()
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  
   268  	return gqlFormationTemplate, nil
   269  }
   270  
   271  // Webhooks queries all webhooks related to the 'obj' Formation Template
   272  func (r *Resolver) Webhooks(ctx context.Context, obj *graphql.FormationTemplate) ([]*graphql.Webhook, error) {
   273  	if obj == nil {
   274  		return nil, apperrors.NewInternalError("Formation Template cannot be empty")
   275  	}
   276  
   277  	tx, err := r.transact.Begin()
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   282  
   283  	ctx = persistence.SaveToContext(ctx, tx)
   284  
   285  	webhooks, err := r.formationTemplateSvc.ListWebhooksForFormationTemplate(ctx, obj.ID)
   286  	if err != nil {
   287  		return nil, err
   288  	}
   289  
   290  	gqlWebhooks, err := r.webhookConverter.MultipleToGraphQL(webhooks)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  
   295  	if err = tx.Commit(); err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	return gqlWebhooks, nil
   300  }
   301  
   302  // FormationConstraint retrieves a FormationConstraint for the specified FormationTemplate
   303  func (r *Resolver) FormationConstraint(ctx context.Context, obj *graphql.FormationTemplate) ([]*graphql.FormationConstraint, error) {
   304  	params := dataloader.ParamFormationConstraint{ID: obj.ID, Ctx: ctx}
   305  	return dataloader.FormationTemplateFor(ctx).FormationConstraintByID.Load(params)
   306  }
   307  
   308  // FormationConstraintsDataLoader retrieves Formation Constraints for each FormationTemplate ID in the keys
   309  func (r *Resolver) FormationConstraintsDataLoader(keys []dataloader.ParamFormationConstraint) ([][]*graphql.FormationConstraint, []error) {
   310  	if len(keys) == 0 {
   311  		return nil, []error{apperrors.NewInternalError("No Formation Templates found")}
   312  	}
   313  
   314  	ctx := keys[0].Ctx
   315  	formationTemplateIDs := make([]string, 0, len(keys))
   316  	for _, key := range keys {
   317  		formationTemplateIDs = append(formationTemplateIDs, key.ID)
   318  	}
   319  
   320  	tx, err := r.transact.Begin()
   321  	if err != nil {
   322  		return nil, []error{err}
   323  	}
   324  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   325  
   326  	ctx = persistence.SaveToContext(ctx, tx)
   327  
   328  	formationConstraintsPerFormation, err := r.formationConstraintSvc.ListByFormationTemplateIDs(ctx, formationTemplateIDs)
   329  	if err != nil {
   330  		return nil, []error{err}
   331  	}
   332  
   333  	gqlFormationConstraints := make([][]*graphql.FormationConstraint, 0, len(formationConstraintsPerFormation))
   334  
   335  	for _, formationConstraints := range formationConstraintsPerFormation {
   336  		gqlFormationConstraints = append(gqlFormationConstraints, r.formationConstraintConverter.MultipleToGraphQL(formationConstraints))
   337  	}
   338  
   339  	if err = tx.Commit(); err != nil {
   340  		return nil, []error{err}
   341  	}
   342  
   343  	return gqlFormationConstraints, nil
   344  }