mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 19:36:20 +00:00
Merge pull request #11683 from strapi/v4/unique-validator
[v4] add `unique` validator
This commit is contained in:
commit
3e9e3f13cb
@ -46,7 +46,7 @@ const advancedForm = {
|
||||
id: getTrad('form.attribute.item.settings.name'),
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
items: [options.required, options.unique, options.private],
|
||||
items: [options.required, options.private],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -209,7 +209,7 @@ const advancedForm = {
|
||||
id: getTrad('form.attribute.item.settings.name'),
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
items: [options.required, options.unique, options.private],
|
||||
items: [options.required, options.private],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -222,7 +222,7 @@ const advancedForm = {
|
||||
id: getTrad('form.attribute.item.settings.name'),
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
items: [options.required, options.unique, options.private],
|
||||
items: [options.required, options.private],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -297,13 +297,7 @@ const advancedForm = {
|
||||
id: getTrad('form.attribute.item.settings.name'),
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
items: [
|
||||
options.required,
|
||||
options.unique,
|
||||
options.maxLength,
|
||||
options.minLength,
|
||||
options.private,
|
||||
],
|
||||
items: [options.required, options.maxLength, options.minLength, options.private],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -330,13 +324,7 @@ const advancedForm = {
|
||||
id: getTrad('form.attribute.item.settings.name'),
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
items: [
|
||||
options.required,
|
||||
options.unique,
|
||||
options.maxLength,
|
||||
options.minLength,
|
||||
options.private,
|
||||
],
|
||||
items: [options.required, options.maxLength, options.minLength, options.private],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@ -51,7 +51,6 @@ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
|
||||
return {
|
||||
multiple: yup.boolean(),
|
||||
required: validators.required,
|
||||
unique: validators.unique,
|
||||
allowedTypes: yup
|
||||
.array()
|
||||
.of(yup.string().oneOf(['images', 'videos', 'files']))
|
||||
@ -129,7 +128,6 @@ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
|
||||
return {
|
||||
default: yup.mixed().test(isValidDefaultJSON),
|
||||
required: validators.required,
|
||||
unique: validators.unique,
|
||||
};
|
||||
}
|
||||
case 'enumeration': {
|
||||
@ -148,7 +146,6 @@ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
|
||||
default: yup.string().when('enum', enumVal => yup.string().oneOf(enumVal)),
|
||||
enumName: yup.string().test(isValidName),
|
||||
required: validators.required,
|
||||
unique: validators.unique,
|
||||
};
|
||||
}
|
||||
case 'password': {
|
||||
@ -225,7 +222,6 @@ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
|
||||
return {
|
||||
default: yup.boolean(),
|
||||
required: validators.required,
|
||||
unique: validators.unique,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -202,9 +202,14 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
||||
|
||||
const isDraft = contentTypesUtils.isDraft(entityToUpdate, model);
|
||||
|
||||
const validData = await entityValidator.validateEntityUpdate(model, data, {
|
||||
isDraft,
|
||||
});
|
||||
const validData = await entityValidator.validateEntityUpdate(
|
||||
model,
|
||||
data,
|
||||
{
|
||||
isDraft,
|
||||
},
|
||||
entityToUpdate
|
||||
);
|
||||
|
||||
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,11 @@ const { yup, validateYupSchema } = strapiUtils;
|
||||
const { isMediaAttribute, isScalarAttribute, getWritableAttributes } = strapiUtils.contentTypes;
|
||||
const { ValidationError } = strapiUtils.errors;
|
||||
|
||||
const addMinMax = (attr, validator, data) => {
|
||||
if (Number.isInteger(attr.min) && (attr.required || (Array.isArray(data) && data.length > 0))) {
|
||||
const addMinMax = (validator, { attr, updatedAttribute }) => {
|
||||
if (
|
||||
Number.isInteger(attr.min) &&
|
||||
(attr.required || (Array.isArray(updatedAttribute.value) && updatedAttribute.value.length > 0))
|
||||
) {
|
||||
validator = validator.min(attr.min);
|
||||
}
|
||||
if (Number.isInteger(attr.max)) {
|
||||
@ -22,7 +25,7 @@ const addMinMax = (attr, validator, data) => {
|
||||
return validator;
|
||||
};
|
||||
|
||||
const addRequiredValidation = createOrUpdate => (required, validator) => {
|
||||
const addRequiredValidation = createOrUpdate => (validator, { attr: { required } }) => {
|
||||
if (required) {
|
||||
if (createOrUpdate === 'creation') {
|
||||
validator = validator.notNil();
|
||||
@ -35,7 +38,7 @@ const addRequiredValidation = createOrUpdate => (required, validator) => {
|
||||
return validator;
|
||||
};
|
||||
|
||||
const addDefault = createOrUpdate => (attr, validator) => {
|
||||
const addDefault = createOrUpdate => (validator, { attr }) => {
|
||||
if (createOrUpdate === 'creation') {
|
||||
if (
|
||||
((attr.type === 'component' && attr.repeatable) || attr.type === 'dynamiczone') &&
|
||||
@ -54,7 +57,7 @@ const addDefault = createOrUpdate => (attr, validator) => {
|
||||
|
||||
const preventCast = validator => validator.transform((val, originalVal) => originalVal);
|
||||
|
||||
const createComponentValidator = createOrUpdate => (attr, data, { isDraft }) => {
|
||||
const createComponentValidator = createOrUpdate => ({ attr, updatedAttribute }, { isDraft }) => {
|
||||
let validator;
|
||||
|
||||
const model = strapi.getModel(attr.component);
|
||||
@ -66,19 +69,23 @@ const createComponentValidator = createOrUpdate => (attr, data, { isDraft }) =>
|
||||
validator = yup
|
||||
.array()
|
||||
.of(
|
||||
yup.lazy(item => createModelValidator(createOrUpdate)(model, item, { isDraft }).notNull())
|
||||
yup.lazy(item =>
|
||||
createModelValidator(createOrUpdate)({ model, data: item }, { isDraft }).notNull()
|
||||
)
|
||||
);
|
||||
validator = addRequiredValidation(createOrUpdate)(true, validator);
|
||||
validator = addMinMax(attr, validator, data);
|
||||
validator = addRequiredValidation(createOrUpdate)(validator, { attr: { required: true } });
|
||||
validator = addMinMax(validator, { attr, updatedAttribute });
|
||||
} else {
|
||||
validator = createModelValidator(createOrUpdate)(model, data, { isDraft });
|
||||
validator = addRequiredValidation(createOrUpdate)(!isDraft && attr.required, validator);
|
||||
validator = createModelValidator(createOrUpdate)({ model, updatedAttribute }, { isDraft });
|
||||
validator = addRequiredValidation(createOrUpdate)(validator, {
|
||||
attr: { required: !isDraft && attr.required },
|
||||
});
|
||||
}
|
||||
|
||||
return validator;
|
||||
};
|
||||
|
||||
const createDzValidator = createOrUpdate => (attr, data, { isDraft }) => {
|
||||
const createDzValidator = createOrUpdate => ({ attr, updatedAttribute }, { isDraft }) => {
|
||||
let validator;
|
||||
|
||||
validator = yup.array().of(
|
||||
@ -95,76 +102,85 @@ const createDzValidator = createOrUpdate => (attr, data, { isDraft }) => {
|
||||
.notNull();
|
||||
|
||||
return model
|
||||
? schema.concat(createModelValidator(createOrUpdate)(model, item, { isDraft }))
|
||||
? schema.concat(createModelValidator(createOrUpdate)({ model, data: item }, { isDraft }))
|
||||
: schema;
|
||||
})
|
||||
);
|
||||
validator = addRequiredValidation(createOrUpdate)(true, validator);
|
||||
validator = addMinMax(attr, validator, data);
|
||||
validator = addRequiredValidation(createOrUpdate)(validator, { attr: { required: true } });
|
||||
validator = addMinMax(validator, { attr, updatedAttribute });
|
||||
|
||||
return validator;
|
||||
};
|
||||
|
||||
const createRelationValidator = createOrUpdate => (attr, data, { isDraft }) => {
|
||||
const createRelationValidator = createOrUpdate => ({ attr, updatedAttribute }, { isDraft }) => {
|
||||
let validator;
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
if (Array.isArray(updatedAttribute.value)) {
|
||||
validator = yup.array().of(yup.mixed());
|
||||
} else {
|
||||
validator = yup.mixed();
|
||||
}
|
||||
validator = addRequiredValidation(createOrUpdate)(!isDraft && attr.required, validator);
|
||||
|
||||
validator = addRequiredValidation(createOrUpdate)(validator, {
|
||||
attr: { required: !isDraft && attr.required },
|
||||
});
|
||||
|
||||
return validator;
|
||||
};
|
||||
|
||||
const createScalarAttributeValidator = createOrUpdate => (attr, { isDraft }) => {
|
||||
const createScalarAttributeValidator = createOrUpdate => (metas, options) => {
|
||||
let validator;
|
||||
|
||||
if (has(attr.type, validators)) {
|
||||
validator = validators[attr.type](attr, { isDraft });
|
||||
if (has(metas.attr.type, validators)) {
|
||||
validator = validators[metas.attr.type](metas, options);
|
||||
} else {
|
||||
// No validators specified - fall back to mixed
|
||||
validator = yup.mixed();
|
||||
}
|
||||
|
||||
validator = addRequiredValidation(createOrUpdate)(!isDraft && attr.required, validator);
|
||||
validator = addRequiredValidation(createOrUpdate)(validator, {
|
||||
attr: { required: !options.isDraft && metas.attr.required },
|
||||
});
|
||||
|
||||
return validator;
|
||||
};
|
||||
|
||||
const createAttributeValidator = createOrUpdate => (attr, data, { isDraft }) => {
|
||||
const createAttributeValidator = createOrUpdate => (metas, options) => {
|
||||
let validator;
|
||||
|
||||
if (isMediaAttribute(attr)) {
|
||||
if (isMediaAttribute(metas.attr)) {
|
||||
validator = yup.mixed();
|
||||
} else if (isScalarAttribute(attr)) {
|
||||
validator = createScalarAttributeValidator(createOrUpdate)(attr, { isDraft });
|
||||
} else if (isScalarAttribute(metas.attr)) {
|
||||
validator = createScalarAttributeValidator(createOrUpdate)(metas, options);
|
||||
} else {
|
||||
if (attr.type === 'component') {
|
||||
validator = createComponentValidator(createOrUpdate)(attr, data, { isDraft });
|
||||
} else if (attr.type === 'dynamiczone') {
|
||||
validator = createDzValidator(createOrUpdate)(attr, data, { isDraft });
|
||||
if (metas.attr.type === 'component') {
|
||||
validator = createComponentValidator(createOrUpdate)(metas, options);
|
||||
} else if (metas.attr.type === 'dynamiczone') {
|
||||
validator = createDzValidator(createOrUpdate)(metas, options);
|
||||
} else {
|
||||
validator = createRelationValidator(createOrUpdate)(attr, data, { isDraft });
|
||||
validator = createRelationValidator(createOrUpdate)(metas, options);
|
||||
}
|
||||
|
||||
validator = preventCast(validator);
|
||||
}
|
||||
|
||||
validator = addDefault(createOrUpdate)(attr, validator);
|
||||
validator = addDefault(createOrUpdate)(validator, metas);
|
||||
|
||||
return validator;
|
||||
};
|
||||
|
||||
const createModelValidator = createOrUpdate => (model, data, { isDraft }) => {
|
||||
const createModelValidator = createOrUpdate => ({ model, data, entity }, options) => {
|
||||
const writableAttributes = model ? getWritableAttributes(model) : [];
|
||||
|
||||
const schema = writableAttributes.reduce((validators, attributeName) => {
|
||||
const validator = createAttributeValidator(createOrUpdate)(
|
||||
model.attributes[attributeName],
|
||||
prop(attributeName, data),
|
||||
{ isDraft }
|
||||
{
|
||||
attr: model.attributes[attributeName],
|
||||
updatedAttribute: { name: attributeName, value: prop(attributeName, data) },
|
||||
model,
|
||||
entity,
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
return assoc(attributeName, validator)(validators);
|
||||
@ -173,7 +189,12 @@ const createModelValidator = createOrUpdate => (model, data, { isDraft }) => {
|
||||
return yup.object().shape(schema);
|
||||
};
|
||||
|
||||
const createValidateEntity = createOrUpdate => async (model, data, { isDraft = false } = {}) => {
|
||||
const createValidateEntity = createOrUpdate => async (
|
||||
model,
|
||||
data,
|
||||
{ isDraft = false } = {},
|
||||
entity = null
|
||||
) => {
|
||||
if (!isObject(data)) {
|
||||
const { displayName } = model.info;
|
||||
|
||||
@ -182,7 +203,14 @@ const createValidateEntity = createOrUpdate => async (model, data, { isDraft = f
|
||||
);
|
||||
}
|
||||
|
||||
const validator = createModelValidator(createOrUpdate)(model, data, { isDraft }).required();
|
||||
const validator = createModelValidator(createOrUpdate)(
|
||||
{
|
||||
model,
|
||||
data,
|
||||
entity,
|
||||
},
|
||||
{ isDraft }
|
||||
).required();
|
||||
return validateYupSchema(validator, { strict: false, abortEarly: false })(data);
|
||||
};
|
||||
|
||||
|
||||
@ -4,72 +4,155 @@ const _ = require('lodash');
|
||||
|
||||
const { yup } = require('@strapi/utils');
|
||||
|
||||
/**
|
||||
* @type {import('yup').StringSchema} StringSchema
|
||||
* @type {import('yup').NumberSchema} NumberSchema
|
||||
* @type {import('yup').AnySchema} AnySchema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility function to compose validators
|
||||
*/
|
||||
const composeValidators = (...fns) => (attr, { isDraft }) => {
|
||||
return fns.reduce((validator, fn) => {
|
||||
return fn(attr, validator, { isDraft });
|
||||
}, yup.mixed());
|
||||
const composeValidators = (...fns) => (...args) => {
|
||||
let validator = yup.mixed();
|
||||
|
||||
// if we receive a schema then use it as base schema for nested composition
|
||||
if (yup.isSchema(args[0])) {
|
||||
validator = args[0];
|
||||
args = args.slice(1);
|
||||
}
|
||||
|
||||
return fns.reduce((validator, fn) => fn(validator, ...args), validator);
|
||||
};
|
||||
|
||||
/* Validator utils */
|
||||
|
||||
/**
|
||||
* Adds minLength validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {StringSchema} validator yup validator
|
||||
* @param {Object} metas
|
||||
* @param {{ minLength: Number }} metas.attr model attribute
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.isDraft
|
||||
*
|
||||
* @returns {StringSchema}
|
||||
*/
|
||||
const addMinLengthValidator = ({ minLength }, validator, { isDraft }) =>
|
||||
_.isInteger(minLength) && !isDraft ? validator.min(minLength) : validator;
|
||||
const addMinLengthValidator = (validator, { attr }, { isDraft }) =>
|
||||
_.isInteger(attr.minLength) && !isDraft ? validator.min(attr.minLength) : validator;
|
||||
|
||||
/**
|
||||
* Adds maxLength validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {StringSchema} validator yup validator
|
||||
* @param {Object} metas
|
||||
* @param {{ maxLength: Number }} metas.attr model attribute
|
||||
*
|
||||
* @returns {StringSchema}
|
||||
*/
|
||||
const addMaxLengthValidator = ({ maxLength }, validator) =>
|
||||
_.isInteger(maxLength) ? validator.max(maxLength) : validator;
|
||||
const addMaxLengthValidator = (validator, { attr }) =>
|
||||
_.isInteger(attr.maxLength) ? validator.max(attr.maxLength) : validator;
|
||||
|
||||
/**
|
||||
* Adds min integer validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {NumberSchema} validator yup validator
|
||||
* @param {Object} metas
|
||||
* @param {{ min: Number }} metas.attr model attribute
|
||||
*
|
||||
* @returns {NumberSchema}
|
||||
*/
|
||||
const addMinIntegerValidator = ({ min }, validator) =>
|
||||
_.isNumber(min) ? validator.min(_.toInteger(min)) : validator;
|
||||
const addMinIntegerValidator = (validator, { attr }) =>
|
||||
_.isNumber(attr.min) ? validator.min(_.toInteger(attr.min)) : validator;
|
||||
|
||||
/**
|
||||
* Adds max integer validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {NumberSchema} validator yup validator
|
||||
* @param {Object} metas
|
||||
* @param {{ max: Number }} metas.attr model attribute
|
||||
*
|
||||
* @returns {NumberSchema}
|
||||
*/
|
||||
const addMaxIntegerValidator = ({ max }, validator) =>
|
||||
_.isNumber(max) ? validator.max(_.toInteger(max)) : validator;
|
||||
const addMaxIntegerValidator = (validator, { attr }) =>
|
||||
_.isNumber(attr.max) ? validator.max(_.toInteger(attr.max)) : validator;
|
||||
|
||||
/**
|
||||
* Adds min float/decimal validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {NumberSchema} validator yup validator
|
||||
* @param {Object} metas
|
||||
* @param {{ min: Number }} metas.attr model attribute
|
||||
*
|
||||
* @returns {NumberSchema}
|
||||
*/
|
||||
const addMinFloatValidator = ({ min }, validator) =>
|
||||
_.isNumber(min) ? validator.min(min) : validator;
|
||||
const addMinFloatValidator = (validator, { attr }) =>
|
||||
_.isNumber(attr.min) ? validator.min(attr.min) : validator;
|
||||
|
||||
/**
|
||||
* Adds max float/decimal validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {NumberSchema} validator yup validator
|
||||
* @param {Object} metas model attribute
|
||||
* @param {{ max: Number }} metas.attr
|
||||
*
|
||||
* @returns {NumberSchema}
|
||||
*/
|
||||
const addMaxFloatValidator = ({ max }, validator) =>
|
||||
_.isNumber(max) ? validator.max(max) : validator;
|
||||
const addMaxFloatValidator = (validator, { attr }) =>
|
||||
_.isNumber(attr.max) ? validator.max(attr.max) : validator;
|
||||
|
||||
/**
|
||||
* Adds regex validator
|
||||
* @param {Object} attribute model attribute
|
||||
* @param {Object} validator yup validator
|
||||
* @param {StringSchema} validator yup validator
|
||||
* @param {Object} metas model attribute
|
||||
* @param {{ regex: RegExp }} metas.attr
|
||||
*
|
||||
* @returns {StringSchema}
|
||||
*/
|
||||
const addStringRegexValidator = ({ regex }, validator) =>
|
||||
_.isUndefined(regex) ? validator : validator.matches(new RegExp(regex));
|
||||
const addStringRegexValidator = (validator, { attr }) =>
|
||||
_.isUndefined(attr.regex) ? validator : validator.matches(new RegExp(attr.regex));
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AnySchema} validator
|
||||
* @param {Object} metas
|
||||
* @param {{ unique: Boolean, type: String }} metas.attr
|
||||
* @param {{ uid: String }} metas.model
|
||||
* @param {{ name: String, value: any }} metas.updatedAttribute
|
||||
* @param {Object} metas.entity
|
||||
*
|
||||
* @returns {AnySchema}
|
||||
*/
|
||||
const addUniqueValidator = (validator, { attr, model, updatedAttribute, entity }) => {
|
||||
if (!attr.unique && attr.type !== 'uid') {
|
||||
return validator;
|
||||
}
|
||||
|
||||
return validator.test('unique', 'This attribute must be unique', async value => {
|
||||
/**
|
||||
* If the attribute value is `null` we want to skip the unique validation.
|
||||
* Otherwise it'll only accept a single `null` entry in the database.
|
||||
*/
|
||||
if (updatedAttribute.value === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the attribute is unchanged we skip the unique verification. This will
|
||||
* prevent the validator to be triggered in case the user activated the
|
||||
* unique constraint after already creating multiple entries with
|
||||
* the same attribute value for that field.
|
||||
*/
|
||||
if (entity && updatedAttribute.value === entity[updatedAttribute.name]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let whereParams = entity
|
||||
? { $and: [{ [updatedAttribute.name]: value }, { $not: { id: entity.id } }] }
|
||||
: { [updatedAttribute.name]: value };
|
||||
|
||||
const record = await strapi.db.query(model.uid).findOne({
|
||||
select: ['id'],
|
||||
where: whereParams,
|
||||
});
|
||||
|
||||
return !record;
|
||||
});
|
||||
};
|
||||
|
||||
/* Type validators */
|
||||
|
||||
@ -77,29 +160,32 @@ const stringValidator = composeValidators(
|
||||
() => yup.string().transform((val, originalVal) => originalVal),
|
||||
addMinLengthValidator,
|
||||
addMaxLengthValidator,
|
||||
addStringRegexValidator
|
||||
addStringRegexValidator,
|
||||
addUniqueValidator
|
||||
);
|
||||
|
||||
const emailValidator = composeValidators(stringValidator, (attr, validator) => validator.email());
|
||||
const emailValidator = composeValidators(stringValidator, validator => validator.email());
|
||||
|
||||
const uidValidator = composeValidators(stringValidator, (attr, validator) =>
|
||||
const uidValidator = composeValidators(stringValidator, validator =>
|
||||
validator.matches(new RegExp('^[A-Za-z0-9-_.~]*$'))
|
||||
);
|
||||
|
||||
const enumerationValidator = attr => {
|
||||
const enumerationValidator = ({ attr }) => {
|
||||
return yup.string().oneOf((Array.isArray(attr.enum) ? attr.enum : [attr.enum]).concat(null));
|
||||
};
|
||||
|
||||
const integerValidator = composeValidators(
|
||||
() => yup.number().integer(),
|
||||
addMinIntegerValidator,
|
||||
addMaxIntegerValidator
|
||||
addMaxIntegerValidator,
|
||||
addUniqueValidator
|
||||
);
|
||||
|
||||
const floatValidator = composeValidators(
|
||||
() => yup.number(),
|
||||
addMinFloatValidator,
|
||||
addMaxFloatValidator
|
||||
addMaxFloatValidator,
|
||||
addUniqueValidator
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
@ -113,11 +199,11 @@ module.exports = {
|
||||
uid: uidValidator,
|
||||
json: () => yup.mixed(),
|
||||
integer: integerValidator,
|
||||
biginteger: () => yup.mixed(),
|
||||
biginteger: composeValidators(addUniqueValidator),
|
||||
float: floatValidator,
|
||||
decimal: floatValidator,
|
||||
date: () => yup.mixed(),
|
||||
time: () => yup.mixed(),
|
||||
datetime: () => yup.mixed(),
|
||||
timestamp: () => yup.mixed(),
|
||||
date: composeValidators(addUniqueValidator),
|
||||
time: composeValidators(addUniqueValidator),
|
||||
datetime: composeValidators(addUniqueValidator),
|
||||
timestamp: composeValidators(addUniqueValidator),
|
||||
};
|
||||
|
||||
@ -159,7 +159,7 @@ describe('Migration - draft and publish', () => {
|
||||
expect(body.results[0].publishedAt).toBeUndefined();
|
||||
});
|
||||
|
||||
test.skip('Unique constraint is kept after disabling the feature', async () => {
|
||||
test('Unique constraint is kept after disabling the feature', async () => {
|
||||
const dogToCreate = { code: 'sameCode' };
|
||||
|
||||
let res = await rq({
|
||||
|
||||
@ -43,7 +43,7 @@ const restart = async () => {
|
||||
rq = await createAuthRequest({ strapi });
|
||||
};
|
||||
|
||||
describe.skip('Migration - unique attribute', () => {
|
||||
describe('Migration - unique attribute', () => {
|
||||
beforeAll(async () => {
|
||||
await builder
|
||||
.addContentType(dogModel)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user