Merge pull request #11031 from strapi/v4/entity-service-refactor

Refacto entity service API to be more consistent with the DB layer
This commit is contained in:
Alexandre BODIN 2021-09-22 14:33:39 +02:00 committed by GitHub
commit 872e7317ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 244 additions and 167 deletions

View File

@ -36,9 +36,8 @@ describe('Content-Manager', () => {
expect(strapi.entityService.update).toBeCalledWith(uid, entity.id, {
data: { published_at: expect.any(Date) },
params: {
populate: {},
},
populate: {},
});
});
});
@ -66,9 +65,8 @@ describe('Content-Manager', () => {
expect(strapi.entityService.update).toHaveBeenCalledWith(uid, entity.id, {
data: { published_at: null },
params: {
populate: {},
},
populate: {},
});
});
});

View File

@ -0,0 +1,17 @@
interface EntityManager {
assocCreatorRoles(): any;
find(): any;
findPage(): any;
findWithRelationCounts(): any;
count(): any;
findOne(): any;
findOneWithCreatorRoles(): any;
create(): any;
update(): any;
delete(): any;
deleteMany(): any;
publish(): any;
unpublish(): any;
}
export default function(opts: { strapi: Strapi }): EntityManager;

View File

@ -10,7 +10,7 @@ const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = strapiUtils.webhook.webhookEvents;
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
const emitEvent = (event, fn) => async (entity, model) => {
const wrapWithEmitEvent = (event, fn) => async (entity, model) => {
const result = await fn(entity, model);
const modelDef = strapi.getModel(model);
@ -92,6 +92,9 @@ const getBasePopulate = (uid, populate) => {
});
};
/**
* @type {import('./entity-manager').default}
*/
module.exports = ({ strapi }) => ({
async assocCreatorRoles(entity) {
if (!entity) {
@ -105,31 +108,31 @@ module.exports = ({ strapi }) => ({
find(opts, uid, populate) {
const params = { ...opts, populate: getDeepPopulate(uid, populate) };
return strapi.entityService.find(uid, { params });
return strapi.entityService.findMany(uid, params);
},
findPage(opts, uid, populate) {
const params = { ...opts, populate: getBasePopulate(uid, populate) };
return strapi.entityService.findPage(uid, { params });
return strapi.entityService.findPage(uid, params);
},
findWithRelationCounts(opts, uid, populate) {
const params = { ...opts, populate: getBasePopulate(uid, populate) };
return strapi.entityService.findWithRelationCounts(uid, { params });
return strapi.entityService.findWithRelationCounts(uid, params);
},
count(opts, uid) {
const params = { ...opts };
return strapi.entityService.count(uid, { params });
return strapi.entityService.count(uid, params);
},
async findOne(id, uid, populate) {
const params = { populate: getDeepPopulate(uid, populate) };
return strapi.entityService.findOne(uid, id, { params });
return strapi.entityService.findOne(uid, id, params);
},
async findOneWithCreatorRoles(id, uid, populate) {
@ -150,33 +153,33 @@ module.exports = ({ strapi }) => ({
publishData[PUBLISHED_AT_ATTRIBUTE] = null;
}
const params = { populate: getDeepPopulate(uid) };
const params = { data: publishData, populate: getDeepPopulate(uid) };
return strapi.entityService.create(uid, { params, data: publishData });
return strapi.entityService.create(uid, params);
},
update(entity, body, uid) {
const publishData = omitPublishedAtField(body);
const params = { populate: getDeepPopulate(uid) };
const params = { data: publishData, populate: getDeepPopulate(uid) };
return strapi.entityService.update(uid, entity.id, { params, data: publishData });
return strapi.entityService.update(uid, entity.id, params);
},
delete(entity, uid) {
const params = { populate: getDeepPopulate(uid) };
return strapi.entityService.delete(uid, entity.id, { params });
return strapi.entityService.delete(uid, entity.id, params);
},
// FIXME: handle relations
deleteMany(opts, uid) {
const params = { ...opts };
return strapi.entityService.deleteMany(uid, { params });
return strapi.entityService.deleteMany(uid, params);
},
publish: emitEvent(ENTRY_PUBLISH, async (entity, uid) => {
publish: wrapWithEmitEvent(ENTRY_PUBLISH, async (entity, uid) => {
if (entity[PUBLISHED_AT_ATTRIBUTE]) {
throw strapi.errors.badRequest('already.published');
}
@ -186,20 +189,20 @@ module.exports = ({ strapi }) => ({
const data = { [PUBLISHED_AT_ATTRIBUTE]: new Date() };
const params = { populate: getDeepPopulate(uid) };
const params = { data, populate: getDeepPopulate(uid) };
return strapi.entityService.update(uid, entity.id, { params, data });
return strapi.entityService.update(uid, entity.id, params);
}),
unpublish: emitEvent(ENTRY_UNPUBLISH, (entity, uid) => {
unpublish: wrapWithEmitEvent(ENTRY_UNPUBLISH, (entity, uid) => {
if (!entity[PUBLISHED_AT_ATTRIBUTE]) {
throw strapi.errors.badRequest('already.draft');
}
const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
const params = { populate: getDeepPopulate(uid) };
const params = { data, populate: getDeepPopulate(uid) };
return strapi.entityService.update(uid, entity.id, { params, data });
return strapi.entityService.update(uid, entity.id, params);
}),
});

View File

@ -63,7 +63,7 @@ describe('Default Service', () => {
test('Creates data when no entity is found', async () => {
const strapi = {
entityService: {
find: jest.fn(() => Promise.resolve(null)),
findMany: jest.fn(() => Promise.resolve(null)),
create: jest.fn(() => Promise.resolve({ id: 1 })),
},
query() {
@ -81,8 +81,8 @@ describe('Default Service', () => {
const input = {};
await service.createOrUpdate(input);
expect(strapi.entityService.find).toHaveBeenCalledWith('testModel', {
params: { publicationState: 'live' },
expect(strapi.entityService.findMany).toHaveBeenCalledWith('testModel', {
publicationState: 'live',
});
expect(strapi.entityService.create).toHaveBeenCalledWith('testModel', { data: input });
@ -91,7 +91,7 @@ describe('Default Service', () => {
test('Updates data when entity is found', async () => {
const strapi = {
entityService: {
find: jest.fn(() => Promise.resolve({ id: 1 })),
findMany: jest.fn(() => Promise.resolve({ id: 1 })),
update: jest.fn(() => Promise.resolve({ id: 1 })),
},
query() {
@ -109,9 +109,9 @@ describe('Default Service', () => {
const input = {};
await service.createOrUpdate(input);
expect(strapi.entityService.find).toHaveBeenCalledWith('testModel', {
expect(strapi.entityService.findMany).toHaveBeenCalledWith('testModel', {
populate: undefined,
params: { publicationState: 'live' },
publicationState: 'live',
});
expect(strapi.entityService.update).toHaveBeenCalledWith('testModel', 1, {
@ -122,7 +122,7 @@ describe('Default Service', () => {
test('Delete data when entity is found', async () => {
const strapi = {
entityService: {
find: jest.fn(() => Promise.resolve({ id: 1 })),
findMany: jest.fn(() => Promise.resolve({ id: 1 })),
delete: jest.fn(() => Promise.resolve({ id: 1 })),
},
};
@ -136,9 +136,9 @@ describe('Default Service', () => {
await service.delete();
expect(strapi.entityService.find).toHaveBeenCalledWith('testModel', {
expect(strapi.entityService.findMany).toHaveBeenCalledWith('testModel', {
populate: undefined,
params: { publicationState: 'live' },
publicationState: 'live',
});
expect(strapi.entityService.delete).toHaveBeenCalledWith('testModel', 1);

View File

@ -16,7 +16,7 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
async find(ctx) {
const { query } = ctx;
const { results, pagination } = await service.find({ params: query });
const { results, pagination } = await service.find(query);
return transformResponse(sanitize(results), { pagination });
},
@ -30,7 +30,7 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
const { id } = ctx.params;
const { query } = ctx;
const entity = await service.findOne(id, { params: query });
const entity = await service.findOne(id, query);
return transformResponse(sanitize(entity));
},
@ -45,7 +45,7 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
const { data, files } = parseBody(ctx);
const entity = await service.create({ params: query, data, files });
const entity = await service.create({ ...query, data, files });
return transformResponse(sanitize(entity));
},
@ -61,7 +61,7 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
const { data, files } = parseBody(ctx);
const entity = await service.update(id, { params: query, data, files });
const entity = await service.update(id, { ...query, data, files });
return transformResponse(sanitize(entity));
},
@ -75,7 +75,7 @@ const createCollectionTypeController = ({ service, sanitize, transformResponse }
const { id } = ctx.params;
const { query } = ctx;
const entity = await service.delete(id, { params: query });
const entity = await service.delete(id, query);
return transformResponse(sanitize(entity));
},
};

View File

@ -14,7 +14,7 @@ const createSingleTypeController = ({ service, sanitize, transformResponse }) =>
*/
async find(ctx) {
const { query } = ctx;
const entity = await service.find({ params: query });
const entity = await service.find(query);
return transformResponse(sanitize(entity));
},
@ -27,7 +27,7 @@ const createSingleTypeController = ({ service, sanitize, transformResponse }) =>
const { query } = ctx.request;
const { data, files } = parseBody(ctx);
const entity = await service.createOrUpdate({ params: query, data, files });
const entity = await service.createOrUpdate({ ...query, data, files });
return transformResponse(sanitize(entity));
},
@ -35,7 +35,7 @@ const createSingleTypeController = ({ service, sanitize, transformResponse }) =>
async delete(ctx) {
const { query } = ctx;
const entity = await service.delete({ params: query });
const entity = await service.delete(query);
return transformResponse(sanitize(entity));
},
};

View File

@ -28,19 +28,18 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
const { sanitizeInput, getFetchParams } = utils;
return {
async find(opts = {}) {
const params = getFetchParams(opts.params);
async find(params = {}) {
const fetchParams = getFetchParams(params);
const paginationInfo = getPaginationInfo(params);
const paginationInfo = getPaginationInfo(fetchParams);
const results = await strapi.entityService.find(uid, {
params: { ...params, ...convertPagedToStartLimit(paginationInfo) },
const results = await strapi.entityService.findMany(uid, {
...fetchParams,
...convertPagedToStartLimit(paginationInfo),
});
if (shouldCount(params)) {
const count = await strapi.entityService.count(uid, {
params: { ...params, ...paginationInfo },
});
if (shouldCount(fetchParams)) {
const count = await strapi.entityService.count(uid, { ...fetchParams, ...paginationInfo });
return {
results,
@ -54,30 +53,30 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
};
},
findOne(entityId, opts = {}) {
const params = getFetchParams(opts.params);
return strapi.entityService.findOne(uid, entityId, { params });
findOne(entityId, params = {}) {
return strapi.entityService.findOne(uid, entityId, getFetchParams(params));
},
create({ params, data, files } = {}) {
create(params = {}) {
const { data } = params;
const sanitizedData = sanitizeInput(data);
if (hasDraftAndPublish(model)) {
setPublishedAt(sanitizedData);
}
return strapi.entityService.create(uid, { params, data: sanitizedData, files });
return strapi.entityService.create(uid, { ...params, data: sanitizedData });
},
update(entityId, { params, data, files } = {}) {
update(entityId, params = {}) {
const { data } = params;
const sanitizedData = sanitizeInput(data);
return strapi.entityService.update(uid, entityId, { params, data: sanitizedData, files });
return strapi.entityService.update(uid, entityId, { ...params, data: sanitizedData });
},
delete(entityId, { params } = {}) {
return strapi.entityService.delete(uid, entityId, { params });
delete(entityId, params = {}) {
return strapi.entityService.delete(uid, entityId, params);
},
};
};

View File

@ -13,9 +13,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
*
* @return {Promise}
*/
find({ params } = {}) {
const normalizedParams = getFetchParams(params);
return strapi.entityService.find(uid, { params: normalizedParams });
find(params = {}) {
return strapi.entityService.findMany(uid, getFetchParams(params));
},
/**
@ -23,9 +22,10 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
*
* @return {Promise}
*/
async createOrUpdate({ params, data, files } = {}) {
const entity = await this.find({ params });
async createOrUpdate(params = {}) {
const entity = await this.find(params);
const { data } = params;
const sanitizedData = sanitizeInput(data);
if (!entity) {
@ -34,14 +34,10 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
throw strapi.errors.badRequest('singleType.alreadyExists');
}
return strapi.entityService.create(uid, { params, data: sanitizedData, files });
} else {
return strapi.entityService.update(uid, entity.id, {
params,
data: sanitizedData,
files,
});
return strapi.entityService.create(uid, { ...params, data: sanitizedData });
}
return strapi.entityService.update(uid, entity.id, { ...params, data: sanitizedData });
},
/**
@ -49,8 +45,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
*
* @return {Promise}
*/
async delete({ params } = {}) {
const entity = await this.find({ params });
async delete(params = {}) {
const entity = await this.find(params);
if (!entity) return;

View File

@ -1,40 +1,14 @@
import { Database } from '@strapi/database';
import { Strapi } from './Strapi';
import { EntityService } from './services/entity-service';
import { Strapi as StrapiClass } from './Strapi';
type ID = number | string;
interface Options<T> {
params: Params<T>;
}
interface Params<T> {
fields: (keyof T)[];
}
interface EntityService {
uploadFiles<T extends keyof AllTypes>(uid: T);
wrapOptions<T extends keyof AllTypes>(uid: T);
find<T extends keyof AllTypes>(uid: T): Promise<AllTypes[T][]>;
findPage<T extends keyof AllTypes>(uid: T): Promise<any>;
findWithRelationCounts<T extends keyof AllTypes>(uid: T): Promise<any>;
findOne<T extends keyof AllTypes>(
uid: T,
id: ID,
opts: Options<AllTypes[T]>
): Promise<AllTypes[T]>;
count<T extends keyof AllTypes>(uid: T): Promise<any>;
create<T extends keyof AllTypes>(uid: T): Promise<any>;
update<T extends keyof AllTypes>(uid: T): Promise<any>;
delete<T extends keyof AllTypes>(uid: T): Promise<any>;
}
interface StrapiInterface extends Strapi {
interface StrapiInterface extends StrapiClass {
query: Database['query'];
entityService: EntityService;
}
export type Strapi = StrapiInterface;
declare global {
interface AllTypes {}
}
@ -44,5 +18,9 @@ declare global {
strapi: StrapiInterface;
}
export type Strapi = StrapiInterface;
const strapi: StrapiInterface;
}
export default function(opts): Strapi;

View File

@ -1,8 +1,8 @@
'use strict';
const { EventEmitter } = require('events');
const createEntityService = require('../entity-service');
const entityValidator = require('../entity-validator');
const createEntityService = require('../');
const entityValidator = require('../../entity-validator');
describe('Entity service', () => {
global.strapi = {
@ -15,7 +15,7 @@ describe('Entity service', () => {
};
describe('Decorator', () => {
test.each(['create', 'update', 'find', 'findOne', 'delete', 'count', 'findPage'])(
test.each(['create', 'update', 'findMany', 'findOne', 'delete', 'count', 'findPage'])(
'Can decorate',
async method => {
const instance = createEntityService({
@ -65,7 +65,7 @@ describe('Entity service', () => {
eventHub: new EventEmitter(),
});
const result = await instance.find('test-model');
const result = await instance.findMany('test-model');
expect(fakeStrapi.getModel).toHaveBeenCalledTimes(1);
expect(fakeStrapi.getModel).toHaveBeenCalledWith('test-model');

View File

@ -0,0 +1,91 @@
import { Database } from '@strapi/database';
import { Strapi } from '../../';
type ID = number | string;
type EntityServiceAction =
| 'findMany'
| 'findPage'
| 'findWithRelationCounts'
| 'findOne'
| 'count'
| 'create'
| 'update'
| 'delete';
type PaginationInfo = {
page: number;
pageSize: number;
pageCount: number;
total: number;
};
type Params<T> = {
fields?: (keyof T)[];
filters?: any;
_q?: string;
populate?: any;
sort?: any;
start?: number;
limit?: number;
page?: number;
pageSize?: number;
publicationState?: string;
data?: any;
files?: any;
};
interface EntityService {
uploadFiles<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, entity, files);
wrapParams<K extends keyof AllTypes, T extends AllTypes[K]>(
params: Params<T>,
{ uid: K, action: EntityServiceAction }
);
findMany<K extends keyof AllTypes, T extends AllTypes[K]>(
uid: K,
params: Params<T>
): Promise<T[]>;
findPage<K extends keyof AllTypes, T extends AllTypes[K]>(
uid: K,
params: Params<T>
): Promise<{
results: T[];
pagination: PaginationInfo;
}>;
findWithRelationCounts<K extends keyof AllTypes, T extends AllTypes[K]>(
uid: K,
params: Params<T>
): Promise<{
results: T[];
pagination: PaginationInfo;
}>;
findOne<K extends keyof AllTypes, T extends AllTypes[K]>(
uid: K,
entityId: ID,
params: Params<T>
): Promise<T>;
count<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, params: Params<T>): Promise<any>;
create<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, params: Params<T>): Promise<any>;
update<K extends keyof AllTypes, T extends AllTypes[K]>(
uid: K,
entityId: ID,
params: Params<T>
): Promise<any>;
delete<K extends keyof AllTypes, T extends AllTypes[K]>(
uid: K,
entityId: ID,
params: Params<T>
): Promise<any>;
}
export default function(opts: {
strapi: Strapi;
db: Database;
// TODO: define types
eventHub: any;
entityValidator: any;
}): EntityService;

View File

@ -45,10 +45,13 @@ module.exports = ctx => {
return service;
};
/**
* @type {import('.').default}
*/
const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) => ({
uploadFiles,
async wrapOptions(options = {}) {
async wrapParams(options = {}) {
return options;
},
@ -61,13 +64,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
});
},
// TODO: rename to findMany
async find(uid, opts) {
async findMany(uid, opts) {
const { kind } = strapi.getModel(uid);
const { params } = await this.wrapOptions(opts, { uid, action: 'find' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
const query = transformParamsToQuery(uid, params);
const query = transformParamsToQuery(uid, wrappedParams);
if (kind === 'singleType') {
return db.query(uid).findOne(query);
@ -77,9 +79,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
},
async findPage(uid, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findPage' });
const query = transformParamsToQuery(uid, params);
const query = transformParamsToQuery(uid, wrappedParams);
return db.query(uid).findPage(query);
},
@ -88,9 +90,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
async findWithRelationCounts(uid, opts) {
const model = strapi.getModel(uid);
const { params } = await this.wrapOptions(opts, { uid, action: 'findWithRelationCounts' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findWithRelationCounts' });
const query = transformParamsToQuery(uid, params);
const query = transformParamsToQuery(uid, wrappedParams);
const { attributes } = model;
@ -121,23 +123,24 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
},
async findOne(uid, entityId, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'findOne' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findOne' });
const query = transformParamsToQuery(uid, pickSelectionParams(params));
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
return db.query(uid).findOne({ ...query, where: { id: entityId } });
},
async count(uid, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'count' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'count' });
const query = transformParamsToQuery(uid, params);
const query = transformParamsToQuery(uid, wrappedParams);
return db.query(uid).count(query);
},
async create(uid, opts) {
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'create' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'create' });
const { data, files } = wrappedParams;
const model = strapi.getModel(uid);
@ -145,7 +148,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
// select / populate
const query = transformParamsToQuery(uid, pickSelectionParams(params));
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
// TODO: wrap into transaction
const componentData = await createComponents(uid, validData);
@ -159,7 +162,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
// FIXME: upload in components
if (files && Object.keys(files).length > 0) {
await this.uploadFiles(uid, entity, files);
entity = await this.findOne(uid, entity.id, { params });
entity = await this.findOne(uid, entity.id, wrappedParams);
}
this.emitEvent(uid, ENTRY_CREATE, entity);
@ -168,7 +171,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
},
async update(uid, entityId, opts) {
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'update' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'update' });
const { data, files } = wrappedParams;
const model = strapi.getModel(uid);
@ -184,7 +188,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
isDraft,
});
const query = transformParamsToQuery(uid, pickSelectionParams(params));
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
// TODO: wrap in transaction
const componentData = await updateComponents(uid, entityToUpdate, validData);
@ -199,7 +203,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
// FIXME: upload in components
if (files && Object.keys(files).length > 0) {
await this.uploadFiles(uid, entity, files);
entity = await this.findOne(uid, entity.id, { params });
entity = await this.findOne(uid, entity.id, wrappedParams);
}
this.emitEvent(uid, ENTRY_UPDATE, entity);
@ -208,10 +212,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
},
async delete(uid, entityId, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
// select / populate
const query = transformParamsToQuery(uid, pickSelectionParams(params));
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
const entityToDelete = await db.query(uid).findOne({
...query,
@ -232,10 +236,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
// FIXME: used only for the CM to be removed
async deleteMany(uid, opts) {
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
// select / populate
const query = transformParamsToQuery(uid, params);
const query = transformParamsToQuery(uid, wrappedParams);
return db.query(uid).deleteMany(query);
},

View File

@ -22,8 +22,8 @@ const transformParamsToQuery = (uid, params = {}) => {
const query = {};
const {
start,
page,
start,
pageSize,
limit,
sort,

View File

@ -36,9 +36,7 @@ const validateLocaleCreation = async (ctx, next) => {
body.locale = entityLocale;
if (modelDef.kind === 'singleType') {
const entity = await strapi.entityService.find(modelDef.uid, {
params: { locale: entityLocale },
});
const entity = await strapi.entityService.findMany(modelDef.uid, { locale: entityLocale });
ctx.request.query.locale = body.locale;

View File

@ -65,54 +65,54 @@ describe('Entity service decorator', () => {
syncNonLocalizedAttributes.mockClear();
});
describe('wrapOptions', () => {
test('Calls original wrapOptions', async () => {
describe('wrapParams', () => {
test('Calls original wrapParams', async () => {
const defaultService = {
wrapOptions: jest.fn(() => Promise.resolve('li')),
wrapParams: jest.fn(() => Promise.resolve('li')),
};
const service = decorator(defaultService);
const input = { populate: ['test'] };
await service.wrapOptions(input, { uid: 'test-model' });
await service.wrapParams(input, { uid: 'test-model' });
expect(defaultService.wrapOptions).toHaveBeenCalledWith(input, { uid: 'test-model' });
expect(defaultService.wrapParams).toHaveBeenCalledWith(input, { uid: 'test-model' });
});
test('Does not wrap options if model is not localized', async () => {
const defaultService = {
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
wrapParams: jest.fn(opts => Promise.resolve(opts)),
};
const service = decorator(defaultService);
const input = { populate: ['test'] };
const output = await service.wrapOptions(input, { uid: 'non-localized-model' });
const output = await service.wrapParams(input, { uid: 'non-localized-model' });
expect(output).toStrictEqual(input);
});
test('does not change non params options', async () => {
const defaultService = {
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
wrapParams: jest.fn(opts => Promise.resolve(opts)),
};
const service = decorator(defaultService);
const input = { populate: ['test'] };
const output = await service.wrapOptions(input, { uid: 'test-model' });
const output = await service.wrapParams(input, { uid: 'test-model' });
expect(output.populate).toStrictEqual(input.populate);
});
test('Adds locale param', async () => {
const defaultService = {
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
wrapParams: jest.fn(opts => Promise.resolve(opts)),
};
const service = decorator(defaultService);
const input = { populate: ['test'] };
const output = await service.wrapOptions(input, { uid: 'test-model' });
const output = await service.wrapParams(input, { uid: 'test-model' });
expect(output).toMatchObject({ params: { filters: { $and: [{ locale: 'en' }] } } });
expect(output).toMatchObject({ filters: { $and: [{ locale: 'en' }] } });
});
const testData = [
@ -130,32 +130,30 @@ describe('Entity service decorator', () => {
"Doesn't add locale param when the params contain id or id_in - %s",
async (action, params) => {
const defaultService = {
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
wrapParams: jest.fn(opts => Promise.resolve(opts)),
};
const service = decorator(defaultService);
const input = Object.assign({ populate: ['test'], params });
const output = await service.wrapOptions(input, { uid: 'test-model', action });
const input = Object.assign({ populate: ['test'], ...params });
const output = await service.wrapParams(input, { uid: 'test-model', action });
expect(output).toEqual({ populate: ['test'], params });
expect(output).toEqual({ populate: ['test'], ...params });
}
);
test('Replaces _locale param', async () => {
const defaultService = {
wrapOptions: jest.fn(opts => Promise.resolve(opts)),
wrapParams: jest.fn(opts => Promise.resolve(opts)),
};
const service = decorator(defaultService);
const input = {
params: {
locale: 'fr',
},
locale: 'fr',
populate: ['test'],
};
const output = await service.wrapOptions(input, { uid: 'test-model' });
const output = await service.wrapParams(input, { uid: 'test-model' });
expect(output).toMatchObject({ params: { filters: { $and: [{ locale: 'fr' }] } } });
expect(output).toMatchObject({ filters: { $and: [{ locale: 'fr' }] } });
});
});

View File

@ -91,23 +91,18 @@ const decorator = service => ({
* @param {object} ctx - Query context
* @param {object} ctx.model - Model that is being used
*/
async wrapOptions(opts = {}, ctx = {}) {
const wrappedOptions = await service.wrapOptions.call(this, opts, ctx);
async wrapParams(params = {}, ctx = {}) {
const wrappedParams = await service.wrapParams.call(this, params, ctx);
const model = strapi.getModel(ctx.uid);
const { isLocalizedContentType } = getService('content-types');
if (!isLocalizedContentType(model)) {
return wrappedOptions;
return wrappedParams;
}
const { params } = opts;
return {
...wrappedOptions,
params: await wrapParams(params, ctx),
};
return wrapParams(params, ctx);
},
/**