mirror of
https://github.com/directus/directus.git
synced 2026-01-25 12:07:56 -05:00
* Add depth limit to filtering * Add depth limit to GraphQL * Add docs * Rename environment variable * Add simple deep filter depth calculation * Update error message * Shift fields depth check to base function * Remove unused var * Implement GraphQL filter depth * Add check for _and & _or filters in GraphQL * Add check for _and & _or filters in REST * Remove commented code * Add check for REST filter query * Add REST tests * Setup m2m using directus fields * Add GraphQL tests * Fix linter error * Cleanup calculateDepth + add docs/tests * Remove validator in GraphQL * Add depth checking for nested sort * Enable source map to display correct error lines * Set max relational depth to be at least 2 * Update tests * Add unit test for deep _sort * Add minimum value in docs * Refactor depth validation to be in validateQuery * Add boolean parameter for calculation of _sort in deep query * Use array of keys to parse dot notation Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
314 lines
9.9 KiB
TypeScript
314 lines
9.9 KiB
TypeScript
import config, { getUrl } from '../../config';
|
|
import vendors from '../../get-dbs-to-test';
|
|
import request from 'supertest';
|
|
import knex, { Knex } from 'knex';
|
|
import { createArtist, createEvent, seedTable } from '../../setup/utils/factories';
|
|
|
|
describe('/items', () => {
|
|
const databases = new Map<string, Knex>();
|
|
|
|
beforeAll(async () => {
|
|
for (const vendor of vendors) {
|
|
databases.set(vendor, knex(config.knexConfig[vendor]!));
|
|
}
|
|
});
|
|
|
|
afterAll(async () => {
|
|
for (const [_vendor, connection] of databases) {
|
|
await connection.destroy();
|
|
}
|
|
});
|
|
|
|
describe('/:collection GET', () => {
|
|
describe('allow queries up to the field depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/artists/${artist.id}?fields=*.*.*.*.*`)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: [expect.any(Number)],
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('deny queries over the field depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
await request(getUrl(vendor))
|
|
.get(`/items/artists/${artist.id}?fields=*.*.*.*.*.*`)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(400);
|
|
});
|
|
});
|
|
|
|
describe('allow queries up to deep depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(
|
|
`/items/artists/${artist.id}?fields=*.*.*.*.*&deep[events][_filter][artists_id][events][artists_id][id][_eq]=${artist.id}`
|
|
)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: [expect.any(Number)],
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('deny queries over the deep depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
await request(getUrl(vendor))
|
|
.get(
|
|
`/items/artists/${artist.id}?fields=*.*.*.*.*&deep[events][_filter][artists_id][events][artists_id][events][id][_eq]=${event.id}`
|
|
)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(400);
|
|
});
|
|
});
|
|
|
|
describe('allow queries up to filter depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(
|
|
`/items/artists/${artist.id}?fields=*.*.*.*.*&filter[events][artists_id][events][artists_id][id][_eq]=${artist.id}`
|
|
)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: [expect.any(Number)],
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('deny queries over the filter depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
await request(getUrl(vendor))
|
|
.get(
|
|
`/items/artists/${artist.id}?fields=*.*.*.*.*&filter[events][artists_id][events][artists_id][events][id][_eq]=${event.id}`
|
|
)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(400);
|
|
});
|
|
});
|
|
|
|
describe('allow queries up to sort depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/artists/${artist.id}?fields=*.*.*.*.*&sort=events.artists_id.events.artists_id.id`)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: [expect.any(Number)],
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('deny queries over the sort depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
await request(getUrl(vendor))
|
|
.get(`/items/artists/${artist.id}?fields=*.*.*.*.*&sort=events.artists_id.events.artists_id.events.id`)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(400);
|
|
});
|
|
});
|
|
|
|
describe('allow queries up to deep sort depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/artists/${artist.id}?fields=*.*.*.*.*&deep[events][_sort]=artists_id.events.artists_id.id`)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
artists_id: expect.objectContaining({
|
|
events: [expect.any(Number)],
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('deny queries over the deep sort depth limit', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const artist = createArtist();
|
|
const event = createEvent();
|
|
await seedTable(databases.get(vendor)!, 1, 'artists', artist);
|
|
await seedTable(databases.get(vendor)!, 1, 'events', event);
|
|
await seedTable(databases.get(vendor)!, 1, 'artists_events', {
|
|
artists_id: artist.id,
|
|
events_id: event.id,
|
|
});
|
|
|
|
await request(getUrl(vendor))
|
|
.get(
|
|
`/items/artists/${artist.id}?fields=*.*.*.*.*&deep[events][_sort]=artists_id.events.artists_id.events.id`
|
|
)
|
|
.set('Authorization', 'Bearer AdminToken')
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(400);
|
|
});
|
|
});
|
|
});
|
|
});
|