-
-
Save christiaanwesterbeek/05161dbc12baba91da7aa31e7e4eb465 to your computer and use it in GitHub Desktop.
dataProvider adaptation for postgraphile flavor
This file contains hidden or 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
// from https://gist.github.com/ak-il/e91bfbd2c7c83086c7ded41512335795 | |
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 fieldList = buildFieldList(resource); | |
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), | |
}; | |
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), | |
}; | |
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), | |
}; | |
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), | |
}; | |
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), | |
}; | |
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), | |
}; | |
default: | |
throw new Error( | |
`${raFetchType} was not implemented yet in dataProvider.builderFactory` | |
); | |
} | |
}; | |
} | |
export const buildQuery = introspectionResults => | |
builderFactory(introspectionResults); | |
export default (client): Promise<any> => { | |
const dataProvider = buildGraphQLProvider({ | |
client, | |
buildQuery, | |
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; | |
}; |
Sorry for the stupid question - but where do you put this in the default ra-admin and what to include in the App.js? I thought I should make a node_module directory for it then just import dataProvider from ra-data-postgraphile but am getting the following errors. Any help would be greatly appreciated, just looking to get started!
Module parse failed: Unexpected token (256:28)
You may need an appropriate loader to handle this file type.
| builderFactory(introspectionResults);
|
export default (client): Promise => {
| const dataProvider = buildGraphQLProvider({
| client,
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
CHANGELOG.md
Fixed
Changed