feat: adds min and max options to relationship with hasMany

This commit is contained in:
Dan Ribbens
2023-03-04 16:12:07 -05:00
parent 812ab9f868
commit 0f38a0dcf6
5 changed files with 112 additions and 8 deletions

View File

@@ -325,6 +325,10 @@ export const relationship = baseField.keys({
isSortable: joi.boolean().default(false),
allowCreate: joi.boolean().default(true),
}),
min: joi.number()
.when('hasMany', { is: joi.not(true), then: joi.forbidden() }),
max: joi.number()
.when('hasMany', { is: joi.not(true), then: joi.forbidden() }),
});
export const blocks = baseField.keys({

View File

@@ -290,7 +290,15 @@ export type RelationshipField = FieldBase & {
isSortable?: boolean;
allowCreate?: boolean;
}
}
} & ({
hasMany: true
min?: number
max?: number
} | {
hasMany?: false | undefined
min?: undefined
max?: undefined
})
export type ValueWithRelation = {
relationTo: string

View File

@@ -1,4 +1,4 @@
import { text, textarea, password, select, point, number } from './validations';
import { text, textarea, password, select, point, number, relationship } from './validations';
import { ValidateOptions } from './config/types';
const t = jest.fn((string) => string);
@@ -185,6 +185,66 @@ describe('Field Validations', () => {
});
});
describe('relationship', () => {
options.relationTo = 'relation';
options.payload = {
collections: {
relation: {
config: {
slug: 'relation',
fields: [{
name: 'id',
type: 'text',
}],
},
},
},
};
it('should handle required', async () => {
options.required = true;
const val = undefined;
const result = await relationship(val, options);
expect(result).not.toBe(true);
});
it('should handle required with hasMany', async () => {
options.required = true;
options.hasMany = true;
const val = [];
const result = await relationship(val, options);
expect(result).not.toBe(true);
});
it('should enforce hasMany min', async () => {
const minOptions = {
...options,
hasMany: true,
min: 2,
};
const val = ['a'];
const result = await relationship(val, minOptions);
expect(result).not.toBe(true);
const allowed = await relationship(['a', 'b'], minOptions);
expect(allowed).toStrictEqual(true);
});
it('should enforce hasMany max', async () => {
const maxOptions = {
...options,
max: 2,
hasMany: true,
};
let val = ['a', 'b', 'c'];
const result = await relationship(val, maxOptions);
expect(result).not.toBe(true);
val = ['a'];
const allowed = await relationship(val, maxOptions);
expect(allowed).toStrictEqual(true);
});
});
describe('select', () => {
options.type = 'select';
options.options = ['one', 'two', 'three'];

View File

@@ -20,7 +20,6 @@ import {
Validate,
fieldAffectsData,
} from './config/types';
import { TypeWithID } from '../collections/config/types';
import canUseDOM from '../utilities/canUseDOM';
import { isValidID } from '../utilities/isValidID';
import { getIDType } from '../utilities/getIDType';
@@ -276,10 +275,29 @@ export const upload: Validate<unknown, unknown, UploadField> = (value: string, o
};
export const relationship: Validate<unknown, unknown, RelationshipField> = async (value: RelationshipValue, options) => {
if ((!value || (Array.isArray(value) && value.length === 0)) && options.required) {
const {
required,
min,
max,
relationTo,
payload,
t,
} = options;
if ((!value || (Array.isArray(value) && value.length === 0)) && required) {
return options.t('validation:required');
}
if (Array.isArray(value)) {
if (min && value.length < min) {
return t('validation:lessThanMin', { count: min, label: t('rows') });
}
if (max && value.length > max) {
return t('validation:greaterThanMax', { count: max, label: t('rows') });
}
}
if (!canUseDOM && typeof value !== 'undefined' && value !== null) {
const values = Array.isArray(value) ? value : [value];
@@ -287,8 +305,8 @@ export const relationship: Validate<unknown, unknown, RelationshipField> = async
let collection: string;
let requestedID: string | number;
if (typeof options.relationTo === 'string') {
collection = options.relationTo;
if (typeof relationTo === 'string') {
collection = relationTo;
// custom id
if (typeof val === 'string' || typeof val === 'number') {
@@ -296,12 +314,12 @@ export const relationship: Validate<unknown, unknown, RelationshipField> = async
}
}
if (Array.isArray(options.relationTo) && typeof val === 'object' && val?.relationTo) {
if (Array.isArray(relationTo) && typeof val === 'object' && val?.relationTo) {
collection = val.relationTo;
requestedID = val.value;
}
const idField = options.payload.collections[collection].config.fields.find((field) => fieldAffectsData(field) && field.name === 'id');
const idField = payload.collections[collection].config.fields.find((field) => fieldAffectsData(field) && field.name === 'id');
let type;
if (idField) {
type = idField.type === 'number' ? 'number' : 'text';

View File

@@ -39,6 +39,20 @@ const RelationshipFields: CollectionConfig = {
value: user.id,
}),
},
{
name: 'relationshipWithMin',
type: 'relationship',
relationTo: 'text-fields',
hasMany: true,
min: 2,
},
{
name: 'relationshipWithMax',
type: 'relationship',
relationTo: 'text-fields',
hasMany: true,
max: 2,
},
],
};