From c2b8a4ee98b702766eda2b8fc90ea07d5873ac3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20No=C3=ABl?= Date: Thu, 10 Feb 2022 13:12:16 +0100 Subject: [PATCH] parse boolean in convertQueryParam instead of parsing in database --- packages/core/database/lib/fields.js | 13 +++++- .../core/database/lib/query/helpers/where.js | 5 +-- packages/core/database/lib/utils/boolean.js | 19 -------- .../core/utils/lib/convert-query-params.js | 44 ++++++++++++------- 4 files changed, 42 insertions(+), 39 deletions(-) delete mode 100644 packages/core/database/lib/utils/boolean.js diff --git a/packages/core/database/lib/fields.js b/packages/core/database/lib/fields.js index 4baa57bd36..127d4cf957 100644 --- a/packages/core/database/lib/fields.js +++ b/packages/core/database/lib/fields.js @@ -3,7 +3,6 @@ const _ = require('lodash/fp'); const dateFns = require('date-fns'); const { InvalidTimeError, InvalidDateError, InvalidDateTimeError } = require('./errors'); -const { parseBoolean } = require('./utils/boolean'); class Field { constructor(config) { @@ -42,7 +41,17 @@ class JSONField extends Field { class BooleanField extends Field { toDB(value) { - return parseBoolean(value); + if (typeof value === 'boolean') return value; + + if (['true', 't', '1', 1].includes(value)) { + return true; + } + + if (['false', 'f', '0', 0].includes(value)) { + return false; + } + + return Boolean(value); } fromDB(value) { diff --git a/packages/core/database/lib/query/helpers/where.js b/packages/core/database/lib/query/helpers/where.js index b082a62ed5..6534bdaefc 100644 --- a/packages/core/database/lib/query/helpers/where.js +++ b/packages/core/database/lib/query/helpers/where.js @@ -3,7 +3,6 @@ const _ = require('lodash/fp'); const types = require('../../types'); -const { parseBoolean } = require('../../utils/boolean'); const { createField } = require('../../fields'); const { createJoin } = require('./join'); const { toColumnName } = require('./transform'); @@ -248,7 +247,7 @@ const applyOperator = (qb, column, operator, value) => { break; } case '$null': { - if (parseBoolean(value)) { + if (value) { qb.whereNull(column); } else { qb.whereNotNull(column); @@ -256,7 +255,7 @@ const applyOperator = (qb, column, operator, value) => { break; } case '$notNull': { - if (parseBoolean(value)) { + if (value) { qb.whereNotNull(column); } else { qb.whereNull(column); diff --git a/packages/core/database/lib/utils/boolean.js b/packages/core/database/lib/utils/boolean.js deleted file mode 100644 index 819dca0af3..0000000000 --- a/packages/core/database/lib/utils/boolean.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const parseBoolean = value => { - if (typeof value === 'boolean') return value; - - if (['true', 't', '1', 1].includes(value)) { - return true; - } - - if (['false', 'f', '0', 0].includes(value)) { - return false; - } - - return Boolean(value); -}; - -module.exports = { - parseBoolean, -}; diff --git a/packages/core/utils/lib/convert-query-params.js b/packages/core/utils/lib/convert-query-params.js index 8b4778370a..208fff93be 100644 --- a/packages/core/utils/lib/convert-query-params.js +++ b/packages/core/utils/lib/convert-query-params.js @@ -4,10 +4,11 @@ * Converts the standard Strapi REST query params to a more usable format for querying * You can read more here: https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#filters */ -const { has, isEmpty, isObject, cloneDeep } = require('lodash/fp'); +const { has, isEmpty, isObject, cloneDeep, get } = require('lodash/fp'); const _ = require('lodash'); const parseType = require('./parse-type'); const contentTypesUtils = require('./content-types'); +const { ApplicationError } = require('./errors'); const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants; @@ -228,10 +229,10 @@ const convertFiltersQueryParams = (filters, schema) => { // Don't mutate the original object const filtersCopy = cloneDeep(filters); - return sanitizeFilters(filtersCopy, schema); + return convertAndSanitizeFilters(filtersCopy, schema); }; -const sanitizeFilters = (filters, schema) => { +const convertAndSanitizeFilters = (filters, schema) => { if (!isObject(filters)) { return filters; } @@ -240,7 +241,7 @@ const sanitizeFilters = (filters, schema) => { return ( filters // Sanitize each filter - .map(filter => sanitizeFilters(filter, schema)) + .map(filter => convertAndSanitizeFilters(filter, schema)) // Filter out empty filters .filter(filter => !isObject(filter) || !isEmpty(filter)) ); @@ -250,39 +251,52 @@ const sanitizeFilters = (filters, schema) => { // Here, `key` can either be an operator or an attribute name for (const [key, value] of Object.entries(filters)) { - const attribute = schema.attributes[key]; + const attribute = get('key', schema.attributes); // Handle attributes if (attribute) { - // Always remove password attributes from filters object - if (attribute.type === 'password') { - removeOperator(key); - } - // Relations if (attribute.type === 'relation') { - filters[key] = sanitizeFilters(value, strapi.getModel(attribute.target)); + filters[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.target)); } // Components else if (attribute.type === 'component') { - filters[key] = sanitizeFilters(value, strapi.getModel(attribute.component)); + filters[key] = convertAndSanitizeFilters(value, strapi.getModel(attribute.component)); } // Media else if (attribute.type === 'media') { - filters[key] = sanitizeFilters(value, strapi.getModel('plugin::upload.file')); + filters[key] = convertAndSanitizeFilters(value, strapi.getModel('plugin::upload.file')); } // Dynamic Zones else if (attribute.type === 'dynamiczone') { removeOperator(key); } + + // Scalar attributes + else { + // Always remove password attributes from filters object + if (attribute.type === 'password') { + removeOperator(key); + } else { + filters[key] = convertAndSanitizeFilters(value); + } + } } // Handle operators - else if (isObject(value)) { - filters[key] = sanitizeFilters(value, schema); + else { + if (isObject(value)) { + filters[key] = convertAndSanitizeFilters(value, schema); + } else if (['$null', '$notNull'].includes(key)) { + try { + filters[key] = parseType({ type: 'boolean', value: filters[key], forceCast: true }); + } catch (e) { + throw new ApplicationError(e.message); + } + } } // Remove empty objects & arrays