Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ra-data-graphql: Update include/exclude introspection logic #5305

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions packages/ra-data-graphql/src/introspection.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@ import { GET_LIST, GET_ONE } from 'ra-core';

import { ALL_TYPES } from './constants';

export const filterTypesByIncludeExclude = ({ include, exclude }) => {
export const isResourceIncluded = ({ include, type }) => {
if (Array.isArray(include)) {
return type => include.includes(type.name);
return include.includes(type.name);
}

if (typeof include === 'function') {
return type => include(type);
return include(type);
}

return false;
};

export const isResourceExcluded = ({ exclude, type }) => {
if (Array.isArray(exclude)) {
return type => !exclude.includes(type.name);
return exclude.includes(type.name);
}

if (typeof exclude === 'function') {
return type => !exclude(type);
return exclude(type);
}

return () => true;
return false;
};

/**
Expand Down Expand Up @@ -56,13 +60,19 @@ export default async (client, options) => {
type.name !== (schema.mutationType && schema.mutationType.name)
);

const isResource = type =>
queries.some(
query => query.name === options.operationNames[GET_LIST](type)
) &&
queries.some(
query => query.name === options.operationNames[GET_ONE](type)
const isResource = type => {
if (isResourceIncluded({ type, ...options })) return true;
if (isResourceExcluded({ type, ...options })) return false;

return (
queries.some(
query => query.name === options.operationNames[GET_LIST](type)
) &&
queries.some(
query => query.name === options.operationNames[GET_ONE](type)
)
);
};

const buildResource = type =>
ALL_TYPES.reduce(
Expand All @@ -78,10 +88,7 @@ export default async (client, options) => {
{ type }
);

const potentialResources = types.filter(isResource);
const filteredResources = potentialResources.filter(
filterTypesByIncludeExclude(options)
);
const filteredResources = types.filter(isResource);
const resources = filteredResources.map(buildResource);

return {
Expand Down
61 changes: 38 additions & 23 deletions packages/ra-data-graphql/src/introspection.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import resolveIntrospection, {
filterTypesByIncludeExclude,
isResourceExcluded,
isResourceIncluded,
} from './introspection';
import {
GET_LIST,
Expand All @@ -12,64 +13,78 @@ import {
} from 'ra-core';

describe('introspection', () => {
describe('filterTypesByIncludeExclude', () => {
describe('isResourceIncluded', () => {
it('return false with an include option containing an array and tested type is not in it', () => {
expect(
filterTypesByIncludeExclude({ include: ['Post', 'Comment'] })({
name: 'NotMe',
isResourceIncluded({
include: ['Post', 'Comment'],
type: {
name: 'NotMe',
},
})
).toBe(false);
});

it('return true with an include option containing an array and tested type is in it', () => {
expect(
filterTypesByIncludeExclude({ include: ['Post', 'Comment'] })({
name: 'Post',
isResourceIncluded({
include: ['Post', 'Comment'],
type: {
name: 'Post',
},
})
).toBe(true);
});

it('return false with an exclude option containing an array and tested type is in it', () => {
it('return false with an include option containing an array and tested type is not in it', () => {
expect(
filterTypesByIncludeExclude({ exclude: ['NotMe'] })({
name: 'NotMe',
isResourceIncluded({
include: ['NotMe'],
type: {
name: 'Post',
},
})
).toBe(false);
});

it('return true with an include option containing an array and tested type is not in it', () => {
expect(
filterTypesByIncludeExclude({ exclude: ['NotMe'] })({
name: 'Post',
})
).toBe(true);
});

it('return true with an include option being a function returning true', () => {
const include = jest.fn(() => true);
const type = { name: 'Post' };
expect(filterTypesByIncludeExclude({ include })(type)).toBe(true);
expect(isResourceIncluded({ include, type })).toBe(true);
expect(include).toHaveBeenCalledWith(type);
});

it('return false with an include option being a function returning false', () => {
const include = jest.fn(() => false);
const type = { name: 'Post' };
expect(filterTypesByIncludeExclude({ include })(type)).toBe(false);
expect(isResourceIncluded({ include, type })).toBe(false);
expect(include).toHaveBeenCalledWith(type);
});
});

describe('isResourceExcluded', () => {
it('return true with an exclude option containing an array and tested type is in it', () => {
expect(
isResourceExcluded({
exclude: ['NotMe'],
type: {
name: 'NotMe',
},
})
).toBe(true);
});

it('return false with an exclude option being a function returning true', () => {
it('return true with an exclude option being a function returning true', () => {
const exclude = jest.fn(() => true);
const type = { name: 'Post' };
expect(filterTypesByIncludeExclude({ exclude })(type)).toBe(false);
expect(isResourceExcluded({ exclude, type })).toBe(true);
expect(exclude).toHaveBeenCalledWith(type);
});

it('return true with an exclude option being a function returning false', () => {
it('return false with an exclude option being a function returning false', () => {
const exclude = jest.fn(() => false);
const type = { name: 'Post' };
expect(filterTypesByIncludeExclude({ exclude })(type)).toBe(true);
expect(isResourceExcluded({ exclude, type })).toBe(false);
expect(exclude).toHaveBeenCalledWith(type);
});
});
Expand Down