feat: working PoC for reusing relationship filters in validate

This commit is contained in:
James
2022-04-04 21:20:21 -04:00
parent 485991bd48
commit df934dfeff
9 changed files with 76 additions and 21 deletions

View File

@@ -218,6 +218,16 @@ export type RelationshipField = FieldBase & {
filterOptions?: Where | ((options: filterOptionsProps) => Where);
}
export type ValueWithRelation = {
relationTo: string
value: string | number
}
export type RelationshipValue = (string | number)
| (string | number)[]
| ValueWithRelation
| ValueWithRelation[]
type RichTextPlugin = (editor: Editor) => Editor;
export type RichTextCustomElement = {

View File

@@ -116,8 +116,8 @@ export default async function performFieldOperations(this: Payload, entityConfig
const hookResults = hookPromises.map((promise) => promise());
await Promise.all(hookResults);
validationPromises.forEach((promise) => promise());
await Promise.all(validationPromises);
const validationResults = validationPromises.map((promise) => promise());
await Promise.all(validationResults);
if (errors.length > 0) {
throw new ValidationError(errors);

View File

@@ -16,6 +16,8 @@ import {
TextField,
UploadField,
Validate,
RelationshipValue,
ValueWithRelation,
} from './config/types';
import canUseDOM from '../utilities/canUseDOM';
import payload from '../index';
@@ -152,14 +154,19 @@ export const upload: Validate<unknown, unknown, UploadField> = (value: string, {
return defaultMessage;
};
export const relationship: Validate<unknown, unknown, RelationshipField> = async (value: string | string[], { required, relationTo, filterOptions, id, data, siblingData, user }) => {
export const relationship: Validate<unknown, unknown, RelationshipField> = async (value: RelationshipValue, { required, relationTo, filterOptions, id, data, siblingData, user }) => {
if ((!value || (Array.isArray(value) && value.length === 0)) && required) {
return defaultMessage;
}
if (!canUseDOM && typeof filterOptions !== 'undefined' && value) {
const options = [];
const options: {
[collection: string]: (string | number)[]
} = {};
const collections = typeof relationTo === 'string' ? [relationTo] : relationTo;
const values: string[] = typeof value === 'string' ? [value] : value;
const values = Array.isArray(value) ? value : [value];
await Promise.all(collections.map(async (collection) => {
const optionFilter = typeof filterOptions === 'function' ? filterOptions({
id,
@@ -168,23 +175,63 @@ export const relationship: Validate<unknown, unknown, RelationshipField> = async
user,
relationTo: collection,
}) : filterOptions;
const result = await payload.find({
const valueIDs: (string | number)[] = [];
values.forEach((val) => {
if (typeof val === 'object' && val?.value) {
valueIDs.push(val.value);
}
if (typeof val === 'string' || typeof val === 'number') {
valueIDs.push(val);
}
});
const result = await payload.find<TypeWithID>({
collection,
depth: 0,
where: {
and: [
{ id: { in: values } },
{ id: { in: valueIDs } },
optionFilter,
],
},
});
options.concat(result.docs.map((item: TypeWithID) => String(item.id)));
options[collection] = result.docs.map((doc) => doc.id);
}));
if (values.some((input) => options.some((option) => (option === input)))) {
return 'This field has an invalid selection';
const invalidRelationships = values.filter((val) => {
let collection: string;
let requestedID: string | number;
if (typeof relationTo === 'string') {
collection = relationTo;
if (typeof val === 'string' || typeof val === 'number') {
requestedID = val;
}
}
if (Array.isArray(relationTo) && typeof val === 'object' && val?.relationTo) {
collection = val.relationTo;
requestedID = val.value;
}
return options[collection].indexOf(requestedID) === -1;
});
if (invalidRelationships.length > 0) {
return invalidRelationships.reduce((err, invalid, i) => {
return `${err} ${JSON.stringify(invalid)}${invalidRelationships.length === i + 1 ? ',' : ''} `;
}, 'This field has the following invalid selections:') as string;
}
return true;
}
return true;
};
export const array: Validate<unknown, unknown, ArrayField> = (value, { minRows, maxRows, required }) => {