mirror of
https://github.com/directus/directus.git
synced 2026-02-11 12:55:08 -05:00
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:
87
app/src/utils/validate-item.test.ts
Normal file
87
app/src/utils/validate-item.test.ts
Normal 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);
|
||||
});
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user