treat empty array as null on relational field (#15958)

* treat empty array as null on relational field

* Run prettier

* add unit test

* Fix linter warnings

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
Nitwel
2022-10-14 20:38:53 +02:00
committed by GitHub
parent 64f60a007a
commit 413d21fe4b
7 changed files with 106 additions and 7 deletions

View File

@@ -0,0 +1,87 @@
import { beforeEach, expect, test } from 'vitest';
import { validateItem } from '@/utils/validate-item';
import { DeepPartial, Field } from '@directus/shared/types';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
const fields: DeepPartial<Field>[] = [
{
field: 'id',
collection: 'users',
type: 'integer',
name: 'ID',
meta: {
required: true,
},
schema: null,
},
{
field: 'name',
collection: 'users',
type: 'string',
name: 'Name',
meta: {
required: true,
},
schema: null,
},
{
field: 'email',
collection: 'users',
type: 'string',
name: 'Email',
schema: null,
},
{
field: 'role',
collection: 'users',
type: 'integer',
name: 'Role',
meta: {
required: true,
},
schema: null,
},
];
beforeEach(() => {
setActivePinia(
createTestingPinia({
createSpy: () => (_collection, field) => {
if (field === 'role') {
return [{ some: 'relation' }];
}
return [];
},
})
);
});
test('Required fields', () => {
let result = validateItem(
{
id: 1,
name: 'test',
email: 'test@test.com',
role: [1, 2],
},
fields as Field[],
true
);
expect(result.length).toEqual(0);
result = validateItem(
{
id: 1,
name: 'test',
email: 'test@test.com',
role: [],
},
fields as Field[],
true
);
expect(result.length).toEqual(1);
});

View File

@@ -1,10 +1,13 @@
import { useRelationsStore } from '@/stores/relations';
import { FailedValidationException } from '@directus/shared/exceptions';
import { Field, LogicalFilterAND } from '@directus/shared/types';
import { validatePayload } from '@directus/shared/utils';
import { flatten, isNil } from 'lodash';
import { cloneDeep, flatten, isEmpty, isNil } from 'lodash';
import { applyConditions } from './apply-conditions';
export function validateItem(item: Record<string, any>, fields: Field[], isNew: boolean) {
const relationsStore = useRelationsStore();
const validationRules = {
_and: [],
} as LogicalFilterAND;
@@ -13,6 +16,8 @@ export function validateItem(item: Record<string, any>, fields: Field[], isNew:
const requiredFields = fieldsWithConditions.filter((field) => field.meta?.required === true);
const updatedItem = cloneDeep(item);
for (const field of requiredFields) {
if (isNew && isNil(field.schema?.default_value)) {
validationRules._and.push({
@@ -22,6 +27,13 @@ export function validateItem(item: Record<string, any>, fields: Field[], isNew:
});
}
const relation = relationsStore.getRelationsForField(field.collection, field.field);
// Check if we are dealing with a relational field that has an empty array as its value
if (relation.length > 0 && Array.isArray(updatedItem[field.field]) && isEmpty(updatedItem[field.field])) {
updatedItem[field.field] = null;
}
validationRules._and.push({
[field.field]: {
_nnull: true,
@@ -30,7 +42,7 @@ export function validateItem(item: Record<string, any>, fields: Field[], isNew:
}
return flatten(
validatePayload(validationRules, item).map((error) =>
validatePayload(validationRules, updatedItem).map((error) =>
error.details.map((details) => new FailedValidationException(details).extensions)
)
).map((error) => {