diff --git a/packages/core/e2e/collection.e2e-spec.ts b/packages/core/e2e/collection.e2e-spec.ts index 87226e516d..8687190924 100644 --- a/packages/core/e2e/collection.e2e-spec.ts +++ b/packages/core/e2e/collection.e2e-spec.ts @@ -225,6 +225,21 @@ describe('Collection resolver', () => { expect(updateCollection.assets.map(a => a.id)).toEqual([assets[3].id, assets[0].id]); }); + + it('removes all assets', async () => { + const { updateCollection } = await client.query< + UpdateCollection.Mutation, + UpdateCollection.Variables + >(UPDATE_COLLECTION, { + input: { + id: pearCollection.id, + assetIds: [], + }, + }); + + expect(updateCollection.assets).toEqual([]); + expect(updateCollection.featuredAsset).toBeNull(); + }); }); it('collection query', async () => { diff --git a/packages/core/src/service/services/asset.service.ts b/packages/core/src/service/services/asset.service.ts index d30e82c7e3..f6d3535f9d 100644 --- a/packages/core/src/service/services/asset.service.ts +++ b/packages/core/src/service/services/asset.service.ts @@ -21,10 +21,15 @@ import { VendureEntity } from '../../entity/base/base.entity'; import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder'; export interface EntityWithAssets extends VendureEntity { - featuredAsset: Asset; + featuredAsset: Asset | null; assets: OrderableAsset[]; } +export interface EntityAssetInput { + assetIds?: ID[] | null; + featuredAssetId?: ID | null; +} + @Injectable() export class AssetService { constructor( @@ -68,7 +73,7 @@ export class AssetService { .findOne(entity.id, { relations: ['featuredAsset'], }); - return entityWithFeaturedAsset && entityWithFeaturedAsset.featuredAsset; + return (entityWithFeaturedAsset && entityWithFeaturedAsset.featuredAsset) || undefined; } async getEntityAssets(entity: T): Promise { @@ -85,11 +90,13 @@ export class AssetService { return assets.sort((a, b) => a.position - b.position).map(a => a.asset); } - async updateFeaturedAsset( - entity: T, - featuredAssetId?: ID | null, - ): Promise { - if (!featuredAssetId) { + async updateFeaturedAsset(entity: T, input: EntityAssetInput): Promise { + const { assetIds, featuredAssetId } = input; + if (featuredAssetId === null || (assetIds && assetIds.length === 0)) { + entity.featuredAsset = null; + return entity; + } + if (featuredAssetId === undefined) { return entity; } const featuredAsset = await this.findOne(featuredAssetId); @@ -102,17 +109,20 @@ export class AssetService { /** * Updates the assets / featuredAsset of an entity, ensuring that only valid assetIds are used. */ - async updateEntityAssets(entity: T, assetIds?: ID[] | null): Promise { + async updateEntityAssets(entity: T, input: EntityAssetInput): Promise { if (!entity.id) { throw new InternalServerError('error.entity-must-have-an-id'); } + const { assetIds, featuredAssetId } = input; if (assetIds && assetIds.length) { const assets = await this.connection.getRepository(Asset).findByIds(assetIds); const sortedAssets = assetIds .map(id => assets.find(a => idsAreEqual(a.id, id))) .filter(notNullOrUndefined); - this.removeExistingOrderableAssets(entity); + await this.removeExistingOrderableAssets(entity); entity.assets = await this.createOrderableAssets(entity, sortedAssets); + } else if (assetIds && assetIds.length === 0) { + await this.removeExistingOrderableAssets(entity); } return entity; } diff --git a/packages/core/src/service/services/collection.service.ts b/packages/core/src/service/services/collection.service.ts index df2b98b5fc..27dc18784e 100644 --- a/packages/core/src/service/services/collection.service.ts +++ b/packages/core/src/service/services/collection.service.ts @@ -250,10 +250,10 @@ export class CollectionService implements OnModuleInit { } coll.position = await this.getNextPositionInParent(ctx, input.parentId || undefined); coll.filters = this.getCollectionFiltersFromInput(input); - await this.assetService.updateFeaturedAsset(coll, input.featuredAssetId); + await this.assetService.updateFeaturedAsset(coll, input); }, }); - await this.assetService.updateEntityAssets(collection, input.assetIds); + await this.assetService.updateEntityAssets(collection, input); this.applyCollectionFilters(ctx, [collection]); return assertFound(this.findOne(ctx, collection.id)); } @@ -267,8 +267,8 @@ export class CollectionService implements OnModuleInit { if (input.filters) { coll.filters = this.getCollectionFiltersFromInput(input); } - await this.assetService.updateFeaturedAsset(coll, input.featuredAssetId); - await this.assetService.updateEntityAssets(coll, input.assetIds); + await this.assetService.updateFeaturedAsset(coll, input); + await this.assetService.updateEntityAssets(coll, input); }, }); if (input.filters) { diff --git a/packages/core/src/service/services/product-variant.service.ts b/packages/core/src/service/services/product-variant.service.ts index c3293610e3..097f9011ed 100644 --- a/packages/core/src/service/services/product-variant.service.ts +++ b/packages/core/src/service/services/product-variant.service.ts @@ -176,14 +176,14 @@ export class ProductVariantService { } variant.product = { id: input.productId } as any; variant.taxCategory = { id: input.taxCategoryId } as any; - await this.assetService.updateFeaturedAsset(variant, input.featuredAssetId); + await this.assetService.updateFeaturedAsset(variant, input); }, typeOrmSubscriberData: { channelId: ctx.channelId, taxCategoryId: input.taxCategoryId, }, }); - await this.assetService.updateEntityAssets(createdVariant, input.assetIds); + await this.assetService.updateEntityAssets(createdVariant, input); if (input.stockOnHand != null && input.stockOnHand !== 0) { await this.stockMovementService.adjustProductVariantStock( createdVariant.id, @@ -227,8 +227,8 @@ export class ProductVariantService { input.stockOnHand, ); } - await this.assetService.updateFeaturedAsset(updatedVariant, input.featuredAssetId); - await this.assetService.updateEntityAssets(updatedVariant, input.assetIds); + await this.assetService.updateFeaturedAsset(updatedVariant, input); + await this.assetService.updateEntityAssets(updatedVariant, input); }, typeOrmSubscriberData: { channelId: ctx.channelId, diff --git a/packages/core/src/service/services/product.service.ts b/packages/core/src/service/services/product.service.ts index b3aaa89279..29efdaf323 100644 --- a/packages/core/src/service/services/product.service.ts +++ b/packages/core/src/service/services/product.service.ts @@ -108,10 +108,10 @@ export class ProductService { if (input.facetValueIds) { p.facetValues = await this.facetValueService.findByIds(input.facetValueIds); } - await this.assetService.updateFeaturedAsset(p, input.featuredAssetId); + await this.assetService.updateFeaturedAsset(p, input); }, }); - await this.assetService.updateEntityAssets(product, input.assetIds); + await this.assetService.updateEntityAssets(product, input); this.eventBus.publish(new CatalogModificationEvent(ctx, product)); return assertFound(this.findOne(ctx, product.id)); } @@ -127,8 +127,8 @@ export class ProductService { if (input.facetValueIds) { p.facetValues = await this.facetValueService.findByIds(input.facetValueIds); } - await this.assetService.updateFeaturedAsset(p, input.featuredAssetId); - await this.assetService.updateEntityAssets(p, input.assetIds); + await this.assetService.updateFeaturedAsset(p, input); + await this.assetService.updateEntityAssets(p, input); }, }); this.eventBus.publish(new CatalogModificationEvent(ctx, product)); @@ -189,12 +189,10 @@ export class ProductService { } private async getProductWithOptionGroups(productId: ID): Promise { - const product = await this.connection - .getRepository(Product) - .findOne(productId, { - relations: ['optionGroups', 'variants', 'variants.options'], - where: { deletedAt: null }, - }); + const product = await this.connection.getRepository(Product).findOne(productId, { + relations: ['optionGroups', 'variants', 'variants.options'], + where: { deletedAt: null }, + }); if (!product) { throw new EntityNotFoundError('Product', productId); }