Last active
October 4, 2019 11:58
-
-
Save alexkubica/e91bfbd2c7c83086c7ded41512335795 to your computer and use it in GitHub Desktop.
dataProvider adaptation for postgraphile flavor, UPDATE: see https://github.com/des-des/ra-postgraphile-client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import gql from 'graphql-tag'; | |
import { | |
GET_LIST, | |
GET_ONE, | |
GET_MANY, | |
CREATE, | |
UPDATE, | |
DELETE | |
} from 'react-admin'; | |
import buildGraphQLProvider from 'ra-data-graphql'; | |
import { plural, singular } from 'pluralize'; | |
import * as _ from 'lodash'; | |
function isScalar(field) { | |
return (_.has(field, 'type.kind') && field.type.kind === 'SCALAR') || | |
(_.has(field, 'type.ofType.kind') && field.type.ofType.kind === 'SCALAR'); | |
} | |
function isInt(field) { | |
return (_.has(field, 'type.kind') && field.type.kind === 'Int') || | |
(_.has(field, 'type.ofType.kind') && field.type.ofType.kind === 'Int'); | |
} | |
function isString(field) { | |
return (_.has(field, 'type.kind') && field.type.kind === 'String') || | |
(_.has(field, 'type.ofType.kind') && field.type.ofType.kind === 'String'); | |
} | |
function buildFieldList(resource) { | |
// Get scalar fields only | |
// TODO use graphql-ast-types helpers | |
return resource.type.fields.filter(isScalar).map(field => { | |
return field.name; | |
}).join('\r\n\); | |
} | |
function buildObjectInput(resource, object) { | |
return Object.keys(object).map(key => { | |
const field = resource.type.fields.find(field => field.name === key); | |
if (!field) { | |
return undefined; | |
} | |
if (isString(field)) { | |
return `${key}: "${object[key]}"`; | |
} | |
if (isInt(field)) { | |
return `${key}: ${object[key]}`; | |
} | |
return undefined; | |
}).join('\r\n\'); | |
} | |
function buildGetManyQuery(ids, resource, getOneQueryName) { | |
const query = `query { | |
${ | |
ids.map(id => { | |
return `id${id}: ${getOneQueryName} ( | |
${`id: ${id}`} | |
) { | |
${fieldList} | |
}`; | |
}).join('\r\n\) | |
} | |
}`; | |
return gql(query); | |
} | |
function builderFactory(introspectionResults) { | |
return (raFetchType, resourceName, params) => { | |
// TODO use ra-data-graphql-simple's buildQuery function as a default | |
const resource = introspectionResults.resources | |
.find(r => r.type.name === singular(_.upperFirst(_.camelCase(resourceName)))); | |
switch (raFetchType) { | |
case GET_LIST: | |
return { | |
query: gql`query { | |
pageResults: ${resource[raFetchType].name}( | |
first: ${params.pagination.perPage} | |
offset: ${Math.floor((params.pagination.page - 1) * params.pagination.perPage)}`, | |
orderBy: ${_.snakeCase(params.sort.field).toUpperCase()}_${params.sort.order} | |
) { | |
nodes { | |
${buildFieldList(resource)} | |
} | |
} | |
total: ${resource[raFetchType].name} { | |
totalCount | |
} | |
}`, | |
variables: params, | |
parseResponse: ((raFetchType, resourceName, params) => { | |
return response => { | |
return { | |
data: response.data.pageResults.nodes, | |
total: response.data.total.totalCount | |
}; | |
}; | |
})(raFetchType, resourceName, params); | |
}; | |
break; | |
case GET_MANY: | |
return { | |
query: buildGetManyQuery(params.ids, resource, resource[GET_ONE].name), | |
variables: params, | |
parseResponse: ((raFetchType, resourceName, params) => { | |
return response => { | |
return { | |
data: Object.keys(response.data).map(key => { | |
return response.data[key]; | |
}); | |
}; | |
}; | |
})(raFetchType, resourceName, params); | |
}; | |
break; | |
case GET_ONE: | |
return { | |
query: gql`query { | |
${resource[raFetchType].name} ( | |
${`id: ${params.id}`} | |
) { | |
${buildFieldList(resource)} | |
} | |
}`, | |
variables: params, | |
parseResponse: ((raFetchType, resourceName, params) => { | |
const queryName = resource[raFetchType].name; | |
return response => { | |
return { | |
data: response.data[queryName]; | |
}; | |
}; | |
})(raFetchType, resourceName, params); | |
}; | |
break; | |
case CREATE: | |
return { | |
query: gql`mutation { | |
${resource[raFetchType].name}(input: { | |
${singular(_.camelCase(resourceName))}: { | |
${buildObjectInput(resource, params.data)} | |
} | |
}) { | |
${singular(_.camelCase(resourceName))} { | |
${buildFieldList(resource)} | |
} | |
} | |
}`, | |
variables: params, | |
parseResponse: ((raFetchType, resourceName, params) => { | |
const queryName = resource[raFetchType].name; | |
return response => { | |
return { | |
data: response.data[queryName][singular(_.camelCase(resourceName))] | |
}; | |
}; | |
})(raFetchType, resourceName, params); | |
}; | |
break; | |
case UPDATE: | |
return { | |
query: gql`mutation { | |
${resource[raFetchType].name}(input: { | |
id: ${params.id} | |
${singular(_.camelCase(resourceName))}Patch: { | |
${buildObjectInput(resource, params.data)} | |
} | |
}) { | |
${singular(_.camelCase(resourceName))} { | |
${buildFieldList(resource)} | |
} | |
} | |
}`, | |
variables: params, | |
parseResponse: ((raFetchType, resourceName, params) => { | |
const queryName = resource[raFetchType].name; | |
return response => { | |
return { | |
data: response.data[queryName][singular(_.camelCase(resourceName))] | |
}; | |
}; | |
})(raFetchType, resourceName, params); | |
}; | |
break; | |
case DELETE: | |
return { | |
query: gql`mutation { | |
${resource[raFetchType].name}(input: { | |
id: ${params.id} | |
}) { | |
${singular(_.camelCase(resourceName))} { | |
${buildFieldList(resource)} | |
} | |
} | |
}`, | |
variables: params, | |
parseResponse: ((raFetchType, resourceName, params) => { | |
const queryName = resource[raFetchType].name; | |
return response => { | |
return { | |
data: response.data[queryName][singular(_.camelCase(resourceName))] | |
}; | |
}; | |
})(raFetchType, resourceName, params); | |
}; | |
break; | |
default: | |
throw new Error(`${raFetchType} was not implemented yet in dataProvider.builderFactory`); | |
} | |
}; | |
} | |
export default (client): Promise<any> => { | |
const dataProvider = buildGraphQLProvider({ | |
client, | |
buildQuery: (introspectionResults) => { | |
return builderFactory(introspectionResults); | |
}, | |
introspection: { | |
operationNames: { | |
[GET_ONE]: (type) => { | |
return `${singular(_.camelCase(type.name))}ById`; | |
}, | |
[GET_LIST]: (type) => { | |
return `all${plural(_.upperFirst(_.camelCase(type.name)))}`; | |
}, | |
[UPDATE]: (type) => { | |
return `update${singular(_.upperFirst(_.camelCase(type.name)))}`; | |
}, | |
[DELETE]: (type) => { | |
return `delete${singular(_.upperFirst(_.camelCase(type.name)))}`; | |
} | |
} | |
} | |
}); | |
return dataProvider; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@anwajler
That's awesome, I added it to the title of the gist :)