Browse Source

feat(server): Return an object from delete mutations

Allows extra information to be returned, e.g. in the case that a warning is returned before a destructive force deletion. Relates to #21
Michael Bromley 7 years ago
parent
commit
d6cd883b52

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


+ 5 - 2
server/e2e/customer.e2e-spec.ts

@@ -9,6 +9,7 @@ import {
 } from '../../admin-ui/src/app/data/definitions/customer-definitions';
 import {
     CreateCustomerAddress,
+    DeletionResult,
     GetCustomer,
     GetCustomerList,
     UpdateCustomer,
@@ -238,7 +239,7 @@ describe('Customer resolver', () => {
         it('deletes a customer', async () => {
             const result = await client.query(DELETE_CUSTOMER, { id: thirdCustomer.id });
 
-            expect(result.deleteCustomer).toBe(true);
+            expect(result.deleteCustomer).toEqual({ result: DeletionResult.DELETED });
         });
 
         it('cannot get a deleted customer', async () => {
@@ -344,6 +345,8 @@ const GET_CUSTOMER_ORDERS = gql`
 
 const DELETE_CUSTOMER = gql`
     mutation DeleteCustomer($id: ID!) {
-        deleteCustomer(id: $id)
+        deleteCustomer(id: $id) {
+            result
+        }
     }
 `;

+ 5 - 2
server/e2e/product.e2e-spec.ts

@@ -14,6 +14,7 @@ import {
 import {
     AddOptionGroupToProduct,
     CreateProduct,
+    DeletionResult,
     GenerateProductVariants,
     GetAssetList,
     GetProductList,
@@ -596,7 +597,7 @@ describe('Product resolver', () => {
             productToDelete = allProducts[0];
             const result = await client.query(DELETE_PRODUCT, { id: productToDelete.id });
 
-            expect(result.deleteProduct).toBe(true);
+            expect(result.deleteProduct).toEqual({ result: DeletionResult.DELETED });
         });
 
         it('cannot get a deleted product', async () => {
@@ -679,6 +680,8 @@ describe('Product resolver', () => {
 
 const DELETE_PRODUCT = gql`
     mutation DeleteProduct($id: ID!) {
-        deleteProduct(id: $id)
+        deleteProduct(id: $id) {
+            result
+        }
     }
 `;

+ 5 - 2
server/e2e/promotion.e2e-spec.ts

@@ -9,6 +9,7 @@ import {
 } from '../../admin-ui/src/app/data/definitions/promotion-definitions';
 import {
     CreatePromotion,
+    DeletionResult,
     GetAdjustmentOperations,
     GetPromotion,
     GetPromotionList,
@@ -147,7 +148,7 @@ describe('Promotion resolver', () => {
             promotionToDelete = allPromotions[0];
             const result = await client.query(DELETE_PROMOTION, { id: promotionToDelete.id });
 
-            expect(result.deletePromotion).toBe(true);
+            expect(result.deletePromotion).toEqual({ result: DeletionResult.DELETED });
         });
 
         it('cannot get a deleted promotion', async () => {
@@ -203,6 +204,8 @@ function generateTestAction(code: string): PromotionAction<any> {
 
 const DELETE_PROMOTION = gql`
     mutation DeletePromotion($id: ID!) {
-        deletePromotion(id: $id)
+        deletePromotion(id: $id) {
+            result
+        }
     }
 `;

+ 2 - 1
server/src/api/resolvers/customer.resolver.ts

@@ -6,6 +6,7 @@ import {
     CustomerQueryArgs,
     CustomersQueryArgs,
     DeleteCustomerMutationArgs,
+    DeletionResponse,
     OrdersCustomerArgs,
     Permission,
     UpdateCustomerAddressMutationArgs,
@@ -108,7 +109,7 @@ export class CustomerResolver {
 
     @Mutation()
     @Allow(Permission.DeleteCustomer)
-    async deleteCustomer(@Args() args: DeleteCustomerMutationArgs): Promise<boolean> {
+    async deleteCustomer(@Args() args: DeleteCustomerMutationArgs): Promise<DeletionResponse> {
         return this.customerService.softDelete(args.id);
     }
 

+ 2 - 1
server/src/api/resolvers/product.resolver.ts

@@ -4,6 +4,7 @@ import {
     AddOptionGroupToProductMutationArgs,
     CreateProductMutationArgs,
     DeleteProductMutationArgs,
+    DeletionResponse,
     GenerateVariantsForProductMutationArgs,
     Permission,
     ProductQueryArgs,
@@ -89,7 +90,7 @@ export class ProductResolver {
     async deleteProduct(
         @Ctx() ctx: RequestContext,
         @Args() args: DeleteProductMutationArgs,
-    ): Promise<boolean> {
+    ): Promise<DeletionResponse> {
         return this.productService.softDelete(args.id);
     }
 

+ 2 - 1
server/src/api/resolvers/promotion.resolver.ts

@@ -3,6 +3,7 @@ import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
 import {
     CreatePromotionMutationArgs,
     DeletePromotionMutationArgs,
+    DeletionResponse,
     Permission,
     PromotionQueryArgs,
     PromotionsQueryArgs,
@@ -61,7 +62,7 @@ export class PromotionResolver {
 
     @Mutation()
     @Allow(Permission.DeleteSettings)
-    deletePromotion(@Args() args: DeletePromotionMutationArgs): Promise<boolean> {
+    deletePromotion(@Args() args: DeletePromotionMutationArgs): Promise<DeletionResponse> {
         return this.promotionService.softDeletePromotion(args.id);
     }
 }

+ 1 - 1
server/src/api/types/customer.api.graphql

@@ -12,7 +12,7 @@ type Mutation {
     updateCustomer(input: UpdateCustomerInput!): Customer!
 
     "Delete a Customer"
-    deleteCustomer(id: ID!): Boolean!
+    deleteCustomer(id: ID!): DeletionResponse!
 
     "Create a new Address and associate it with the Customer specified by customerId"
     createCustomerAddress(customerId: ID!, input: CreateAddressInput!): Address!

+ 1 - 1
server/src/api/types/product.api.graphql

@@ -11,7 +11,7 @@ type Mutation {
     updateProduct(input: UpdateProductInput!): Product!
 
     "Delete a Product"
-    deleteProduct(id: ID!): Boolean
+    deleteProduct(id: ID!): DeletionResponse!
 
     "Add an OptionGroup to a Product"
     addOptionGroupToProduct(productId: ID!, optionGroupId: ID!): Product!

+ 1 - 1
server/src/api/types/promotion.api.graphql

@@ -12,7 +12,7 @@ type AdjustmentOperations {
 type Mutation {
     createPromotion(input: CreatePromotionInput!): Promotion!
     updatePromotion(input: UpdatePromotionInput!): Promotion!
-    deletePromotion(id: ID!): Boolean
+    deletePromotion(id: ID!): DeletionResponse!
 }
 
 type PromotionList implements PaginatedList {

+ 12 - 0
server/src/common/types/common-types.graphql

@@ -32,6 +32,18 @@ type AdjustmentOperation {
     description: String!
 }
 
+enum DeletionResult {
+    "The entity was successfully deleted"
+    DELETED
+    "Deletion did not take place, reason given in message"
+    NOT_DELETED
+}
+
+type DeletionResponse {
+    result: DeletionResult!
+    message: String
+}
+
 input ConfigArgInput {
     name: String!
     value: String!

+ 6 - 2
server/src/service/services/customer.service.ts

@@ -5,6 +5,8 @@ import { Connection } from 'typeorm';
 import {
     CreateAddressInput,
     CreateCustomerInput,
+    DeletionResponse,
+    DeletionResult,
     RegisterCustomerInput,
     UpdateAddressInput,
     UpdateCustomerInput,
@@ -189,10 +191,12 @@ export class CustomerService {
         return updatedAddress;
     }
 
-    async softDelete(customerId: ID): Promise<boolean> {
+    async softDelete(customerId: ID): Promise<DeletionResponse> {
         await getEntityOrThrow(this.connection, Customer, customerId);
         await this.connection.getRepository(Customer).update({ id: customerId }, { deletedAt: new Date() });
-        return true;
+        return {
+            result: DeletionResult.DELETED,
+        };
     }
 
     private async enforceSingleDefaultAddress(addressId: ID, input: CreateAddressInput | UpdateAddressInput) {

+ 10 - 3
server/src/service/services/product.service.ts

@@ -2,7 +2,12 @@ import { Injectable } from '@nestjs/common';
 import { InjectConnection } from '@nestjs/typeorm';
 import { Connection, FindConditions, In } from 'typeorm';
 
-import { CreateProductInput, UpdateProductInput } from '../../../../shared/generated-types';
+import {
+    CreateProductInput,
+    DeletionResponse,
+    DeletionResult,
+    UpdateProductInput,
+} from '../../../../shared/generated-types';
 import { ID, PaginatedList } from '../../../../shared/shared-types';
 import { RequestContext } from '../../api/common/request-context';
 import { EntityNotFoundError } from '../../common/error/errors';
@@ -132,10 +137,12 @@ export class ProductService {
         return assertFound(this.findOne(ctx, product.id));
     }
 
-    async softDelete(productId: ID): Promise<boolean> {
+    async softDelete(productId: ID): Promise<DeletionResponse> {
         await getEntityOrThrow(this.connection, Product, productId);
         await this.connection.getRepository(Product).update({ id: productId }, { deletedAt: new Date() });
-        return true;
+        return {
+            result: DeletionResult.DELETED,
+        };
     }
 
     async addOptionGroupToProduct(

+ 6 - 2
server/src/service/services/promotion.service.ts

@@ -6,6 +6,8 @@ import {
     AdjustmentOperation,
     AdjustmentOperationInput,
     CreatePromotionInput,
+    DeletionResponse,
+    DeletionResult,
     UpdatePromotionInput,
 } from '../../../../shared/generated-types';
 import { omit } from '../../../../shared/omit';
@@ -120,10 +122,12 @@ export class PromotionService {
         return assertFound(this.findOne(updatedAdjustmentSource.id));
     }
 
-    async softDeletePromotion(promotionId: ID): Promise<boolean> {
+    async softDeletePromotion(promotionId: ID): Promise<DeletionResponse> {
         await getEntityOrThrow(this.connection, Promotion, promotionId);
         await this.connection.getRepository(Promotion).update({ id: promotionId }, { deletedAt: new Date() });
-        return true;
+        return {
+            result: DeletionResult.DELETED,
+        };
     }
 
     /**

+ 37 - 9
shared/generated-types.ts

@@ -687,7 +687,7 @@ export interface Mutation {
     removeCustomersFromGroup: CustomerGroup;
     createCustomer: Customer;
     updateCustomer: Customer;
-    deleteCustomer: boolean;
+    deleteCustomer: DeletionResponse;
     createCustomerAddress: Address;
     updateCustomerAddress: Address;
     createFacet: Facet;
@@ -712,14 +712,14 @@ export interface Mutation {
     updateProductOptionGroup: ProductOptionGroup;
     createProduct: Product;
     updateProduct: Product;
-    deleteProduct?: boolean | null;
+    deleteProduct: DeletionResponse;
     addOptionGroupToProduct: Product;
     removeOptionGroupFromProduct: Product;
     generateVariantsForProduct: Product;
     updateProductVariants: (ProductVariant | null)[];
     createPromotion: Promotion;
     updatePromotion: Promotion;
-    deletePromotion?: boolean | null;
+    deletePromotion: DeletionResponse;
     createRole: Role;
     updateRole: Role;
     reindex: boolean;
@@ -744,6 +744,11 @@ export interface LoginResult {
     user: CurrentUser;
 }
 
+export interface DeletionResponse {
+    result: DeletionResult;
+    message?: string | null;
+}
+
 export interface ImportInfo {
     errors?: string[] | null;
     processed: number;
@@ -2220,6 +2225,11 @@ export enum AdjustmentType {
     SHIPPING_REFUND = 'SHIPPING_REFUND',
 }
 
+export enum DeletionResult {
+    DELETED = 'DELETED',
+    NOT_DELETED = 'NOT_DELETED',
+}
+
 export namespace QueryResolvers {
     export interface Resolvers<Context = any> {
         administrators?: AdministratorsResolver<AdministratorList, any, Context>;
@@ -4409,7 +4419,7 @@ export namespace MutationResolvers {
         removeCustomersFromGroup?: RemoveCustomersFromGroupResolver<CustomerGroup, any, Context>;
         createCustomer?: CreateCustomerResolver<Customer, any, Context>;
         updateCustomer?: UpdateCustomerResolver<Customer, any, Context>;
-        deleteCustomer?: DeleteCustomerResolver<boolean, any, Context>;
+        deleteCustomer?: DeleteCustomerResolver<DeletionResponse, any, Context>;
         createCustomerAddress?: CreateCustomerAddressResolver<Address, any, Context>;
         updateCustomerAddress?: UpdateCustomerAddressResolver<Address, any, Context>;
         createFacet?: CreateFacetResolver<Facet, any, Context>;
@@ -4434,14 +4444,14 @@ export namespace MutationResolvers {
         updateProductOptionGroup?: UpdateProductOptionGroupResolver<ProductOptionGroup, any, Context>;
         createProduct?: CreateProductResolver<Product, any, Context>;
         updateProduct?: UpdateProductResolver<Product, any, Context>;
-        deleteProduct?: DeleteProductResolver<boolean | null, any, Context>;
+        deleteProduct?: DeleteProductResolver<DeletionResponse, any, Context>;
         addOptionGroupToProduct?: AddOptionGroupToProductResolver<Product, any, Context>;
         removeOptionGroupFromProduct?: RemoveOptionGroupFromProductResolver<Product, any, Context>;
         generateVariantsForProduct?: GenerateVariantsForProductResolver<Product, any, Context>;
         updateProductVariants?: UpdateProductVariantsResolver<(ProductVariant | null)[], any, Context>;
         createPromotion?: CreatePromotionResolver<Promotion, any, Context>;
         updatePromotion?: UpdatePromotionResolver<Promotion, any, Context>;
-        deletePromotion?: DeletePromotionResolver<boolean | null, any, Context>;
+        deletePromotion?: DeletePromotionResolver<DeletionResponse, any, Context>;
         createRole?: CreateRoleResolver<Role, any, Context>;
         updateRole?: UpdateRoleResolver<Role, any, Context>;
         reindex?: ReindexResolver<boolean, any, Context>;
@@ -4650,7 +4660,7 @@ export namespace MutationResolvers {
         input: UpdateCustomerInput;
     }
 
-    export type DeleteCustomerResolver<R = boolean, Parent = any, Context = any> = Resolver<
+    export type DeleteCustomerResolver<R = DeletionResponse, Parent = any, Context = any> = Resolver<
         R,
         Parent,
         Context,
@@ -4901,7 +4911,7 @@ export namespace MutationResolvers {
         input: UpdateProductInput;
     }
 
-    export type DeleteProductResolver<R = boolean | null, Parent = any, Context = any> = Resolver<
+    export type DeleteProductResolver<R = DeletionResponse, Parent = any, Context = any> = Resolver<
         R,
         Parent,
         Context,
@@ -4975,7 +4985,7 @@ export namespace MutationResolvers {
         input: UpdatePromotionInput;
     }
 
-    export type DeletePromotionResolver<R = boolean | null, Parent = any, Context = any> = Resolver<
+    export type DeletePromotionResolver<R = DeletionResponse, Parent = any, Context = any> = Resolver<
         R,
         Parent,
         Context,
@@ -5153,6 +5163,24 @@ export namespace LoginResultResolvers {
     export type UserResolver<R = CurrentUser, Parent = any, Context = any> = Resolver<R, Parent, Context>;
 }
 
+export namespace DeletionResponseResolvers {
+    export interface Resolvers<Context = any> {
+        result?: ResultResolver<DeletionResult, any, Context>;
+        message?: MessageResolver<string | null, any, Context>;
+    }
+
+    export type ResultResolver<R = DeletionResult, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context
+    >;
+    export type MessageResolver<R = string | null, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context
+    >;
+}
+
 export namespace ImportInfoResolvers {
     export interface Resolvers<Context = any> {
         errors?: ErrorsResolver<string[] | null, any, Context>;

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