github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/eventdef/resolver.go (about) 1 package eventdef 2 3 import ( 4 "context" 5 6 "github.com/kyma-incubator/compass/components/director/pkg/resource" 7 "github.com/kyma-incubator/compass/components/director/pkg/str" 8 9 dataloader "github.com/kyma-incubator/compass/components/director/internal/dataloaders" 10 11 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 12 13 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 14 15 "github.com/kyma-incubator/compass/components/director/pkg/log" 16 "github.com/pkg/errors" 17 18 "github.com/kyma-incubator/compass/components/director/internal/model" 19 20 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 21 ) 22 23 // EventDefService is responsible for the service-layer EventDefinition operations. 24 // 25 //go:generate mockery --name=EventDefService --output=automock --outpkg=automock --case=underscore --disable-version-string 26 type EventDefService interface { 27 CreateInBundle(ctx context.Context, resourceType resource.Type, resourceID string, bundleID string, in model.EventDefinitionInput, spec *model.SpecInput) (string, error) 28 CreateInApplication(ctx context.Context, appID string, in model.EventDefinitionInput, spec *model.SpecInput) (string, error) 29 Update(ctx context.Context, resourceType resource.Type, id string, in model.EventDefinitionInput, spec *model.SpecInput) error 30 UpdateForApplication(ctx context.Context, id string, in model.EventDefinitionInput, specIn *model.SpecInput) error 31 Get(ctx context.Context, id string) (*model.EventDefinition, error) 32 Delete(ctx context.Context, resourceType resource.Type, id string) error 33 ListByApplicationIDPage(ctx context.Context, appID string, pageSize int, cursor string) (*model.EventDefinitionPage, error) 34 ListFetchRequests(ctx context.Context, eventDefIDs []string) ([]*model.FetchRequest, error) 35 } 36 37 // EventDefConverter converts EventDefinitions between the model.EventDefinition service-layer representation and the graphql-layer representation. 38 // 39 //go:generate mockery --name=EventDefConverter --output=automock --outpkg=automock --case=underscore --disable-version-string 40 type EventDefConverter interface { 41 ToGraphQL(in *model.EventDefinition, spec *model.Spec, bundleReference *model.BundleReference) (*graphql.EventDefinition, error) 42 MultipleToGraphQL(in []*model.EventDefinition, specs []*model.Spec, bundleRefs []*model.BundleReference) ([]*graphql.EventDefinition, error) 43 MultipleInputFromGraphQL(in []*graphql.EventDefinitionInput) ([]*model.EventDefinitionInput, []*model.SpecInput, error) 44 InputFromGraphQL(in *graphql.EventDefinitionInput) (*model.EventDefinitionInput, *model.SpecInput, error) 45 } 46 47 // FetchRequestConverter converts FetchRequest from the model.FetchRequest service-layer representation to the graphql-layer one. 48 // 49 //go:generate mockery --name=FetchRequestConverter --output=automock --outpkg=automock --case=underscore --disable-version-string 50 type FetchRequestConverter interface { 51 ToGraphQL(in *model.FetchRequest) (*graphql.FetchRequest, error) 52 } 53 54 // BundleService is responsible for the service-layer Bundle operations. 55 // 56 //go:generate mockery --name=BundleService --output=automock --outpkg=automock --case=underscore --disable-version-string 57 type BundleService interface { 58 Get(ctx context.Context, id string) (*model.Bundle, error) 59 } 60 61 // Resolver is an object responsible for resolver-layer EventDefinition operations 62 type Resolver struct { 63 transact persistence.Transactioner 64 svc EventDefService 65 bndlSvc BundleService 66 bndlRefSvc BundleReferenceService 67 converter EventDefConverter 68 frConverter FetchRequestConverter 69 specConverter SpecConverter 70 specService SpecService 71 } 72 73 // NewResolver returns a new object responsible for resolver-layer EventDefinition operations. 74 func NewResolver(transact persistence.Transactioner, svc EventDefService, bndlSvc BundleService, bndlRefSvc BundleReferenceService, converter EventDefConverter, frConverter FetchRequestConverter, specService SpecService, specConverter SpecConverter) *Resolver { 75 return &Resolver{ 76 transact: transact, 77 svc: svc, 78 bndlSvc: bndlSvc, 79 bndlRefSvc: bndlRefSvc, 80 converter: converter, 81 frConverter: frConverter, 82 specConverter: specConverter, 83 specService: specService, 84 } 85 } 86 87 // EventDefinitionsForApplication lists all EventDefinitions for a given application ID with paging. 88 func (r *Resolver) EventDefinitionsForApplication(ctx context.Context, appID string, first *int, after *graphql.PageCursor) (*graphql.EventDefinitionPage, error) { 89 tx, err := r.transact.Begin() 90 if err != nil { 91 return nil, err 92 } 93 defer r.transact.RollbackUnlessCommitted(ctx, tx) 94 95 log.C(ctx).Infof("Listing EventDefinition for Application with ID %s", appID) 96 97 ctx = persistence.SaveToContext(ctx, tx) 98 99 var cursor string 100 if after != nil { 101 cursor = string(*after) 102 } 103 if first == nil { 104 return nil, apperrors.NewInvalidDataError("missing required parameter 'first'") 105 } 106 107 eventPage, err := r.svc.ListByApplicationIDPage(ctx, appID, *first, cursor) 108 if err != nil { 109 return nil, errors.Wrapf(err, "while listing EventDefinition for Application with ID %s", appID) 110 } 111 112 gqlEvents := make([]*graphql.EventDefinition, 0, len(eventPage.Data)) 113 for _, event := range eventPage.Data { 114 spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, event.ID) 115 if err != nil { 116 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", event.ID) 117 } 118 119 gqlEvent, err := r.converter.ToGraphQL(event, spec, nil) 120 if err != nil { 121 return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", event.ID) 122 } 123 124 gqlEvents = append(gqlEvents, gqlEvent) 125 } 126 127 if err = tx.Commit(); err != nil { 128 return nil, err 129 } 130 131 return &graphql.EventDefinitionPage{ 132 Data: gqlEvents, 133 TotalCount: eventPage.TotalCount, 134 PageInfo: &graphql.PageInfo{ 135 StartCursor: graphql.PageCursor(eventPage.PageInfo.StartCursor), 136 EndCursor: graphql.PageCursor(eventPage.PageInfo.EndCursor), 137 HasNextPage: eventPage.PageInfo.HasNextPage, 138 }, 139 }, nil 140 } 141 142 // AddEventDefinitionToBundle adds an EventDefinition to a Bundle with a given ID. 143 func (r *Resolver) AddEventDefinitionToBundle(ctx context.Context, bundleID string, in graphql.EventDefinitionInput) (*graphql.EventDefinition, error) { 144 tx, err := r.transact.Begin() 145 if err != nil { 146 return nil, err 147 } 148 defer r.transact.RollbackUnlessCommitted(ctx, tx) 149 150 log.C(ctx).Infof("Adding EventDefinition to bundle with id %s", bundleID) 151 152 ctx = persistence.SaveToContext(ctx, tx) 153 154 convertedIn, convertedSpec, err := r.converter.InputFromGraphQL(&in) 155 if err != nil { 156 return nil, errors.Wrap(err, "while converting GraphQL input to EventDefinition") 157 } 158 159 bndl, err := r.bndlSvc.Get(ctx, bundleID) 160 if err != nil { 161 if apperrors.IsNotFoundError(err) { 162 return nil, apperrors.NewInvalidDataError("cannot add Event Definition to not existing Bundle") 163 } 164 return nil, errors.Wrapf(err, "while checking existence of Bundle with id %s when adding EventDefinition", bundleID) 165 } 166 167 id, err := r.svc.CreateInBundle(ctx, resource.Application, str.PtrStrToStr(bndl.ApplicationID), bundleID, *convertedIn, convertedSpec) 168 if err != nil { 169 return nil, errors.Wrapf(err, "while creating EventDefinition in Bundle with id %s", bundleID) 170 } 171 172 event, err := r.svc.Get(ctx, id) 173 if err != nil { 174 return nil, err 175 } 176 177 spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, event.ID) 178 if err != nil { 179 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", event.ID) 180 } 181 182 bndlRef, err := r.bndlRefSvc.GetForBundle(ctx, model.BundleEventReference, &event.ID, &bundleID) 183 if err != nil { 184 return nil, errors.Wrapf(err, "while getting bundle reference for EventDefinition with id %q", event.ID) 185 } 186 187 gqlEvent, err := r.converter.ToGraphQL(event, spec, bndlRef) 188 if err != nil { 189 return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", event.ID) 190 } 191 192 err = tx.Commit() 193 if err != nil { 194 return nil, err 195 } 196 197 log.C(ctx).Infof("EventDefinition with id %s successfully added to bundle with id %s", id, bundleID) 198 return gqlEvent, nil 199 } 200 201 // AddEventDefinitionToApplication adds an EventDefinition in the context of an Application without Bundle 202 func (r *Resolver) AddEventDefinitionToApplication(ctx context.Context, appID string, in graphql.EventDefinitionInput) (*graphql.EventDefinition, error) { 203 tx, err := r.transact.Begin() 204 if err != nil { 205 return nil, err 206 } 207 defer r.transact.RollbackUnlessCommitted(ctx, tx) 208 209 log.C(ctx).Infof("Adding EventDefinition to Application with id %s", appID) 210 211 ctx = persistence.SaveToContext(ctx, tx) 212 213 convertedIn, convertedSpec, err := r.converter.InputFromGraphQL(&in) 214 if err != nil { 215 return nil, errors.Wrap(err, "while converting GraphQL input to EventDefinition") 216 } 217 218 id, err := r.svc.CreateInApplication(ctx, appID, *convertedIn, convertedSpec) 219 if err != nil { 220 return nil, errors.Wrapf(err, "while creating EventDefinition in Application with id %s", appID) 221 } 222 223 event, err := r.svc.Get(ctx, id) 224 if err != nil { 225 return nil, err 226 } 227 228 spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, event.ID) 229 if err != nil { 230 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", event.ID) 231 } 232 233 gqlEvent, err := r.converter.ToGraphQL(event, spec, nil) 234 if err != nil { 235 return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", event.ID) 236 } 237 238 if err = tx.Commit(); err != nil { 239 return nil, err 240 } 241 242 log.C(ctx).Infof("EventDefinition with id %s successfully added to Application with id %s", id, appID) 243 return gqlEvent, nil 244 } 245 246 // UpdateEventDefinition updates an EventDefinition by its ID. 247 func (r *Resolver) UpdateEventDefinition(ctx context.Context, id string, in graphql.EventDefinitionInput) (*graphql.EventDefinition, error) { 248 tx, err := r.transact.Begin() 249 if err != nil { 250 return nil, err 251 } 252 defer r.transact.RollbackUnlessCommitted(ctx, tx) 253 254 log.C(ctx).Infof("Updating EventDefinition with id %s", id) 255 256 ctx = persistence.SaveToContext(ctx, tx) 257 258 convertedIn, convertedSpec, err := r.converter.InputFromGraphQL(&in) 259 if err != nil { 260 return nil, errors.Wrapf(err, "while converting GraphQL input to EventDefinition with id %s", id) 261 } 262 263 err = r.svc.Update(ctx, resource.Application, id, *convertedIn, convertedSpec) 264 if err != nil { 265 return nil, err 266 } 267 268 event, err := r.svc.Get(ctx, id) 269 if err != nil { 270 return nil, err 271 } 272 273 spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, event.ID) 274 if err != nil { 275 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", event.ID) 276 } 277 278 bndlRef, err := r.bndlRefSvc.GetForBundle(ctx, model.BundleEventReference, &event.ID, nil) 279 if err != nil { 280 return nil, errors.Wrapf(err, "while getting bundle reference for EventDefinition with id %q", event.ID) 281 } 282 283 gqlEvent, err := r.converter.ToGraphQL(event, spec, bndlRef) 284 if err != nil { 285 return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", event.ID) 286 } 287 288 err = tx.Commit() 289 if err != nil { 290 return nil, err 291 } 292 293 log.C(ctx).Infof("EventDefinition with id %s successfully updated.", id) 294 return gqlEvent, nil 295 } 296 297 // UpdateEventDefinitionForApplication updates an EventDefinition for Application without being in a Bundle 298 func (r *Resolver) UpdateEventDefinitionForApplication(ctx context.Context, id string, in graphql.EventDefinitionInput) (*graphql.EventDefinition, error) { 299 tx, err := r.transact.Begin() 300 if err != nil { 301 return nil, err 302 } 303 defer r.transact.RollbackUnlessCommitted(ctx, tx) 304 305 log.C(ctx).Infof("Updating EventDefinition with id %s", id) 306 307 ctx = persistence.SaveToContext(ctx, tx) 308 309 convertedIn, convertedSpec, err := r.converter.InputFromGraphQL(&in) 310 if err != nil { 311 return nil, errors.Wrapf(err, "while converting GraphQL input to EventDefinition with id %s", id) 312 } 313 314 err = r.svc.UpdateForApplication(ctx, id, *convertedIn, convertedSpec) 315 if err != nil { 316 return nil, err 317 } 318 319 event, err := r.svc.Get(ctx, id) 320 if err != nil { 321 return nil, err 322 } 323 324 spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, event.ID) 325 if err != nil { 326 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", event.ID) 327 } 328 329 gqlEvent, err := r.converter.ToGraphQL(event, spec, nil) 330 if err != nil { 331 return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", event.ID) 332 } 333 334 if err = tx.Commit(); err != nil { 335 return nil, err 336 } 337 338 log.C(ctx).Infof("EventDefinition with id %s successfully updated.", id) 339 return gqlEvent, nil 340 } 341 342 // DeleteEventDefinition deletes an EventDefinition by its ID. 343 func (r *Resolver) DeleteEventDefinition(ctx context.Context, id string) (*graphql.EventDefinition, error) { 344 tx, err := r.transact.Begin() 345 if err != nil { 346 return nil, err 347 } 348 defer r.transact.RollbackUnlessCommitted(ctx, tx) 349 350 log.C(ctx).Infof("Deleting EventDefinition with id %s", id) 351 352 ctx = persistence.SaveToContext(ctx, tx) 353 354 event, err := r.svc.Get(ctx, id) 355 if err != nil { 356 return nil, err 357 } 358 359 spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, event.ID) 360 if err != nil { 361 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", event.ID) 362 } 363 364 bndlRef, err := r.bndlRefSvc.GetForBundle(ctx, model.BundleEventReference, &event.ID, nil) 365 if err != nil { 366 return nil, errors.Wrapf(err, "while getting bundle reference for EventDefinition with id %q", event.ID) 367 } 368 369 gqlEvent, err := r.converter.ToGraphQL(event, spec, bndlRef) 370 if err != nil { 371 return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", event.ID) 372 } 373 374 err = r.svc.Delete(ctx, resource.Application, id) 375 if err != nil { 376 return nil, err 377 } 378 379 err = tx.Commit() 380 if err != nil { 381 return nil, err 382 } 383 384 log.C(ctx).Infof("EventDefinition with id %s successfully deleted.", id) 385 return gqlEvent, nil 386 } 387 388 // RefetchEventDefinitionSpec refetches an EventDefinitionSpec for EventDefinition with given ID. 389 func (r *Resolver) RefetchEventDefinitionSpec(ctx context.Context, eventID string) (*graphql.EventSpec, error) { 390 tx, err := r.transact.Begin() 391 if err != nil { 392 return nil, err 393 } 394 defer r.transact.RollbackUnlessCommitted(ctx, tx) 395 396 log.C(ctx).Infof("Refetching EventDefinitionSpec for EventDefinition with id %s", eventID) 397 398 ctx = persistence.SaveToContext(ctx, tx) 399 400 dbSpec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, eventID) 401 if err != nil { 402 return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", eventID) 403 } 404 405 if dbSpec == nil { 406 return nil, errors.Errorf("spec for Event with id %q not found", eventID) 407 } 408 409 spec, err := r.specService.RefetchSpec(ctx, dbSpec.ID, model.EventSpecReference) 410 if err != nil { 411 return nil, err 412 } 413 414 converted, err := r.specConverter.ToGraphQLEventSpec(spec) 415 if err != nil { 416 return nil, err 417 } 418 419 err = tx.Commit() 420 if err != nil { 421 return nil, err 422 } 423 424 log.C(ctx).Infof("Successfully refetched EventDefinitionSpec for EventDefinition with id %s", eventID) 425 return converted, nil 426 } 427 428 // FetchRequest returns a FetchRequest by a given EventSpec via dataloaders. 429 func (r *Resolver) FetchRequest(ctx context.Context, obj *graphql.EventSpec) (*graphql.FetchRequest, error) { 430 params := dataloader.ParamFetchRequestEventDef{ID: obj.ID, Ctx: ctx} 431 return dataloader.ForFetchRequestEventDef(ctx).FetchRequestEventDefByID.Load(params) 432 } 433 434 // FetchRequestEventDefDataLoader is the dataloader implementation. 435 func (r *Resolver) FetchRequestEventDefDataLoader(keys []dataloader.ParamFetchRequestEventDef) ([]*graphql.FetchRequest, []error) { 436 if len(keys) == 0 { 437 return nil, []error{apperrors.NewInternalError("No EventDef specs found")} 438 } 439 440 ctx := keys[0].Ctx 441 442 specIDs := make([]string, 0, len(keys)) 443 for _, key := range keys { 444 if key.ID == "" { 445 return nil, []error{apperrors.NewInternalError("Cannot fetch FetchRequest. EventDefinition Spec ID is empty")} 446 } 447 specIDs = append(specIDs, key.ID) 448 } 449 450 tx, err := r.transact.Begin() 451 if err != nil { 452 return nil, []error{err} 453 } 454 defer r.transact.RollbackUnlessCommitted(ctx, tx) 455 456 ctx = persistence.SaveToContext(ctx, tx) 457 458 fetchRequests, err := r.svc.ListFetchRequests(ctx, specIDs) 459 if err != nil { 460 return nil, []error{err} 461 } 462 463 if fetchRequests == nil { 464 return nil, nil 465 } 466 467 gqlFetchRequests := make([]*graphql.FetchRequest, 0, len(fetchRequests)) 468 for _, fr := range fetchRequests { 469 fetchRequest, err := r.frConverter.ToGraphQL(fr) 470 if err != nil { 471 return nil, []error{err} 472 } 473 gqlFetchRequests = append(gqlFetchRequests, fetchRequest) 474 } 475 476 err = tx.Commit() 477 if err != nil { 478 return nil, []error{err} 479 } 480 481 log.C(ctx).Infof("Successfully fetched requests for Specifications %v", specIDs) 482 return gqlFetchRequests, nil 483 }