mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 10:55:37 +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