Browse Source

feat(core): Implement deleteCollection mutation

Michael Bromley 6 years ago
parent
commit
051f2f3822

+ 149 - 142
packages/common/src/generated-types.ts

@@ -1544,32 +1544,28 @@ export type MoveCollectionInput = {
 
 export type Mutation = {
   __typename?: 'Mutation',
-  /** Create a new Administrator */
-  createAdministrator: Administrator,
-  /** Update an existing Administrator */
-  updateAdministrator: Administrator,
-  /** Assign a Role to an Administrator */
-  assignRoleToAdministrator: Administrator,
   /** Create a new Asset */
   createAssets: Array<Asset>,
   login: LoginResult,
   logout: Scalars['Boolean'],
-  /** Create a new Channel */
-  createChannel: Channel,
-  /** Update an existing Channel */
-  updateChannel: Channel,
   /** Create a new Collection */
   createCollection: Collection,
   /** Update an existing Collection */
   updateCollection: Collection,
+  /** Delete a Collection */
+  deleteCollection: DeletionResponse,
   /** Move a Collection to a different parent or index */
   moveCollection: Collection,
-  /** Create a new Country */
-  createCountry: Country,
-  /** Update an existing Country */
-  updateCountry: Country,
-  /** Delete a Country */
-  deleteCountry: DeletionResponse,
+  /** Create a new Channel */
+  createChannel: Channel,
+  /** Update an existing Channel */
+  updateChannel: Channel,
+  /** Create a new Administrator */
+  createAdministrator: Administrator,
+  /** Update an existing Administrator */
+  updateAdministrator: Administrator,
+  /** Assign a Role to an Administrator */
+  assignRoleToAdministrator: Administrator,
   /** Create a new CustomerGroup */
   createCustomerGroup: CustomerGroup,
   /** Update an existing CustomerGroup */
@@ -1578,6 +1574,14 @@ export type Mutation = {
   addCustomersToGroup: CustomerGroup,
   /** Remove Customers from a CustomerGroup */
   removeCustomersFromGroup: CustomerGroup,
+  /** Create a new Country */
+  createCountry: Country,
+  /** Update an existing Country */
+  updateCountry: Country,
+  /** Delete a Country */
+  deleteCountry: DeletionResponse,
+  importProducts?: Maybe<ImportInfo>,
+  updateGlobalSettings: GlobalSettings,
   /** Create a new Customer. If a password is provided, a new User will also be created an linked to the Customer. */
   createCustomer: Customer,
   /** Update an existing Customer */
@@ -1602,14 +1606,13 @@ export type Mutation = {
   updateFacetValues: Array<FacetValue>,
   /** Delete one or more FacetValues */
   deleteFacetValues: Array<DeletionResponse>,
-  importProducts?: Maybe<ImportInfo>,
-  updateGlobalSettings: GlobalSettings,
   settlePayment: Payment,
   fulfillOrder: Fulfillment,
   cancelOrder: Order,
   refundOrder: Refund,
   settleRefund: Refund,
   addNoteToOrder: Order,
+  reindex: JobInfo,
   /** Update an existing PaymentMethod */
   updatePaymentMethod: PaymentMethod,
   /** Create a new ProductOptionGroup */
@@ -1620,7 +1623,6 @@ export type Mutation = {
   createProductOption: ProductOption,
   /** Create a new ProductOption within a ProductOptionGroup */
   updateProductOption: ProductOption,
-  reindex: JobInfo,
   /** Create a new Product */
   createProduct: Product,
   /** Update an existing Product */
@@ -1637,9 +1639,6 @@ export type Mutation = {
   updateProductVariants: Array<Maybe<ProductVariant>>,
   /** Delete a ProductVariant */
   deleteProductVariant: DeletionResponse,
-  createPromotion: Promotion,
-  updatePromotion: Promotion,
-  deletePromotion: DeletionResponse,
   /** Create a new Role */
   createRole: Role,
   /** Update an existing Role */
@@ -1648,14 +1647,13 @@ export type Mutation = {
   createShippingMethod: ShippingMethod,
   /** Update an existing ShippingMethod */
   updateShippingMethod: ShippingMethod,
+  createPromotion: Promotion,
+  updatePromotion: Promotion,
+  deletePromotion: DeletionResponse,
   /** Create a new TaxCategory */
   createTaxCategory: TaxCategory,
   /** Update an existing TaxCategory */
   updateTaxCategory: TaxCategory,
-  /** Create a new TaxRate */
-  createTaxRate: TaxRate,
-  /** Update an existing TaxRate */
-  updateTaxRate: TaxRate,
   /** Create a new Zone */
   createZone: Zone,
   /** Update an existing Zone */
@@ -1666,22 +1664,10 @@ export type Mutation = {
   addMembersToZone: Zone,
   /** Remove members from a Zone */
   removeMembersFromZone: Zone,
-};
-
-
-export type MutationCreateAdministratorArgs = {
-  input: CreateAdministratorInput
-};
-
-
-export type MutationUpdateAdministratorArgs = {
-  input: UpdateAdministratorInput
-};
-
-
-export type MutationAssignRoleToAdministratorArgs = {
-  administratorId: Scalars['ID'],
-  roleId: Scalars['ID']
+  /** Create a new TaxRate */
+  createTaxRate: TaxRate,
+  /** Update an existing TaxRate */
+  updateTaxRate: TaxRate,
 };
 
 
@@ -1697,16 +1683,6 @@ export type MutationLoginArgs = {
 };
 
 
-export type MutationCreateChannelArgs = {
-  input: CreateChannelInput
-};
-
-
-export type MutationUpdateChannelArgs = {
-  input: UpdateChannelInput
-};
-
-
 export type MutationCreateCollectionArgs = {
   input: CreateCollectionInput
 };
@@ -1717,23 +1693,39 @@ export type MutationUpdateCollectionArgs = {
 };
 
 
+export type MutationDeleteCollectionArgs = {
+  id: Scalars['ID']
+};
+
+
 export type MutationMoveCollectionArgs = {
   input: MoveCollectionInput
 };
 
 
-export type MutationCreateCountryArgs = {
-  input: CreateCountryInput
+export type MutationCreateChannelArgs = {
+  input: CreateChannelInput
 };
 
 
-export type MutationUpdateCountryArgs = {
-  input: UpdateCountryInput
+export type MutationUpdateChannelArgs = {
+  input: UpdateChannelInput
 };
 
 
-export type MutationDeleteCountryArgs = {
-  id: Scalars['ID']
+export type MutationCreateAdministratorArgs = {
+  input: CreateAdministratorInput
+};
+
+
+export type MutationUpdateAdministratorArgs = {
+  input: UpdateAdministratorInput
+};
+
+
+export type MutationAssignRoleToAdministratorArgs = {
+  administratorId: Scalars['ID'],
+  roleId: Scalars['ID']
 };
 
 
@@ -1759,6 +1751,31 @@ export type MutationRemoveCustomersFromGroupArgs = {
 };
 
 
+export type MutationCreateCountryArgs = {
+  input: CreateCountryInput
+};
+
+
+export type MutationUpdateCountryArgs = {
+  input: UpdateCountryInput
+};
+
+
+export type MutationDeleteCountryArgs = {
+  id: Scalars['ID']
+};
+
+
+export type MutationImportProductsArgs = {
+  csvFile: Scalars['Upload']
+};
+
+
+export type MutationUpdateGlobalSettingsArgs = {
+  input: UpdateGlobalSettingsInput
+};
+
+
 export type MutationCreateCustomerArgs = {
   input: CreateCustomerInput,
   password?: Maybe<Scalars['String']>
@@ -1823,16 +1840,6 @@ export type MutationDeleteFacetValuesArgs = {
 };
 
 
-export type MutationImportProductsArgs = {
-  csvFile: Scalars['Upload']
-};
-
-
-export type MutationUpdateGlobalSettingsArgs = {
-  input: UpdateGlobalSettingsInput
-};
-
-
 export type MutationSettlePaymentArgs = {
   id: Scalars['ID']
 };
@@ -1930,21 +1937,6 @@ export type MutationDeleteProductVariantArgs = {
 };
 
 
-export type MutationCreatePromotionArgs = {
-  input: CreatePromotionInput
-};
-
-
-export type MutationUpdatePromotionArgs = {
-  input: UpdatePromotionInput
-};
-
-
-export type MutationDeletePromotionArgs = {
-  id: Scalars['ID']
-};
-
-
 export type MutationCreateRoleArgs = {
   input: CreateRoleInput
 };
@@ -1965,23 +1957,28 @@ export type MutationUpdateShippingMethodArgs = {
 };
 
 
-export type MutationCreateTaxCategoryArgs = {
-  input: CreateTaxCategoryInput
+export type MutationCreatePromotionArgs = {
+  input: CreatePromotionInput
 };
 
 
-export type MutationUpdateTaxCategoryArgs = {
-  input: UpdateTaxCategoryInput
+export type MutationUpdatePromotionArgs = {
+  input: UpdatePromotionInput
 };
 
 
-export type MutationCreateTaxRateArgs = {
-  input: CreateTaxRateInput
+export type MutationDeletePromotionArgs = {
+  id: Scalars['ID']
 };
 
 
-export type MutationUpdateTaxRateArgs = {
-  input: UpdateTaxRateInput
+export type MutationCreateTaxCategoryArgs = {
+  input: CreateTaxCategoryInput
+};
+
+
+export type MutationUpdateTaxCategoryArgs = {
+  input: UpdateTaxCategoryInput
 };
 
 
@@ -2011,6 +2008,16 @@ export type MutationRemoveMembersFromZoneArgs = {
   memberIds: Array<Scalars['ID']>
 };
 
+
+export type MutationCreateTaxRateArgs = {
+  input: CreateTaxRateInput
+};
+
+
+export type MutationUpdateTaxRateArgs = {
+  input: UpdateTaxRateInput
+};
+
 export type Node = {
   __typename?: 'Node',
   id: Scalars['ID'],
@@ -2507,63 +2514,53 @@ export type PromotionSortParameter = {
 
 export type Query = {
   __typename?: 'Query',
-  administrators: AdministratorList,
-  administrator?: Maybe<Administrator>,
   assets: AssetList,
   asset?: Maybe<Asset>,
   me?: Maybe<CurrentUser>,
-  channels: Array<Channel>,
-  channel?: Maybe<Channel>,
-  activeChannel: Channel,
   collections: CollectionList,
   collection?: Maybe<Collection>,
   collectionFilters: Array<ConfigurableOperation>,
-  countries: CountryList,
-  country?: Maybe<Country>,
+  channels: Array<Channel>,
+  channel?: Maybe<Channel>,
+  activeChannel: Channel,
+  administrators: AdministratorList,
+  administrator?: Maybe<Administrator>,
   customerGroups: Array<CustomerGroup>,
   customerGroup?: Maybe<CustomerGroup>,
+  countries: CountryList,
+  country?: Maybe<Country>,
+  globalSettings: GlobalSettings,
   customers: CustomerList,
   customer?: Maybe<Customer>,
   facets: FacetList,
   facet?: Maybe<Facet>,
-  globalSettings: GlobalSettings,
   job?: Maybe<JobInfo>,
   jobs: Array<JobInfo>,
   order?: Maybe<Order>,
   orders: OrderList,
+  search: SearchResponse,
   paymentMethods: PaymentMethodList,
   paymentMethod?: Maybe<PaymentMethod>,
   productOptionGroups: Array<ProductOptionGroup>,
   productOptionGroup?: Maybe<ProductOptionGroup>,
-  search: SearchResponse,
   products: ProductList,
   /** Get a Product either by id or slug. If neither id nor slug is speicified, an error will result. */
   product?: Maybe<Product>,
-  promotion?: Maybe<Promotion>,
-  promotions: PromotionList,
-  adjustmentOperations: AdjustmentOperations,
   roles: RoleList,
   role?: Maybe<Role>,
   shippingMethods: ShippingMethodList,
   shippingMethod?: Maybe<ShippingMethod>,
   shippingEligibilityCheckers: Array<ConfigurableOperation>,
   shippingCalculators: Array<ConfigurableOperation>,
+  promotion?: Maybe<Promotion>,
+  promotions: PromotionList,
+  adjustmentOperations: AdjustmentOperations,
   taxCategories: Array<TaxCategory>,
   taxCategory?: Maybe<TaxCategory>,
-  taxRates: TaxRateList,
-  taxRate?: Maybe<TaxRate>,
   zones: Array<Zone>,
   zone?: Maybe<Zone>,
-};
-
-
-export type QueryAdministratorsArgs = {
-  options?: Maybe<AdministratorListOptions>
-};
-
-
-export type QueryAdministratorArgs = {
-  id: Scalars['ID']
+  taxRates: TaxRateList,
+  taxRate?: Maybe<TaxRate>,
 };
 
 
@@ -2577,11 +2574,6 @@ export type QueryAssetArgs = {
 };
 
 
-export type QueryChannelArgs = {
-  id: Scalars['ID']
-};
-
-
 export type QueryCollectionsArgs = {
   languageCode?: Maybe<LanguageCode>,
   options?: Maybe<CollectionListOptions>
@@ -2594,12 +2586,17 @@ export type QueryCollectionArgs = {
 };
 
 
-export type QueryCountriesArgs = {
-  options?: Maybe<CountryListOptions>
+export type QueryChannelArgs = {
+  id: Scalars['ID']
 };
 
 
-export type QueryCountryArgs = {
+export type QueryAdministratorsArgs = {
+  options?: Maybe<AdministratorListOptions>
+};
+
+
+export type QueryAdministratorArgs = {
   id: Scalars['ID']
 };
 
@@ -2609,6 +2606,16 @@ export type QueryCustomerGroupArgs = {
 };
 
 
+export type QueryCountriesArgs = {
+  options?: Maybe<CountryListOptions>
+};
+
+
+export type QueryCountryArgs = {
+  id: Scalars['ID']
+};
+
+
 export type QueryCustomersArgs = {
   options?: Maybe<CustomerListOptions>
 };
@@ -2651,6 +2658,11 @@ export type QueryOrdersArgs = {
 };
 
 
+export type QuerySearchArgs = {
+  input: SearchInput
+};
+
+
 export type QueryPaymentMethodsArgs = {
   options?: Maybe<PaymentMethodListOptions>
 };
@@ -2673,11 +2685,6 @@ export type QueryProductOptionGroupArgs = {
 };
 
 
-export type QuerySearchArgs = {
-  input: SearchInput
-};
-
-
 export type QueryProductsArgs = {
   languageCode?: Maybe<LanguageCode>,
   options?: Maybe<ProductListOptions>
@@ -2691,16 +2698,6 @@ export type QueryProductArgs = {
 };
 
 
-export type QueryPromotionArgs = {
-  id: Scalars['ID']
-};
-
-
-export type QueryPromotionsArgs = {
-  options?: Maybe<PromotionListOptions>
-};
-
-
 export type QueryRolesArgs = {
   options?: Maybe<RoleListOptions>
 };
@@ -2721,17 +2718,17 @@ export type QueryShippingMethodArgs = {
 };
 
 
-export type QueryTaxCategoryArgs = {
+export type QueryPromotionArgs = {
   id: Scalars['ID']
 };
 
 
-export type QueryTaxRatesArgs = {
-  options?: Maybe<TaxRateListOptions>
+export type QueryPromotionsArgs = {
+  options?: Maybe<PromotionListOptions>
 };
 
 
-export type QueryTaxRateArgs = {
+export type QueryTaxCategoryArgs = {
   id: Scalars['ID']
 };
 
@@ -2740,6 +2737,16 @@ export type QueryZoneArgs = {
   id: Scalars['ID']
 };
 
+
+export type QueryTaxRatesArgs = {
+  options?: Maybe<TaxRateListOptions>
+};
+
+
+export type QueryTaxRateArgs = {
+  id: Scalars['ID']
+};
+
 export type Refund = Node & {
   __typename?: 'Refund',
   id: Scalars['ID'],

+ 129 - 4
packages/core/e2e/collection.e2e-spec.ts

@@ -3,6 +3,7 @@ import { ROOT_COLLECTION_NAME } from '@vendure/common/lib/shared-constants';
 import gql from 'graphql-tag';
 import path from 'path';
 
+import { pick } from '../../common/lib/pick';
 import { StringOperator } from '../src/common/configurable-operation';
 import { facetValueCollectionFilter, variantNameCollectionFilter } from '../src/config/collection/default-collection-filters';
 
@@ -14,7 +15,9 @@ import {
     CreateCollection,
     CreateCollectionInput,
     CreateCollectionSelectVariants,
+    DeleteCollection,
     DeleteProduct,
+    DeletionResult,
     FacetValueFragment,
     GetAssetList,
     GetCollection,
@@ -23,6 +26,7 @@ import {
     GetCollections,
     GetCollectionsForProducts,
     GetFacetValues,
+    GetProductCollections,
     GetProductsWithVariantIds,
     LanguageCode,
     MoveCollection,
@@ -391,6 +395,105 @@ describe('Collection resolver', () => {
         }
     });
 
+    describe('deleteCollection', () => {
+
+        let collectionToDelete: CreateCollection.CreateCollection;
+        let laptopProductId: string;
+
+        beforeAll(async () => {
+            const { createCollection } = await client.query<CreateCollection.Mutation, CreateCollection.Variables>(
+                CREATE_COLLECTION,
+                {
+                    input: {
+                        filters: [
+                            {
+                                code: variantNameCollectionFilter.code,
+                                arguments: [
+                                    {
+                                        name: 'operator',
+                                        value: 'contains',
+                                        type: ConfigArgType.STRING_OPERATOR,
+                                    },
+                                    {
+                                        name: 'term',
+                                        value: 'laptop',
+                                        type: ConfigArgType.STRING,
+                                    },
+                                ],
+                            },
+                        ],
+                        translations: [
+                            { languageCode: LanguageCode.en, name: 'Delete Me', description: '' },
+                        ],
+                    },
+                },
+            );
+            collectionToDelete = createCollection;
+        });
+
+        it('throws for invalid collection id', assertThrowsWithMessage(async () => {
+                await client.query<DeleteCollection.Mutation, DeleteCollection.Variables>(DELETE_COLLECTION, {
+                    id: 'T_999',
+                });
+            },
+            'No Collection with the id \'999\' could be found',
+            ),
+        );
+
+        it('collection and product related prior to deletion', async () => {
+            const { collection } = await client.query<GetCollectionProducts.Query, GetCollectionProducts.Variables>(GET_COLLECTION_PRODUCT_VARIANTS, {
+                id: collectionToDelete.id,
+            });
+            expect(collection!.productVariants.items.map(pick(['name']))).toEqual([
+                { name: 'Laptop 13 inch 8GB' },
+                { name: 'Laptop 15 inch 8GB' },
+                { name: 'Laptop 13 inch 16GB' },
+                { name: 'Laptop 15 inch 16GB' },
+            ]);
+
+            laptopProductId = collection!.productVariants.items[0].productId;
+
+            const { product } = await client.query<GetProductCollections.Query, GetProductCollections.Variables>(GET_PRODUCT_COLLECTIONS, {
+                id: laptopProductId,
+            });
+
+            expect(product!.collections).toEqual([
+                { id: 'T_3', name: 'Electronics' },
+                { id: 'T_4', name: 'Computers' },
+                { id: 'T_5', name: 'Pear' },
+                { id: 'T_6', name: 'Delete Me' },
+            ]);
+        });
+
+        it('deleteCollection works', async () => {
+            const { deleteCollection } = await client.query<DeleteCollection.Mutation, DeleteCollection.Variables>(DELETE_COLLECTION, {
+                id: collectionToDelete.id,
+            });
+
+            expect(deleteCollection.result).toBe(DeletionResult.DELETED);
+        });
+
+        it('deleted collection is null', async () => {
+            const { collection } = await client.query<GetCollection.Query, GetCollection.Variables>(GET_COLLECTION, {
+                id: collectionToDelete.id,
+            });
+            expect(collection).toBeNull();
+        });
+
+        it('product no longer lists collection', async () => {
+            const { product } = await client.query<GetProductCollections.Query, GetProductCollections.Variables>(GET_PRODUCT_COLLECTIONS, {
+                id: laptopProductId,
+            });
+
+            expect(product!.collections).toEqual([
+                { id: 'T_3', name: 'Electronics' },
+                { id: 'T_4', name: 'Computers' },
+                { id: 'T_5', name: 'Pear' },
+            ]);
+        });
+
+    });
+
     describe('filters', () => {
         it('Collection with no filters has no productVariants', async () => {
             const result = await client.query<
@@ -770,10 +873,10 @@ describe('Collection resolver', () => {
             expect(result.products.items[0].collections).toEqual([
                 { id: 'T_3', name: 'Electronics' },
                 { id: 'T_5', name: 'Pear' },
-                { id: 'T_7', name: 'Photo AND Pear' },
-                { id: 'T_8', name: 'Photo OR Pear' },
-                { id: 'T_9', name: 'contains camera' },
-                { id: 'T_11', name: 'endsWith camera' },
+                { id: 'T_8', name: 'Photo AND Pear' },
+                { id: 'T_9', name: 'Photo OR Pear' },
+                { id: 'T_10', name: 'contains camera' },
+                { id: 'T_12', name: 'endsWith camera' },
             ]);
         });
     });
@@ -864,6 +967,7 @@ const GET_COLLECTION_PRODUCT_VARIANTS = gql`
                     facetValues {
                         code
                     }
+                    productId
                 }
             }
         }
@@ -908,3 +1012,24 @@ const GET_COLLECTIONS_FOR_PRODUCTS = gql`
         }
     }
 `;
+
+const DELETE_COLLECTION = gql`
+    mutation DeleteCollection($id: ID!) {
+        deleteCollection(id: $id) {
+            result
+            message
+        }
+    }
+`;
+
+const GET_PRODUCT_COLLECTIONS = gql`
+    query GetProductCollections($id: ID!) {
+        product(id: $id) {
+            id
+            collections {
+                id
+                name
+            }
+        }
+    }
+`;

+ 168 - 127
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -1541,32 +1541,28 @@ export type MoveCollectionInput = {
 
 export type Mutation = {
     __typename?: 'Mutation';
-    /** Create a new Administrator */
-    createAdministrator: Administrator;
-    /** Update an existing Administrator */
-    updateAdministrator: Administrator;
-    /** Assign a Role to an Administrator */
-    assignRoleToAdministrator: Administrator;
     /** Create a new Asset */
     createAssets: Array<Asset>;
     login: LoginResult;
     logout: Scalars['Boolean'];
-    /** Create a new Channel */
-    createChannel: Channel;
-    /** Update an existing Channel */
-    updateChannel: Channel;
     /** Create a new Collection */
     createCollection: Collection;
     /** Update an existing Collection */
     updateCollection: Collection;
+    /** Delete a Collection */
+    deleteCollection: DeletionResponse;
     /** Move a Collection to a different parent or index */
     moveCollection: Collection;
-    /** Create a new Country */
-    createCountry: Country;
-    /** Update an existing Country */
-    updateCountry: Country;
-    /** Delete a Country */
-    deleteCountry: DeletionResponse;
+    /** Create a new Channel */
+    createChannel: Channel;
+    /** Update an existing Channel */
+    updateChannel: Channel;
+    /** Create a new Administrator */
+    createAdministrator: Administrator;
+    /** Update an existing Administrator */
+    updateAdministrator: Administrator;
+    /** Assign a Role to an Administrator */
+    assignRoleToAdministrator: Administrator;
     /** Create a new CustomerGroup */
     createCustomerGroup: CustomerGroup;
     /** Update an existing CustomerGroup */
@@ -1575,6 +1571,14 @@ export type Mutation = {
     addCustomersToGroup: CustomerGroup;
     /** Remove Customers from a CustomerGroup */
     removeCustomersFromGroup: CustomerGroup;
+    /** Create a new Country */
+    createCountry: Country;
+    /** Update an existing Country */
+    updateCountry: Country;
+    /** Delete a Country */
+    deleteCountry: DeletionResponse;
+    importProducts?: Maybe<ImportInfo>;
+    updateGlobalSettings: GlobalSettings;
     /** Create a new Customer. If a password is provided, a new User will also be created an linked to the Customer. */
     createCustomer: Customer;
     /** Update an existing Customer */
@@ -1599,14 +1603,13 @@ export type Mutation = {
     updateFacetValues: Array<FacetValue>;
     /** Delete one or more FacetValues */
     deleteFacetValues: Array<DeletionResponse>;
-    importProducts?: Maybe<ImportInfo>;
-    updateGlobalSettings: GlobalSettings;
     settlePayment: Payment;
     fulfillOrder: Fulfillment;
     cancelOrder: Order;
     refundOrder: Refund;
     settleRefund: Refund;
     addNoteToOrder: Order;
+    reindex: JobInfo;
     /** Update an existing PaymentMethod */
     updatePaymentMethod: PaymentMethod;
     /** Create a new ProductOptionGroup */
@@ -1617,7 +1620,6 @@ export type Mutation = {
     createProductOption: ProductOption;
     /** Create a new ProductOption within a ProductOptionGroup */
     updateProductOption: ProductOption;
-    reindex: JobInfo;
     /** Create a new Product */
     createProduct: Product;
     /** Update an existing Product */
@@ -1634,9 +1636,6 @@ export type Mutation = {
     updateProductVariants: Array<Maybe<ProductVariant>>;
     /** Delete a ProductVariant */
     deleteProductVariant: DeletionResponse;
-    createPromotion: Promotion;
-    updatePromotion: Promotion;
-    deletePromotion: DeletionResponse;
     /** Create a new Role */
     createRole: Role;
     /** Update an existing Role */
@@ -1645,14 +1644,13 @@ export type Mutation = {
     createShippingMethod: ShippingMethod;
     /** Update an existing ShippingMethod */
     updateShippingMethod: ShippingMethod;
+    createPromotion: Promotion;
+    updatePromotion: Promotion;
+    deletePromotion: DeletionResponse;
     /** Create a new TaxCategory */
     createTaxCategory: TaxCategory;
     /** Update an existing TaxCategory */
     updateTaxCategory: TaxCategory;
-    /** Create a new TaxRate */
-    createTaxRate: TaxRate;
-    /** Update an existing TaxRate */
-    updateTaxRate: TaxRate;
     /** Create a new Zone */
     createZone: Zone;
     /** Update an existing Zone */
@@ -1663,19 +1661,10 @@ export type Mutation = {
     addMembersToZone: Zone;
     /** Remove members from a Zone */
     removeMembersFromZone: Zone;
-};
-
-export type MutationCreateAdministratorArgs = {
-    input: CreateAdministratorInput;
-};
-
-export type MutationUpdateAdministratorArgs = {
-    input: UpdateAdministratorInput;
-};
-
-export type MutationAssignRoleToAdministratorArgs = {
-    administratorId: Scalars['ID'];
-    roleId: Scalars['ID'];
+    /** Create a new TaxRate */
+    createTaxRate: TaxRate;
+    /** Update an existing TaxRate */
+    updateTaxRate: TaxRate;
 };
 
 export type MutationCreateAssetsArgs = {
@@ -1688,14 +1677,6 @@ export type MutationLoginArgs = {
     rememberMe?: Maybe<Scalars['Boolean']>;
 };
 
-export type MutationCreateChannelArgs = {
-    input: CreateChannelInput;
-};
-
-export type MutationUpdateChannelArgs = {
-    input: UpdateChannelInput;
-};
-
 export type MutationCreateCollectionArgs = {
     input: CreateCollectionInput;
 };
@@ -1704,20 +1685,33 @@ export type MutationUpdateCollectionArgs = {
     input: UpdateCollectionInput;
 };
 
+export type MutationDeleteCollectionArgs = {
+    id: Scalars['ID'];
+};
+
 export type MutationMoveCollectionArgs = {
     input: MoveCollectionInput;
 };
 
-export type MutationCreateCountryArgs = {
-    input: CreateCountryInput;
+export type MutationCreateChannelArgs = {
+    input: CreateChannelInput;
 };
 
-export type MutationUpdateCountryArgs = {
-    input: UpdateCountryInput;
+export type MutationUpdateChannelArgs = {
+    input: UpdateChannelInput;
 };
 
-export type MutationDeleteCountryArgs = {
-    id: Scalars['ID'];
+export type MutationCreateAdministratorArgs = {
+    input: CreateAdministratorInput;
+};
+
+export type MutationUpdateAdministratorArgs = {
+    input: UpdateAdministratorInput;
+};
+
+export type MutationAssignRoleToAdministratorArgs = {
+    administratorId: Scalars['ID'];
+    roleId: Scalars['ID'];
 };
 
 export type MutationCreateCustomerGroupArgs = {
@@ -1738,6 +1732,26 @@ export type MutationRemoveCustomersFromGroupArgs = {
     customerIds: Array<Scalars['ID']>;
 };
 
+export type MutationCreateCountryArgs = {
+    input: CreateCountryInput;
+};
+
+export type MutationUpdateCountryArgs = {
+    input: UpdateCountryInput;
+};
+
+export type MutationDeleteCountryArgs = {
+    id: Scalars['ID'];
+};
+
+export type MutationImportProductsArgs = {
+    csvFile: Scalars['Upload'];
+};
+
+export type MutationUpdateGlobalSettingsArgs = {
+    input: UpdateGlobalSettingsInput;
+};
+
 export type MutationCreateCustomerArgs = {
     input: CreateCustomerInput;
     password?: Maybe<Scalars['String']>;
@@ -1790,14 +1804,6 @@ export type MutationDeleteFacetValuesArgs = {
     force?: Maybe<Scalars['Boolean']>;
 };
 
-export type MutationImportProductsArgs = {
-    csvFile: Scalars['Upload'];
-};
-
-export type MutationUpdateGlobalSettingsArgs = {
-    input: UpdateGlobalSettingsInput;
-};
-
 export type MutationSettlePaymentArgs = {
     id: Scalars['ID'];
 };
@@ -1876,18 +1882,6 @@ export type MutationDeleteProductVariantArgs = {
     id: Scalars['ID'];
 };
 
-export type MutationCreatePromotionArgs = {
-    input: CreatePromotionInput;
-};
-
-export type MutationUpdatePromotionArgs = {
-    input: UpdatePromotionInput;
-};
-
-export type MutationDeletePromotionArgs = {
-    id: Scalars['ID'];
-};
-
 export type MutationCreateRoleArgs = {
     input: CreateRoleInput;
 };
@@ -1904,20 +1898,24 @@ export type MutationUpdateShippingMethodArgs = {
     input: UpdateShippingMethodInput;
 };
 
-export type MutationCreateTaxCategoryArgs = {
-    input: CreateTaxCategoryInput;
+export type MutationCreatePromotionArgs = {
+    input: CreatePromotionInput;
 };
 
-export type MutationUpdateTaxCategoryArgs = {
-    input: UpdateTaxCategoryInput;
+export type MutationUpdatePromotionArgs = {
+    input: UpdatePromotionInput;
 };
 
-export type MutationCreateTaxRateArgs = {
-    input: CreateTaxRateInput;
+export type MutationDeletePromotionArgs = {
+    id: Scalars['ID'];
 };
 
-export type MutationUpdateTaxRateArgs = {
-    input: UpdateTaxRateInput;
+export type MutationCreateTaxCategoryArgs = {
+    input: CreateTaxCategoryInput;
+};
+
+export type MutationUpdateTaxCategoryArgs = {
+    input: UpdateTaxCategoryInput;
 };
 
 export type MutationCreateZoneArgs = {
@@ -1942,6 +1940,14 @@ export type MutationRemoveMembersFromZoneArgs = {
     memberIds: Array<Scalars['ID']>;
 };
 
+export type MutationCreateTaxRateArgs = {
+    input: CreateTaxRateInput;
+};
+
+export type MutationUpdateTaxRateArgs = {
+    input: UpdateTaxRateInput;
+};
+
 export type Node = {
     __typename?: 'Node';
     id: Scalars['ID'];
@@ -2436,61 +2442,53 @@ export type PromotionSortParameter = {
 
 export type Query = {
     __typename?: 'Query';
-    administrators: AdministratorList;
-    administrator?: Maybe<Administrator>;
     assets: AssetList;
     asset?: Maybe<Asset>;
     me?: Maybe<CurrentUser>;
-    channels: Array<Channel>;
-    channel?: Maybe<Channel>;
-    activeChannel: Channel;
     collections: CollectionList;
     collection?: Maybe<Collection>;
     collectionFilters: Array<ConfigurableOperation>;
-    countries: CountryList;
-    country?: Maybe<Country>;
+    channels: Array<Channel>;
+    channel?: Maybe<Channel>;
+    activeChannel: Channel;
+    administrators: AdministratorList;
+    administrator?: Maybe<Administrator>;
     customerGroups: Array<CustomerGroup>;
     customerGroup?: Maybe<CustomerGroup>;
+    countries: CountryList;
+    country?: Maybe<Country>;
+    globalSettings: GlobalSettings;
     customers: CustomerList;
     customer?: Maybe<Customer>;
     facets: FacetList;
     facet?: Maybe<Facet>;
-    globalSettings: GlobalSettings;
     job?: Maybe<JobInfo>;
     jobs: Array<JobInfo>;
     order?: Maybe<Order>;
     orders: OrderList;
+    search: SearchResponse;
     paymentMethods: PaymentMethodList;
     paymentMethod?: Maybe<PaymentMethod>;
     productOptionGroups: Array<ProductOptionGroup>;
     productOptionGroup?: Maybe<ProductOptionGroup>;
-    search: SearchResponse;
     products: ProductList;
     /** Get a Product either by id or slug. If neither id nor slug is speicified, an error will result. */
     product?: Maybe<Product>;
-    promotion?: Maybe<Promotion>;
-    promotions: PromotionList;
-    adjustmentOperations: AdjustmentOperations;
     roles: RoleList;
     role?: Maybe<Role>;
     shippingMethods: ShippingMethodList;
     shippingMethod?: Maybe<ShippingMethod>;
     shippingEligibilityCheckers: Array<ConfigurableOperation>;
     shippingCalculators: Array<ConfigurableOperation>;
+    promotion?: Maybe<Promotion>;
+    promotions: PromotionList;
+    adjustmentOperations: AdjustmentOperations;
     taxCategories: Array<TaxCategory>;
     taxCategory?: Maybe<TaxCategory>;
-    taxRates: TaxRateList;
-    taxRate?: Maybe<TaxRate>;
     zones: Array<Zone>;
     zone?: Maybe<Zone>;
-};
-
-export type QueryAdministratorsArgs = {
-    options?: Maybe<AdministratorListOptions>;
-};
-
-export type QueryAdministratorArgs = {
-    id: Scalars['ID'];
+    taxRates: TaxRateList;
+    taxRate?: Maybe<TaxRate>;
 };
 
 export type QueryAssetsArgs = {
@@ -2501,10 +2499,6 @@ export type QueryAssetArgs = {
     id: Scalars['ID'];
 };
 
-export type QueryChannelArgs = {
-    id: Scalars['ID'];
-};
-
 export type QueryCollectionsArgs = {
     languageCode?: Maybe<LanguageCode>;
     options?: Maybe<CollectionListOptions>;
@@ -2515,11 +2509,15 @@ export type QueryCollectionArgs = {
     languageCode?: Maybe<LanguageCode>;
 };
 
-export type QueryCountriesArgs = {
-    options?: Maybe<CountryListOptions>;
+export type QueryChannelArgs = {
+    id: Scalars['ID'];
 };
 
-export type QueryCountryArgs = {
+export type QueryAdministratorsArgs = {
+    options?: Maybe<AdministratorListOptions>;
+};
+
+export type QueryAdministratorArgs = {
     id: Scalars['ID'];
 };
 
@@ -2527,6 +2525,14 @@ export type QueryCustomerGroupArgs = {
     id: Scalars['ID'];
 };
 
+export type QueryCountriesArgs = {
+    options?: Maybe<CountryListOptions>;
+};
+
+export type QueryCountryArgs = {
+    id: Scalars['ID'];
+};
+
 export type QueryCustomersArgs = {
     options?: Maybe<CustomerListOptions>;
 };
@@ -2561,6 +2567,10 @@ export type QueryOrdersArgs = {
     options?: Maybe<OrderListOptions>;
 };
 
+export type QuerySearchArgs = {
+    input: SearchInput;
+};
+
 export type QueryPaymentMethodsArgs = {
     options?: Maybe<PaymentMethodListOptions>;
 };
@@ -2579,10 +2589,6 @@ export type QueryProductOptionGroupArgs = {
     languageCode?: Maybe<LanguageCode>;
 };
 
-export type QuerySearchArgs = {
-    input: SearchInput;
-};
-
 export type QueryProductsArgs = {
     languageCode?: Maybe<LanguageCode>;
     options?: Maybe<ProductListOptions>;
@@ -2594,14 +2600,6 @@ export type QueryProductArgs = {
     languageCode?: Maybe<LanguageCode>;
 };
 
-export type QueryPromotionArgs = {
-    id: Scalars['ID'];
-};
-
-export type QueryPromotionsArgs = {
-    options?: Maybe<PromotionListOptions>;
-};
-
 export type QueryRolesArgs = {
     options?: Maybe<RoleListOptions>;
 };
@@ -2618,15 +2616,15 @@ export type QueryShippingMethodArgs = {
     id: Scalars['ID'];
 };
 
-export type QueryTaxCategoryArgs = {
+export type QueryPromotionArgs = {
     id: Scalars['ID'];
 };
 
-export type QueryTaxRatesArgs = {
-    options?: Maybe<TaxRateListOptions>;
+export type QueryPromotionsArgs = {
+    options?: Maybe<PromotionListOptions>;
 };
 
-export type QueryTaxRateArgs = {
+export type QueryTaxCategoryArgs = {
     id: Scalars['ID'];
 };
 
@@ -2634,6 +2632,14 @@ export type QueryZoneArgs = {
     id: Scalars['ID'];
 };
 
+export type QueryTaxRatesArgs = {
+    options?: Maybe<TaxRateListOptions>;
+};
+
+export type QueryTaxRateArgs = {
+    id: Scalars['ID'];
+};
+
 export type Refund = Node & {
     __typename?: 'Refund';
     id: Scalars['ID'];
@@ -3242,7 +3248,7 @@ export type GetCollectionProductsQuery = { __typename?: 'Query' } & {
         { __typename?: 'Collection' } & {
             productVariants: { __typename?: 'ProductVariantList' } & {
                 items: Array<
-                    { __typename?: 'ProductVariant' } & Pick<ProductVariant, 'id' | 'name'> & {
+                    { __typename?: 'ProductVariant' } & Pick<ProductVariant, 'id' | 'name' | 'productId'> & {
                             facetValues: Array<{ __typename?: 'FacetValue' } & Pick<FacetValue, 'code'>>;
                         }
                 >;
@@ -3291,6 +3297,26 @@ export type GetCollectionsForProductsQuery = { __typename?: 'Query' } & {
     };
 };
 
+export type DeleteCollectionMutationVariables = {
+    id: Scalars['ID'];
+};
+
+export type DeleteCollectionMutation = { __typename?: 'Mutation' } & {
+    deleteCollection: { __typename?: 'DeletionResponse' } & Pick<DeletionResponse, 'result' | 'message'>;
+};
+
+export type GetProductCollectionsQueryVariables = {
+    id: Scalars['ID'];
+};
+
+export type GetProductCollectionsQuery = { __typename?: 'Query' } & {
+    product: Maybe<
+        { __typename?: 'Product' } & Pick<Product, 'id'> & {
+                collections: Array<{ __typename?: 'Collection' } & Pick<Collection, 'id' | 'name'>>;
+            }
+    >;
+};
+
 export type DeleteCountryMutationVariables = {
     id: Scalars['ID'];
 };
@@ -4696,6 +4722,21 @@ export namespace GetCollectionsForProducts {
     >;
 }
 
+export namespace DeleteCollection {
+    export type Variables = DeleteCollectionMutationVariables;
+    export type Mutation = DeleteCollectionMutation;
+    export type DeleteCollection = DeleteCollectionMutation['deleteCollection'];
+}
+
+export namespace GetProductCollections {
+    export type Variables = GetProductCollectionsQueryVariables;
+    export type Query = GetProductCollectionsQuery;
+    export type Product = NonNullable<GetProductCollectionsQuery['product']>;
+    export type Collections = NonNullable<
+        (NonNullable<GetProductCollectionsQuery['product']>)['collections'][0]
+    >;
+}
+
 export namespace DeleteCountry {
     export type Variables = DeleteCountryMutationVariables;
     export type Mutation = DeleteCountryMutation;

+ 14 - 3
packages/core/src/api/resolvers/admin/collection.resolver.ts

@@ -1,12 +1,14 @@
 import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
 import {
-    QueryCollectionArgs,
-    QueryCollectionsArgs,
     ConfigurableOperation,
+    DeletionResponse,
     MutationCreateCollectionArgs,
+    MutationDeleteCollectionArgs,
     MutationMoveCollectionArgs,
-    Permission,
     MutationUpdateCollectionArgs,
+    Permission,
+    QueryCollectionArgs,
+    QueryCollectionsArgs,
 } from '@vendure/common/lib/generated-types';
 import { PaginatedList } from '@vendure/common/lib/shared-types';
 
@@ -93,6 +95,15 @@ export class CollectionResolver {
         return this.collectionService.move(ctx, input).then(this.encodeFilters);
     }
 
+    @Mutation()
+    @Allow(Permission.DeleteCatalog)
+    async deleteCollection(
+        @Ctx() ctx: RequestContext,
+        @Args() args: MutationDeleteCollectionArgs,
+    ): Promise<DeletionResponse> {
+        return this.collectionService.delete(ctx, args.id);
+    }
+
     /**
      * Encodes any entity IDs used in the filter arguments.
      */

+ 3 - 0
packages/core/src/api/schema/admin-api/collection.api.graphql

@@ -11,6 +11,9 @@ type Mutation {
     "Update an existing Collection"
     updateCollection(input: UpdateCollectionInput!): Collection!
 
+    "Delete a Collection"
+    deleteCollection(id: ID!): DeletionResponse!
+
     "Move a Collection to a different parent or index"
     moveCollection(input: MoveCollectionInput!): Collection!
 }

+ 1 - 1
packages/core/src/entity/collection/collection-translation.entity.ts

@@ -20,7 +20,7 @@ export class CollectionTranslation extends VendureEntity implements Translation<
 
     @Column() description: string;
 
-    @ManyToOne(type => Collection, base => base.translations)
+    @ManyToOne(type => Collection, base => base.translations, { onDelete: 'CASCADE' })
     base: Collection;
 
     @Column(type => CustomCollectionFieldsTranslation)

+ 18 - 1
packages/core/src/service/services/collection.service.ts

@@ -1,6 +1,13 @@
 import { OnModuleInit } from '@nestjs/common';
 import { InjectConnection } from '@nestjs/typeorm';
-import { ConfigurableOperation, CreateCollectionInput, MoveCollectionInput, UpdateCollectionInput } from '@vendure/common/lib/generated-types';
+import {
+    ConfigurableOperation,
+    CreateCollectionInput,
+    DeletionResponse,
+    DeletionResult,
+    MoveCollectionInput,
+    UpdateCollectionInput
+} from '@vendure/common/lib/generated-types';
 import { pick } from '@vendure/common/lib/pick';
 import { ROOT_COLLECTION_NAME } from '@vendure/common/lib/shared-constants';
 import { ID, PaginatedList } from '@vendure/common/lib/shared-types';
@@ -257,6 +264,16 @@ export class CollectionService implements OnModuleInit {
         return assertFound(this.findOne(ctx, collection.id));
     }
 
+    async delete(ctx: RequestContext, id: ID): Promise<DeletionResponse> {
+        const collection = await getEntityOrThrow(this.connection, Collection, id);
+        const affectedVariantIds = await this.getCollectionProductVariantIds(collection);
+        await this.connection.getRepository(Collection).remove(collection);
+        this.eventBus.publish(new CollectionModificationEvent(ctx, collection, affectedVariantIds));
+        return {
+            result: DeletionResult.DELETED,
+        };
+    }
+
     async move(ctx: RequestContext, input: MoveCollectionInput): Promise<Translated<Collection>> {
         const target = await getEntityOrThrow(this.connection, Collection, input.collectionId, {
             relations: ['parent'],

File diff suppressed because it is too large
+ 0 - 0
schema-admin.json


Some files were not shown because too many files changed in this diff