mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
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:
commit
872e7317ca
@ -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: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
17
packages/core/content-manager/services/entity-manager.d.ts
vendored
Normal file
17
packages/core/content-manager/services/entity-manager.d.ts
vendored
Normal 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;
|
||||
@ -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);
|
||||
}),
|
||||
});
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
},
|
||||
};
|
||||
|
||||
@ -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));
|
||||
},
|
||||
};
|
||||
|
||||
@ -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);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
40
packages/core/strapi/lib/index.d.ts
vendored
40
packages/core/strapi/lib/index.d.ts
vendored
@ -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;
|
||||
|
||||
@ -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');
|
||||
91
packages/core/strapi/lib/services/entity-service/index.d.ts
vendored
Normal file
91
packages/core/strapi/lib/services/entity-service/index.d.ts
vendored
Normal 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;
|
||||
@ -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);
|
||||
},
|
||||
|
||||
@ -22,8 +22,8 @@ const transformParamsToQuery = (uid, params = {}) => {
|
||||
const query = {};
|
||||
|
||||
const {
|
||||
start,
|
||||
page,
|
||||
start,
|
||||
pageSize,
|
||||
limit,
|
||||
sort,
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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' }] } });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user