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

     1  package bundle
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
     7  
     8  	dataloader "github.com/kyma-incubator/compass/components/director/internal/dataloaders"
     9  
    10  	"github.com/kyma-incubator/compass/components/director/internal/model"
    11  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    12  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    13  
    14  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    15  
    16  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    17  	"github.com/pkg/errors"
    18  
    19  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    20  )
    21  
    22  // BundleService missing godoc
    23  //
    24  //go:generate mockery --name=BundleService --output=automock --outpkg=automock --case=underscore --disable-version-string
    25  type BundleService interface {
    26  	Create(ctx context.Context, resourceType resource.Type, resourceID string, in model.BundleCreateInput) (string, error)
    27  	Update(ctx context.Context, resourceType resource.Type, id string, in model.BundleUpdateInput) error
    28  	Delete(ctx context.Context, resourceType resource.Type, id string) error
    29  	Get(ctx context.Context, id string) (*model.Bundle, error)
    30  }
    31  
    32  // BundleConverter missing godoc
    33  //
    34  //go:generate mockery --name=BundleConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    35  type BundleConverter interface {
    36  	ToGraphQL(in *model.Bundle) (*graphql.Bundle, error)
    37  	CreateInputFromGraphQL(in graphql.BundleCreateInput) (model.BundleCreateInput, error)
    38  	UpdateInputFromGraphQL(in graphql.BundleUpdateInput) (*model.BundleUpdateInput, error)
    39  }
    40  
    41  // BundleInstanceAuthService missing godoc
    42  //
    43  //go:generate mockery --name=BundleInstanceAuthService --output=automock --outpkg=automock --case=underscore --disable-version-string
    44  type BundleInstanceAuthService interface {
    45  	GetForBundle(ctx context.Context, id string, bundleID string) (*model.BundleInstanceAuth, error)
    46  	List(ctx context.Context, id string) ([]*model.BundleInstanceAuth, error)
    47  }
    48  
    49  // BundleInstanceAuthConverter missing godoc
    50  //
    51  //go:generate mockery --name=BundleInstanceAuthConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    52  type BundleInstanceAuthConverter interface {
    53  	ToGraphQL(in *model.BundleInstanceAuth) (*graphql.BundleInstanceAuth, error)
    54  	MultipleToGraphQL(in []*model.BundleInstanceAuth) ([]*graphql.BundleInstanceAuth, error)
    55  }
    56  
    57  // APIService missing godoc
    58  //
    59  //go:generate mockery --name=APIService --output=automock --outpkg=automock --case=underscore --disable-version-string
    60  type APIService interface {
    61  	ListByBundleIDs(ctx context.Context, bundleIDs []string, pageSize int, cursor string) ([]*model.APIDefinitionPage, error)
    62  	GetForBundle(ctx context.Context, id string, bundleID string) (*model.APIDefinition, error)
    63  	CreateInBundle(ctx context.Context, resourceType resource.Type, resourceID string, bundleID string, in model.APIDefinitionInput, spec *model.SpecInput) (string, error)
    64  	DeleteAllByBundleID(ctx context.Context, bundleID string) error
    65  }
    66  
    67  // APIConverter missing godoc
    68  //
    69  //go:generate mockery --name=APIConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    70  type APIConverter interface {
    71  	ToGraphQL(in *model.APIDefinition, spec *model.Spec, bundleRef *model.BundleReference) (*graphql.APIDefinition, error)
    72  	MultipleToGraphQL(in []*model.APIDefinition, specs []*model.Spec, bundleRefs []*model.BundleReference) ([]*graphql.APIDefinition, error)
    73  	MultipleInputFromGraphQL(in []*graphql.APIDefinitionInput) ([]*model.APIDefinitionInput, []*model.SpecInput, error)
    74  }
    75  
    76  // EventService missing godoc
    77  //
    78  //go:generate mockery --name=EventService --output=automock --outpkg=automock --case=underscore --disable-version-string
    79  type EventService interface {
    80  	ListByBundleIDs(ctx context.Context, bundleIDs []string, pageSize int, cursor string) ([]*model.EventDefinitionPage, error)
    81  	GetForBundle(ctx context.Context, id string, bundleID string) (*model.EventDefinition, error)
    82  	CreateInBundle(ctx context.Context, resourceType resource.Type, resourceID string, bundleID string, in model.EventDefinitionInput, spec *model.SpecInput) (string, error)
    83  	DeleteAllByBundleID(ctx context.Context, bundleID string) error
    84  }
    85  
    86  // EventConverter missing godoc
    87  //
    88  //go:generate mockery --name=EventConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    89  type EventConverter interface {
    90  	ToGraphQL(in *model.EventDefinition, spec *model.Spec, bundleReference *model.BundleReference) (*graphql.EventDefinition, error)
    91  	MultipleToGraphQL(in []*model.EventDefinition, specs []*model.Spec, bundleRefs []*model.BundleReference) ([]*graphql.EventDefinition, error)
    92  	MultipleInputFromGraphQL(in []*graphql.EventDefinitionInput) ([]*model.EventDefinitionInput, []*model.SpecInput, error)
    93  }
    94  
    95  // DocumentService missing godoc
    96  //
    97  //go:generate mockery --name=DocumentService --output=automock --outpkg=automock --case=underscore --disable-version-string
    98  type DocumentService interface {
    99  	GetForBundle(ctx context.Context, id string, bundleID string) (*model.Document, error)
   100  	CreateInBundle(ctx context.Context, resourceType resource.Type, resourceID string, bundleID string, in model.DocumentInput) (string, error)
   101  	ListByBundleIDs(ctx context.Context, bundleIDs []string, pageSize int, cursor string) ([]*model.DocumentPage, error)
   102  }
   103  
   104  // DocumentConverter missing godoc
   105  //
   106  //go:generate mockery --name=DocumentConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
   107  type DocumentConverter interface {
   108  	ToGraphQL(in *model.Document) *graphql.Document
   109  	MultipleToGraphQL(in []*model.Document) []*graphql.Document
   110  	MultipleInputFromGraphQL(in []*graphql.DocumentInput) ([]*model.DocumentInput, error)
   111  }
   112  
   113  // SpecService missing godoc
   114  //
   115  //go:generate mockery --name=SpecService --output=automock --outpkg=automock --case=underscore --disable-version-string
   116  type SpecService interface {
   117  	GetByReferenceObjectID(ctx context.Context, resourceType resource.Type, objectType model.SpecReferenceObjectType, objectID string) (*model.Spec, error)
   118  	ListByReferenceObjectIDs(ctx context.Context, objectType model.SpecReferenceObjectType, objectIDs []string) ([]*model.Spec, error)
   119  }
   120  
   121  // BundleReferenceService missing godoc
   122  //
   123  //go:generate mockery --name=BundleReferenceService --output=automock --outpkg=automock --case=underscore --disable-version-string
   124  type BundleReferenceService interface {
   125  	GetForBundle(ctx context.Context, objectType model.BundleReferenceObjectType, objectID, bundleID *string) (*model.BundleReference, error)
   126  	ListByBundleIDs(ctx context.Context, objectType model.BundleReferenceObjectType, bundleIDs []string, pageSize int, cursor string) ([]*model.BundleReference, map[string]int, error)
   127  }
   128  
   129  // ApplicationService is responsible for the service-layer Application operations.
   130  //
   131  //go:generate mockery --name=ApplicationService --output=automock --outpkg=automock --case=underscore --disable-version-string
   132  type ApplicationService interface {
   133  	UpdateBaseURL(ctx context.Context, appID, targetURL string) error
   134  }
   135  
   136  // Resolver missing godoc
   137  type Resolver struct {
   138  	transact persistence.Transactioner
   139  
   140  	bundleSvc             BundleService
   141  	bundleInstanceAuthSvc BundleInstanceAuthService
   142  	bundleReferenceSvc    BundleReferenceService
   143  	apiSvc                APIService
   144  	eventSvc              EventService
   145  	documentSvc           DocumentService
   146  	appSvc                ApplicationService
   147  
   148  	bundleConverter             BundleConverter
   149  	bundleInstanceAuthConverter BundleInstanceAuthConverter
   150  	apiConverter                APIConverter
   151  	eventConverter              EventConverter
   152  	documentConverter           DocumentConverter
   153  
   154  	specService SpecService
   155  }
   156  
   157  // NewResolver missing godoc
   158  func NewResolver(
   159  	transact persistence.Transactioner,
   160  	bundleSvc BundleService,
   161  	bundleInstanceAuthSvc BundleInstanceAuthService,
   162  	bundleReferenceSvc BundleReferenceService,
   163  	apiSvc APIService,
   164  	eventSvc EventService,
   165  	documentSvc DocumentService,
   166  	bundleConverter BundleConverter,
   167  	bundleInstanceAuthConverter BundleInstanceAuthConverter,
   168  	apiConv APIConverter,
   169  	eventConv EventConverter,
   170  	documentConv DocumentConverter,
   171  	specSerice SpecService,
   172  	appSvc ApplicationService) *Resolver {
   173  	return &Resolver{
   174  		transact:                    transact,
   175  		bundleConverter:             bundleConverter,
   176  		bundleSvc:                   bundleSvc,
   177  		bundleInstanceAuthSvc:       bundleInstanceAuthSvc,
   178  		bundleReferenceSvc:          bundleReferenceSvc,
   179  		apiSvc:                      apiSvc,
   180  		eventSvc:                    eventSvc,
   181  		documentSvc:                 documentSvc,
   182  		bundleInstanceAuthConverter: bundleInstanceAuthConverter,
   183  		apiConverter:                apiConv,
   184  		eventConverter:              eventConv,
   185  		documentConverter:           documentConv,
   186  		specService:                 specSerice,
   187  		appSvc:                      appSvc,
   188  	}
   189  }
   190  
   191  // AddBundle missing godoc
   192  func (r *Resolver) AddBundle(ctx context.Context, applicationID string, in graphql.BundleCreateInput) (*graphql.Bundle, error) {
   193  	tx, err := r.transact.Begin()
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   198  
   199  	log.C(ctx).Infof("Adding bundle to Application with id %s", applicationID)
   200  
   201  	ctx = persistence.SaveToContext(ctx, tx)
   202  
   203  	convertedIn, err := r.bundleConverter.CreateInputFromGraphQL(in)
   204  	if err != nil {
   205  		return nil, errors.Wrap(err, "while converting input from GraphQL")
   206  	}
   207  
   208  	id, err := r.bundleSvc.Create(ctx, resource.Application, applicationID, convertedIn)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	bndl, err := r.bundleSvc.Get(ctx, id)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	if len(in.APIDefinitions) > 0 {
   219  		if err = r.appSvc.UpdateBaseURL(ctx, *bndl.ApplicationID, in.APIDefinitions[0].TargetURL); err != nil {
   220  			return nil, errors.Wrapf(err, "while trying to update baseURL")
   221  		}
   222  	}
   223  
   224  	gqlBundle, err := r.bundleConverter.ToGraphQL(bndl)
   225  	if err != nil {
   226  		return nil, errors.Wrapf(err, "while converting Bundle with id %s to GraphQL", id)
   227  	}
   228  
   229  	err = tx.Commit()
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	log.C(ctx).Infof("Bundle with id %s successfully added to Application with id %s", id, applicationID)
   235  	return gqlBundle, nil
   236  }
   237  
   238  // UpdateBundle missing godoc
   239  func (r *Resolver) UpdateBundle(ctx context.Context, id string, in graphql.BundleUpdateInput) (*graphql.Bundle, error) {
   240  	tx, err := r.transact.Begin()
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   245  
   246  	log.C(ctx).Infof("Updating Bundle with id %s", id)
   247  
   248  	ctx = persistence.SaveToContext(ctx, tx)
   249  
   250  	convertedIn, err := r.bundleConverter.UpdateInputFromGraphQL(in)
   251  	if err != nil {
   252  		return nil, errors.Wrapf(err, "while converting converting GraphQL input to Bundle with id %s", id)
   253  	}
   254  
   255  	err = r.bundleSvc.Update(ctx, resource.Application, id, *convertedIn)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	bndl, err := r.bundleSvc.Get(ctx, id)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	gqlBndl, err := r.bundleConverter.ToGraphQL(bndl)
   266  	if err != nil {
   267  		return nil, errors.Wrapf(err, "while converting Bundle with id %s to GraphQL", id)
   268  	}
   269  
   270  	err = tx.Commit()
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  
   275  	log.C(ctx).Infof("Bundle with id %s successfully updated.", id)
   276  	return gqlBndl, nil
   277  }
   278  
   279  // DeleteBundle missing godoc
   280  func (r *Resolver) DeleteBundle(ctx context.Context, id string) (*graphql.Bundle, error) {
   281  	tx, err := r.transact.Begin()
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   286  
   287  	log.C(ctx).Infof("Deleting Bundle with id %s", id)
   288  
   289  	ctx = persistence.SaveToContext(ctx, tx)
   290  
   291  	bndl, err := r.bundleSvc.Get(ctx, id)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	err = r.apiSvc.DeleteAllByBundleID(ctx, id)
   297  	if err != nil {
   298  		return nil, err
   299  	}
   300  
   301  	err = r.eventSvc.DeleteAllByBundleID(ctx, id)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	err = r.bundleSvc.Delete(ctx, resource.Application, id)
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  
   311  	deletedBndl, err := r.bundleConverter.ToGraphQL(bndl)
   312  	if err != nil {
   313  		return nil, errors.Wrapf(err, "while converting Bundle with id %s to GraphQL", id)
   314  	}
   315  
   316  	err = tx.Commit()
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	log.C(ctx).Infof("Bundle with id %s successfully deleted.", id)
   322  	return deletedBndl, nil
   323  }
   324  
   325  // InstanceAuth missing godoc
   326  func (r *Resolver) InstanceAuth(ctx context.Context, obj *graphql.Bundle, id string) (*graphql.BundleInstanceAuth, error) {
   327  	if obj == nil {
   328  		return nil, apperrors.NewInternalError("Bundle cannot be empty")
   329  	}
   330  
   331  	tx, err := r.transact.Begin()
   332  	if err != nil {
   333  		return nil, err
   334  	}
   335  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   336  
   337  	ctx = persistence.SaveToContext(ctx, tx)
   338  
   339  	bndl, err := r.bundleInstanceAuthSvc.GetForBundle(ctx, id, obj.ID)
   340  	if err != nil {
   341  		if apperrors.IsNotFoundError(err) {
   342  			return nil, tx.Commit()
   343  		}
   344  		return nil, err
   345  	}
   346  
   347  	gqlAuth, err := r.bundleInstanceAuthConverter.ToGraphQL(bndl)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	err = tx.Commit()
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  
   357  	return gqlAuth, nil
   358  }
   359  
   360  // InstanceAuths missing godoc
   361  func (r *Resolver) InstanceAuths(ctx context.Context, obj *graphql.Bundle) ([]*graphql.BundleInstanceAuth, error) {
   362  	if obj == nil {
   363  		return nil, apperrors.NewInternalError("Bundle cannot be empty")
   364  	}
   365  
   366  	tx, err := r.transact.Begin()
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   371  	ctx = persistence.SaveToContext(ctx, tx)
   372  
   373  	bndlInstanceAuths, err := r.bundleInstanceAuthSvc.List(ctx, obj.ID)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  
   378  	gqlAuths, err := r.bundleInstanceAuthConverter.MultipleToGraphQL(bndlInstanceAuths)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  
   383  	err = tx.Commit()
   384  	if err != nil {
   385  		return nil, err
   386  	}
   387  
   388  	return gqlAuths, nil
   389  }
   390  
   391  // APIDefinition missing godoc
   392  func (r *Resolver) APIDefinition(ctx context.Context, obj *graphql.Bundle, id string) (*graphql.APIDefinition, error) {
   393  	tx, err := r.transact.Begin()
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   398  
   399  	ctx = persistence.SaveToContext(ctx, tx)
   400  
   401  	api, err := r.apiSvc.GetForBundle(ctx, id, obj.ID)
   402  	if err != nil {
   403  		if apperrors.IsNotFoundError(err) {
   404  			return nil, tx.Commit()
   405  		}
   406  		return nil, err
   407  	}
   408  
   409  	spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.APISpecReference, api.ID)
   410  	if err != nil {
   411  		return nil, errors.Wrapf(err, "while getting spec for APIDefinition with id %q", api.ID)
   412  	}
   413  
   414  	bndlRef, err := r.bundleReferenceSvc.GetForBundle(ctx, model.BundleAPIReference, &api.ID, nil)
   415  	if err != nil {
   416  		return nil, errors.Wrapf(err, "while getting bundle reference for APIDefinition with id %q", api.ID)
   417  	}
   418  
   419  	gqlAPI, err := r.apiConverter.ToGraphQL(api, spec, bndlRef)
   420  	if err != nil {
   421  		return nil, errors.Wrapf(err, "while converting APIDefinition with id %q to graphQL", api.ID)
   422  	}
   423  
   424  	err = tx.Commit()
   425  	if err != nil {
   426  		return nil, err
   427  	}
   428  
   429  	return gqlAPI, nil
   430  }
   431  
   432  // APIDefinitions missing godoc
   433  func (r *Resolver) APIDefinitions(ctx context.Context, obj *graphql.Bundle, group *string, first *int, after *graphql.PageCursor) (*graphql.APIDefinitionPage, error) {
   434  	param := dataloader.ParamAPIDef{ID: obj.ID, Ctx: ctx, First: first, After: after}
   435  	return dataloader.APIDefFor(ctx).APIDefByID.Load(param)
   436  }
   437  
   438  // APIDefinitionsDataLoader missing godoc
   439  func (r *Resolver) APIDefinitionsDataLoader(keys []dataloader.ParamAPIDef) ([]*graphql.APIDefinitionPage, []error) {
   440  	if len(keys) == 0 {
   441  		return nil, []error{apperrors.NewInternalError("No Bundles found")}
   442  	}
   443  
   444  	if keys[0].First == nil {
   445  		return nil, []error{apperrors.NewInvalidDataError("missing required parameter 'first'")}
   446  	}
   447  
   448  	ctx := keys[0].Ctx
   449  	first := keys[0].First
   450  
   451  	bundleIDs := make([]string, 0, len(keys))
   452  	for _, key := range keys {
   453  		bundleIDs = append(bundleIDs, key.ID)
   454  	}
   455  
   456  	var cursor string
   457  	if keys[0].After != nil {
   458  		cursor = string(*keys[0].After)
   459  	}
   460  
   461  	tx, err := r.transact.Begin()
   462  	if err != nil {
   463  		return nil, []error{err}
   464  	}
   465  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   466  
   467  	ctx = persistence.SaveToContext(ctx, tx)
   468  
   469  	apiDefPages, err := r.apiSvc.ListByBundleIDs(ctx, bundleIDs, *first, cursor)
   470  	if err != nil {
   471  		return nil, []error{err}
   472  	}
   473  
   474  	var apiDefIDs []string
   475  	for _, page := range apiDefPages {
   476  		for _, apiDefinition := range page.Data {
   477  			apiDefIDs = append(apiDefIDs, apiDefinition.ID)
   478  		}
   479  	}
   480  
   481  	specs, err := r.specService.ListByReferenceObjectIDs(ctx, model.APISpecReference, apiDefIDs)
   482  	if err != nil {
   483  		return nil, []error{err}
   484  	}
   485  
   486  	references, _, err := r.bundleReferenceSvc.ListByBundleIDs(ctx, model.BundleAPIReference, bundleIDs, *first, cursor)
   487  	if err != nil {
   488  		return nil, []error{err}
   489  	}
   490  
   491  	refsByBundleID := map[string][]*model.BundleReference{}
   492  	for _, ref := range references {
   493  		refsByBundleID[*ref.BundleID] = append(refsByBundleID[*ref.BundleID], ref)
   494  	}
   495  
   496  	apiDefIDtoSpec := make(map[string]*model.Spec)
   497  	for _, spec := range specs {
   498  		apiDefIDtoSpec[spec.ObjectID] = spec
   499  	}
   500  
   501  	gqlAPIDefs := make([]*graphql.APIDefinitionPage, 0, len(apiDefPages))
   502  	for i, apisPage := range apiDefPages {
   503  		apiSpecs := make([]*model.Spec, 0, len(apisPage.Data))
   504  		apiBundleRefs := make([]*model.BundleReference, 0, len(apisPage.Data))
   505  		for _, api := range apisPage.Data {
   506  			apiSpecs = append(apiSpecs, apiDefIDtoSpec[api.ID])
   507  			br, err := getBundleReferenceForAPI(api.ID, refsByBundleID[bundleIDs[i]])
   508  			if err != nil {
   509  				return nil, []error{err}
   510  			}
   511  			apiBundleRefs = append(apiBundleRefs, br)
   512  		}
   513  
   514  		gqlAPIs, err := r.apiConverter.MultipleToGraphQL(apisPage.Data, apiSpecs, apiBundleRefs)
   515  		if err != nil {
   516  			return nil, []error{errors.Wrapf(err, "while converting api definitions")}
   517  		}
   518  
   519  		gqlAPIDefs = append(gqlAPIDefs, &graphql.APIDefinitionPage{Data: gqlAPIs, TotalCount: apisPage.TotalCount, PageInfo: &graphql.PageInfo{
   520  			StartCursor: graphql.PageCursor(apisPage.PageInfo.StartCursor),
   521  			EndCursor:   graphql.PageCursor(apisPage.PageInfo.EndCursor),
   522  			HasNextPage: apisPage.PageInfo.HasNextPage,
   523  		}})
   524  	}
   525  
   526  	err = tx.Commit()
   527  	if err != nil {
   528  		return nil, []error{err}
   529  	}
   530  
   531  	log.C(ctx).Infof("Successfully fetched api definitions for bundles %v", bundleIDs)
   532  	return gqlAPIDefs, nil
   533  }
   534  
   535  // EventDefinition missing godoc
   536  func (r *Resolver) EventDefinition(ctx context.Context, obj *graphql.Bundle, id string) (*graphql.EventDefinition, error) {
   537  	tx, err := r.transact.Begin()
   538  	if err != nil {
   539  		return nil, err
   540  	}
   541  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   542  
   543  	ctx = persistence.SaveToContext(ctx, tx)
   544  
   545  	eventAPI, err := r.eventSvc.GetForBundle(ctx, id, obj.ID)
   546  	if err != nil {
   547  		if apperrors.IsNotFoundError(err) {
   548  			return nil, tx.Commit()
   549  		}
   550  		return nil, err
   551  	}
   552  
   553  	spec, err := r.specService.GetByReferenceObjectID(ctx, resource.Application, model.EventSpecReference, eventAPI.ID)
   554  	if err != nil {
   555  		return nil, errors.Wrapf(err, "while getting spec for EventDefinition with id %q", eventAPI.ID)
   556  	}
   557  
   558  	bndlRef, err := r.bundleReferenceSvc.GetForBundle(ctx, model.BundleEventReference, &eventAPI.ID, nil)
   559  	if err != nil {
   560  		return nil, errors.Wrapf(err, "while getting bundle reference for EventDefinition with id %q", eventAPI.ID)
   561  	}
   562  
   563  	gqlEvent, err := r.eventConverter.ToGraphQL(eventAPI, spec, bndlRef)
   564  	if err != nil {
   565  		return nil, errors.Wrapf(err, "while converting EventDefinition with id %q to graphQL", eventAPI.ID)
   566  	}
   567  
   568  	err = tx.Commit()
   569  	if err != nil {
   570  		return nil, err
   571  	}
   572  
   573  	return gqlEvent, nil
   574  }
   575  
   576  // EventDefinitions missing godoc
   577  func (r *Resolver) EventDefinitions(ctx context.Context, obj *graphql.Bundle, group *string, first *int, after *graphql.PageCursor) (*graphql.EventDefinitionPage, error) {
   578  	param := dataloader.ParamEventDef{ID: obj.ID, Ctx: ctx, First: first, After: after}
   579  	return dataloader.EventDefFor(ctx).EventDefByID.Load(param)
   580  }
   581  
   582  // EventDefinitionsDataLoader missing godoc
   583  func (r *Resolver) EventDefinitionsDataLoader(keys []dataloader.ParamEventDef) ([]*graphql.EventDefinitionPage, []error) {
   584  	if len(keys) == 0 {
   585  		return nil, []error{apperrors.NewInternalError("No Bundles found")}
   586  	}
   587  
   588  	if keys[0].First == nil {
   589  		return nil, []error{apperrors.NewInvalidDataError("missing required parameter 'first'")}
   590  	}
   591  
   592  	ctx := keys[0].Ctx
   593  	first := keys[0].First
   594  
   595  	bundleIDs := make([]string, 0, len(keys))
   596  	for _, key := range keys {
   597  		bundleIDs = append(bundleIDs, key.ID)
   598  	}
   599  
   600  	var cursor string
   601  	if keys[0].After != nil {
   602  		cursor = string(*keys[0].After)
   603  	}
   604  
   605  	tx, err := r.transact.Begin()
   606  	if err != nil {
   607  		return nil, []error{err}
   608  	}
   609  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   610  
   611  	ctx = persistence.SaveToContext(ctx, tx)
   612  
   613  	eventAPIDefPages, err := r.eventSvc.ListByBundleIDs(ctx, bundleIDs, *first, cursor)
   614  	if err != nil {
   615  		return nil, []error{err}
   616  	}
   617  
   618  	var eventAPIDefIDs []string
   619  	for _, page := range eventAPIDefPages {
   620  		for _, eventAPIDefinition := range page.Data {
   621  			eventAPIDefIDs = append(eventAPIDefIDs, eventAPIDefinition.ID)
   622  		}
   623  	}
   624  
   625  	specs, err := r.specService.ListByReferenceObjectIDs(ctx, model.EventSpecReference, eventAPIDefIDs)
   626  	if err != nil {
   627  		return nil, []error{err}
   628  	}
   629  
   630  	references, _, err := r.bundleReferenceSvc.ListByBundleIDs(ctx, model.BundleEventReference, bundleIDs, *first, cursor)
   631  	if err != nil {
   632  		return nil, []error{err}
   633  	}
   634  
   635  	eventAPIDefIDtoSpec := make(map[string]*model.Spec)
   636  	for _, spec := range specs {
   637  		eventAPIDefIDtoSpec[spec.ObjectID] = spec
   638  	}
   639  
   640  	eventAPIDefIDtoRef := make(map[string]*model.BundleReference)
   641  	for _, reference := range references {
   642  		eventAPIDefIDtoRef[*reference.ObjectID] = reference
   643  	}
   644  
   645  	gqlEventDefs := make([]*graphql.EventDefinitionPage, 0, len(eventAPIDefPages))
   646  	for _, eventPage := range eventAPIDefPages {
   647  		eventSpecs := make([]*model.Spec, 0, len(eventPage.Data))
   648  		eventBundleRefs := make([]*model.BundleReference, 0, len(eventPage.Data))
   649  		for _, event := range eventPage.Data {
   650  			eventSpecs = append(eventSpecs, eventAPIDefIDtoSpec[event.ID])
   651  			eventBundleRefs = append(eventBundleRefs, eventAPIDefIDtoRef[event.ID])
   652  		}
   653  
   654  		gqlEvents, err := r.eventConverter.MultipleToGraphQL(eventPage.Data, eventSpecs, eventBundleRefs)
   655  		if err != nil {
   656  			return nil, []error{errors.Wrapf(err, "while converting event definitions")}
   657  		}
   658  
   659  		gqlEventDefs = append(gqlEventDefs, &graphql.EventDefinitionPage{Data: gqlEvents, TotalCount: eventPage.TotalCount, PageInfo: &graphql.PageInfo{
   660  			StartCursor: graphql.PageCursor(eventPage.PageInfo.StartCursor),
   661  			EndCursor:   graphql.PageCursor(eventPage.PageInfo.EndCursor),
   662  			HasNextPage: eventPage.PageInfo.HasNextPage,
   663  		}})
   664  	}
   665  
   666  	err = tx.Commit()
   667  	if err != nil {
   668  		return nil, []error{err}
   669  	}
   670  
   671  	log.C(ctx).Infof("Successfully fetched event definitions for bundles %v", bundleIDs)
   672  	return gqlEventDefs, nil
   673  }
   674  
   675  // Document missing godoc
   676  func (r *Resolver) Document(ctx context.Context, obj *graphql.Bundle, id string) (*graphql.Document, error) {
   677  	tx, err := r.transact.Begin()
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   682  
   683  	ctx = persistence.SaveToContext(ctx, tx)
   684  
   685  	eventAPI, err := r.documentSvc.GetForBundle(ctx, id, obj.ID)
   686  	if err != nil {
   687  		if apperrors.IsNotFoundError(err) {
   688  			return nil, tx.Commit()
   689  		}
   690  		return nil, err
   691  	}
   692  
   693  	err = tx.Commit()
   694  	if err != nil {
   695  		return nil, err
   696  	}
   697  
   698  	return r.documentConverter.ToGraphQL(eventAPI), nil
   699  }
   700  
   701  // Documents missing godoc
   702  func (r *Resolver) Documents(ctx context.Context, obj *graphql.Bundle, first *int, after *graphql.PageCursor) (*graphql.DocumentPage, error) {
   703  	param := dataloader.ParamDocument{ID: obj.ID, Ctx: ctx, First: first, After: after}
   704  	return dataloader.DocumentFor(ctx).DocumentByID.Load(param)
   705  }
   706  
   707  // DocumentsDataLoader missing godoc
   708  func (r *Resolver) DocumentsDataLoader(keys []dataloader.ParamDocument) ([]*graphql.DocumentPage, []error) {
   709  	if len(keys) == 0 {
   710  		return nil, []error{apperrors.NewInternalError("No Bundles found")}
   711  	}
   712  
   713  	if keys[0].First == nil {
   714  		return nil, []error{apperrors.NewInvalidDataError("missing required parameter 'first'")}
   715  	}
   716  
   717  	ctx := keys[0].Ctx
   718  	first := keys[0].First
   719  
   720  	bundleIDs := make([]string, 0, len(keys))
   721  	for _, key := range keys {
   722  		bundleIDs = append(bundleIDs, key.ID)
   723  	}
   724  
   725  	var cursor string
   726  	if keys[0].After != nil {
   727  		cursor = string(*keys[0].After)
   728  	}
   729  
   730  	tx, err := r.transact.Begin()
   731  	if err != nil {
   732  		return nil, []error{err}
   733  	}
   734  	defer r.transact.RollbackUnlessCommitted(ctx, tx)
   735  
   736  	ctx = persistence.SaveToContext(ctx, tx)
   737  
   738  	documentPages, err := r.documentSvc.ListByBundleIDs(ctx, bundleIDs, *first, cursor)
   739  	if err != nil {
   740  		return nil, []error{err}
   741  	}
   742  
   743  	err = tx.Commit()
   744  	if err != nil {
   745  		return nil, []error{err}
   746  	}
   747  
   748  	gqlDocumentPages := make([]*graphql.DocumentPage, 0, len(documentPages))
   749  	for _, page := range documentPages {
   750  		gqlDocuments := r.documentConverter.MultipleToGraphQL(page.Data)
   751  
   752  		gqlDocumentPages = append(gqlDocumentPages, &graphql.DocumentPage{
   753  			Data:       gqlDocuments,
   754  			TotalCount: page.TotalCount,
   755  			PageInfo: &graphql.PageInfo{
   756  				StartCursor: graphql.PageCursor(page.PageInfo.StartCursor),
   757  				EndCursor:   graphql.PageCursor(page.PageInfo.EndCursor),
   758  				HasNextPage: page.PageInfo.HasNextPage,
   759  			},
   760  		})
   761  	}
   762  
   763  	return gqlDocumentPages, nil
   764  }
   765  
   766  func getBundleReferenceForAPI(apiID string, bundleReferences []*model.BundleReference) (*model.BundleReference, error) {
   767  	for _, br := range bundleReferences {
   768  		if str.PtrStrToStr(br.ObjectID) == apiID {
   769  			return br, nil
   770  		}
   771  	}
   772  	return nil, errors.Errorf("could not find BundleReference for API with id %s", apiID)
   773  }