Browse Source

refactor(admin-ui): Use type-safe pick function for mutations

Michael Bromley 7 years ago
parent
commit
252d7b2691

+ 0 - 9
admin-ui/src/app/common/utilities/common.ts

@@ -1,9 +0,0 @@
-/**
- * Like assertNever, but at runtime this will be reached due to the way that all actions
- * are dispatched and piped through all reducers. So this just provides a compile-time
- * exhaustiveness check for those reducers which use a switch statement over
- * a discriminated union type of actions.
- */
-export function reducerCaseNever(x: never, errorMessage?: string): void {
-    // this function intentionally left empty
-}

+ 32 - 0
admin-ui/src/app/common/utilities/pick.spec.ts

@@ -0,0 +1,32 @@
+import { pick } from './pick';
+
+describe('pick()', () => {
+    it('picks specified properties', () => {
+        const input = {
+            foo: 1,
+            bar: 2,
+            baz: [1, 2, 3],
+        };
+
+        const result = pick(input, ['foo', 'baz']);
+        expect(result).toEqual({
+            foo: 1,
+            baz: [1, 2, 3],
+        });
+    });
+
+    it('partially applies the pick when signle argument is array', () => {
+        const input = {
+            foo: 1,
+            bar: 2,
+            baz: [1, 2, 3],
+        };
+
+        const result = pick(['foo', 'baz']);
+        expect(typeof result).toBe('function');
+        expect(result(input)).toEqual({
+            foo: 1,
+            baz: [1, 2, 3],
+        });
+    });
+});

+ 25 - 0
admin-ui/src/app/common/utilities/pick.ts

@@ -0,0 +1,25 @@
+/**
+ * Returns a new object which is a subject of the input, including only the specified properties.
+ * Can be called with a single argument (array of props to pick), in which case it returns a partially
+ * applied pick function.
+ */
+export function pick<T extends object, U extends T = any>(props: Array<keyof T>): (input: U) => T;
+export function pick<T extends object, U extends T = any>(input: U, props: Array<keyof T>): T;
+export function pick<T extends object, U extends T = any>(
+    inputOrProps: U | Array<keyof T>,
+    maybeProps?: Array<keyof T>,
+): T | ((input: U) => T) {
+    if (Array.isArray(inputOrProps)) {
+        return (input: U) => _pick(input, inputOrProps);
+    } else {
+        return _pick(inputOrProps, maybeProps || []);
+    }
+}
+
+function _pick<T extends object, U extends T = any>(input: U, props: Array<keyof T>): T {
+    const output: any = {};
+    for (const prop of props) {
+        output[prop] = input[prop];
+    }
+    return output;
+}

+ 5 - 22
admin-ui/src/app/data/providers/facet-data.service.ts

@@ -1,6 +1,7 @@
 import { Observable } from 'rxjs';
 
 import { getDefaultLanguage } from '../../common/utilities/get-default-language';
+import { pick } from '../../common/utilities/pick';
 import { addCustomFields } from '../add-custom-fields';
 import {
     CREATE_FACET,
@@ -56,12 +57,7 @@ export class FacetDataService {
 
     createFacet(facet: CreateFacetInput): Observable<CreateFacet> {
         const input: CreateFacetVariables = {
-            input: {
-                code: facet.code,
-                translations: facet.translations,
-                values: facet.values,
-                customFields: facet.customFields,
-            },
+            input: pick(facet, ['code', 'translations', 'values', 'customFields']),
         };
         return this.baseDataService.mutate<CreateFacet, CreateFacetVariables>(
             addCustomFields(CREATE_FACET),
@@ -71,12 +67,7 @@ export class FacetDataService {
 
     updateFacet(facet: UpdateFacetInput): Observable<UpdateFacet> {
         const input: UpdateFacetVariables = {
-            input: {
-                id: facet.id,
-                code: facet.code,
-                translations: facet.translations,
-                customFields: facet.customFields,
-            },
+            input: pick(facet, ['id', 'code', 'translations', 'customFields']),
         };
         return this.baseDataService.mutate<UpdateFacet, UpdateFacetVariables>(
             addCustomFields(UPDATE_FACET),
@@ -86,11 +77,7 @@ export class FacetDataService {
 
     createFacetValues(facetValues: CreateFacetValueInput[]): Observable<CreateFacetValues> {
         const input: CreateFacetValuesVariables = {
-            input: facetValues.map(fv => ({
-                facetId: fv.facetId,
-                code: fv.code,
-                translations: fv.translations,
-            })),
+            input: facetValues.map(pick(['facetId', 'code', 'translations'])),
         };
         return this.baseDataService.mutate<CreateFacetValues, CreateFacetValuesVariables>(
             addCustomFields(CREATE_FACET_VALUES),
@@ -100,11 +87,7 @@ export class FacetDataService {
 
     updateFacetValues(facetValues: UpdateFacetValueInput[]): Observable<UpdateFacetValues> {
         const input: UpdateFacetValuesVariables = {
-            input: facetValues.map(fv => ({
-                id: fv.id,
-                code: fv.code,
-                translations: fv.translations,
-            })),
+            input: facetValues.map(pick(['id', 'code', 'translations'])),
         };
         return this.baseDataService.mutate<UpdateFacetValues, UpdateFacetValuesVariables>(
             addCustomFields(UPDATE_FACET_VALUES),

+ 4 - 19
admin-ui/src/app/data/providers/product-data.service.ts

@@ -1,6 +1,7 @@
 import { Observable } from 'rxjs';
 
 import { getDefaultLanguage } from '../../common/utilities/get-default-language';
+import { pick } from '../../common/utilities/pick';
 import { addCustomFields } from '../add-custom-fields';
 import {
     ADD_OPTION_GROUP_TO_PRODUCT,
@@ -71,12 +72,7 @@ export class ProductDataService {
 
     createProduct(product: CreateProductInput): Observable<CreateProduct> {
         const input: CreateProductVariables = {
-            input: {
-                image: product.image,
-                translations: product.translations,
-                optionGroupCodes: product.optionGroupCodes,
-                customFields: product.customFields,
-            },
+            input: pick(product, ['image', 'translations', 'optionGroupCodes', 'customFields']),
         };
         return this.baseDataService.mutate<CreateProduct, CreateProductVariables>(
             addCustomFields(CREATE_PRODUCT),
@@ -86,12 +82,7 @@ export class ProductDataService {
 
     updateProduct(product: UpdateProductInput): Observable<UpdateProduct> {
         const input: UpdateProductVariables = {
-            input: {
-                id: product.id,
-                image: product.image,
-                translations: product.translations,
-                customFields: product.customFields,
-            },
+            input: pick(product, ['id', 'image', 'translations', 'customFields']),
         };
         return this.baseDataService.mutate<UpdateProduct, UpdateProductVariables>(
             addCustomFields(UPDATE_PRODUCT),
@@ -112,13 +103,7 @@ export class ProductDataService {
 
     updateProductVariants(variants: UpdateProductVariantInput[]): Observable<UpdateProductVariants> {
         const input: UpdateProductVariantsVariables = {
-            input: variants.map(v => ({
-                id: v.id,
-                translations: v.translations,
-                sku: v.sku,
-                image: v.image,
-                price: v.price,
-            })),
+            input: variants.map(pick(['id', 'translations', 'sku', 'image', 'price'])),
         };
         return this.baseDataService.mutate<UpdateProductVariants, UpdateProductVariantsVariables>(
             UPDATE_PRODUCT_VARIANTS,