github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/spec/repository.go (about) 1 package spec 2 3 import ( 4 "context" 5 6 "github.com/kyma-incubator/compass/components/director/pkg/resource" 7 8 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 9 10 "github.com/kyma-incubator/compass/components/director/internal/model" 11 "github.com/kyma-incubator/compass/components/director/internal/repo" 12 "github.com/pkg/errors" 13 ) 14 15 const ( 16 specificationsTable = `public.specifications` 17 apiDefIDColumn = "api_def_id" 18 eventAPIDefIDColumn = "event_def_id" 19 pageSize = 1 20 cursor = "" 21 ) 22 23 var ( 24 specificationsColumns = []string{"id", apiDefIDColumn, eventAPIDefIDColumn, "spec_data", "api_spec_format", "api_spec_type", "event_spec_format", "event_spec_type", "custom_type"} 25 orderByColumns = repo.OrderByParams{repo.NewAscOrderBy("created_at"), repo.NewAscOrderBy("id")} 26 ) 27 28 // Converter missing godoc 29 // 30 //go:generate mockery --name=Converter --output=automock --outpkg=automock --case=underscore --disable-version-string 31 type Converter interface { 32 ToEntity(in *model.Spec) *Entity 33 FromEntity(in *Entity) (*model.Spec, error) 34 } 35 36 type repository struct { 37 creator repo.Creator 38 creatorGlobal repo.CreatorGlobal 39 lister repo.Lister 40 listerGlobal repo.ListerGlobal 41 idLister repo.Lister 42 idListerGlobal repo.ListerGlobal 43 unionLister repo.UnionLister 44 getter repo.SingleGetter 45 getterGlobal repo.SingleGetterGlobal 46 deleter repo.Deleter 47 deleterGlobal repo.DeleterGlobal 48 updater repo.Updater 49 updaterGlobal repo.UpdaterGlobal 50 existQuerier repo.ExistQuerier 51 conv Converter 52 } 53 54 // NewRepository missing godoc 55 func NewRepository(conv Converter) *repository { 56 return &repository{ 57 creator: repo.NewCreator(specificationsTable, specificationsColumns), 58 creatorGlobal: repo.NewCreatorGlobal(resource.Specification, specificationsTable, specificationsColumns), 59 getter: repo.NewSingleGetter(specificationsTable, specificationsColumns), 60 getterGlobal: repo.NewSingleGetterGlobal(resource.Specification, specificationsTable, specificationsColumns), 61 lister: repo.NewListerWithOrderBy(specificationsTable, specificationsColumns, repo.OrderByParams{ 62 { 63 Field: "created_at", 64 Dir: repo.AscOrderBy, 65 }, 66 }), 67 listerGlobal: repo.NewListerGlobal(resource.Specification, specificationsTable, specificationsColumns), 68 idLister: repo.NewListerWithOrderBy(specificationsTable, []string{"id"}, repo.OrderByParams{ 69 { 70 Field: "created_at", 71 Dir: repo.AscOrderBy, 72 }, 73 }), 74 idListerGlobal: repo.NewListerGlobalWithOrderBy(resource.Specification, specificationsTable, []string{"id"}, repo.OrderByParams{ 75 { 76 Field: "created_at", 77 Dir: repo.AscOrderBy, 78 }, 79 }), 80 unionLister: repo.NewUnionLister(specificationsTable, specificationsColumns), 81 deleter: repo.NewDeleter(specificationsTable), 82 deleterGlobal: repo.NewDeleterGlobal(resource.Specification, specificationsTable), 83 updater: repo.NewUpdater(specificationsTable, []string{"spec_data", "api_spec_format", "api_spec_type", "event_spec_format", "event_spec_type"}, []string{"id"}), 84 updaterGlobal: repo.NewUpdaterGlobal(resource.Specification, specificationsTable, []string{"spec_data", "api_spec_format", "api_spec_type", "event_spec_format", "event_spec_type"}, []string{"id"}), 85 existQuerier: repo.NewExistQuerier(specificationsTable), 86 conv: conv, 87 } 88 } 89 90 // GetByID missing godoc 91 func (r *repository) GetByID(ctx context.Context, tenantID string, id string, objectType model.SpecReferenceObjectType) (*model.Spec, error) { 92 var specEntity Entity 93 err := r.getter.Get(ctx, objectType.GetResourceType(), tenantID, repo.Conditions{repo.NewEqualCondition("id", id)}, repo.NoOrderBy, &specEntity) 94 if err != nil { 95 return nil, errors.Wrapf(err, "while getting Specification with id %q", id) 96 } 97 98 specModel, err := r.conv.FromEntity(&specEntity) 99 if err != nil { 100 return nil, err 101 } 102 103 return specModel, nil 104 } 105 106 // GetByIDGlobal gets a Spec by ID without tenant isolation 107 func (r *repository) GetByIDGlobal(ctx context.Context, id string) (*model.Spec, error) { 108 var specEntity Entity 109 err := r.getterGlobal.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", id)}, repo.NoOrderBy, &specEntity) 110 if err != nil { 111 return nil, errors.Wrapf(err, "while getting Specification with id %q", id) 112 } 113 114 specModel, err := r.conv.FromEntity(&specEntity) 115 if err != nil { 116 return nil, err 117 } 118 119 return specModel, nil 120 } 121 122 // Create creates a spec in the scope of a tenant 123 func (r *repository) Create(ctx context.Context, tenant string, item *model.Spec) error { 124 if item == nil { 125 return apperrors.NewInternalError("item can not be empty") 126 } 127 128 entity := r.conv.ToEntity(item) 129 130 return r.creator.Create(ctx, item.ObjectType.GetResourceType(), tenant, entity) 131 } 132 133 // CreateGlobal create a spec without a tenant isolation 134 func (r *repository) CreateGlobal(ctx context.Context, item *model.Spec) error { 135 if item == nil { 136 return apperrors.NewInternalError("item can not be empty") 137 } 138 139 entity := r.conv.ToEntity(item) 140 141 return r.creatorGlobal.Create(ctx, entity) 142 } 143 144 // ListIDByReferenceObjectID retrieves all spec ids by objectType and objectID 145 func (r *repository) ListIDByReferenceObjectID(ctx context.Context, tenant string, objectType model.SpecReferenceObjectType, objectID string) ([]string, error) { 146 conditions, err := r.buildReferenceObjectIDConditions(objectType, objectID) 147 if err != nil { 148 return nil, err 149 } 150 151 var specCollection SpecCollection 152 err = r.idLister.List(ctx, objectType.GetResourceType(), tenant, &specCollection, conditions...) 153 if err != nil { 154 return nil, err 155 } 156 157 return extractIDsFromCollection(specCollection), nil 158 } 159 160 // ListIDByReferenceObjectIDGlobal retrieves all spec ids by objectType and objectID 161 func (r *repository) ListIDByReferenceObjectIDGlobal(ctx context.Context, objectType model.SpecReferenceObjectType, objectID string) ([]string, error) { 162 conditions, err := r.buildReferenceObjectIDConditions(objectType, objectID) 163 if err != nil { 164 return nil, err 165 } 166 167 var specCollection SpecCollection 168 err = r.idListerGlobal.ListGlobal(ctx, &specCollection, conditions...) 169 if err != nil { 170 return nil, err 171 } 172 173 return extractIDsFromCollection(specCollection), nil 174 } 175 176 // ListByReferenceObjectID missing godoc 177 func (r *repository) ListByReferenceObjectID(ctx context.Context, tenant string, objectType model.SpecReferenceObjectType, objectID string) ([]*model.Spec, error) { 178 fieldName, err := r.referenceObjectFieldName(objectType) 179 if err != nil { 180 return nil, err 181 } 182 conditions := repo.Conditions{ 183 repo.NewEqualCondition(fieldName, objectID), 184 } 185 186 var specCollection SpecCollection 187 err = r.lister.List(ctx, objectType.GetResourceType(), tenant, &specCollection, conditions...) 188 if err != nil { 189 return nil, err 190 } 191 192 items := make([]*model.Spec, 0, len(specCollection)) 193 194 for _, specEnt := range specCollection { 195 m, err := r.conv.FromEntity(&specEnt) 196 if err != nil { 197 return nil, err 198 } 199 200 items = append(items, m) 201 } 202 203 return items, nil 204 } 205 206 // ListByReferenceObjectIDGlobal lists specs by a model.SpecReferenceObjectType without tenant isolation 207 func (r *repository) ListByReferenceObjectIDGlobal(ctx context.Context, objectType model.SpecReferenceObjectType, objectID string) ([]*model.Spec, error) { 208 fieldName, err := r.referenceObjectFieldName(objectType) 209 if err != nil { 210 return nil, err 211 } 212 conditions := repo.Conditions{ 213 repo.NewEqualCondition(fieldName, objectID), 214 } 215 216 var specCollection SpecCollection 217 err = r.listerGlobal.ListGlobal(ctx, &specCollection, conditions...) 218 if err != nil { 219 return nil, err 220 } 221 222 items := make([]*model.Spec, 0, len(specCollection)) 223 224 for _, specEnt := range specCollection { 225 m, err := r.conv.FromEntity(&specEnt) 226 if err != nil { 227 return nil, err 228 } 229 230 items = append(items, m) 231 } 232 233 return items, nil 234 } 235 236 func (r *repository) ListByReferenceObjectIDs(ctx context.Context, tenant string, objectType model.SpecReferenceObjectType, objectIDs []string) ([]*model.Spec, error) { 237 objectFieldName, err := r.referenceObjectFieldName(objectType) 238 if err != nil { 239 return nil, err 240 } 241 242 conditions := repo.Conditions{ 243 repo.NewNotNullCondition(objectFieldName), 244 } 245 246 var specs SpecCollection 247 _, err = r.unionLister.List(ctx, objectType.GetResourceType(), tenant, objectIDs, objectFieldName, pageSize, cursor, orderByColumns, &specs, conditions...) 248 if err != nil { 249 return nil, err 250 } 251 252 specifications := make([]*model.Spec, 0, len(specs)) 253 for _, s := range specs { 254 entity, err := r.conv.FromEntity(&s) 255 if err != nil { 256 return nil, err 257 } 258 specifications = append(specifications, entity) 259 } 260 261 return specifications, nil 262 } 263 264 // Delete missing godoc 265 func (r *repository) Delete(ctx context.Context, tenant, id string, objectType model.SpecReferenceObjectType) error { 266 return r.deleter.DeleteOne(ctx, objectType.GetResourceType(), tenant, repo.Conditions{repo.NewEqualCondition("id", id)}) 267 } 268 269 // DeleteByReferenceObjectID missing godoc 270 func (r *repository) DeleteByReferenceObjectID(ctx context.Context, tenant string, objectType model.SpecReferenceObjectType, objectID string) error { 271 fieldName, err := r.referenceObjectFieldName(objectType) 272 if err != nil { 273 return err 274 } 275 276 return r.deleter.DeleteMany(ctx, objectType.GetResourceType(), tenant, repo.Conditions{repo.NewEqualCondition(fieldName, objectID)}) 277 } 278 279 // DeleteByReferenceObjectIDGlobal deletes a reference object with a given ID without tenant isolation 280 func (r *repository) DeleteByReferenceObjectIDGlobal(ctx context.Context, objectType model.SpecReferenceObjectType, objectID string) error { 281 fieldName, err := r.referenceObjectFieldName(objectType) 282 if err != nil { 283 return err 284 } 285 286 return r.deleterGlobal.DeleteManyGlobal(ctx, repo.Conditions{repo.NewEqualCondition(fieldName, objectID)}) 287 } 288 289 // Update missing godoc 290 func (r *repository) Update(ctx context.Context, tenant string, item *model.Spec) error { 291 if item == nil { 292 return apperrors.NewInternalError("item cannot be nil") 293 } 294 295 entity := r.conv.ToEntity(item) 296 297 return r.updater.UpdateSingle(ctx, item.ObjectType.GetResourceType(), tenant, entity) 298 } 299 300 // UpdateGlobal updates a Spec without tenant isolation 301 func (r *repository) UpdateGlobal(ctx context.Context, item *model.Spec) error { 302 if item == nil { 303 return apperrors.NewInternalError("item cannot be nil") 304 } 305 306 entity := r.conv.ToEntity(item) 307 308 return r.updaterGlobal.UpdateSingleGlobal(ctx, entity) 309 } 310 311 // Exists missing godoc 312 func (r *repository) Exists(ctx context.Context, tenantID, id string, objectType model.SpecReferenceObjectType) (bool, error) { 313 return r.existQuerier.Exists(ctx, objectType.GetResourceType(), tenantID, repo.Conditions{repo.NewEqualCondition("id", id)}) 314 } 315 316 func (r *repository) referenceObjectFieldName(objectType model.SpecReferenceObjectType) (string, error) { 317 switch objectType { 318 case model.APISpecReference: 319 return apiDefIDColumn, nil 320 case model.EventSpecReference: 321 return eventAPIDefIDColumn, nil 322 } 323 324 return "", apperrors.NewInternalError("Invalid type of the Specification reference object") 325 } 326 327 func (r *repository) buildReferenceObjectIDConditions(objectType model.SpecReferenceObjectType, objectID string) (repo.Conditions, error) { 328 fieldName, err := r.referenceObjectFieldName(objectType) 329 if err != nil { 330 return nil, err 331 } 332 333 return repo.Conditions{ 334 repo.NewEqualCondition(fieldName, objectID), 335 }, nil 336 } 337 338 // SpecCollection missing godoc 339 type SpecCollection []Entity 340 341 // Len missing godoc 342 func (r SpecCollection) Len() int { 343 return len(r) 344 } 345 346 func extractIDsFromCollection(specCollection SpecCollection) []string { 347 items := make([]string, 0, len(specCollection)) 348 349 for _, specEnt := range specCollection { 350 items = append(items, specEnt.ID) 351 } 352 353 return items 354 }