mirror of
https://github.com/strapi/strapi.git
synced 2025-12-29 08:04:51 +00:00
move operators to utils
This commit is contained in:
parent
7747d1d3d1
commit
980edbbcce
@ -1,55 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash/fp');
|
||||
const { isArray, castArray, keys, isPlainObject } = require('lodash/fp');
|
||||
|
||||
const { isOperatorOfType } = require('@strapi/utils').operators;
|
||||
const types = require('../../types');
|
||||
const { createField } = require('../../fields');
|
||||
const { createJoin } = require('./join');
|
||||
const { toColumnName } = require('./transform');
|
||||
const { isKnexQuery } = require('../../utils/knex');
|
||||
|
||||
const GROUP_OPERATORS = ['$and', '$or'];
|
||||
const OPERATORS = [
|
||||
'$not',
|
||||
'$in',
|
||||
'$notIn',
|
||||
'$eq',
|
||||
'$eqi',
|
||||
'$ne',
|
||||
'$gt',
|
||||
'$gte',
|
||||
'$lt',
|
||||
'$lte',
|
||||
'$null',
|
||||
'$notNull',
|
||||
'$between',
|
||||
'$startsWith',
|
||||
'$endsWith',
|
||||
'$startsWithi',
|
||||
'$endsWithi',
|
||||
'$contains',
|
||||
'$notContains',
|
||||
'$containsi',
|
||||
'$notContainsi',
|
||||
];
|
||||
|
||||
const CAST_OPERATORS = [
|
||||
'$not',
|
||||
'$in',
|
||||
'$notIn',
|
||||
'$eq',
|
||||
'$ne',
|
||||
'$gt',
|
||||
'$gte',
|
||||
'$lt',
|
||||
'$lte',
|
||||
'$between',
|
||||
];
|
||||
|
||||
const ARRAY_OPERATORS = ['$in', '$notIn', '$between'];
|
||||
|
||||
const isOperator = (key) => OPERATORS.includes(key);
|
||||
|
||||
const castValue = (value, attribute) => {
|
||||
if (!attribute) {
|
||||
return value;
|
||||
@ -65,12 +24,12 @@ const castValue = (value, attribute) => {
|
||||
};
|
||||
|
||||
const processAttributeWhere = (attribute, where, operator = '$eq') => {
|
||||
if (_.isArray(where)) {
|
||||
if (isArray(where)) {
|
||||
return where.map((sub) => processAttributeWhere(attribute, sub, operator));
|
||||
}
|
||||
|
||||
if (!_.isPlainObject(where)) {
|
||||
if (CAST_OPERATORS.includes(operator)) {
|
||||
if (!isPlainObject(where)) {
|
||||
if (isOperatorOfType('cast', operator)) {
|
||||
return castValue(where, attribute);
|
||||
}
|
||||
|
||||
@ -82,7 +41,7 @@ const processAttributeWhere = (attribute, where, operator = '$eq') => {
|
||||
for (const key of Object.keys(where)) {
|
||||
const value = where[key];
|
||||
|
||||
if (!isOperator(key)) {
|
||||
if (!isOperatorOfType('where', key)) {
|
||||
throw new Error(`Undefined attribute level operator ${key}`);
|
||||
}
|
||||
|
||||
@ -100,16 +59,16 @@ const processAttributeWhere = (attribute, where, operator = '$eq') => {
|
||||
* @returns {Object}
|
||||
*/
|
||||
const processWhere = (where, ctx) => {
|
||||
if (!_.isArray(where) && !_.isPlainObject(where)) {
|
||||
if (!isArray(where) && !isPlainObject(where)) {
|
||||
throw new Error('Where must be an array or an object');
|
||||
}
|
||||
|
||||
if (_.isArray(where)) {
|
||||
if (isArray(where)) {
|
||||
return where.map((sub) => processWhere(sub, ctx));
|
||||
}
|
||||
|
||||
const processNested = (where, ctx) => {
|
||||
if (!_.isPlainObject(where)) {
|
||||
if (!isPlainObject(where)) {
|
||||
return where;
|
||||
}
|
||||
|
||||
@ -126,7 +85,7 @@ const processWhere = (where, ctx) => {
|
||||
const value = where[key];
|
||||
|
||||
// if operator $and $or then loop over them
|
||||
if (GROUP_OPERATORS.includes(key)) {
|
||||
if (isOperatorOfType('group', key)) {
|
||||
filters[key] = value.map((sub) => processNested(sub, ctx));
|
||||
continue;
|
||||
}
|
||||
@ -136,7 +95,7 @@ const processWhere = (where, ctx) => {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isOperator(key)) {
|
||||
if (isOperatorOfType('where', key)) {
|
||||
throw new Error(
|
||||
`Only $and, $or and $not can only be used as root level operators. Found ${key}.`
|
||||
);
|
||||
@ -165,7 +124,7 @@ const processWhere = (where, ctx) => {
|
||||
uid: attribute.target,
|
||||
});
|
||||
|
||||
if (!_.isPlainObject(nestedWhere) || isOperator(_.keys(nestedWhere)[0])) {
|
||||
if (!isPlainObject(nestedWhere) || isOperatorOfType('where', keys(nestedWhere)[0])) {
|
||||
nestedWhere = { [qb.aliasColumn('id', subAlias)]: nestedWhere };
|
||||
}
|
||||
|
||||
@ -192,7 +151,7 @@ const processWhere = (where, ctx) => {
|
||||
|
||||
// TODO: add type casting per operator at some point
|
||||
const applyOperator = (qb, column, operator, value) => {
|
||||
if (Array.isArray(value) && !ARRAY_OPERATORS.includes(operator)) {
|
||||
if (Array.isArray(value) && !isOperatorOfType('array', operator)) {
|
||||
return qb.where((subQB) => {
|
||||
value.forEach((subValue) =>
|
||||
subQB.orWhere((innerQB) => {
|
||||
@ -209,12 +168,12 @@ const applyOperator = (qb, column, operator, value) => {
|
||||
}
|
||||
|
||||
case '$in': {
|
||||
qb.whereIn(column, isKnexQuery(value) ? value : _.castArray(value));
|
||||
qb.whereIn(column, isKnexQuery(value) ? value : castArray(value));
|
||||
break;
|
||||
}
|
||||
|
||||
case '$notIn': {
|
||||
qb.whereNotIn(column, isKnexQuery(value) ? value : _.castArray(value));
|
||||
qb.whereNotIn(column, isKnexQuery(value) ? value : castArray(value));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -328,7 +287,7 @@ const applyOperator = (qb, column, operator, value) => {
|
||||
};
|
||||
|
||||
const applyWhereToColumn = (qb, column, columnWhere) => {
|
||||
if (!_.isPlainObject(columnWhere)) {
|
||||
if (!isPlainObject(columnWhere)) {
|
||||
if (Array.isArray(columnWhere)) {
|
||||
return qb.whereIn(column, columnWhere);
|
||||
}
|
||||
@ -344,11 +303,11 @@ const applyWhereToColumn = (qb, column, columnWhere) => {
|
||||
};
|
||||
|
||||
const applyWhere = (qb, where) => {
|
||||
if (!_.isArray(where) && !_.isPlainObject(where)) {
|
||||
if (!isArray(where) && !isPlainObject(where)) {
|
||||
throw new Error('Where must be an array or an object');
|
||||
}
|
||||
|
||||
if (_.isArray(where)) {
|
||||
if (isArray(where)) {
|
||||
return qb.where((subQB) => where.forEach((subWhere) => applyWhere(subQB, subWhere)));
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
"lint": "run -T eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@strapi/utils": "4.10.2",
|
||||
"date-fns": "2.29.3",
|
||||
"debug": "4.3.4",
|
||||
"fs-extra": "10.0.0",
|
||||
|
||||
@ -29,6 +29,7 @@ const {
|
||||
isDynamicZoneAttribute,
|
||||
isMorphToRelationalAttribute,
|
||||
} = require('./content-types');
|
||||
const { isOperator } = require('./operators');
|
||||
|
||||
const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
|
||||
|
||||
@ -378,7 +379,7 @@ const convertNestedPopulate = (subPopulate, schema) => {
|
||||
return query;
|
||||
};
|
||||
|
||||
// TODO: ensure field is valid in content types (will probably have to check strapi.contentTypes since it can be a string.path)
|
||||
// TODO: ensure field is valid in content types (will probably have to check strapi.contentTypes since it can be a string.path)
|
||||
const convertFieldsQueryParams = (fields, depth = 0) => {
|
||||
if (depth === 0 && fields === '*') {
|
||||
return undefined;
|
||||
@ -398,11 +399,6 @@ const convertFieldsQueryParams = (fields, depth = 0) => {
|
||||
throw new Error('Invalid fields parameter. Expected a string or an array of strings');
|
||||
};
|
||||
|
||||
// TODO: this is temporary as a POC, get operators from @strapi/database (will likely require refactoring)
|
||||
const isOperator = (key) => {
|
||||
return key.startsWith('$');
|
||||
};
|
||||
|
||||
const isValidSchemaAttribute = (key, schema) => {
|
||||
if (key.trim().toLowerCase() === 'id') {
|
||||
return true;
|
||||
@ -459,7 +455,7 @@ const convertAndSanitizeFilters = (filters, schema) => {
|
||||
// Here, `key` can either be an operator or an attribute name
|
||||
for (const [key, value] of Object.entries(filters)) {
|
||||
const attribute = get(key, schema?.attributes);
|
||||
const validKey = isOperator(key) || isValidSchemaAttribute(key, schema);
|
||||
const validKey = isOperator(key, true) || isValidSchemaAttribute(key, schema);
|
||||
|
||||
if (!validKey) {
|
||||
removeOperator(key);
|
||||
|
||||
@ -43,6 +43,7 @@ const importDefault = require('./import-default');
|
||||
const template = require('./template');
|
||||
const file = require('./file');
|
||||
const traverse = require('./traverse');
|
||||
const operators = require('./operators');
|
||||
|
||||
module.exports = {
|
||||
yup,
|
||||
@ -93,4 +94,5 @@ module.exports = {
|
||||
importDefault,
|
||||
file,
|
||||
traverse,
|
||||
operators,
|
||||
};
|
||||
|
||||
74
packages/core/utils/lib/operators.js
Normal file
74
packages/core/utils/lib/operators.js
Normal file
@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
const GROUP_OPERATORS = ['$and', '$or'];
|
||||
|
||||
const WHERE_OPERATORS = [
|
||||
'$not',
|
||||
'$in',
|
||||
'$notIn',
|
||||
'$eq',
|
||||
'$eqi',
|
||||
'$ne',
|
||||
'$gt',
|
||||
'$gte',
|
||||
'$lt',
|
||||
'$lte',
|
||||
'$null',
|
||||
'$notNull',
|
||||
'$between',
|
||||
'$startsWith',
|
||||
'$endsWith',
|
||||
'$startsWithi',
|
||||
'$endsWithi',
|
||||
'$contains',
|
||||
'$notContains',
|
||||
'$containsi',
|
||||
'$notContainsi',
|
||||
];
|
||||
|
||||
const CAST_OPERATORS = [
|
||||
'$not',
|
||||
'$in',
|
||||
'$notIn',
|
||||
'$eq',
|
||||
'$ne',
|
||||
'$gt',
|
||||
'$gte',
|
||||
'$lt',
|
||||
'$lte',
|
||||
'$between',
|
||||
];
|
||||
|
||||
const ARRAY_OPERATORS = ['$in', '$notIn', '$between'];
|
||||
|
||||
const OPERATORS = {
|
||||
where: WHERE_OPERATORS,
|
||||
cast: CAST_OPERATORS,
|
||||
group: GROUP_OPERATORS,
|
||||
array: ARRAY_OPERATORS,
|
||||
};
|
||||
|
||||
// for performance, cache all operators in lowercase
|
||||
const OPERATORS_LOWERCASE = Object.fromEntries(
|
||||
Object.entries(OPERATORS).map(([key, values]) => [
|
||||
key,
|
||||
values.map((value) => value.toLowerCase()),
|
||||
])
|
||||
);
|
||||
|
||||
const isOperatorOfType = (type, key, ignoreCase = false) => {
|
||||
if (ignoreCase) {
|
||||
return OPERATORS_LOWERCASE[type]?.includes(key.toLowerCase());
|
||||
}
|
||||
return OPERATORS[type]?.includes(key);
|
||||
};
|
||||
|
||||
const isOperator = (key, ignoreCase = false) => {
|
||||
return Object.keys(OPERATORS).some((type) => isOperatorOfType(type, key, ignoreCase));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
isOperator,
|
||||
isOperatorOfType,
|
||||
OPERATORS,
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user