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 }