@fleye-me/ra-data-nest-crud
Version:
A NestJS data provider for React Admin
309 lines (259 loc) • 9.22 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('ra-core'), require('@nestjsx/crud-request')) :
typeof define === 'function' && define.amd ? define(['exports', 'ra-core', '@nestjsx/crud-request'], factory) :
(global = global || self, factory(global.index = {}, global.raCore, global.crudRequest));
}(this, function (exports, raCore, crudRequest) { 'use strict';
const MAGIC_SEPARATOR = "_._._._";
const POSSIBLE_SINGLE_ACTIONS = ["GET_ONE", "GET_MANY", "CREATE", "UPDATE", "DELETE"];
function extractRealData(resource) {
// Not encoded, return it
if (resource.indexOf(MAGIC_SEPARATOR) === -1) {
return {
realResource: resource
};
}
const [realResource, paramsStr] = resource.split(MAGIC_SEPARATOR);
try {
const integratedParams = JSON.parse(paramsStr);
return {
realResource,
integratedParams
};
} catch (error) {
console.warn("failed to parse params", {
realResource,
paramsStr,
error
});
return {
realResource
};
}
}
function httpParse(rawResponse, request) {
const {
json
} = rawResponse;
let toReturn = POSSIBLE_SINGLE_ACTIONS.includes(request.type) ? {
data: json
} : json;
return toReturn;
}
function composeFilter(paramsFilter) {
const flatFilter = raCore.fetchUtils.flattenObject(paramsFilter);
if (paramsFilter["$search"]) {
return {
s: paramsFilter["$search"]
};
}
const filter = Object.keys(flatFilter).map(key => {
const splitKey = key.split("||");
const operator = splitKey[1] || crudRequest.CondOperator.CONTAINS;
let field = splitKey[0];
if (field.indexOf("_") === 0 && field.indexOf(".") !== -1) {
field = field.split(/\.(.+)/)[1];
}
return {
field,
operator,
value: flatFilter[key]
};
});
return filter;
}
/* eslint-disable @typescript-eslint/no-object-literal-type-assertion */
function dataRequestToHTTP(apiUrl, type, resource, params) {
let url = "";
const options = {};
const parsedResource = extractRealData(resource);
const {
realResource
} = parsedResource;
const integratedParams = parsedResource.integratedParams || {};
switch (type) {
case raCore.GET_LIST:
{
const {
page,
perPage
} = params.pagination;
const composedFilter = composeFilter(params.filter);
let filter = {};
if (composedFilter["s"]) {
filter = composedFilter["s"];
} else {
filter = {
filter: composedFilter
};
}
let query = crudRequest.RequestQueryBuilder.create({ ...filter
}).setLimit(perPage).setPage(page).sortBy(params.sort).setOffset((page - 1) * perPage);
if (integratedParams.join) {
integratedParams.join.forEach(join => {
query = query.setJoin(join);
});
}
if (integratedParams.fields) {
query = query.select(integratedParams.fields);
}
url = `${apiUrl}/${realResource}?${query.query()}`;
break;
}
case raCore.GET_ONE:
{
let query = crudRequest.RequestQueryBuilder.create();
if (integratedParams.join) {
integratedParams.join.forEach(join => {
query = query.setJoin(join);
});
}
if (integratedParams.fields) {
query = query.select(integratedParams.fields);
}
url = `${apiUrl}/${realResource}/${params.id}?${query.query()}`;
break;
}
case raCore.GET_MANY:
{
let query = crudRequest.RequestQueryBuilder.create().setFilter({
field: "id",
operator: crudRequest.CondOperator.IN,
value: `${params.ids}`
});
if (integratedParams.join) {
integratedParams.join.forEach(join => {
query = query.setJoin(join);
});
}
if (integratedParams.fields) {
query = query.select(integratedParams.fields);
}
url = `${apiUrl}/${realResource}?${query.query()}`;
break;
}
case raCore.GET_MANY_REFERENCE:
{
const {
page,
perPage
} = params.pagination;
const filter = composeFilter(params.filter);
filter.push({
field: params.target,
operator: crudRequest.CondOperator.EQUALS,
value: params.id
});
let query = crudRequest.RequestQueryBuilder.create({
filter
}).sortBy(params.sort).setLimit(perPage).setOffset((page - 1) * perPage);
if (integratedParams.join) {
integratedParams.join.forEach(join => {
query = query.setJoin(join);
});
}
if (integratedParams.fields) {
query = query.select(integratedParams.fields);
}
url = `${apiUrl}/${realResource}?${query.query()}`;
break;
}
case raCore.UPDATE:
{
url = `${apiUrl}/${realResource}/${params.id}`;
options.method = "PATCH";
options.body = JSON.stringify(params.data);
break;
}
case raCore.CREATE:
{
url = `${apiUrl}/${realResource}`;
options.method = "POST";
options.body = JSON.stringify(params.data);
break;
}
case raCore.DELETE:
{
url = `${apiUrl}/${realResource}/${params.id}`;
options.method = "DELETE";
break;
}
default:
throw new Error(`Unsupported fetch action type ${type}`);
}
return {
url,
options
};
}
/**
* Experimental, not directly exposed
* Will give us a hook to customize requets/responses
*/
async function makeRequest(apiUrl, httpClient = raCore.fetchUtils.fetchJson, configuration, type, resource, params) {
let rawResponse;
const parsedResource = extractRealData(resource);
let requestIntermediate = {
type,
resource: parsedResource.realResource,
params,
integratedParams: parsedResource.integratedParams
};
if (configuration && configuration.requestMutator) {
requestIntermediate = configuration.requestMutator(requestIntermediate);
}
if (requestIntermediate.type === raCore.UPDATE_MANY) {
rawResponse = await Promise.all(requestIntermediate.params.ids.map(id => httpClient(`${apiUrl}/${parsedResource.realResource}/${id}`, {
method: "PUT",
body: JSON.stringify(requestIntermediate.params.data)
})));
} else if (requestIntermediate.type === raCore.DELETE_MANY) {
rawResponse = await Promise.all(requestIntermediate.params.ids.map(id => httpClient(`${apiUrl}/${parsedResource.realResource}/${id}`, {
method: "DELETE"
})));
} else {
const {
url,
options
} = dataRequestToHTTP(apiUrl, requestIntermediate.type, // Original and not intermediate here.
resource, requestIntermediate.params);
rawResponse = await httpClient(url, options);
} // maybe pass here original and not intermediate values?
let responseIntermediate = {
response: rawResponse,
type: requestIntermediate.type,
resource: requestIntermediate.resource,
params: requestIntermediate.params
};
if (configuration && configuration.responseMutator) {
responseIntermediate = configuration.responseMutator(responseIntermediate, requestIntermediate);
}
let oneMoreIntermediateResponse = httpParse(responseIntermediate.response, requestIntermediate); // in some conditions, we want to fetch fresh copy of the data from nest/crud.
switch (requestIntermediate.type) {
case "CREATE":
case "UPDATE":
return makeRequest(apiUrl, httpClient, configuration, "GET_ONE", resource, {
id: responseIntermediate.response.json.id
});
default:
return oneMoreIntermediateResponse;
}
}
function createNestjsxCrudClient(apiUrl, httpClient = raCore.fetchUtils.fetchJson) {
return makeRequest.bind(null, apiUrl, httpClient, {});
}
/**
* Not documented yet. Experimental.
* Will give us a hook to customize requets/responses
*/
function createNestjsxCrudClientWithConfig(apiUrl, httpClient = raCore.fetchUtils.fetchJson, configuration = {}) {
return makeRequest.bind(null, apiUrl, httpClient, configuration);
}
function encodeParamsInResource(resource, paramsToIntegrate) {
return `${resource}${MAGIC_SEPARATOR}${JSON.stringify(paramsToIntegrate)}`;
}
exports.createNestjsxCrudClientWithConfig = createNestjsxCrudClientWithConfig;
exports.default = createNestjsxCrudClient;
exports.encodeParamsInResource = encodeParamsInResource;
Object.defineProperty(exports, '__esModule', { value: true });
}));
//# sourceMappingURL=index.js.map