3
\$\begingroup\$

This is the original code for accessing a service endpoint that returns information about a product. The exported methods of this module each take a single param of "id" and returns a Promise.

I've attempted to refactor this code using curry and compose with ramda.js and would like feedback and possibly a better solution.

Original:

import {client} from '@core/GraphQLProvider';
import {CatalogItem, CatalogItemFullDetail, CatalogItemAccessories} from './query.graphql';

const locale = 'en-US';

const formatSku = id => /-/.test( id ) ? id : id + '-';

const fetch = async ( query ) => {
    const resp = await client.query( query );
    return resp.data.product;
};

export default {

    async getDetail ( id ) {
        const skuValues = formatSku( id );

        return fetch( {
            query: CatalogItem,
            variables: {skuValues, locale}
        } );
    },

    async getFullDetail ( id ) {
        const skuValues = formatSku( id );

        return fetch( {
            query: CatalogItemFullDetail,
            variables: {skuValues, locale}
        } );
    },

    async getPurchaseDetail ( id ) {
        const skuValues = formatSku( id );

        return fetch( {
            query: CatalogItem,
            variables: {skuValues, locale, withPrice: true}
        } );
    },

    async getDetailWithAccessories ( id ) {
        const skuValues = formatSku( id );

        return fetch( {
            query: CatalogItem,
            variables: {skuValues, locale, withAccessories: true}
        } );
    },

    async getAccessories ( id ) {
        const skuValues = formatSku( id );

        const resp = await client.query( {
            query: CatalogItemAccessories,
            variables: {skuValues, locale}
        } );

        return resp.data.product.accessories;
    }
};

Refactored:

import {client} from '@core/GraphQLProvider';
import {CatalogItem, CatalogItemFullDetail, CatalogItemAccessories} from './query.graphql';
import curry from 'ramda/src/curry';
import compose from 'ramda/src/compose';
import pCompose from 'ramda/src/composeP';
import prop from 'ramda/src/prop';

const locale = 'en-US';
const DEFAULT_OPTIONS = {
    withAccessories: false,
    withPrice: false
};
const formatSku = id => /-/.test( id ) ? id : id + '-';
const buildQuery = curry(
    ( locale, query, withOptions, skuValues ) => ({
            query,
        variables: {
            locale,
            ...withOptions,
            skuValues: formatSku( skuValues )
        }
    })
);
const buildQueryWithLocale = buildQuery( locale );
const queryProp = propName => pCompose( prop( propName ), prop( 'data' ), client.query );
const queryProductWithOptions = curry( compose( queryProp( 'product' ), buildQueryWithLocale ) );

export default {
    getDetail: queryProductWithOptions( CatalogItem, DEFAULT_OPTIONS ),
    getDetailWithAccessories: queryProductWithOptions( CatalogItem, {withAccessories: true} ),
    getPurchaseDetail: queryProductWithOptions( CatalogItem, {withPrice: true} ),
    getFullDetail: queryProductWithOptions( CatalogItemFullDetail, DEFAULT_OPTIONS ),
    getFullDetailWithAccessories: queryProductWithOptions( CatalogItemFullDetail, {withAccessories: true} ),

    async getAccessories ( id ) {
        const product = await queryProductWithOptions( CatalogItemAccessories, DEFAULT_OPTIONS, id );
        return product.accessories;
    }
};
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.