mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-04 03:43:34 +00:00 
			
		
		
		
	Filters working
This commit is contained in:
		
							parent
							
								
									3711ca3072
								
							
						
					
					
						commit
						e973804399
					
				@ -11,7 +11,7 @@ Object {
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "collectionName": "tests",
 | 
			
		||||
    "connection": "default",
 | 
			
		||||
    "connection": undefined,
 | 
			
		||||
    "description": "My description",
 | 
			
		||||
    "draftAndPublish": false,
 | 
			
		||||
    "kind": "singleType",
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const { formatContentType } = require('../ContentTypes');
 | 
			
		||||
const { formatContentType } = require('../content-types');
 | 
			
		||||
 | 
			
		||||
describe('Content types service', () => {
 | 
			
		||||
  describe('format ContentType', () => {
 | 
			
		||||
 | 
			
		||||
@ -83,8 +83,6 @@ class SqliteDialect extends Dialect {
 | 
			
		||||
    // TODO: get strapi.dir from somewhere else
 | 
			
		||||
 | 
			
		||||
    this.db.config.connection.connection.filename = path.resolve(
 | 
			
		||||
      // TODO: do this somewhere else
 | 
			
		||||
      global.strapi ? global.strapi.dir : process.cwd(),
 | 
			
		||||
      this.db.config.connection.connection.filename
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ const types = require('./types');
 | 
			
		||||
const { createField } = require('./fields');
 | 
			
		||||
const { createQueryBuilder } = require('./query');
 | 
			
		||||
const { createRepository } = require('./entity-repository');
 | 
			
		||||
const { isBidirectional } = require('./metadata/relations');
 | 
			
		||||
 | 
			
		||||
// TODO: move to query layer
 | 
			
		||||
const toRow = (metadata, data = {}) => {
 | 
			
		||||
@ -269,6 +270,7 @@ const createEntityManager = db => {
 | 
			
		||||
     * @param {ID} id - entity ID
 | 
			
		||||
     * @param {object} data - data received for creation
 | 
			
		||||
     */
 | 
			
		||||
    // TODO: wrap Transaction
 | 
			
		||||
    async attachRelations(metadata, id, data) {
 | 
			
		||||
      const { attributes } = metadata;
 | 
			
		||||
 | 
			
		||||
@ -276,7 +278,11 @@ const createEntityManager = db => {
 | 
			
		||||
        const attribute = attributes[attributeName];
 | 
			
		||||
 | 
			
		||||
        if (attribute.joinColumn && attribute.owner) {
 | 
			
		||||
          if (attribute.relation === 'oneToOne' && data[attributeName]) {
 | 
			
		||||
          if (
 | 
			
		||||
            attribute.relation === 'oneToOne' &&
 | 
			
		||||
            isBidirectional(attribute) &&
 | 
			
		||||
            data[attributeName]
 | 
			
		||||
          ) {
 | 
			
		||||
            await this.createQueryBuilder(metadata.uid)
 | 
			
		||||
              .where({ [attribute.joinColumn.name]: data[attributeName], id: { $ne: id } })
 | 
			
		||||
              .update({ [attribute.joinColumn.name]: null })
 | 
			
		||||
@ -315,7 +321,10 @@ const createEntityManager = db => {
 | 
			
		||||
          // TODO: redefine
 | 
			
		||||
          // TODO: check it is an id & the entity exists (will throw due to FKs otherwise so not a big pbl in SQL)
 | 
			
		||||
          if (data[attributeName]) {
 | 
			
		||||
            if (['oneToOne', 'oneToMany'].includes(attribute.relation)) {
 | 
			
		||||
            if (
 | 
			
		||||
              ['oneToOne', 'oneToMany'].includes(attribute.relation) &&
 | 
			
		||||
              isBidirectional(attribute)
 | 
			
		||||
            ) {
 | 
			
		||||
              await this.createQueryBuilder(joinTable.name)
 | 
			
		||||
                .delete()
 | 
			
		||||
                .where({ [inverseJoinColumn.name]: _.castArray(data[attributeName]) })
 | 
			
		||||
@ -333,7 +342,7 @@ const createEntityManager = db => {
 | 
			
		||||
 | 
			
		||||
            // if there is nothing to insert
 | 
			
		||||
            if (insert.length === 0) {
 | 
			
		||||
              return;
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await this.createQueryBuilder(joinTable.name)
 | 
			
		||||
@ -353,6 +362,7 @@ const createEntityManager = db => {
 | 
			
		||||
     * @param {object} data - data received for creation
 | 
			
		||||
     */
 | 
			
		||||
    // TODO: check relation exists (handled by FKs except for polymorphics)
 | 
			
		||||
    // TODO: wrap Transaction
 | 
			
		||||
    async updateRelations(metadata, id, data) {
 | 
			
		||||
      const { attributes } = metadata;
 | 
			
		||||
 | 
			
		||||
@ -424,7 +434,7 @@ const createEntityManager = db => {
 | 
			
		||||
 | 
			
		||||
              // if there is nothing to insert
 | 
			
		||||
              if (insert.length === 0) {
 | 
			
		||||
                return;
 | 
			
		||||
                continue;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              await this.createQueryBuilder(joinTable.name)
 | 
			
		||||
@ -445,6 +455,7 @@ const createEntityManager = db => {
 | 
			
		||||
     * @param {Metadata} metadata - model metadta
 | 
			
		||||
     * @param {ID} id - entity ID
 | 
			
		||||
     */
 | 
			
		||||
    // TODO: wrap Transaction
 | 
			
		||||
    async deleteRelations(metadata, id) {
 | 
			
		||||
      // TODO: Implement correctly
 | 
			
		||||
      if (db.dialect.usesForeignKeys()) {
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,13 @@
 | 
			
		||||
 | 
			
		||||
const _ = require('lodash/fp');
 | 
			
		||||
 | 
			
		||||
const hasInversedBy = _.has('inversedBy');
 | 
			
		||||
const hasMappedBy = _.has('mappedBy');
 | 
			
		||||
 | 
			
		||||
const isBidirectional = attribute => hasInversedBy(attribute) || hasMappedBy(attribute);
 | 
			
		||||
const isOwner = attribute => !isBidirectional(attribute) || hasInversedBy(attribute);
 | 
			
		||||
const shouldUseJoinTable = attribute => attribute.useJoinTable !== false;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creates a relation metadata
 | 
			
		||||
 *
 | 
			
		||||
@ -186,13 +193,6 @@ const relationFactoryMap = {
 | 
			
		||||
  manyToMany: createManyToMany,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const hasInversedBy = _.has('inversedBy');
 | 
			
		||||
const hasMappedBy = _.has('mappedBy');
 | 
			
		||||
 | 
			
		||||
const isBidirectional = attribute => hasInversedBy(attribute) || hasMappedBy(attribute);
 | 
			
		||||
const isOwner = attribute => !isBidirectional(attribute) || hasInversedBy(attribute);
 | 
			
		||||
const shouldUseJoinTable = attribute => attribute.useJoinTable !== false;
 | 
			
		||||
 | 
			
		||||
const createJoinColum = (metadata, { attribute /*attributeName, meta */ }) => {
 | 
			
		||||
  const targetMeta = metadata.get(attribute.target);
 | 
			
		||||
 | 
			
		||||
@ -226,8 +226,13 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
 | 
			
		||||
 | 
			
		||||
  const joinTableName = _.snakeCase(`${meta.tableName}_${attributeName}_links`);
 | 
			
		||||
 | 
			
		||||
  const joinColumnName = _.snakeCase(`${meta.singularName}_id`);
 | 
			
		||||
  const inverseJoinColumnName = _.snakeCase(`${targetMeta.singularName}_id`);
 | 
			
		||||
  let joinColumnName = _.snakeCase(`${meta.singularName}_id`);
 | 
			
		||||
  let inverseJoinColumnName = _.snakeCase(`${targetMeta.singularName}_id`);
 | 
			
		||||
 | 
			
		||||
  // if relation is slef referencing
 | 
			
		||||
  if (joinColumnName === inverseJoinColumnName) {
 | 
			
		||||
    inverseJoinColumnName = `inv_${inverseJoinColumnName}`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  metadata.add({
 | 
			
		||||
    uid: joinTableName,
 | 
			
		||||
@ -296,4 +301,6 @@ const createJoinTable = (metadata, { attributeName, attribute, meta }) => {
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  createRelation,
 | 
			
		||||
 | 
			
		||||
  isBidirectional,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -24,8 +24,11 @@ const OPERATORS = [
 | 
			
		||||
  '$startsWith',
 | 
			
		||||
  '$endsWith',
 | 
			
		||||
  '$contains',
 | 
			
		||||
  '$notContains',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const ARRAY_OPERATORS = ['$in', '$notIn', '$between'];
 | 
			
		||||
 | 
			
		||||
const createPivotJoin = (qb, joinTable, alias, tragetMeta) => {
 | 
			
		||||
  const joinAlias = qb.getAlias();
 | 
			
		||||
  qb.join({
 | 
			
		||||
@ -249,8 +252,135 @@ const processWhere = (where, ctx, depth = 0) => {
 | 
			
		||||
  return filters;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const applyOperator = (qb, column, operator, value) => {
 | 
			
		||||
  if (Array.isArray(value) && !ARRAY_OPERATORS.includes(operator)) {
 | 
			
		||||
    return qb.where(subQB => {
 | 
			
		||||
      value.forEach(subValue =>
 | 
			
		||||
        subQB.orWhere(innerQB => {
 | 
			
		||||
          applyOperator(innerQB, column, operator, subValue);
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch (operator) {
 | 
			
		||||
    case '$not': {
 | 
			
		||||
      qb.whereNot(qb => applyWhereToColumn(qb, column, value));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case '$in': {
 | 
			
		||||
      qb.whereIn(column, _.castArray(value));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case '$notIn': {
 | 
			
		||||
      qb.whereNotIn(column, _.castArray(value));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case '$eq': {
 | 
			
		||||
      if (value === null) {
 | 
			
		||||
        qb.whereNull(column);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      qb.where(column, value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$ne': {
 | 
			
		||||
      if (value === null) {
 | 
			
		||||
        qb.whereNotNull(column);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      qb.where(column, '<>', value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$gt': {
 | 
			
		||||
      qb.where(column, '>', value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$gte': {
 | 
			
		||||
      qb.where(column, '>=', value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$lt': {
 | 
			
		||||
      qb.where(column, '<', value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$lte': {
 | 
			
		||||
      qb.where(column, '<=', value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$null': {
 | 
			
		||||
      // TODO: make this better
 | 
			
		||||
      if (value) {
 | 
			
		||||
        qb.whereNull(column);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$notNull': {
 | 
			
		||||
      if (value) {
 | 
			
		||||
        qb.whereNotNull(column);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$between': {
 | 
			
		||||
      qb.whereBetween(column, value);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    // case '$regexp': {
 | 
			
		||||
    //   // TODO:
 | 
			
		||||
    //
 | 
			
		||||
    // break;
 | 
			
		||||
    // }
 | 
			
		||||
    // // string
 | 
			
		||||
    // // TODO: use $case to make it case insensitive
 | 
			
		||||
    // case '$like': {
 | 
			
		||||
    //   qb.where(column, 'like', value);
 | 
			
		||||
    // break;
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    // TODO: add casting logic
 | 
			
		||||
    case '$startsWith': {
 | 
			
		||||
      qb.where(column, 'like', `${value}%`);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$endsWith': {
 | 
			
		||||
      qb.where(column, 'like', `%${value}`);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case '$contains': {
 | 
			
		||||
      // TODO: handle insensitive
 | 
			
		||||
 | 
			
		||||
      qb.where(column, 'like', `%${value}%`);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case '$notContains': {
 | 
			
		||||
      // TODO: handle insensitive
 | 
			
		||||
      qb.whereNot(column, 'like', `%${value}%`);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: json operators
 | 
			
		||||
 | 
			
		||||
    // TODO: relational operators every/some/exists/size ...
 | 
			
		||||
 | 
			
		||||
    default: {
 | 
			
		||||
      throw new Error(`Undefined operator ${operator}`);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const applyWhereToColumn = (qb, column, columnWhere) => {
 | 
			
		||||
  if (!_.isPlainObject(columnWhere)) {
 | 
			
		||||
    if (Array.isArray(columnWhere)) {
 | 
			
		||||
      return qb.whereIn(column, columnWhere);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return qb.where(column, columnWhere);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -258,122 +388,13 @@ const applyWhereToColumn = (qb, column, columnWhere) => {
 | 
			
		||||
  Object.keys(columnWhere).forEach(operator => {
 | 
			
		||||
    const value = columnWhere[operator];
 | 
			
		||||
 | 
			
		||||
    switch (operator) {
 | 
			
		||||
      case '$not': {
 | 
			
		||||
        qb.whereNot(qb => applyWhereToColumn(qb, column, value));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case '$in': {
 | 
			
		||||
        qb.whereIn(column, _.castArray(value));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case '$notIn': {
 | 
			
		||||
        qb.whereNotIn(column, _.castArray(value));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case '$eq': {
 | 
			
		||||
        if (Array.isArray(value)) {
 | 
			
		||||
          return qb.whereIn(column, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (value === null) {
 | 
			
		||||
          qb.whereNull(column);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qb.where(column, value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$ne': {
 | 
			
		||||
        if (Array.isArray(value)) {
 | 
			
		||||
          return qb.whereNotIn(column, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (value === null) {
 | 
			
		||||
          qb.whereNotNull(column);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qb.where(column, '<>', value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$gt': {
 | 
			
		||||
        qb.where(column, '>', value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$gte': {
 | 
			
		||||
        qb.where(column, '>=', value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$lt': {
 | 
			
		||||
        qb.where(column, '<', value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$lte': {
 | 
			
		||||
        qb.where(column, '<=', value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$null': {
 | 
			
		||||
        // TODO: make this better
 | 
			
		||||
        if (value) {
 | 
			
		||||
          qb.whereNull(column);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$notNull': {
 | 
			
		||||
        if (value) {
 | 
			
		||||
          qb.whereNotNull(column);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$between': {
 | 
			
		||||
        qb.whereBetween(column, value);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      // case '$regexp': {
 | 
			
		||||
      //   // TODO:
 | 
			
		||||
      //
 | 
			
		||||
      // break;
 | 
			
		||||
      // }
 | 
			
		||||
      // // string
 | 
			
		||||
      // // TODO: use $case to make it case insensitive
 | 
			
		||||
      // case '$like': {
 | 
			
		||||
      //   qb.where(column, 'like', value);
 | 
			
		||||
      // break;
 | 
			
		||||
      // }
 | 
			
		||||
 | 
			
		||||
      // TODO: add casting logic
 | 
			
		||||
      case '$startsWith': {
 | 
			
		||||
        qb.where(column, 'like', `${value}%`);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$endsWith': {
 | 
			
		||||
        qb.where(column, 'like', `%${value}`);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case '$contains': {
 | 
			
		||||
        qb.where(column, 'like', `%${value}%`);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // TODO: json operators
 | 
			
		||||
 | 
			
		||||
      // TODO: relational operators every/some/exists/size ...
 | 
			
		||||
 | 
			
		||||
      default: {
 | 
			
		||||
        throw new Error(`Undefined operator ${operator}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    applyOperator(qb, column, operator, value);
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const applyWhere = (qb, where) => {
 | 
			
		||||
  if (Array.isArray(where)) {
 | 
			
		||||
    return where.forEach(subWhere => applyWhere(qb, subWhere));
 | 
			
		||||
    return qb.where(subQB => where.forEach(subWhere => applyWhere(subQB, subWhere)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!_.isPlainObject(where)) {
 | 
			
		||||
@ -384,14 +405,14 @@ const applyWhere = (qb, where) => {
 | 
			
		||||
    const value = where[key];
 | 
			
		||||
 | 
			
		||||
    if (key === '$and') {
 | 
			
		||||
      return qb.where(qb => {
 | 
			
		||||
        value.forEach(v => applyWhere(qb, v));
 | 
			
		||||
      return qb.where(subQB => {
 | 
			
		||||
        value.forEach(v => applyWhere(subQB, v));
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (key === '$or') {
 | 
			
		||||
      return qb.where(qb => {
 | 
			
		||||
        value.forEach(v => qb.orWhere(inner => applyWhere(inner, v)));
 | 
			
		||||
      return qb.where(subQB => {
 | 
			
		||||
        value.forEach(v => subQB.orWhere(inner => applyWhere(inner, v)));
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -513,6 +534,8 @@ const applyPopulate = async (results, populate, ctx) => {
 | 
			
		||||
          results.forEach(result => {
 | 
			
		||||
            result[key] = null;
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const rows = await db.entityManager
 | 
			
		||||
@ -541,8 +564,6 @@ const applyPopulate = async (results, populate, ctx) => {
 | 
			
		||||
          referencedColumn: referencedColumnName,
 | 
			
		||||
        } = joinTable.joinColumn;
 | 
			
		||||
 | 
			
		||||
        // TODO: create aliases for the columns
 | 
			
		||||
 | 
			
		||||
        const alias = qb.getAlias();
 | 
			
		||||
        const rows = await qb
 | 
			
		||||
          .init(populateValue)
 | 
			
		||||
@ -584,6 +605,7 @@ const applyPopulate = async (results, populate, ctx) => {
 | 
			
		||||
          results.forEach(result => {
 | 
			
		||||
            result[key] = null;
 | 
			
		||||
          });
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const rows = await db.entityManager
 | 
			
		||||
@ -675,7 +697,7 @@ const applyPopulate = async (results, populate, ctx) => {
 | 
			
		||||
 | 
			
		||||
const fromRow = (metadata, row) => {
 | 
			
		||||
  if (Array.isArray(row)) {
 | 
			
		||||
    return row.map(row => fromRow(metadata, row));
 | 
			
		||||
    return row.map(singleRow => fromRow(metadata, singleRow));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const { attributes } = metadata;
 | 
			
		||||
 | 
			
		||||
@ -155,81 +155,87 @@ const createQueryBuilder = (uid, db) => {
 | 
			
		||||
      return this.alias + '.' + columnName;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async execute({ mapResults = true } = {}) {
 | 
			
		||||
    getKnexQuery() {
 | 
			
		||||
      const aliasedTableName = state.type === 'insert' ? tableName : { [this.alias]: tableName };
 | 
			
		||||
 | 
			
		||||
      const qb = db.connection(aliasedTableName);
 | 
			
		||||
 | 
			
		||||
      switch (state.type) {
 | 
			
		||||
        case 'select': {
 | 
			
		||||
          if (state.select.length === 0) {
 | 
			
		||||
            state.select = [this.aliasColumn('*')];
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (state.joins.length > 0) {
 | 
			
		||||
            // add ordered columns to distinct in case of joins
 | 
			
		||||
            // TODO: make sure we return the right data
 | 
			
		||||
            qb.distinct(`${this.alias}.id`);
 | 
			
		||||
            // TODO: add column if they aren't there already
 | 
			
		||||
            state.select.unshift(...state.orderBy.map(({ column }) => column));
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          qb.select(state.select);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'count': {
 | 
			
		||||
          qb.count({ count: state.count });
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'insert': {
 | 
			
		||||
          qb.insert(state.data);
 | 
			
		||||
 | 
			
		||||
          if (db.dialect.useReturning() && _.has('id', meta.attributes)) {
 | 
			
		||||
            qb.returning('id');
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'update': {
 | 
			
		||||
          qb.update(state.data);
 | 
			
		||||
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'delete': {
 | 
			
		||||
          qb.del();
 | 
			
		||||
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.limit) {
 | 
			
		||||
        qb.limit(state.limit);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.offset) {
 | 
			
		||||
        qb.offset(state.offset);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.orderBy.length > 0) {
 | 
			
		||||
        qb.orderBy(state.orderBy);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.first) {
 | 
			
		||||
        qb.first();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.groupBy.length > 0) {
 | 
			
		||||
        qb.groupBy(state.groupBy);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.where) {
 | 
			
		||||
        helpers.applyWhere(qb, state.where);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (state.joins.length > 0) {
 | 
			
		||||
        helpers.applyJoins(qb, state.joins);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return qb;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async execute({ mapResults = true } = {}) {
 | 
			
		||||
      try {
 | 
			
		||||
        const qb = db.connection(aliasedTableName);
 | 
			
		||||
 | 
			
		||||
        switch (state.type) {
 | 
			
		||||
          case 'select': {
 | 
			
		||||
            if (state.select.length === 0) {
 | 
			
		||||
              state.select = [this.aliasColumn('*')];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (state.joins.length > 0) {
 | 
			
		||||
              // add ordered columns to distinct in case of joins
 | 
			
		||||
              // TODO: make sure we return the right data
 | 
			
		||||
              qb.distinct(`${this.alias}.id`);
 | 
			
		||||
              // TODO: add column if they aren't there already
 | 
			
		||||
              state.select.unshift(...state.orderBy.map(({ column }) => column));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            qb.select(state.select);
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          case 'count': {
 | 
			
		||||
            qb.count({ count: state.count });
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          case 'insert': {
 | 
			
		||||
            qb.insert(state.data);
 | 
			
		||||
 | 
			
		||||
            if (db.dialect.useReturning() && _.has('id', meta.attributes)) {
 | 
			
		||||
              qb.returning('id');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          case 'update': {
 | 
			
		||||
            qb.update(state.data);
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          case 'delete': {
 | 
			
		||||
            qb.del();
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.limit) {
 | 
			
		||||
          qb.limit(state.limit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.offset) {
 | 
			
		||||
          qb.offset(state.offset);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.orderBy.length > 0) {
 | 
			
		||||
          qb.orderBy(state.orderBy);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.first) {
 | 
			
		||||
          qb.first();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.groupBy.length > 0) {
 | 
			
		||||
          qb.groupBy(state.groupBy);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.where) {
 | 
			
		||||
          helpers.applyWhere(qb, state.where);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.joins.length > 0) {
 | 
			
		||||
          helpers.applyJoins(qb, state.joins);
 | 
			
		||||
        }
 | 
			
		||||
        const qb = this.getKnexQuery();
 | 
			
		||||
 | 
			
		||||
        const rows = await qb;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -312,7 +312,7 @@ class Strapi {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Kill process
 | 
			
		||||
    process.exit(exitCode);
 | 
			
		||||
    // process.exit(exitCode);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async load() {
 | 
			
		||||
@ -362,11 +362,7 @@ class Strapi {
 | 
			
		||||
      models: Database.transformContentTypes(contentTypes),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (process.env.NODE_ENV === 'test') {
 | 
			
		||||
      await this.db.schema.reset();
 | 
			
		||||
    } else {
 | 
			
		||||
      await this.db.schema.sync();
 | 
			
		||||
    }
 | 
			
		||||
    await this.db.schema.sync();
 | 
			
		||||
 | 
			
		||||
    await this.runLifecyclesFunctions(LIFECYCLES.REGISTER);
 | 
			
		||||
    // await this.db.initialize();
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,12 @@
 | 
			
		||||
const { pick } = require('lodash/fp');
 | 
			
		||||
const delegate = require('delegates');
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
  convertSortQueryParams,
 | 
			
		||||
  convertLimitQueryParams,
 | 
			
		||||
  convertStartQueryParams,
 | 
			
		||||
} = require('@strapi/utils/lib/convert-rest-query-params');
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
  sanitizeEntity,
 | 
			
		||||
  webhook: webhookUtils,
 | 
			
		||||
@ -36,27 +42,22 @@ module.exports = ctx => {
 | 
			
		||||
  return service;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const defaultLimit = 10;
 | 
			
		||||
// TODO: move to Controller ?
 | 
			
		||||
const transformParamsToQuery = (params = {}) => {
 | 
			
		||||
  const query = {};
 | 
			
		||||
 | 
			
		||||
  // TODO: check invalid values add defaults ....
 | 
			
		||||
  if (params.pagination) {
 | 
			
		||||
    const { pagination } = params;
 | 
			
		||||
    if (pagination.start || pagination.limit) {
 | 
			
		||||
      query.limit = Number(pagination.limit) || defaultLimit;
 | 
			
		||||
      query.offset = Number(pagination.start) || 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pagination.page || pagination.pageSize) {
 | 
			
		||||
      query.limit = Number(pagination.pageSize) || defaultLimit;
 | 
			
		||||
      query.offset = (Number(pagination.page) - 1) * query.limit;
 | 
			
		||||
    }
 | 
			
		||||
  if (params.start) {
 | 
			
		||||
    query.offset = convertStartQueryParams(params.start);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (params.limit) {
 | 
			
		||||
    query.limit = convertLimitQueryParams(params.limit);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (params.sort) {
 | 
			
		||||
    // TODO: impl
 | 
			
		||||
    query.orderBy = params.sort;
 | 
			
		||||
    query.orderBy = convertSortQueryParams(params.sort);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (params.filters) {
 | 
			
		||||
@ -102,14 +103,25 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
 | 
			
		||||
  async findPage(uid, opts) {
 | 
			
		||||
    const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' });
 | 
			
		||||
 | 
			
		||||
    const { page = 1, pageSize = 100 } = params;
 | 
			
		||||
 | 
			
		||||
    const pagination = {
 | 
			
		||||
      page: parseInt(page),
 | 
			
		||||
      pageSize: parseInt(pageSize),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const query = transformParamsToQuery(params);
 | 
			
		||||
 | 
			
		||||
    query.limit = pagination.pageSize;
 | 
			
		||||
    query.offset = pagination.page * pagination.pageSize;
 | 
			
		||||
 | 
			
		||||
    const [results, total] = await db.query(uid).findWithCount(query);
 | 
			
		||||
 | 
			
		||||
    // TODO: cleanup
 | 
			
		||||
    return {
 | 
			
		||||
      results,
 | 
			
		||||
      pagination: {
 | 
			
		||||
        ...pagination,
 | 
			
		||||
        pageCount: Math.ceil(total / pageSize),
 | 
			
		||||
        total,
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
@ -161,6 +173,8 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
 | 
			
		||||
    //   entry = await this.findOne({ params: { id: entry.id } }, { model });
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    // TODO: Implement components CRUD ?
 | 
			
		||||
 | 
			
		||||
    eventHub.emit(ENTRY_CREATE, {
 | 
			
		||||
      model: modelDef.modelName,
 | 
			
		||||
      entry: sanitizeEntity(entry, { model: modelDef }),
 | 
			
		||||
 | 
			
		||||
@ -76,6 +76,9 @@ describe('Core API - Basic + compo', () => {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
      url: '/product-with-compos',
 | 
			
		||||
      body: product,
 | 
			
		||||
      qs: {
 | 
			
		||||
        populate: ['compo'],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(res.statusCode).toBe(200);
 | 
			
		||||
@ -88,6 +91,9 @@ describe('Core API - Basic + compo', () => {
 | 
			
		||||
    const res = await rq({
 | 
			
		||||
      method: 'GET',
 | 
			
		||||
      url: '/product-with-compos',
 | 
			
		||||
      qs: {
 | 
			
		||||
        populate: ['compo'],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(res.statusCode).toBe(200);
 | 
			
		||||
@ -110,6 +116,9 @@ describe('Core API - Basic + compo', () => {
 | 
			
		||||
      method: 'PUT',
 | 
			
		||||
      url: `/product-with-compos/${data.productsWithCompo[0].id}`,
 | 
			
		||||
      body: product,
 | 
			
		||||
      qs: {
 | 
			
		||||
        populate: ['compo'],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(res.statusCode).toBe(200);
 | 
			
		||||
@ -123,6 +132,9 @@ describe('Core API - Basic + compo', () => {
 | 
			
		||||
    const res = await rq({
 | 
			
		||||
      method: 'DELETE',
 | 
			
		||||
      url: `/product-with-compos/${data.productsWithCompo[0].id}`,
 | 
			
		||||
      qs: {
 | 
			
		||||
        populate: ['compo'],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(res.statusCode).toBe(200);
 | 
			
		||||
@ -138,6 +150,7 @@ describe('Core API - Basic + compo', () => {
 | 
			
		||||
        name: 'Product 1',
 | 
			
		||||
        description: 'Product description',
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        url: '/product-with-compos',
 | 
			
		||||
 | 
			
		||||
@ -106,7 +106,7 @@ describe('Deep Filtering API', () => {
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/collectors',
 | 
			
		||||
          qs: {
 | 
			
		||||
            'cards.name': data.card[0].name,
 | 
			
		||||
            filters: { cards: { name: data.card[0].name } },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -121,7 +121,7 @@ describe('Deep Filtering API', () => {
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/collectors',
 | 
			
		||||
          qs: {
 | 
			
		||||
            'cards.name': data.card[1].name,
 | 
			
		||||
            filters: { cards: { name: data.card[1].name } },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -137,7 +137,7 @@ describe('Deep Filtering API', () => {
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/collectors',
 | 
			
		||||
          qs: {
 | 
			
		||||
            'collector_friends.name': data.collector[0].name,
 | 
			
		||||
            filters: { collector_friends: { name: data.collector[0].name } },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -148,14 +148,18 @@ describe('Deep Filtering API', () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('With search', () => {
 | 
			
		||||
  describe.skip('With search', () => {
 | 
			
		||||
    describe('Filter on a manyWay relation', () => {
 | 
			
		||||
      test('cards.name + empty search', async () => {
 | 
			
		||||
        const res = await rq({
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/collectors',
 | 
			
		||||
          qs: {
 | 
			
		||||
            'cards.name': data.card[0].name,
 | 
			
		||||
            filters: {
 | 
			
		||||
              cards: {
 | 
			
		||||
                name: data.card[0].name,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            _q: '',
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ describe('Create Strapi API End to End', () => {
 | 
			
		||||
 | 
			
		||||
  afterAll(async () => {
 | 
			
		||||
    await strapi.destroy();
 | 
			
		||||
    // await builder.cleanup();
 | 
			
		||||
    await builder.cleanup();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('Test manyToMany relation (article - tag) with Content Manager', () => {
 | 
			
		||||
 | 
			
		||||
@ -297,9 +297,7 @@ describe('Filtering API', () => {
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: {
 | 
			
		||||
                $not: {
 | 
			
		||||
                  $contains: 'production',
 | 
			
		||||
                },
 | 
			
		||||
                $notContains: 'production',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
@ -314,7 +312,7 @@ describe('Filtering API', () => {
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: { $not: { $contains: 'ProdUctIon' } },
 | 
			
		||||
              name: { $notContains: 'ProdUctIon' },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
@ -328,7 +326,7 @@ describe('Filtering API', () => {
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: { $not: { $contains: 'product' } },
 | 
			
		||||
              name: { $notContains: 'product' },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
@ -340,7 +338,7 @@ describe('Filtering API', () => {
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: { $not: { $contains: 'ProDuCt' } },
 | 
			
		||||
              name: { $notContains: 'ProDuCt' },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
@ -350,62 +348,74 @@ describe('Filtering API', () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // FIXME: Not working on sqlite due to https://www.sqlite.org/draft/pragma.html#pragma_case_sensitive_like
 | 
			
		||||
    // describe('Filter contains sensitive', () => {
 | 
			
		||||
    //   test.skip('Should return empty if the case does not match', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    describe('Filter contains sensitive', () => {
 | 
			
		||||
      test.skip('Should return empty if the case does not match', async () => {
 | 
			
		||||
        const res = await rq({
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: {
 | 
			
		||||
                $contains: 'product',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    //         name_containss: 'product',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
        expect(res.body).toEqual([]);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual([]);
 | 
			
		||||
    //   });
 | 
			
		||||
      test('Should return the entities if the case matches', async () => {
 | 
			
		||||
        const res = await rq({
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: {
 | 
			
		||||
                $contains: 'Product',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    //   test('Should return the entities if the case matches', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
        expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //         name_containss: 'Product',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    // FIXME: Not working on sqlite due to https://www.sqlite.org/draft/pragma.html#pragma_case_sensitive_like
 | 
			
		||||
    describe('Filter not contains sensitive', () => {
 | 
			
		||||
      test.skip('Should return the entities if the case does not match', async () => {
 | 
			
		||||
        const res = await rq({
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: {
 | 
			
		||||
                $contains: 'product',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
    // });
 | 
			
		||||
        expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    // // FIXME: Not working on sqlite due to https://www.sqlite.org/draft/pragma.html#pragma_case_sensitive_like
 | 
			
		||||
    // describe('Filter not contains sensitive', () => {
 | 
			
		||||
    //   test.skip('Should return the entities if the case does not match', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
      test('Should return an empty array if the case matches', async () => {
 | 
			
		||||
        const res = await rq({
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
          url: '/products',
 | 
			
		||||
          qs: {
 | 
			
		||||
            filters: {
 | 
			
		||||
              name: {
 | 
			
		||||
                $notContains: 'Product',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    //         name_ncontainss: 'product',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
 | 
			
		||||
    //   test('Should return an empty array if the case matches', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
 | 
			
		||||
    //         name_ncontainss: 'Product',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual([]);
 | 
			
		||||
    //   });
 | 
			
		||||
    // });
 | 
			
		||||
        expect(res.body).toEqual([]);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('Filter in', () => {
 | 
			
		||||
      test('Should return the Product with a single value', async () => {
 | 
			
		||||
@ -919,11 +929,7 @@ describe('Filtering API', () => {
 | 
			
		||||
                    price: { $gt: 28 },
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    $or: [
 | 
			
		||||
                      {
 | 
			
		||||
                        rank: 91,
 | 
			
		||||
                      },
 | 
			
		||||
                    ],
 | 
			
		||||
                    $or: [{ rank: 91 }],
 | 
			
		||||
                  },
 | 
			
		||||
                ],
 | 
			
		||||
              ],
 | 
			
		||||
@ -934,7 +940,9 @@ describe('Filtering API', () => {
 | 
			
		||||
        expect(res.body).toEqual(expect.arrayContaining([data.product[0], data.product[2]]));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('Implict or', () => {
 | 
			
		||||
    test('Filter equals', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
@ -963,365 +971,388 @@ describe('Filtering API', () => {
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // test('Filter contains insensitive', async () => {
 | 
			
		||||
    //   const res = await rq({
 | 
			
		||||
    //     method: 'GET',
 | 
			
		||||
    //     url: '/products',
 | 
			
		||||
    //     qs: {
 | 
			
		||||
    //       filters: {
 | 
			
		||||
    //         name_contains: ['Product', '1'],
 | 
			
		||||
    //       },
 | 
			
		||||
    //     },
 | 
			
		||||
    //   });
 | 
			
		||||
    test.skip('Filter contains insensitive', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $contains: ['Product', '1'],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //   expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // test('Filter not contains insensitive', async () => {
 | 
			
		||||
    //   const res = await rq({
 | 
			
		||||
    //     method: 'GET',
 | 
			
		||||
    //     url: '/products',
 | 
			
		||||
    //     qs: {
 | 
			
		||||
    //       filters: {
 | 
			
		||||
    //         name_ncontains: ['Product', 'Non existent'],
 | 
			
		||||
    //       },
 | 
			
		||||
    //     },
 | 
			
		||||
    //   });
 | 
			
		||||
    test.skip('Filter not contains insensitive', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $notContains: ['Product', 'Non existent'],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //   expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // test('Filter contains sensitive', async () => {
 | 
			
		||||
    //   const res = await rq({
 | 
			
		||||
    //     method: 'GET',
 | 
			
		||||
    //     url: '/products',
 | 
			
		||||
    //     qs: {
 | 
			
		||||
    //       filters: {
 | 
			
		||||
    //         name_containss: ['Product', 'Non existent'],
 | 
			
		||||
    //       },
 | 
			
		||||
    //     },
 | 
			
		||||
    //   });
 | 
			
		||||
    test('Filter contains sensitive', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $contains: ['Product', 'Non existent'],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //   expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // test('Filter not contains sensitive', async () => {
 | 
			
		||||
    //   const res = await rq({
 | 
			
		||||
    //     method: 'GET',
 | 
			
		||||
    //     url: '/products',
 | 
			
		||||
    //     qs: {
 | 
			
		||||
    //       filters: {
 | 
			
		||||
    //         name_ncontainss: ['product', 'Non existent'],
 | 
			
		||||
    //       },
 | 
			
		||||
    //     },
 | 
			
		||||
    //   });
 | 
			
		||||
    test('Filter not contains sensitive', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $notContains: ['product', 'Non existent'],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //   expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Filter greater than', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_gt: [12, 56],
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Filter greater than', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: { $gt: [12, 56] },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Filter greater than or equal', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_gte: [42, 56],
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Filter greater than or equal', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: {
 | 
			
		||||
              $gte: [42, 56],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Filter less than', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_lt: [56, 12],
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Filter less than', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: { $lt: [56, 12] },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Filter less than or equal', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_lte: [12, 42],
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Filter less than or equal', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: { $lte: [12, 42] },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
    // describe('Complexe filtering', () => {
 | 
			
		||||
    //   test('Greater than and less than at the same time', async () => {
 | 
			
		||||
    //     let res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_lte: 42,
 | 
			
		||||
    //           rank_gte: 42,
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
  describe('Complexe filtering', () => {
 | 
			
		||||
    test('Greater than and less than at the same time', async () => {
 | 
			
		||||
      let res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: {
 | 
			
		||||
              $lte: 42,
 | 
			
		||||
              $gte: 42,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
 | 
			
		||||
    //     res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_lt: 43,
 | 
			
		||||
    //           rank_gt: 41,
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
      res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: {
 | 
			
		||||
              $lt: 43,
 | 
			
		||||
              $gt: 41,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
 | 
			
		||||
    //     res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           rank_lt: 43,
 | 
			
		||||
    //           rank_gt: 431,
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
      res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            rank: { $lt: 43, $gt: 431 },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual([]);
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual([]);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Contains and Not contains on same column', async () => {
 | 
			
		||||
    //     let res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           name_contains: 'Product',
 | 
			
		||||
    //           name_ncontains: '1',
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Contains and Not contains on same column', async () => {
 | 
			
		||||
      let res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $contains: 'Product',
 | 
			
		||||
              $notContains: '1',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining(data.product.slice(1)));
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining(data.product.slice(1)));
 | 
			
		||||
 | 
			
		||||
    //     res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           name_contains: 'Product 1',
 | 
			
		||||
    //           name_ncontains: ['2', '3'],
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
      res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $contains: 'Product 1',
 | 
			
		||||
              $notContains: ['2', '3'],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.not.arrayContaining([data.product[1], data.product[2]]));
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
      expect(res.body).toEqual(expect.not.arrayContaining([data.product[1], data.product[2]]));
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
 | 
			
		||||
    //     res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           name_contains: '2',
 | 
			
		||||
    //           name_ncontains: 'Product',
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
      res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $contains: '2',
 | 
			
		||||
              $notContains: 'Product',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual([]);
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual([]);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Combined filters', async () => {
 | 
			
		||||
    //     let res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         filters: {
 | 
			
		||||
    //           name_contains: 'Product',
 | 
			
		||||
    //           rank_lt: 45,
 | 
			
		||||
    //         },
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Combined filters', async () => {
 | 
			
		||||
      let res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          filters: {
 | 
			
		||||
            name: {
 | 
			
		||||
              $contains: 'Product',
 | 
			
		||||
            },
 | 
			
		||||
            rank: {
 | 
			
		||||
              $lt: 45,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
    // describe('Sorting', () => {
 | 
			
		||||
    //   test('Default sorting is asc', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _sort: 'rank',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
  describe('Sorting', () => {
 | 
			
		||||
    test('Default sorting is asc', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          sort: 'rank',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(
 | 
			
		||||
    //       expect.arrayContaining(data.product.slice(0).sort((a, b) => a.rank - b.rank))
 | 
			
		||||
    //     );
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(
 | 
			
		||||
        expect.arrayContaining(data.product.slice(0).sort((a, b) => a.rank - b.rank))
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Simple sorting', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _sort: 'rank:asc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Simple sorting', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          sort: 'rank:asc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(
 | 
			
		||||
    //       expect.arrayContaining(data.product.slice(0).sort((a, b) => a.rank - b.rank))
 | 
			
		||||
    //     );
 | 
			
		||||
      expect(res.body).toEqual(
 | 
			
		||||
        expect.arrayContaining(data.product.slice(0).sort((a, b) => a.rank - b.rank))
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    //     const res2 = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _sort: 'rank:desc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
      const res2 = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          sort: 'rank:desc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res2.body).toEqual(
 | 
			
		||||
    //       expect.arrayContaining(data.product.slice(0).sort((a, b) => b.rank - a.rank))
 | 
			
		||||
    //     );
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res2.body).toEqual(
 | 
			
		||||
        expect.arrayContaining(data.product.slice(0).sort((a, b) => b.rank - a.rank))
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Multi column sorting', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _sort: 'price:asc,rank:desc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Multi column sorting', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          sort: 'price:asc,rank:desc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     [data.product[3], data.product[0], data.product[2], data.product[1]].forEach(expectedPost => {
 | 
			
		||||
    //       expect(res.body).toEqual(expect.arrayContaining([expectedPost]));
 | 
			
		||||
    //     });
 | 
			
		||||
    //   });
 | 
			
		||||
    // });
 | 
			
		||||
      [data.product[3], data.product[0], data.product[2], data.product[1]].forEach(expectedPost => {
 | 
			
		||||
        expect(res.body).toEqual(expect.arrayContaining([expectedPost]));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
    // describe('Limit and offset', () => {
 | 
			
		||||
    //   test('Limit', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _limit: 1,
 | 
			
		||||
    //         _sort: 'rank:asc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
  describe('Limit and offset', () => {
 | 
			
		||||
    test('Limit', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          limit: 1,
 | 
			
		||||
          sort: 'rank:asc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Limit with sorting', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _limit: 1,
 | 
			
		||||
    //         _sort: 'rank:desc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Limit with sorting', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          limit: 1,
 | 
			
		||||
          sort: 'rank:desc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[data.product.length - 1]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[data.product.length - 1]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Offset', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _start: 1,
 | 
			
		||||
    //         _sort: 'rank:asc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Offset', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          start: 1,
 | 
			
		||||
          sort: 'rank:asc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining(data.product.slice(1)));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining(data.product.slice(1)));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Offset with limit', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _limit: 1,
 | 
			
		||||
    //         _start: 1,
 | 
			
		||||
    //         _sort: 'rank:asc',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Offset with limit', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          limit: 1,
 | 
			
		||||
          start: 1,
 | 
			
		||||
          sort: 'rank:asc',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining(data.product.slice(1, 2)));
 | 
			
		||||
    //   });
 | 
			
		||||
    // });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining(data.product.slice(1, 2)));
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
    // describe('Text query', () => {
 | 
			
		||||
    //   test('Cyrillic query', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _q: 'Опис',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
  describe.skip('Text query', () => {
 | 
			
		||||
    test('Cyrillic query', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          _q: 'Опис',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[4]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[4]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Multi word query', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _q: 'Product description',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Multi word query', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          _q: 'Product description',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[0]]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //   test('Multi word cyrillic query', async () => {
 | 
			
		||||
    //     const res = await rq({
 | 
			
		||||
    //       method: 'GET',
 | 
			
		||||
    //       url: '/products',
 | 
			
		||||
    //       qs: {
 | 
			
		||||
    //         _q: 'Опис на продукт',
 | 
			
		||||
    //       },
 | 
			
		||||
    //     });
 | 
			
		||||
    test('Multi word cyrillic query', async () => {
 | 
			
		||||
      const res = await rq({
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        url: '/products',
 | 
			
		||||
        qs: {
 | 
			
		||||
          _q: 'Опис на продукт',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    //     expect(res.body).toEqual(expect.arrayContaining([data.product[4]]));
 | 
			
		||||
    //   });
 | 
			
		||||
      expect(res.body).toEqual(expect.arrayContaining([data.product[4]]));
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -93,6 +93,8 @@ const convertSortQueryParams = sortQuery => {
 | 
			
		||||
    throw new Error(`convertSortQueryParams expected a string, got ${typeof sortQuery}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: handle array input
 | 
			
		||||
 | 
			
		||||
  const sortKeys = [];
 | 
			
		||||
 | 
			
		||||
  sortQuery.split(',').forEach(part => {
 | 
			
		||||
@ -107,12 +109,10 @@ const convertSortQueryParams = sortQuery => {
 | 
			
		||||
      throw new Error('order can only be one of asc|desc|ASC|DESC');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sortKeys.push({ field, order: order.toLowerCase() });
 | 
			
		||||
    sortKeys.push({ [field]: order.toLowerCase() });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    sort: sortKeys,
 | 
			
		||||
  };
 | 
			
		||||
  return sortKeys;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -126,9 +126,7 @@ const convertStartQueryParams = startQuery => {
 | 
			
		||||
    throw new Error(`convertStartQueryParams expected a positive integer got ${startAsANumber}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    start: startAsANumber,
 | 
			
		||||
  };
 | 
			
		||||
  return startAsANumber;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -142,9 +140,7 @@ const convertLimitQueryParams = limitQuery => {
 | 
			
		||||
    throw new Error(`convertLimitQueryParams expected a positive integer got ${limitAsANumber}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    limit: limitAsANumber,
 | 
			
		||||
  };
 | 
			
		||||
  return limitAsANumber;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -239,6 +235,9 @@ const convertWhereClause = (whereClause, value) => {
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  convertRestQueryParams,
 | 
			
		||||
  convertSortQueryParams,
 | 
			
		||||
  convertStartQueryParams,
 | 
			
		||||
  convertLimitQueryParams,
 | 
			
		||||
  VALID_REST_OPERATORS,
 | 
			
		||||
  QUERY_OPERATORS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,10 @@
 | 
			
		||||
const path = require('path');
 | 
			
		||||
 | 
			
		||||
module.exports = ({ env }) => ({
 | 
			
		||||
  connection: {
 | 
			
		||||
    client: 'sqlite',
 | 
			
		||||
    connection: {
 | 
			
		||||
      filename: env('DATABASE_FILENAME', '<%= connection.filename %>'),
 | 
			
		||||
      filename: path.join(__dirname, '..', env('DATABASE_FILENAME', '<%= connection.filename %>')),
 | 
			
		||||
    },
 | 
			
		||||
    useNullAsDefault: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ const createTestBuilder = (options = {}) => {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    sanitizedFixturesFor(modelName, strapi) {
 | 
			
		||||
      const model = strapi.getModel(modelName);
 | 
			
		||||
      const model = strapi.getModel(`application::${modelName}.${modelName}`);
 | 
			
		||||
      const fixtures = this.fixturesFor(modelName);
 | 
			
		||||
 | 
			
		||||
      return sanitizeEntity(fixtures, { model });
 | 
			
		||||
@ -77,7 +77,7 @@ const createTestBuilder = (options = {}) => {
 | 
			
		||||
 | 
			
		||||
      if (enableTestDataAutoCleanup) {
 | 
			
		||||
        for (const model of models.reverse()) {
 | 
			
		||||
          await modelsUtils.cleanupModel(model.uid || model.modelName);
 | 
			
		||||
          await modelsUtils.cleanupModel(model.modelName);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -122,7 +122,7 @@ const deleteContentTypes = async (modelsName, { strapi } = {}) => {
 | 
			
		||||
 | 
			
		||||
async function cleanupModels(models, { strapi } = {}) {
 | 
			
		||||
  for (const model of models) {
 | 
			
		||||
    await cleanupModel(`application::${model}.${model}`, { strapi });
 | 
			
		||||
    await cleanupModel(model, { strapi });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user