rsm-hcd / AndcultureCode.JavaScript.React

Common patterns, functions, etc... used when building react applications
6 stars 8 forks source link

Add service factories for batched api calls #55

Open snsavage opened 3 years ago

snsavage commented 3 years ago

We've recently added service factories for batchedListService and nestedBatchedListService to a client project. These should be moved to src/services/service-factory.ts in this project. To do this, several pieces will be needed.

Types:

export type BatchedListService<TRecord, TQueryParams> = (
    queryParams: TQueryParams,
    property: keyof TQueryParams,
    size: number
) => Promise<ServiceResponse<TRecord>>;
export type NestedBatchedListService<TRecord, TPathParams, TQueryParams> = (
    pathParams: TPathParams,
    queryParams: TQueryParams,
    property: keyof TQueryParams,
    size: number
) => Promise<ServiceResponse<TRecord>>

Public Functions:

const ServiceFactory = {
    batchedList: <TRecord, TQueryParams>(
        recordType: { new (): TRecord },
        baseEndpoint: string
    ): BatchedListService<TRecord, TQueryParams> => {
        return async (
            queryParams: TQueryParams,
            property: keyof TQueryParams,
            size: number
        ) => {
            return _batchList(
                recordType,
                baseEndpoint,
                property,
                size,
                queryParams
            );
        };
    },
    nestedBatchedList: <TRecord, TPathParams, TQueryParams>(
        recordType: { new (): TRecord },
        baseEndpoint: string
    ): NestedBatchedListService<TRecord, TPathParams, TQueryParams> => {
        return async (
            pathParams: TPathParams,
            queryParams: TQueryParams,
            property: keyof TQueryParams,
            size: number
        ) => {
            return _batchList(
                recordType,
                baseEndpoint,
                property,
                size,
                queryParams,
                pathParams
            );
        };
    }
}

Private Function:

const _batchedList = async function<
    TRecord,
    TQueryParams,
    TPathParams = undefined
>(
    recordType: { new (): TRecord },
    baseEndpoint: string,
    property: keyof TQueryParams,
    size: number,
    queryParams: TQueryParams,
    pathParams?: TPathParams
) {
    const values = queryParams[property];
    if (!(values instanceof Array) || CollectionUtils.isEmpty(values)) {
        return ServiceResponseFactory.successfulList<TRecord>();
    }

    const batches = _.chunk(values, size);

    const requests = batches.map((batchValues) => {
        const batchedParams = Object.assign({}, queryParams);
        batchedParams[property] = batchValues as any;

        if (pathParams != null) {
            return AndcultureCodeServiceFactory.nestedList<
                TRecord,
                TPathParams,
                TQueryParams
            >(recordType, baseEndpoint)(pathParams, batchedParams);
        }

        return AndcultureCodeServiceFactory.list<TRecord, TQueryParams>(
            recordType,
            baseEndpoint
        )(batchedParams);
    }) as Promise<ServiceResponse<TRecord>>[];

    const results = await PromiseUtils.toArray(requests);
    return ServiceResponseFactory.successfulList(results, values.length);
};

After the _batchedList private function is added to service-factory.ts the calls to AndcultureCodeServiceFactory.nestedList and AndcultureCodeServiceFactory.list can be swapped out for a single call to the service-factory's private _list function.

Finally, a service-response-factory was added to return a successfulList result. This should also be brought over.

const ServiceResponseFactory = {
    /**
     * Default successful list response
     */
    successfulList<T>(
        resultObjects?: Array<T>,
        rowCount?: number
    ): ServiceResponse<T> {
        return {
            resultObjects: resultObjects ?? [],
            rowCount: rowCount ?? 0,
            status: 200,
        };
    },
};

The implementation in the client project has been tagged with this issue for reference.